Buckle up. This is going to be a bumpy ride. Don't blame me, this is all between Apple & Unity
Real talk: MacOS isn't a very popular platform for games, and Unity's support for it reflects that. At the time of this writing (April 2 - 2020) none of the stable versions of Unity will let you build a MacOS version as an XCode project.
Unity just builds a "vanilla" binary and calls it a day. This won't do. CloudKit requires certain entitlements to run, and when entitlements are involved, code-signing is required. OSX will terminate an unsigned app as soon as it tries to do something it is not entitled to do.
Without an XCode project to help with that, our only recourse is to build a MacOS version, crack it open, modify a bunch of files, and then resign all the binaries via the command line.
But don't worry, we created a script to make this as easy as possible.
At it's simplest, all you should need to do is configure your plugin's build settings and the PostProcess script takes care of resigning the MacOS application.
You will need to fill in:
Then just hit "build' and the post-process script takes care of the rest.
Simple right?
Well, hopefully. Truth is, code signing is never that easy. A lot can go wrong.
In this tutorial we'll provide a quick start guide. This is for people who are already familiar with the signing process. If your less familiar with the signing process then the step-by-step guide is the one for you. We'll guide you through double-checking your settings step-by-step and explain how the tools work in the process
You will need:
Open the Build Setting Asset inside the folder "Plugins->HovelHouse->CloudKit->Resources". In the inspector window: Make sure that "Post Process Mac Build" is checked. The following image shows the recommended settings for most users.
Open KeychainAccess and look for an entry of the form: Mac Developer: FirstName LastName (CERTIFICATE_ID)
. Select this certificate and copy this value to the clipboard.
Paste this value in the "Code Signing Identity" textfield in the plugins build settings.
There is currently a bug with the MacOS build script that ignores the Add Default Containers checkbox in the settings. It is recommended that you disable this checkbox, and enter your apps default container manually in the Custom Containers list. The default container is of the form iCloud.{your-bundle-identifier}
. If you don't fill in the correct value here, your app will fail codesigning.
If you haven't already, make a developer provisioning profile for your app. Download it and place it somewhere.
In the inspector, hit the find button next to the text field and point it to your provisioning profile. Only files with the extension "*.provisionprofile" are selectable.
You can skip this step if your app does not require custom or additional plist entries.
Create a new plist file and save it somewhere on your computer
Open it in xcode and add your custom entries. You do not need to add the ones Unity adds by default
Use the find button to locate the file you created
You can skip this step if your app does not require custom entitlements
The plugin will add the entitlements required by CloudKit, but if you have additional entitlements to add, the plugin provides a way for you to merge them into the build.
Create a new entitlements file
Add your custom entries
Use the find button to locate the file you created
Known Issue: There is currently a bug where the code-signing script has its permissions modified by the unity package importer, which results in the script not being marked as executable. Building for MacOS may result in an error containing the following message: Native error= Access denied System.Diagnostics.Process.StartWithCreateProcess To fix this, you will need to chmod the file before it can be run from an editor process.
/Packages/Cloud Kit Plugin/ShellScripts/Resign.sh
. Right click it and select "show in finder" to open a window at it's installed location.terminal
" and hit enter."chmod +x "
then drag the signing script into the terminal window. The will copy the files path to the cursor position. Hit enter.All you should have to do now is build. The post process build script will merge your plist and entitlements files if provided, then run a shell script which re-signs the application with the specified certificate and provisioning profile. Once signing is complete, you should be able to double-click your application to run it.
In this step by step guide we'll go through how the build script works and talk about some of the common pitfalls in the code signing process. This is useful information for Troubleshooting your MacOS build when code-signing fails.
Open the Build Setting Asset inside the folder "Plugins->HovelHouse->CloudKit->Resources".
In the inspector window: Make sure that "Post Process Mac Build" is checked.
If you haven't already done so, you will need to create a certificate for you MacOS app on the apple developer portal and install it on your computer. This certificate will need to be present in the provisioning profile you sign with. Confused? Don't worry we'll cover that later.
Once the certificate is installed, we need to find it's Common Name and paste it into the textarea labeled Code Signing Identity
Open KeychainAccess and look for an entry of the form Mac Developer: FirstName LastName (CERTIFICATE_ID). Select this certificate and copy this value to the clipboard. Pay close attention to the spelling. You may have another entry that starts Apple Developer: FirstName LastName... don't select that one. It won't work.
Paste this value in the Code Signing Identity textfield in the plugins build settings.
There is currently a bug with the MacOS build script that ignores the Add Default Containers checkbox in the settings. It is recommended that you disable this checkbox, and enter your apps default container manually in the Custom Containers list. The default container is of the form iCloud.{your-bundle-identifier}
. If you don't fill in the correct value here, your app will fail codesigning.
If you haven't already done so. You'll need to create a provisioning profile for your MacOs application. This is typically the most error prone part of the signing process, as it is easy to misconfigure.
Download it and use the find button to locate it on your hard drive. This path is passed as a parameter to the code signing script
A provisioning profile has a list of things that all need to be correct in order for your app to run. If any one of them is incorrect, codesigning will complete as if nothing bad has happened, but your app will crash with a codesigning error on startup. The error message Apple provides contains no information as to which of these things is misconfigured. Your only recourse is to double check each of these things one by one.
They are as follows:You can typically verify this information by right clicking on the provisioning profile, and selecting get info. The preview view will show you a list of key-value pairs that you can use to verify that you have set everything up correctly.
Codesigning is used (among other things) to verify that your app has not been tampered with. This means that the plist file cannot be changed after codesigning has completed. If your app requires custom plist entries, the plugin provies a way for you to add them to the mac build before the codesigning script is run.
The plist file you make will be merged into the default one provided by unity, so you do not need to provide a complete file. Just create one with the entries that are missing, this'll ensure that the entries that Unity modifies (like bundle version) don't get clobbered
Place your partial plist somewhere in your project, and use the find button to point to it.
Similar to the previous step, an apps entitlements are using during codesigning and cannot be changed after codesigning occurs. The plugin provies a way to merge in any additional entitlements into the ones required by CloudKit before code signing occurs.
The merged entitlements file is saved to the build directory, the path to this file is then sent as an argument to the build signing script
Known Issue: There is currently a bug where the code-signing script has its permissions modified by the unity package importer, which results in the script not being marked as executable. Building for MacOS may result in an error containing the following message: Native error= Access denied System.Diagnostics.Process.StartWithCreateProcess To fix this, you will need to chmod the file before it can be run from an editor process.
/Packages/Cloud Kit Plugin/ShellScripts/Resign.sh
. Right click it and select "show in finder" to open a window at it's installed location.terminal
" and hit enter."chmod +x "
then drag the signing script into the terminal window. The will copy the files path to the cursor position. Hit enter.Unity will make a MacOS binary. The plugin will then modify the plist file, create an entitlements file, and then run a codesigning script located in "Packages/CloudKit/ShellScripts/resign.sh" with the arguments you provided in the inspector. If there are any errors, they will show in the console window.
(╯°□°)╯︵ ┻━┻
The PostProcess Build step conflicts with another
If you have your own custom build script, or another native plugin installed, there's a chance it could conflict with this one. We make every effort to insure that our script plays friendly with others, but it's not possible to cover every use case.
To make your life easier, each step of the post process script can be disabled. Additionally, the bash script which does the signing may be run by itself in terminal with arguments you provide
The app crashed on startup
This is usually an indicator that the app was signed with a misconfigured provisioning profile. There can be many reasons this can happen, and sadly, the crash report will never say exactly what the problem is. The only thing we can do is double-triple check that our provisioning profile is set up correctly.
The app crashed after the splash screen
If your app is FairPlay encrypted, OSX will not permit it to run outside of the applications folder. Drag your build app into the applications folder and run it from there
The app crashed after my first call to a CloudKit function
This is usually an indicator that the app wasn't signed with the correct entitlements.