macOS 10.15 "Catalina" will require app notarization by default. This is required regardless of whether you're distributing it via the app store or independently.

If this process is not followed, you may end up with a warning that your app is from an "unidentified developer" even if you've signed the application with a key from Apple.

This process is relatively straightforward if you use xcode, but if you build an application bundle with Qt (qmake, cmake or Qbs) or any other platform which doesn't use xcode, this can be somewhat tricky. Luckily this is a pretty straight forward, quick and easy to automate process.

The steps you'll need to follow to notarize your applications are:

  • Build your app with a hardened runtime
  • Submit the app for notarization
  • Staple the notarization ticket apple approves the application

Before you begin, you need to:

  • Have the Qt SDK set up
  • Have a code signing certificate installed (you should be able to see it when you run security find-identity -v -p codesigning )
  • Have xcode 10 installed
  • Create an app specific password in your Apple ID site

Let's create an example basic Qt project with Qt Creator:

Step 1: Build and prepare for release

Once you run the build process with your tool of choice, you should have a .app bundle. Run macdeployqt to copy the Qt framework files.

You need to run codesign to sign the app binary. You need to pass --options=runtime. This is what it means to "Enable a hardened runtime" which doesn't involve anything at the compilation step. Be sure to include the right key name.

Next you need to prepare a zip file. Use ditto to create a zip file which we will upload to apple.

$ cd path/to/build
$ macdeployqt "example_app.app"
$ codesign -s "<Key Name>" --options "runtime" "example_app.app/" 
$ ditto -ck --rsrc --sequesterRsrc "example_app.app" "example_app.zip"

Step 2: Upload the app to Apple

You'll  first need to find the bundle identifier by checking example_app.app/Contents/Info.plist. The default value of com.yourcompany.example-app is used in this case.

You'll need to provide your apple ID and app specific password that you should have set up. There are better ways of handling the username and password by using the keychain as described in this article but for the purposes of this tutorial, we can enter the app specific password.

$ xcrun altool --notarize-app -t osx -f example_app.zip --primary-bundle-id="com.yourcompany.example-app" -u "your_apple_id@example.com" -p "<app specific password>"
2019-07-07 16:48:12.886 altool[60776:1120353] No errors uploading 'example_app.zip'.
RequestUUID = <your uuid>

Take note of the UUID returned by the tool. You can check the status whether it's passed/failed/in progress using this command. When it finishes you should see something like this:

$ xcrun altool --notarization-info <your uuid> -u "your_apple_id@example.com" -p "<app specific password>"
2019-07-07 16:51:43.066 altool[60849:1122341] No errors getting notarization info.

   RequestUUID: <hidden>
          Date: 2019-07-07 20:48:16 +0000
        Status: success
    LogFileURL: <hidden>
   Status Code: 0
Status Message: Package Approved

If there were any issues, you can view the Log file URL in your browser to see the details of what the issue was.

Step 3: Staple the notarization ticket

Now that you have notarized the application, you will still have to add a signature to your app bundle before distribution.

$ xcrun stapler staple "example_app.app"
Processing: /Users/you/app/example_app.app
Processing: /Users/you/app/example_app.app
The staple and validate action worked!

Now you can distribute the app as a zip file, or dmg. Please do not distribute the zip file you created earlier since it doesn't have the notarization ticket attached.