With the launch of macOS Catalina (10.15), Apple introduced a requirement to "notarize" (US English) all macOS software which has been built and codesigned after the end of July 2019. For more information on this announcement, please see this Apple Developer page: Notarizing Your App Before Distribution.
In order to comply with this, you currently need to have Xcode 10 or above installed, plus be using macOS Mojave or newer when making your games. As of the start of November 2023, this rises to Xcode 14.1 - https://developer.apple.com/news/upcoming-requirements/?id=11012023a
You will also need a paid Apple Developer account if you want to give your app to anyone else as only dev-testing on your own machine is allowed as a free Apple Developer user.
If you do not codesign your package, Gatekeeper will say it's damaged and tell you to delete it (on Mojave and above), so not applying codesigning is not a realistic method of bypassing notarisation.
There is nothing that GameMaker can do to help you get around these requirements. We have to do it with our own software, including GameMaker itself (every single build we make, not just the public releases you see...).
Will This Affect Me?
This will affect you if you want to send your apps to any other Mac than the one on which your own developer details are installed, including:
- Making a game to send to anyone who is using Catalina or a newer version of macOS (possibly Mojave also - see below)
- Selling on the App Store (Xcode will deal with it all automatically for you)
- Selling on Steam
- Selling on Itch.io
- Selling on wherever else you currently distribute your macOS games...
Note that because Steam also requires you to submit your test builds each time nowadays, that means each build you do will need to be notarised and then sent to them, so you may want to disable Steam integration during testing as much as possible.
It will also affect students submitting games for grading if either the student or the person doing the grading is using Catalina or newer - we would suggest whenever possible it's a .yyz Export which is sent for grading, as the project can then be opened and built on the local machine, rather than the student building the package and sending the executable. You would then avoid having to do any of the steps in this article.
As mentioned above, Mojave also supports this "hardened runtimes" protection, but it was an optional setting you could toggle during a reformat (and the default was off). In Catalina and newer, there is no facility to turn this protection off and everyone will be affected.
What Do I Need To Do When Building My Game?
You need to be using GMS2 2.2.4 or newer when you build the package and you do need to have Xcode installed as per our Required SDKs guide, but beyond that you don't need to do anything differently within GameMaker, as the notarisation process is handled by Apple's own tools once your package has been made.
Please note that we recommend you always build your final packages using YYC, as Xcode makes it much simpler, faster, and easier to diagnose compatibility issues - and Xcode's uploading UI can then be used, which will do a lot of the work for you.
However, the process you will need to follow in order to notarise your package once it has been built differs between VM and YYC and whether your game is for the App Store or not, so see the relevant section below for more info.
Be aware that hardened runtimes support requires even more stringent development standards, especially if you are using .dylib extensions, but the exact changes you need to make to your project are not something we can document, as it depends on the contents of that specific project. In general, be aware that you may need to do some additional work before a hardened runtime project build will succeed inside Xcode.
Additional Considerations For If Your Project Contains Extensions
The new rules around "hardened runtimes" means any dylib extensions (which until August 2019 you may not have been codesigning yourself) will now need to be codesigned by you before them adding to your GameMaker project or manually on the Mac within Xcode after you click Create Exe inside GameMaker. Any existing codesigning by a third-party will need to be overwritten, as all codesigning must be with your certificate.
Also be aware that your extensions now need to be 64-bit only, otherwise macOS will refuse to run them.
What if I get server issues when trying to notarise?
https://developer.apple.com/system-status/ is the page which tells you if the notarisation service itself has issues at Apple's end. If you find yourself getting errors that servers/values can't be found, check here to see if you should try again later.
Unfortunately, this isn't something YoYo Games can help you fix.
Submitting Via Xcode
See this Apple tech post for more details on the process.
macOS YYC building for the App Store:
- "Create Exe" inside GM. This will build your Xcode project and archive as per usual.
- Open Xcode > Window > Organizer > Archives and select your game from the panel down the left. Click on the archive you wish to send, and then click the Distribute App button in the panel on the right.
- Follow the wizard for submitting to the App Store.
- This will perform the notarisation and stapling automatically as part of the upload and initial submission process.
macOS YYC building for any other form of distribution:
- "Create Exe" inside GM. This will build your Xcode project and archive as per usual.
- In Xcode go to Signing & Capabilities and then select the +Capabilities section. From the window that opens, double click on the Hardened Runtime option. (Recent versions of GMS2 and above, this may be ticked already.)
- You now need to create a new archive with this option enabled by going to Product > Archive. Fix any issues Xcode asks you to resolve before it will complete the build.
- Open Xcode > Window > Organizer > Archives and select your game from the panel down the left. Click on the archive you wish to send (the newest one), and then click the Distribute App button in the panel on the right.
- Click the "Developer ID" option ("Distribute direct to customers"), then click Next.
- Click the "Upload" option, then click Next.
- This will send the package off to Apple so they can scan it and confirm all is okay.
- You can continue testing locally during this time, but you can't send the package to anyone else yet.
- At some point later (Apple advise "typically less than an hour"), Xcode will be told your notarisation is okay and will download the "ticket". Xcode will perform the stapling of this ticket to the app for you.
- You can now repeat steps 2 and 3, and then this time choose "Export". Xcode will now make you a package which is safe to use on other Macs.
Submitting Via Command Line Tools
See this Apple tech post for more details on the process.
Please note that we would recommend you do not actually use either of these two routes, and instead you always build your final packages using YYC, as that will be much simpler, faster, and easier to diagnose issues. These following sections are provided for completeness / for if you have a custom build workflow that you really want to keep using VM with.
We can't really offer support if you have issues when following these routes, as we would need your project to be sent to us, etc. We will just recommend you test your project and your extensions are suitably codesigned and hardened-runtime-compatible by building your project for YYC...
macOS VM building for the App Store or any other form of distribution
In general, the five steps that are always needed are, in order:
- Build the .app in GameMaker
- Sign the app (this attaches the developer digital signature)
- Notarize the app using the notarytool command with the submit option
- In case notarization was successful, attach the ticket to the app using the stapler command's staple option
- The .app can now be uploaded to the App Store or sent to anyone
To automate steps 3 to 5 you can use Textedit or similar to make a shell script which uses the following commands.
Validate App
xcrun altool --validate-app -f path/to/application.ipa -t ios -u <appstore_username@example.com> -p <appstore_password>
Notarize App
Upload App
xcrun altool --upload-app -f path/to/application.ipa -t ios -u <appstore_username@example.com> -p <appstore_password>
The script containing these commands needs to be saved as a .sh file and given the file-permission to be executable. You would then run the script by calling it in Terminal. Please note that your shell needs to be set to bash (not zsh or whichever other shell you might be using), otherwise you will have to modify the script to fit your shell's needs.
The following code shows a good reference of how this should be done in general:
#!/bin/bash # Variables APP_PATH="<path/to/your/app.app>" APP_BUNDLE_ID="<your.app.bundle.identifier>" SIGNING_IDENTITY="<Developer ID Application: Your Name (XXXXXXXXXX)>" TEAM_ID="<your_team_id>" NOTARIZATION_USER="<your_apple_id_email>" NOTARIZATION_PASS="<your_app_specific_password>" APPSTORE_CONNECT_API_KEY="<path/to/your/appstoreconnect_api_key.json>" # Code sign the app echo "Code signing the app..." codesign --deep --force --verbose --options runtime --timestamp --sign "$SIGNING_IDENTITY" "$APP_PATH" # Verify the code signature echo "Verifying the code signature..." codesign --verify --deep --strict --verbose=2 "$APP_PATH" # Check for any issues with the app echo "Checking for issues with the app..." spctl -a -t exec -vv "$APP_PATH" # Zip the app for notarization echo "Zipping the app for notarization..." zip -r -y "${APP_PATH%.*}.zip" "$APP_PATH" # Notarize the app echo "Notarizing the app..." notary_request_id=$(xcrun notarytool submit "${APP_PATH%.*}.zip" \ --key "$APPSTORE_CONNECT_API_KEY" \ --bundle-id "$APP_BUNDLE_ID" \ --wait \ --output-format json | jq -r '.id') # Staple the notarization ticket to the app echo "Stapling the notarization ticket to the app..." xcrun stapler staple "$APP_PATH" # Verify the notarization ticket echo "Verifying the notarization ticket..." spctl -a -t exec -vv --strict "$APP_PATH" # Upload to the App Store echo "Uploading to the App Store..." xcrun altool --upload-app -f "${APP_PATH%.*}.zip" -t platform -u "$NOTARIZATION_USER" -p "$NOTARIZATION_PASS" --apiKeyFilePath "$APPSTORE_CONNECT_API_KEY" # Clean up echo "Cleaning up..." rm "${APP_PATH%.*}.zip" echo "Done!"
Then, for each game package you wish to distribute:
- Create Exe inside GM. This will build your .app.zip as per usual (Apple won't accept the .app without it being in a .zip).
- Change the $APP_PATH parameter to the full path and filename for your .app file.
- Run the script and wait.
- Assuming the notarization and stapling succeeded, then you can now send the .app to your customers (up to you if you leave it in the .zip or not when sending it).
As mentioned a little way up this guide, if you have dylib extensions inside the project, then you will need to modify our script there to codesign each of your dylibs in turn before doing the notarization. Add this as new lines between our "filename" and "notarize_uuid" lines.
Be aware that if you intend to add your .app into your own custom format installer, then you will need to complete the notarisation process twice - first for the .app payload itself and then a second time for your own installer executable once the notarised .app is inside it. We don't support this, but largely you would just repeat the steps above as required. This does not apply to standard Apple format installer packages, such as .pkg or .dmg, which the notarisation service knows about - for those, you skip notarising the .app on its own and instead just notarise the whole thing as you would send it to a customer.