Building Unity Apps to macOS: The Ultimate Guide

Eric Yoon
6 min readDec 10, 2021

Publishing shouldn’t be this hard. While trying to figure out how to build my Unity game to macOS, I encountered dozens of errors and read heaps of StackOverflow posts, documentation pages, and Q&As. So, I’ve packaged what I’ve learned in a guide. Here’s how to build Unity games to macOS, for either sideloading or for Mac App Store distribution.

This guide will take you through Apple Developer certificates, code signing, packaging an installer, and notarization, and there’s even a bash script for easy automation!

Creating an App Password

Before we get started, we’re going to need an App-Specific Password from Apple. Head to Security Settings on the Apple ID webpage, click App-Specific Passwords, and create one. Take note of the generated password.

Downloading Certificates

You’ll need an Apple Developer account to complete this guide, but there are already many great tutorials on how to do this, so I’m going to assume you’re already set up.

The first step is downloading the correct certificates from Apple. Without these, we can’t tell Apple our app is safe and your users might encounter “untrusted” or “unsafe” popups.

You’ll first have to create your own Certificate Signing Request (CSR) file from Keychain Access on your Mac. This file acts as your private key.

Choose Keychain Access in the menu bar ➤ Certificate AssistantRequest a Certificate From a Certificate Authority.

Screenshot of menu option

You’ll want to enter your email address; you can give the request a name in the Common Name field.
Leave the “CA Email Address” field blank.
Select “Request is: Saved to disk.”
Check “Let me specify key pair information”.

Press Continue and choose a file location. On the next screen, keep Key Size set to 2048 bits and Algorithm set to RSA.

Press Continue. You’ll want to keep your .certSigningRequest file around in case you ever need to request additional certificates in the future.

Head to Certificates, Identifiers, and Profiles on the Apple Developer account settings page. You’ll need to generate two certificates depending on where you plan on distributing your app.

If you want to sideload your app (i.e. sending a file to friends or publishing through a non-Apple marketplace), create 1) a Developer ID Application certificate and 2) a Developer ID Installer certificate.

If you want to upload your app to the Mac App Store, create 1) a Mac App Distribution certificate and 2) a Mac Installer Distribution certificate.

To create these certificates, you’ll have to upload the .certSigningRequest file you generated. After you download these certificates, simply double-click them to add them to Keychain Access.

Take note of the names of these certificates—you can view this by opening the quick preview (press spacebar). They should look like “Developer ID Application: John Doe (XXXXXXXXXX)” or “3rd Party Mac Developer Application: John Doe (XXXXXXXXXX)” depending on which certificates you created. The code in parentheses is called your provider short name.

Declaring Entitlements

We first need to make a list of entitlements. This file tells Apple what capabilities and requirements your app has. Create a file at the root of your project directory called YourGameName.entitlements . Copy the text below into the file:

<?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.app-sandbox</key>
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
</dict>
</plist>

You can add any additional entitlements that your app might need. For example, if your game connects to the Internet, include the com.apple.security.network.client key and add <true/> below. Here’s a complete list of entitlements.

Code Signing

First, build out your .app file from Unity with Mac, PC, and Linux Standalone as your platform. You may also need to grant execution permissions by running this Terminal command:

chmod -R a+xr "Path/To/Your/Game.app"

Code sign your app using this XCode command (you may have to open XCode for the first time and install developer tools). Run this command from your project’s root folder.

codesign --deep --force --verify --verbose --timestamp --options runtime --entitlements "YourGameName.entitlements" --sign "Developer ID Application: John Doe (XXXXXXXXXX)" "Path/To/Your/Game.app"

Fields that you need to edit are bolded. Change Developer ID Application to 3rd Party Mac Developer Application if you’re deploying to the Mac App Store (in other words, this should be the name of your Application certificate).

Creating a .pkg Installer

There are a few types of containers an app can be shipped in—a .zip file, a .dmg disk image, or a .pkg installer. A .pkg file is what the Mac App Store expects and is in general the most frictionless for users.

Use the built-in XCode command below to create a .pkg and codesign it all in one step (both the inside .app and its .pkg need to be signed). We specify that we want our app to be installed to the user’s Applications folder, but you can change this as you wish.

productbuild --component "Path/To/Your/Game.app" /Applications --sign "Developer ID Installer: John Doe (XXXXXXXXXX)" "Your/Build/Folder/YourGameName.pkg"

Note that the certificate name argument in this command is not the same as the one you used to codesign your app! This should start with either Developer ID Installer or 3rd Party Mac Developer Installer .

Notarization (for sideloading only)

Starting with macOS 10.14.5, Apple requires sideloaded apps to be notarized as an additional layer of protection. You do not need to complete this step if you only intend to distribute through the Mac App Store.

First, let’s upload our app for notarization to Apple servers:

xcrun notarytool submit --apple-id "your.apple.id@example.com" --team-id "XXXXXXXXXX" --password "your-apps-pass-word" "Path/To/YourPackage.pkg" --wait

Remember, your team-id is the code in parentheses at the end of your certificate names.

Wait for the command to finish. Run one last command to “staple” the notarization info to your package:

xcrun stapler staple "Path/To/YourPackage.pkg"

You’re now ready to distribute your .pkg to anywhere for sideloading!

Uploading to the Mac App Store

If you’re looking to distribute your app through the Mac App Store, uploading your package is easy. After you’ve created and configured your app in App Store Connect, you can upload your first build using XCode:

xcrun altool --upload-app --file "Path/To/YourPackage.pkg" --type macos --username "your.apple.id@example.com" --password "your-apps-pass-word"

Automating With a Bash Script

I’ve written a bash script to automate this entire process. Simply copy into a file at the root of your project directory, chmod +x yourscript.sh , and fill in the variables at the top.

#!/bin/bashAPPLE_ID="your.apple.id@example.com"
DEV_ID_APPLICATION_CERT_NAME="Developer ID Application: John Doe (XXXXXXXXXX)"
DEV_ID_INSTALLER_CERT_NAME="Developer ID Installer: John Doe (XXXXXXXXXX)"
APPLE_APPLICATION_CERT_NAME="3rd Party Mac Developer Application: John Doe (XXXXXXXXXX)"
APPLE_INSTALLER_CERT_NAME="3rd Party Mac Developer Installer: John Doe (XXXXXXXXXX)"
APP_PWD="your-apps-pass-word"
TEAM_SHORT_NAME="XXXXXXXXXX"
APP_LOCATION="Path/To/Your/Game.app"
PKG_LOCATION="Your/Build/Folder/GameName.pkg"
ENTITLEMENTS_FILE="YourGameName.entitlements"
chmod -R a+xr "$APP_LOCATION"read -p "Do you want to package app for sideloading or for the Mac App Store? (mac/sideload) " targetif [ "$target" == "mac" ]; then
APPLICATION_CERT_NAME="$APPLE_APPLICATION_CERT_NAME"
INSTALLER_CERT_NAME="$APPLE_INSTALLER_CERT_NAME"
else
APPLICATION_CERT_NAME="$DEV_ID_APPLICATION_CERT_NAME"
INSTALLER_CERT_NAME="$DEV_ID_INSTALLER_CERT_NAME"
fi
echo "Code signing..."
codesign --deep --force --verify --verbose --timestamp --options runtime --entitlements "$ENTITLEMENTS_FILE" --sign "$APPLICATION_CERT_NAME" "$APP_LOCATION"
echo "Generating pkg and signing..."
productbuild --component "$APP_LOCATION" /Applications --sign "$INSTALLER_CERT_NAME" "$PKG_LOCATION"
if [ "$target" != "mac" ]; then
echo "Uploading for notarization... check back here in a few minutes."
xcrun notarytool submit --apple-id "$APPLE_ID" --team-id "$TEAM_SHORT_NAME" --password "$APP_PWD" "$PKG_LOCATION" --wait
echo "Stapling notarization..."
xcrun stapler staple "$PKG_LOCATION"
fi
if [ "$target" == "mac" ]; then
read -n1 -p "Do you want to upload to App Store now? (y/n) " choice
echo ""
if [ "$choice" == "y" ]; then
echo "Uploading to app store..."
xcrun altool --upload-app --file "$PKG_LOCATION" --type macos --username "$APPLE_ID" --password "$APP_PWD"
fi
fi
echo "Finished"

Additional Reading

Here are some of the StackOverflow posts and documentation I read trying to get this all set up! Take a look if you’re stuck.

SO: How to obtain Certificate Signing Request
Unity Docs: Delivering your application to the Mac App Store
Apple Docs: Notarizing macOS Software Before Distribution
Apple Docs: Customizing the Notarization Workflow
SO: macOS: Notarize in Script?
Apple Forums: How to notarize app at CI Build?
Apple Support: Using app-specific passwords
Notarizing installers for macOS Catalina
How to notarize a Unity build for macOs 10.15 Catalina
Getting a “certificate is not trusted” error for iOS Distribution Certificate

Changelog

  • 2023–11–28: Updated script to use notarytool instead of the deprecated altool notary feature.
  • 2023–12–02: Added JIT entitlement.

Hope this guide helps. You can check out out my work at yoonicode.com. Bye!

--

--