Well, after procrastinating for a while, I finally published my first iTunes Mac App Store app, which you can see here: https://itunes.apple.com/us/app/jigsaw-summer-joy-puzzles/id659813149?ls=1&mt=12. This is not a mobile app, but a desktop version built for Mac OS from the same code base that has been used for mobile builds here: https://itunes.apple.com/eg/app/jigsaw-summer-joy-puzzles/id659813149?mt=12.
I want to share my experience in the hope that it will be useful. Credit and thanks to pigsels guide at http://pigsels.com/2012/04/air-app-store-publishing-guide, which helped in the process. The process is actually quite lengthy the first time around and to me surprise, it went smoothly and my app was approved by Apple in less than a week on the first submission. I did ran into some issues which I will describe below. Now, keep in mind also that not all apps is suitable for publishing as desktop app, and sandboxing may prevent some type of apps to pass the submission.
– A Mac machine — this is needed to build a Mac OS build. Also make sure you have AIR SDK installed on a Mac too (here’s some instruction to set paths after installation: http://www.laaker.com/micah/blog/2007/installing-the-adobe-air-sdk-on-a-mac). I’m using AIR SDK 3.7.
– Be a registered Mac Developer (https://developer.apple.com/programs/mac/). You need the certificates which you will get from the Developer section. The certificates are used to sign the app, the app installer, and submit to the Apple Mac OS store.
– I assume most readers of this guide already has experiences publishing to the iOS store.
1. Publish the AIR swf using mxmlc or whatever you use to build the AIR swf. I use FlashDevelop on the PC (should be the same in FlashBuilder), which goes something like this:
mxmlc -load-config+=objJigsawMobileSummerConfig.xml -incremental=true +configname=air -swf-version=18 -define+=CONFIG::AIR,true -o ….
2. Go to a Mac machine now if you’re not already on a Mac. Open a terminal window. Package the output using adt. Eq:
[terminal]>adt -package -storetype pkcs12 -keystore “cert/AIRSelfSigned.p12″ -storepass password -target bundle dist/JigsawSummerJoy.app applicationDesktop.xml -C bin . -C “icons/ios” .
bin is the folder where my swf generated in Step 1 is located, along with support files.
-target bundle tells adt to build for desktop (instead of mobile devices)
applicationDesktop.xml is the application descriptor. I just used the one generated by FlashDevelop and changed several stuff, the key ones highlighted below:
<?xml version=”1.0″ encoding=”utf-8″?>
<name>Jigsaw Summer Joy</name>
<copyright>2013 F. Permadi</copyright>
<title>Jigsaw Summer Joy</title>
See more: http://livedocs.adobe.com/flex/3/html/help.html?content=File_formats_1.html
The command above also tells adt to sign the output with an AIR certificate (not the Apple certificate). I used a self signed certificate in the above example (cert/AIRSelfSigned.p12), which I created following this guide: http://help.adobe.com/en_US/AIR/1.5/devappshtml/WS5b3ccc516d4fbf351e63e3d118666ade46-7f74.html. (If you encountered problems copying and pasting the command from the Adobe page, saying “2048-RSA” is invalid value or something like that, retype instead of copying/pasting — obviously you shouldn’t copy/paste the password and name). Also see: http://myguide.bagarinao.com/2008/09/05/generating-self-signed-certificate-using-adt-to-sign-air-applications.htm
3. After step 2, adt should produce the output app file in the dist folder (which I specified). This is the application file and it should run. Try to run it and make sure it runs first before going further.
4. Once you confirmed the app works, drill it down to the Contents/Info.plist within the app bundle. We need to change something there. Set the app category key:
For list of categories, see the bottom of http://developer.apple.com/library/mac/#releasenotes/General/SubmittingToMacAppStore/index.html
I recommend copying this Info.plist so you don’t have to keep editing it every-time you rebuild. For me, I saved this Info.plist in a folder named MacProcess (outside the app bundle). Whenever I rebuild I can just use it to replace the one inside the app with something like:
[terminal]>cp MacProcess/Info.plist dist/JigsawSummerJoy.app/Contents/Info.plist
4. I also had to replace the icons manually because apparently, ApplicationLoader (which is used to submit to AppStore) wants icons in icns format and for reasons I didn’t bother finding out, it doesn’t like the one generated by adt.
I followed this guide to create the icns: http://cocoadevblog.avisnocturna.com/2012/10/how-to-create-1024×1024-icons-for-mac-apps/. Some of the files are redundant dimensions but I include them anyway.
I saved the icns in a folder named MacProcess again (so that I don’t have to keep recreating if I need to repeat steps 2 onward). Once you do this, you can use it to replace the one inside the app bundle:
[terminal]>cp MacProcess/Icon.icns dist/JigsawSummerJoy.app/Contents/Resources/Icon.icns
5. Change permissions in the app. Why? Quoting pigsels: “By default when ATD builds your app-file it sets your current user as owner of all files inside of app it creates. This may prevent Application Loader from reading all data when uploading your app to the Mac App Store. Just use chmod command to set necessary permissions (we used 777 that gives all permissions to read, write and execute) to all files inside of your app:”
[terminal]>chmod -R 777 dist/JigsawSummerJoy.app/
6. Thanks to pigsels again because I wouldn’t know this step otherwise: Need to remove Webkit library from AIR because Webkit calls undocumented APIs and an app should not call undocumented APIS.
[terminal]>rm dist/JigsawSummerJoy.app/Contents/Frameworks/Adobe AIR.framework/Versions/1.0/Resources/WebKit.dylib
7. Then sign the apps as well as the libraries. To find what signature to use, open the Keychain to see the name of your certificate, then copy and paste it. I was actually stumped here because when I signed up to the Mac Developer Portal, there are 5 or 6 certificates that I had created — because I wanted to make sure I didn’t miss anything I needed. The key here is to use the one that begins with “3rd Party Mac Developer Application:”
Once that’s clear, the steps are identical to pigsels guide:
[terminal]>codesign -f -v -s “3rd Party Mac Developer Application: Your Name (id)” JigsawSummerJoy.app/Contents/Frameworks/Adobe AIR.framework
[terminal]>codesign -f -v -s “3rd Party Mac Developer Application: Your Name (id)” JigsawSummerJoy.app/Contents/Frameworks/Adobe AIR.framework/Versions/1.0/Resources/AdobeCP15.plugin
[terminal]>codesign -f -v -s “3rd Party Mac Developer Application: Your Name (id)” JigsawSummerJoy.app/Contents/Frameworks/Adobe AIR.framework/Versions/1.0/Resources/Flash Player.plugin
[terminal]>codesign -f -v -s “3rd Party Mac Developer Application: Your Name (id)” JigsawSummerJoy.app/Contents/Frameworks/Adobe AIR.framework/Versions/1.0/Resources/adobecp.plugin
[terminal]>codesign -f -v -s “3rd Party Mac Developer Application: Your Name (id)” JigsawSummerJoy.app/Contents/Frameworks/Adobe AIR.framework/Versions/1.0
PS: In AIR 3.7 adobecp.plugin seems to no longer exists (I got an error saying it didn’t exists and ignored it, the app is accepted in the store)
8. We’re almost done, but there’s something about sandboxing that we need to handle. All apps submitted now must run in a sandbox, as discussed here: http://developer.apple.com/library/mac/#documentation/Security/Conceptual/AppSandboxDesignGuide/AboutAppSandbox/AboutAppSandbox.html.
Create a file named entitlement.plist to enable sandboxing.
Here’s what I have in that file:
<?xml version=”1.0″ encoding=”utf-8″?>
9. Now, you can sign the app, including the entitlement.plist.
[terminal]>codesign -f -v -s “3rd Party Mac Developer Application: Your Name (id)” –entitlements path-to/entitlement.plist JigsawSummerJoy.app
10. Are we done yet? Almost there. We still need to build the installer — this is the final file which will get submitted to the App Store. Again, the installer need to be signed. To find what signature to use, open the Keychain to see the name of your certificate, then copy and paste it. I was actually stumped here again because when I signed up to the Mac Developer Portal, there are 5 or 6 certificates to chose from (such as Mac Developer: Your Name). The key here is to use the one that begins with “3rd Party Mac Developer Installer:”
[terminal]>productbuild –component JigsawSummerJoy.app /Applications JigsawSummerJoyInstall.pkg –sign “3rd Party Mac Developer Installer: Your Name (id)”
11. The final steps is ‘test’ and ‘test’. Try to install using the .pkg file you have just created. Make sure the app installs to the Application folder and that there’s no problem. If everything works, it might be time to submit.
12. Bonus steps. Put all the blue lines above into a shell file so you don’t have to keep retyping all those whenever you rebuild. In my experience, it’s also best to delete the previously created output if you need to redo anything. So add this before adding the rest of the blue lines:
rm -R dist/JigsawSummerJoy.app
[add the blue lines from step 2 to 10]
Issues for me
I’m mentioning this as an example. Most apps doesn’t need extended entitlement at all, so you might not need to worry about this at all.
In my specific case of packaging this game, I encountered a problem in that after I added the entitlements.plist (which sets the app to run in the sandbox mode), the FileReference.browse() dialog no longer works. This dialog is used to allows users to import image files from their Mac to be used as puzzles in the app. I.e.: user clicks a button, which opens the File Browser dialog, from which the user can pick an image file to import into the app.
At first I didn’t know what to do and I was thinking about removing that feature but I think it’s an important feature so I dig more. After researching, I found out that I would need to add com.apple.security.files.user-selected.read-only as an extended entitlement. By the way, the Console app (Applications->Utilities->Console) http://www.macworld.com/article/1061222/jan08geekfactor.html is helpful in pinpointing what entitlement is needed.
So I added that into the entitlement.plist and repackaged.
<?xml version=”1.0″ encoding=”utf-8″?>
It solved the problem. Would Apple approve it? They did. Now, it is important to keep in mind that Apple has good reasons for sandboxing. Apple reviews every entitlement that your app requested, so the app should have good reasons to request additional entitlements. Therefore, in the iTunes App Details page when submitting , explain to Apple what each entitlement is used for, including step by steps use case(s) in precise and clear manner.
So that’s my journey. If you want to give the app a try: https://itunes.apple.com/us/app/jigsaw-summer-joy-puzzles/id659813149?ls=1&mt=12. Please do review and rate it in iTunes if you enjoy the app.
Next up, I’m going to build one of my Haxe NME app for the desktop store, too. Stay tuned.