Thursday, December 5, 2013

Signing a Unity game for the Mac App Store

A compiled list of the hoops you have to jump through for getting a game built with Unity 4.3.0f4 signed for the Mac App Store.

There's a handful of posts already on this but I found that many were out of date or missing a step or two. Terminal Commands are in Blue, Error messages are in Red, and any reference to or Game.pkg should be substituted with your game name. Let's jump in!

1. Create a Mac Installer Distribution and Mac App Distribution certificate on the developer portal.

2. In Unity > File > Build Settings > Player Settings...  make sure that Mac App Store Validation is turned ON. Then build your game.

3. Right-click your built file and select Show Package Contents. Under Contents... open up Info.plist and ensure that CFBundleShortVersionString and CFBundleVersion match the version set for your app awaiting upload on iTunesConnect.

You also have to add a string value for the LSApplicationCategoryType key and set it to your sub/primary category in the form of " category" In the case of Wriggle 3D (a puzzle game) it was

4. From the Unity documentation: Fix the read permissions for your app with

chmod -R a+xr

5. Here's a tricky part. At the time of writing, you must download an older version of Xcode and use its codesign tool instead (Current version is 5.0.2). Download Xcode 4.6.3 and install it somewhere other than your existing Xcode location (so as not to overwrite it!). Then in your terminal export this variable:

export CODESIGN_ALLOCATE="path to Xcode4.6.3/Contents/Developer/usr/bin/codesign_allocate"

Skipping this step will result in later errors with the following message: object file format unrecognized, invalid, or unsuitable

6. Once you've done that, create an entitlements.plist file with the following entitlement (and others if your app requires them)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "">
<plist version="1.0">

And run this command:

codesign -f -s "3rd Party Mac Developer Application: **Company Name**" --entitlements "entitlements.plist"

Skipping this step will result in later rejection with the following message:

App sandbox not enabled - The following executables must include the "" entitlement with a Boolean value of true in the entitlements property list. Refer to the App Sandbox page for more information on sandboxing your app.

7. Now we have to codesign all *.dylib and *.bundle files in the following directories:
  • Contents/Frameworks
  • Contents/Plugins
8. After this, it's time to package the app with this command:

productbuild --component --sign "3rd Party Mac Developer Installer: **Company Name**" Game.pkg

8. Now under Xcode > Open Developer Tool > Application Loader... you should be able to upload Game.pkg to the store! Pat yourself on the back :)

Coming from an iOS developer used to working exclusively with Xcode, this is an annoying, but ultimately manageable, process. If you'd like to see the finished product that was submitted after all this, check out Wriggle 3D!


  1. I was wondering if you ever ran into the issue I am having. I have followed/understood all of your steps but when it comes to run the productbuild I get this:

    2014-03-20 11:48:38.733 productbuild[5843:707] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** setObjectForKey: key cannot be nil'
    *** First throw call stack:
    0 CoreFoundation 0x00007fff92651b06 __exceptionPreprocess + 198
    1 libobjc.A.dylib 0x00007fff8c8da3f0 objc_exception_throw + 43
    2 CoreFoundation 0x00007fff926e05b7 -[__NSDictionaryM setObject:forKey:] + 135
    3 productbuild 0x000000010454b7fd productbuild + 51197
    4 productbuild 0x00000001045413c3 productbuild + 9155
    5 libdyld.dylib 0x00007fff8fa027e1 start + 0
    libc++abi.dylib: terminate called throwing an exception
    Abort trap: 6

    Just curious if you ever saw this or know what causes it.


  2. Hi Justin! Are you using any objective-c libraries? Perhaps for networking or analytics? This looks like somewhere in your code a dictionary is trying to pass nil for a key.