Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
How to notarize a Unity build for MacOs 10.15 Catalina

How to notarize a Unity build for macOs 10.15 Catalina

As of January 2020, all apps running on macOs 10.15 Catalina are required to be notarized. For Unity games distributed outside the Mac App Store, such as with Steam, the notarization process is done post build using a series of Xcode command line tools.

Prerequisites

  • a Mac that is compatible with macOs 10.15 Catalina :
    • MacBook (2015 or newer)
    • MacBook Air (2012 or newer)
    • MacBook Pro (2012 or newer)
    • Mac mini (2012 or newer)
    • iMac (2012 or newer)
    • iMac Pro (from 2017)
    • Mac Pro (2013 or newer)
  • macOs 10.15 Catalina installed
  • Xcode 11.0 installed
  • Apple developer account at https://developer.apple.com/
  • Apple Id account at https://appleid.apple.com

Developer ID Application certificate

This certificate will be used for code signing the build. If you don't already have one, you can create one in the account section of the Apple developer website https://developer.apple.com/account/resources/certificates/add

In the "Create a New Certificate" section, select to add a "Developer ID Application" certificate. After clicking continue, you should see further instructions about how you'll first need to create and upload a "Certificate Signing Request" using the Keychain Access app https://help.apple.com/developer-account/#/devbfa00fef7

After you've uploaded the Certificate Signing Request file, you should then be able to download the Developer Id Application certificate. Once downloaded, clicking on the file should add it to Keychain Access where you'll see it under the certificates section. It will be called something like "Developer ID Applicate : YourCompanyName (0123456789)"

Generated Password

To upload a build to Apple servers you'll need to use a "generated password". To create one, go to https://appleid.apple.com and then in the "Security" section click on "Generated Password..."

The password you generate will look similar to the format abcd-efgh-ijkl-mnop

Unity Build & Player Settings

  • In the Build Settings, target platform should be set to Mac OS
  • In Player Settings, use default settings and set a unique Bundle Identifier

Entitlements file

This is an xml file used to give executable permissions to the app when code signing. In particular, all apps need to have "Hardened Runtime" entitlements. Here are the minimum entitlements needed for a Unity build :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
	       <key>com.apple.security.cs.disable-library-validation</key>
	       <true/>
	       <key>com.apple.security.cs.disable-executable-page-protection</key>
	       <true/>
    </dict>
</plist>

Save this file as "YourGame.entitlements". Additional entitlements can be found at https://developer.apple.com/documentation/bundleresources/entitlements

Notarization

The following steps use the Terminal command line and assume your build and entitlements file are in the same directory.

Change all file permissions in the app

For the code signing to work in a later step, we need to change permissions for files within the app directory.

chmod -R a+xr "YourGame.app"

Code sign the app

Next, in the command line, we need to use the codesign tool on the permission changed files by using your Developer ID Application certificate (literally the name of the certificate in double quotes).

codesign --deep --force --verify --verbose --timestamp --options runtime --entitlements "YourGame.entitlements" --sign "Developer ID Application : YourCompanyName (0123456789)" "YourApp.app"

If successful, you should see a message similar to:

YourGame.app: signed app bundle with Mach-O thin (x86_64) [com.YourCompany.YourGame]

Create a zip

Once the code is signed, we need to compress the application into a zip file for uploading. You can do this in the command line.

zip -r "YourGame.zip" "YourGame.app"

Upload the zip to Apple's notarization service

Now that we have the compressed zip file, we'll want to upload it to the Apple servers for notarization using the xcrun altool in the command line. In order to do this, you'll need your Apple ID username (usually an email address), your Apple ID generated password (the one with the format abcd-efgh-ijkl-mnop) and your Apple Developer "Provider Short Name". Often the "Provider Short Name" is your Team ID (ten digit alphanumeric id), you can find in the membership section of your Apple developer account https://developer.apple.com/account/#/membership/

However, if your "Provider Short Name" is not the same as your Team ID, you can find it by running the following command:

xcrun iTMSTransporter -m provider -u YourAppleIDUsername -p abcd-efgh-ijkl-mnop

Also, you'll need your game's bundle id that you defined in Unity Player Settings. Usually the format for that is similar to com.YourCompany.YourGame

To upload the build to the notarization service, run the command:

xcrun altool --notarize-app --username YourAppleIDUsername --password abcd-efgh-ijkl-mnop --asc-provider ProviderShortName --primary-bundle-id com.YourCompany.YourGame --file YourGame.zip

If the upload was successful, you should see a message with a RequestUUID similar to:

No errors uploading 'YourGame.zip'.
RequestUUID = xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

From there, you will need to wait for the notarization service to process the upload. This can take anywhere from 1 minute to an hour or sometimes longer if the service is overloaded. When it's completed you'll get an email with the subject "Your Mac software was successfully notarized". Alternatively, you can ping the service for the current status of the upload using that RequestUUID by running the following command.

xcrun altool --notarization-info xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx --username YourAppleIDUsername --password abcd-efgh-ijkl-mnop --asc-provider YourAppleDeveloperTeamID

Staple the app

After notarization is completed, Apple creates a ticket that you need to "staple" to the app. To do that, we'll use the xcrun stapler tool.

xcrun stapler staple "YourGame.app"

If successful you should see the following message:

The staple and validate action worked!

Check notarization

After everything is completed we can use the spctl tool to check if the app is recognized as having the proper notarization.

spctl -a -v YourGame.app

If successful, you should see a message similar to:

YourGame.app: accepted
source=Notarized Developer ID

Now, whether or not the notarization was successful, if you try and open the app on your local machine, everything will appear to work fine. A good way to double check everything is actually working is to upload the notarized build to somewhere on the web (eg Google Drive), download it, and then see if the app opens properly. If working correctly, then all you should see is a small warning that you downloaded it from the web and then it should open normally.

@GiovanniFrigo

This comment has been minimized.

Copy link

GiovanniFrigo commented Jan 10, 2020

Thanks for the guide!
However, if your app needs network connectivity (i.e. steam login), it seems like <key>com.apple.security.app-sandbox</key> breaks it. I removed it and it works great!

@dpid

This comment has been minimized.

Copy link
Owner Author

dpid commented Jan 10, 2020

@GiovanniFrigo Glad it helped you out and thank you for the feedback. I went ahead an removed that key. It looks like the sandbox was more a Mac App Store dependency.

@GiovanniFrigo

This comment has been minimized.

Copy link

GiovanniFrigo commented Jan 13, 2020

Another observation after some tests: to make the steam overlay work in the notarized app (if your game is distributed through steam), it appears that the key <key>com.apple.security.cs.allow-dyld-environment-variables</key> needs to be set to true as well.

At the moment, the complete working configuration for me is this one:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
           <key>com.apple.security.network.client</key>
           <true/>
           <key>com.apple.security.cs.disable-library-validation</key>
           <true/>
           <key>com.apple.security.cs.disable-executable-page-protection</key>
           <true/>
           <key>com.apple.security.cs.allow-dyld-environment-variables</key>
           <true/>
    </dict>
</plist>

Please note that this may vary depending on the capabilities of your game. Our has Steam login, Steam overlay support, and needs to connect to the internet to allow online multiplayer matches.

@hallgrimgames

This comment has been minimized.

Copy link

hallgrimgames commented Mar 18, 2020

A tip for anyone having problems getting notarization to work despite code signing apparently working correctly. After a length search in various forums, the tip that got it working for me was to use /usr/bin/ditto -c -k --sequesterRsrc --keepParent "My App.app" "My App.zip" instead of the zip -r "YourGame.zip" "YourGame.app".

@virgilcwylie

This comment has been minimized.

Copy link

virgilcwylie commented Apr 15, 2020

Make sure to do -f instead of --files

@virgilcwylie

This comment has been minimized.

Copy link

virgilcwylie commented Apr 16, 2020

--files works too. My mistake.

@villemonkkonen

This comment has been minimized.

Copy link

villemonkkonen commented May 3, 2020

With the Steam library, in addition to codesigning the app, I also had to specifically codesign the libsteam_api.dylib. Otherwise the notarization would complain about invalid signature on that binary.

Also using zip command method broke the signature and notarization thought nothing had been signed. I tried using ditto, but for some reason it would always say "can't archive multiple sources". In the end I used the right click compress command from Finder, and that seemed to compress the signature successfully.

@JordanSchuetz

This comment has been minimized.

Copy link

JordanSchuetz commented May 21, 2020

This is an A+ developer guide. If you are trying to build your Mac application via Unity, THIS is the guide you've been looking for.

I do stress that you need the most recent OS and XCode installed to get this working at least on my end.

Thanks again @dpid

@tolosafan

This comment has been minimized.

Copy link

tolosafan commented May 25, 2020

Thanks a lot for your tutorial. You saved our week!
Anyway, if anyone faces this issue after the notarize step (xcrun altool ....) in the result log send by Apple (accessing with the URL found in the Apple's email):
Embedded entitlements are invalid: syntax error near line 1

We followed these steps in the Terminal, before signing the app:
plutil -convert xml1 <Project_Name.entitlements>
plutil -lint <Project_Name.entitlements>

And it works!
You can check the validity of the entitlement file by using:
codesign -d --entitlements :- <path to signed .app or command-line tool>
If the output of this command contains the text bplist00, the executable has a binary property list, which the notary service will reject with an error message like
"Embedded entitlements are invalid: syntax error near line 1"

@Pie-Lord

This comment has been minimized.

Copy link

Pie-Lord commented May 25, 2020

Hey, thanks for making this guide! I've never really used macs but I'm trying to export a mac version for my game. I've already run into a problem hahah. I'm at the "changing all file permissions" step and I keep getting this message from the terminal
chmod: sweet_resurrection.app: No such file or directory
My built game and entitlements file are both on the desktop, spelled the same way... does anyone know why I'd be having this issue? Again, mac noob here so any help is very appreciated :)
Untitled

@yudiz-mobilegames

This comment has been minimized.

Copy link

yudiz-mobilegames commented May 29, 2020

Really appreciate your effort!

I managed to get my app notarized but when I upload the pkg file to drive and download it from there. When I open the pkg file, It shows me a warning "myapp.pkg can’t be opened because Apple cannot check it for malicious software." Nothing happens and It does not open up the installer.

Has anyone faced this issue even after your app was notarized by Apple?

P.S. after a bit of google found that If you open the file by right-clicking on it then the installer shows up but if open by double-clicking on the file or open via the browser the warning shows up.

@dpid

This comment has been minimized.

Copy link
Owner Author

dpid commented May 29, 2020

Hey, thanks for making this guide! I've never really used macs but I'm trying to export a mac version for my game. I've already run into a problem hahah. I'm at the "changing all file permissions" step and I keep getting this message from the terminal
chmod: sweet_resurrection.app: No such file or directory
My built game and entitlements file are both on the desktop, spelled the same way... does anyone know why I'd be having this issue? Again, mac noob here so any help is very appreciated :)
Untitled

Make sure you're in the correct directory in terminal when running chmod.

@dpid

This comment has been minimized.

Copy link
Owner Author

dpid commented May 29, 2020

Really appreciate your effort!

I managed to get my app notarized but when I upload the pkg file to drive and download it from there. When I open the pkg file, It shows me a warning "myapp.pkg can’t be opened because Apple cannot check it for malicious software." Nothing happens and It does not open up the installer.

Has anyone faced this issue even after your app was notarized by Apple?

P.S. after a bit of google found that If you open the file by right-clicking on it then the installer shows up but if open by double-clicking on the file or open via the browser the warning shows up.

That warning usually shows up if notarization failed in someway. You shouldn't need to right click it. I'd recommend double checking through all the notarization steps.

@reysantana

This comment has been minimized.

Copy link

reysantana commented May 31, 2020

Hi @dpid
How to fix unsealed contents present in the bundle root?

@EddieCameron

This comment has been minimized.

Copy link

EddieCameron commented Jun 2, 2020

Thanks for the guide! Minor fix, the call to iTMSTransporter to get the provider name needs to be xcrun iTMSTransporter -m provider -u YourAppleIDUsername -p abcd-efgh-ijkl-mnop (not --password)

@dpid

This comment has been minimized.

Copy link
Owner Author

dpid commented Jun 2, 2020

Thanks for the guide! Minor fix, the call to iTMSTransporter to get the provider name needs to be xcrun iTMSTransporter -m provider -u YourAppleIDUsername -p abcd-efgh-ijkl-mnop (not --password)

Updated. Thank you.

@EddieCameron

This comment has been minimized.

Copy link

EddieCameron commented Jun 2, 2020

Another couple notes:

  • I also had to specifically sign any native plugins inside Contents/Plugins (Steam, InControl). This didn't work until I deleted all the .meta files inside them that Unity copies in from the editor.
  • If you open the files in finder, it might add metadata that messes up the code signing, you can remove it all at once before signing with xattr -cr $APP_BUNDLE https://developer.apple.com/library/archive/qa/qa1940/_index.html
@ThunderboxEntertainment

This comment has been minimized.

Copy link

ThunderboxEntertainment commented Jun 3, 2020

Hi there!
Fantastic guide. Thank you so much.
I too had trouble notarizing because I had to specifically sign some Steam files... and also some Wwise files.
My log file was full of various errors about timestamps, weak signiatures, etc...
After a bit of google-fu, I found these two commands that fixed all my signing issues...

//Sign ALL the sub-files
find ./YOURAPP.app -type f -exec codesign --timestamp --keychain /Users/builduser/Library/Keychains/login.keychain-db -s "Developer ID Application: YOUR SPECIAL ID" -f --verbose=9 --deep --options=runtime --entitlements "YOURENTITLEMENTS.entitlements" {} +

//Sign the main app
codesign --timestamp --keychain /Users/builduser/Library/Keychains/login.keychain-db -s "Developer ID Application: YOUR SPECIAL ID" -f --verbose=9 --deep --options=runtime --entitlements "YOURENTITLEMENTS.entitlements" YOURAPP.app

Cheers,
Dan

@m3m3x

This comment has been minimized.

Copy link

m3m3x commented Jun 12, 2020

Awesome Guide! Have been able to go through all the steps and uploaded my zip just as instructed, but my app fails notarization because my Plugins aren't properly cosigned. Specifically my FMOD Plugin (a 3rd party Sound Mixing tool) and this error:

Contents/Frameworks/Mono/MonoEmbedRuntime/osx/libmono.0.dylib", "message": "The binary uses an SDK older than the 10.9 SDK.",

Any ideas/recommendations on how to fix this?

@EddieCameron

This comment has been minimized.

Copy link

EddieCameron commented Jun 12, 2020

Using old versions of Unity causes the same issue. For Unity you can hexedit the mono libraries to change their min sdk to 10.9. It should still work for FMOD https://asmaloney.com/2020/03/howto/notarizing-older-unity-games-on-macos/

@dpid

This comment has been minimized.

Copy link
Owner Author

dpid commented Jun 14, 2020

@EddieCameron @ThunderboxEntertainment , thanks for the extra tips.

@m3m3x

This comment has been minimized.

Copy link

m3m3x commented Jun 14, 2020

Updating Unity and getting FMOD from the asset store both helped, but now I've got one remaining error on a binary in the contents folder that of the same name as my game. It's listed as:

TheLastSurvey_OSXv4.1.app/Contents/MacOS/TheLastSurvey"
"The signature of the binary is invalid."

I tried to codesign just that binary with:
codesign -vvv --deep --strict \path\

As per Apple's recommendations to common issues, but still am getting the error after uploading to notarization using xcrun. Any thoughts?

@m3m3x

This comment has been minimized.

Copy link

m3m3x commented Jun 14, 2020

I used @ThuderboxEntertainment's step for codesigning the binary directly with specific reference to my keychain and that seemed to solve the issue. My game is now notarized, stabled, and ready for distro :)

Thanks @dpid & @EddieCameron

@russellquinn

This comment has been minimized.

Copy link

russellquinn commented Jun 23, 2020

Everything works for me. And the notarized app works fine on the computer that did the notarizing.

But, when I try to run it on another Mac, it crashes immediately with: Termination Reason: Namespace CODESIGNING, Code 0x1

Any ideas? Thanks.

@dpid

This comment has been minimized.

Copy link
Owner Author

dpid commented Jun 23, 2020

@russellquinn , since the termination reason mentions codesigning, I recommend trying out the extra codesigning tips mentioned here in the comments. If one of them works for you, please share what resolved your issue.

@russellquinn

This comment has been minimized.

Copy link

russellquinn commented Jun 24, 2020

@dpid I just figured it out! I was stuck on this for two days. I found my answer here: https://developer.apple.com/library/archive/qa/qa1884/_index.html#//apple_ref/doc/uid/DTS40015141

It mentions that you can't run an app signed with "Mac App Store distribution identity, with the certificate’s Subject Common Name starting with “3rd Party Mac Developer Application," which was not my case. I double-checked and was definitely using "Developer ID Application." Curious…

But further in the article it says "Recently, the com.apple.developer.team-identifier entitlement was added to all new Mac provisioning profiles" and this tipped me off.

I had com.apple.application-identifier and com.apple.developer.team-identifier in my .entitlements file — a hangover from when I based my Steam-build .entitlements on my Mac App Store .entitlements. I removed those two entries, redid the entire process and it works!

tl;dr: If you have com.apple.application-identifier and/or com.apple.developer.team-identifier in your .entitlements file the app will still run on the machine you codesigned it on, but it appears to trigger Apple's "distribution builds" check when run on another Mac.

@JordanSchuetz

This comment has been minimized.

Copy link

JordanSchuetz commented Jun 25, 2020

Ok everyone, I encountered a pretty huge issue once I went to notarize my application and submit it to Apple. After submission, I got a notification letting me know that my application failed notarization. So to check the error, I ran the command: spctl -a -v MyApp.app but I got the return message in my terminal:

MyApp.app: rejected
source=Unnotarized Developer ID

I had no clue why this was happening because I was able to successfully notarize my previous build. Then I ran the command:

xcrun altool --notarization-info xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx --username YourAppleIDUsername --password abcd-efgh-ijkl-mnop --asc-provider YourAppleDeveloperTeamID

And I got a JSON document that was returned.

{
  "logFormatVersion": 1,
  "jobId": "XXXXXXXXXXX",
  "status": "Invalid",
  "statusSummary": "Archive contains critical validation errors",
  "statusCode": 4000,
  "archiveFilename": "MyApp.zip",
  "uploadDate": "2020-06-25T06:02:20Z",
  "sha256": "XXXXXXXX",
  "ticketContents": null,
  "issues": [
    {
      "severity": "error",
      "code": null,
      "path": "MyApp.zip/MyApp.app/Contents/Plugins/discord_game_sdk.bundle",
      "message": "The binary is not signed.",
      "docUrl": null,
      "architecture": "x86_64"
    },
    {
      "severity": "error",
      "code": null,
      "path": "MyApp.zip/MyApp.app/Contents/Plugins/discord_game_sdk.bundle",
      "message": "The signature does not include a secure timestamp.",
      "docUrl": null,
      "architecture": "x86_64"
    },
    {
      "severity": "error",
      "code": null,
      "path": "MyApp.zip/MyApp.app/Contents/Plugins/discord_game_sdk.dylib",
      "message": "The binary is not signed.",
      "docUrl": null,
      "architecture": "x86_64"
    },
    {
      "severity": "error",
      "code": null,
      "path": "MyApp.zip/MyApp.app/Contents/Plugins/discord_game_sdk.dylib",
      "message": "The signature does not include a secure timestamp.",
      "docUrl": null,
      "architecture": "x86_64"
    },
    {
      "severity": "error",
      "code": null,
      "path": "MyApp.zip/MyApp.app/Contents/Plugins/steam_api.bundle/Contents/MacOS/libsteam_api.dylib",
      "message": "The signature of the binary is invalid.",
      "docUrl": null,
      "architecture": "i386"
    },
    {
      "severity": "error",
      "code": null,
      "path": "MyApp.zip/MyApp.app/Contents/Plugins/steam_api.bundle/Contents/MacOS/libsteam_api.dylib",
      "message": "The signature algorithm used is too weak.",
      "docUrl": null,
      "architecture": "i386"
    },
    {
      "severity": "error",
      "code": null,
      "path": "MyApp.zip/MyApp.app/Contents/Plugins/steam_api.bundle/Contents/MacOS/libsteam_api.dylib",
      "message": "The signature of the binary is invalid.",
      "docUrl": null,
      "architecture": "x86_64"
    },
    {
      "severity": "error",
      "code": null,
      "path": "MyApp.zip/MyApp.app/Contents/Plugins/steam_api.bundle/Contents/MacOS/libsteam_api.dylib",
      "message": "The signature algorithm used is too weak.",
      "docUrl": null,
      "architecture": "x86_64"
    }
  ]
}

What I found out was that notarization requires all libraries to be signed, including 3rd party ones. You are required to do a deep signing and force sign libraries you did not build. Okay so you may be wondering how to do this...simply type the follow code below and fill in your own information. This is how you notarize the Steam API:

codesign --deep --force --verify --verbose --timestamp --options runtime --entitlements "MyApp.entitlements" --sign "Developer ID Application : YourCompanyName" "MyApp.app/Contents/Plugins/steam_api.bundle/Contents/MacOS/libsteam_api.dylib""

Then run the same command to notarize the Discord API Steam Bundle:

codesign --deep --force --verify --verbose --timestamp --options runtime --entitlements "MyApp.entitlements" --sign "Developer ID Application: YourCompanyName" "MyApp.app/Contents/Plugins/discord_game_sdk.dylib"

Also you will need to codesign the Discord API bundle as well:

codesign --deep --force --verify --verbose --timestamp --options runtime --entitlements "MyApp.entitlements" --sign "Developer ID Application: YourCompanyName" "MyApp.app/Contents/Plugins/discord_game_sdk.bundle"

If you get this status message, you know it was successful:

signed Mach-O thin (x86_64) [discord_game_sdk]

So now after you have signed each component, now go ahead and continue with the tutorial by signing the entire package.

Hope this helped everyone! Cheers.

Regards,
Jordan Schuetz
https://jordanschuetz.com

@MonkeyGland

This comment has been minimized.

Copy link

MonkeyGland commented Jul 2, 2020

Hi

Many thanks for this guide - very much appreciated.

I've followed the steps successfully with apple notarizing the app etc.

Issues comes when I test the app post stapling. I check the notarization using spctl -a -v YourGame.app and all is well.

However, when I upload to GDrive and then download to test, I get the dreaded "The application cannot be opened". I check that version with spctl and get "a sealed resource is missing or invalid".

I followed @ThuderboxEntertainment steps too.

Anyone got any ideas?

Thanks in advance all

@GiovanniFrigo

This comment has been minimized.

Copy link

GiovanniFrigo commented Jul 2, 2020

@MonkeyGland if you uploaded the .app file to google drive directly, bad things could happen. Never upload a .app file to google drive without zipping it first!

MacOS apps are basically just directories, and google drive treats them like so, so it can change properties of internal app files.

@MonkeyGland

This comment has been minimized.

Copy link

MonkeyGland commented Jul 2, 2020

@GiovanniFrigo D'oh - I can't believe I missed that. Thank you mate - much appreciated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.