macOS App Sandbox Entitlements

An example of setting up a macOS App that needs access outside the App Sandbox environment.  If you are going to submit a desktop macOS app to the Apple App Store it needs to run in the App Sandbox, but any user files need to be save outside the App Sandbox.  This requires some macOS API calls, and that what this example is all about.

Jump to macOS App Sandbox page for details


FileStore SDK

A cross platform C++ code base for defined record storage with btree indexing.


The goal of the FileStore SDK is to provide the base classes upon which you build your final file and record definitions.  The SDK provides the file I/O operations and logging.


The compiled SDK is free to use.  Available for use under the LGPLv3 license.


Jump to Using FileStore SDK Page for more information.



Creating a Qt/QML application that uses the System Tray

Source code current not available.

So you want to build a Qt/QML application that puts an icon in the system tray and hides the icon on the taskbar when minimized.   This example will do just that.

Before you begin be aware that you'll need Qt 5.9.3.  I started with 5.9.1 but I found an issue with Qt's SystemTrayIcon class not giving the mouse context correctly.  It was fixed in Qt 5.9.3.

In short, I started by creating a basic Qt/QML application from their new project templates.  I created a QML file call SysTray that contains all necessary code to support the system tray icon functionality.  And you'll need to edit main.cpp and main.qml to wire it all up.

Things are briefly described here, please read the code to fully understand it.

In main.cpp you need to make sure you use QApplcation app(..).  Most likely you'll find QGuiApplciation app(..), remove it.  This has to be changed because QWidget functionality is needed to support the system tray icon.  I also added app.setWindowIcon(..) to give the application the same icon as the system tray.  Its not needed but it looks nice.

 QApplication app(argc, argv);
 app.setWindowIcon( QIcon(":/talk_icon.png") )

In the main.qml file I added the code to handle what happens when the application is minimized to the taskbar, see onVisibilityChanged, and I added code to activate the system tray icon, see SysTray.

onVisibilityChanged { .. }

SysTray { .. }

SysTray.qml is completely made up.  The initial code comes from QML's SystemTrayIcon  documentation.  Then modified to fit the example.

Since Qt's SysTrayIcon relies on some QWidget functionality so you'll need to add widgets to the project.   Add Qt += widgets to the project (.pro) file.

QT += widgets


How it works  


There are two parts.  There is the application hiding the taskbar icon and functionality behind the system tray icon. 

Hiding the application taskbar icon is relatively straight forward.  In the QML main application window I am monitoring the visibility state of the application, onVisibilityChanged.  'visibility' provides a property value of the current state.  When 'visibility' is 3, minimized state, the application has been minimize to the taskbar.  At that point you can call hide() and the application's icon will appear to disappear.

In the SysTray code there are two main parts, one that monitors when the mouse has clicked (ie activated) the system tray icon, onActivate, and the menu that may or may not appear at the system tray icon.  If you left click the system tray icon the application will be restored on the screen if not already there. 

If you right click the system tray icon the menu will pop up regardless of the state of the application's main window.  If the main window is hidden you can activated it.  In this example you can also close the application.  See the SystemTrayIcon documentation for more details.

Testing it from the start

Example Project: https://github.com/alscube/TestingFromTheStart

This is an example of Test Driven Development at compile time.

As you read this blog and look at the sample code you'll notice that I am believer in Test Driven Development.   Years ago I started a company that created testing software to do regression testing.  I did it because I do not enjoy testing and re-testing software, I think it is the death of any programmer. 

Now with all the test frameworks available every programmer should be involved with testing their software.  There should be no excuse.  There are handful of frameworks and I'm sure everyone is going to choose their preferred package.  I've used Google Test, CPP Unit, JUnit, and QTest.   They essentially work the same so moving from one to another shouldn't be too difficult.

Test driven development is great at keeping you focused on what you are delivering and it lets you know immediately if something is broken.  The unit tests created should be compact and run quickly.   If possible they should run almost every time you do a local build and they should definitely run each time you do a full build.

The example code linked above was created with Qt.  It uses QTest as the test framework.  The project builds a static library, a dynamic library and a main app.   The library code is essential tested at compile time, as soon as each library is built it is immediately tested.  If the test passes the next library is built, if the test fails all compiling stops. 

The build sequence is as follows; 

    Static library is built 
    Static library Test App is built and executed.  

    If the static library test passes ....

    Dynamic library is built 
    Dynamic library Test is built and executed

    If that dynamic library test passes ...

    Main Project is built and executed


The project layout is:

SUBDIRS =
    ./AddLibrary/AddLibrary.pro
        SUBDIRS = 
            ./AddLibrary/AddLibrary.pro
                TARGET = AddLibrary
            ./AddLibraryTest/AddLibraryTest.pro
                TARGET = AddLibraryTest
        
    ./SubLibrary/SubLibrary.pro
        SUBDIRS = 
            ./SubLibrary/Sublibrary.pro
                TARGET = SubLibrary
            ./SubLibraryTest/SubLibraryTest.pro
                TARGET = SubLibraryTest

    ./MainProject/MainProject.pro
        TARGET = MainProject


I chose the Qt environment because it makes the testing easy.  In the project file a command is added to execute the just built file.  So the static library test project looks like:

    TARGET = AddLibraryTest

    CONFIG += c++14
    CONFIG += console
    CONFIG += testcase

    QT -= gui
    QT += testlib

    INCLUDEPATH = ../AddLibrary

    HEADERS += \
        AddLibraryTest.h

    SOURCES += \
        AddLibraryTest.cpp \
        AddLibraryTestMain.cpp

    macx {
        DESTDIR = .
        CONFIG -= app_bundle
        LIBS += ../AddLibrary/libAddLibrary.a
    }

    QMAKE_POST_LINK = $$DESTDIR/$$TARGET


Its this last line that makes it all work:

    QMAKE_POST_LINK = $$DESTDIR/$$TARGET

The QMAKE_POST_LINK tells the build environment to execute what it is assigned to.  In my case the TARGET app is my unit test.  It immediately runs at the end of a the test code build.

If you watch the compiler output window you'll see the code being compiled, then you'll see the test output:

........ rms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk -mmacosx-version-min=10.14 -Wl,-rpath,@executable_path/../Frameworks -Wl,-rpath,/Users/user/Qt/6.2.3/6.2.3/macos/lib -o ./AddLibraryTest AddLibraryTest.o AddLibraryTestMain.o moc_AddLibraryTest.o   -F/Users/user/Qt/6.2.3/6.2.3/macos/lib ../AddLibrary/libAddLibrary.a -framework QtTest -framework Security -framework AppKit -framework ApplicationServices -framework Foundation -framework QtCore -framework DiskArbitration -framework IOKit   
./AddLibraryTest
********* Start testing of AddLibraryTest *********
Config: Using QtTest library 6.2.3, Qt 6.2.3 (x86_64-little_endian-lp64 shared (dynamic) release build; by Clang 13.0.0 (clang-1300.0.29.3) (Apple)), macos 12.6
PASS   : AddLibraryTest::initTestCase()
PASS   : AddLibraryTest::AddTenTest()
PASS   : AddLibraryTest::AddOneHundredTest()
PASS   : AddLibraryTest::cleanupTestCase()
Totals: 4 passed, 0 failed, 0 skipped, 0 blacklisted, 0ms
********* Finished testing of AddLibraryTest *********

(and more code being compiled)

......... table_path/../Frameworks -Wl,-rpath,/Users/user/Qt/6.2.3/6.2.3/macos/lib -o SubLibraryTest SubLibraryTest.o main.o moc_SubLibraryTest.o   -F/Users/user/Qt/6.2.3/6.2.3/macos/lib /Users/user/Workspace/Projects/AlsCube/TestingFromTheStart/build/SubLibrary/SubLibrary/libSubLibrary.dylib -framework QtTest -framework Security -framework AppKit -framework ApplicationServices -framework Foundation -framework QtCore -framework DiskArbitration -framework IOKit   
/Users/user/Workspace/Projects/AlsCube/TestingFromTheStart/build/SubLibrary/SubLibraryTest/SubLibraryTest
********* Start testing of SubLibraryTest *********
Config: Using QtTest library 6.2.3, Qt 6.2.3 (x86_64-little_endian-lp64 shared (dynamic) release build; by Clang 13.0.0 (clang-1300.0.29.3) (Apple)), macos 12.6
PASS   : SubLibraryTest::initTestCase()
PASS   : SubLibraryTest::SubTenTest()
PASS   : SubLibraryTest::SubOneHundredTest()
PASS   : SubLibraryTest::cleanupTestCase()
Totals: 4 passed, 0 failed, 0 skipped, 0 blacklisted, 0ms
********* Finished testing of SubLibraryTest *********

(then the main project)

........ utable_path/../Frameworks -Wl,-rpath,/Users/user/Qt/6.2.3/6.2.3/macos/lib -o MainProject main.o   -F/Users/user/Qt/6.2.3/6.2.3/macos/lib /Users/user/Workspace/Projects/AlsCube/TestingFromTheStart/build/MainProject/../AddLibrary/AddLibrary/libAddLibrary.a /Users/user/Workspace/Projects/AlsCube/TestingFromTheStart/build/MainProject/../SubLibrary/SubLibrary/libSubLibrary.dylib -framework QtCore -framework DiskArbitration -framework IOKit   
/Users/user/Workspace/Projects/AlsCube/TestingFromTheStart/build/MainProject/MainProject
MainProject add 50
MainProject sub 800


Another example is the FileStore SDK project.  You can download it from Github.  The sample project provided is the actual unit tests used to validate the FileStore I/O and record operations.   The FileStore library is built as a dynamic library, the test code is built and it validates the library.  There are four separate test files with a total of 93 tests.

If you have never done test driven development you'll need to get use to not writing a lot of production code up front.   The purists will tell you to write the test first then the code the test operates against.  The test code validates what you want to do and the production code is how you want to do it.   I still write the production code first, but only up to the point that it can do something useful, then I write the test.  Only when I have proven my general theory do I go back to the production code and start implementing the details and exception handling, and as I do each addition I go back and write the supporting test to prove the additional code.    If you end up doing this correctly you can achieve a very high level of code coverage.

When it comes to writing unit tests my approach is to write multiple unit tests per function to be tested, not a single unit test that tests all features and cases.  So you'll find that I have one or more positive tests, these test the function as it should work.  Then I'll have a series of negative tests, forcing it to fail.  If you find that your unit tests are becoming long, that may be a sign that you should break up the production code into smaller functions.

At first it will seam like you are writing a lot of extra code, but your code will function as expected and when a change comes a long and breaks things you immediately know it.