Signing and Uploading apps to the Mac App Store

This article is a checklist of all the tasks I ran into that were required to get a LiveCode macOS app onto the AppStore, last used February 20, 2019. Because the AppStore requirements change continually, this checklist will slowly get out of date, experience bit-rot. Let me know if these instructions fail you and I'll attempt to fix them. My thanks to the LiveCode community and LiveCode support team. Much of this arcane voodoo was passed on to me by others. 

Mark Smith, Mattias Rebbe, Panos Merakos provided very useful updates January 2024. Thank you. If something doesn't work, please let me know how you think I should edit these instructions. This is a group effort.

Please note, line wrapping within this article for the command line commands can hide or imply spaces. Suggest you copy the command lines into a text editor to see the correct command, spaces or not. Kee Nethery

0. Apple Developer Certificates

To upload to the App Store you need an Apple Developer account and corresponding developer certificates. Enroll in Apple's developer program at:

https://developer.apple.com/programs/enroll/

Create your Apple Developer installer and application certificate pair, and store them in your keychain on your development Mac.

1. Application Icon / Document Icon

The application icon is required to be available in a set of sizes. Instead of an asset catalog, LiveCode uses an .icns file for the app icon images. I found two ways to generate the .icns file and both require a 1024x1024 png app icon image.

GraphicConverter 10: Open the png and Save As the file type .icns. 

https://youtu.be/WRJE4TivKAc

Asset Catalog Builder: Is available on the App Store. Creates an asset catalog of all the required icon resolutions but it does not put them into an .icns file. Take the output folder from asset catalog builder, remove the json file, rename the folder "<whatever>.iconset". Replace <whatever> with any word you desire. The important part is that the name end in ".iconset". In Terminal enter:

iconutil --convert icns <path_to_iconset_folder>

for example:

iconutil --convert icns "/Users/myname/SDK Mac Apps/MyApp/grafica/icon.iconset"

Note, if you are not familiar with Terminal, it is in Applications / Utilities and instead of typing the path to the iconset folder, you can drag and drop that folder into Terminal and it will enter the complete path for you.

Select the resulting .icns files in your Standalone Application Settings...

https://youtu.be/wUhbB-ixjaM

To verify your .icns file has a 1024x1024 image, open it in Preview and "Get Info" on the images to see if one is 1024x1024. The first image in my .icns file is that resolution.

Mark Smith just uses a single 1024x1024 image and as of January 2024, that works fine.

2. Prepare your stack for building

If you have an automated script that cleans up your stack before you turn it into an application, run that now. Not everyone has this so not everyone needs this reminder.

3. Set the version number

This step is not needed for local development testing. Is required for uploading to the Mac App Store.

https://youtu.be/dHqyGygtSQA

Each upload to the App Store needs a unique version number. In LiveCode Application Settings / Mac / Short Version, increment the version number. In my case I submitted 2.0 and that version was rejected so I changed the next version to be reviewed to 2.0.1. The App Store uses the version values in the Standalone Application Settings windows so be sure to provide that exact version to the App Store.

Note, the version number (CFBundleVersion and CFBundleShortVersionString) can be at most three positive integers separated by periods. LiveCode defaults to 1.0.0.0 which violates that rule. A version number of the format 1.0.0 is acceptable.

Note also that each version that gets uploaded needs a new version number. When you upload a new version and Apple comes back with an error email telling you about something that needs to be fixed, you will need to increment your version number before uploading the corrected application.

4. Build the standalone

Save as standalone application. Build for Mac OS X 64-bit only. Apps with any 32-bit code in them will be rejected when uploading.

5. Remove extended attributes

As of January 2024 Mark Smith and Mattias Rebbe have indicated that this step might no longer be required. Am leaving it here just in case.

https://youtu.be/8UG3aqWSQ_A

LiveCode saves a bunch of extended attributes into the files in the standalone application and they must all be removed. Use the Terminal command line to see all the stuff that needs to be removed:

sudo xattr -lr <path_to_standalone_app_bundle>

And to actually remove all that cruft:

sudo xattr -cr <path_to_standalone_app_bundle>

Run the first command line "-lr" a second time to verify that all the cruft has been removed.

6. Rename localization files

This step is not needed for local development testing. Is required for uploading to the Mac App Store.

https://youtu.be/DYi-teC-qUg

The App Store looks at the list of localization .lproj files to determine which languages the app supports. Apple is no longer using the names of languages (English, Dutch, Japanese, etc), instead the lproj folders must use the proper ISO codes. For example en.lproj is for English, jp.lproj is for Japanese, etc.

Open the standalone app to Show Package Contents / Contents / Resources and remove all the lproj folders that your app does not support. Rename the others using the ISO codes. My app only supports English so the only lproj folder in my app is en.lproj.

7. Check the standalone icon

This step is not needed for local development testing. Is required for uploading to the Mac App Store.

https://youtu.be/J8zBrqamNyc

In that resources folder should be the icns file you created. It will be renamed to "Standalone.icns". If not, you didn't select your icns file in the Livecode / Standalone Application Settings / Mac OS window.

8. Add an encryption key to the plist

This step is not needed for local development testing. Is required for uploading to the Mac App Store.

https://youtu.be/TqNy7hMtKcc

If your app uses no encryption other than HTTPS (yes HTTPS is encryption, it is OK to use), add into the plist the flag that tells Apple "I'm not using encryption other than HTTPS". Go to Show Package Contents / Contents / Info.plist and add in:

	<key>ITSAppUsesNonExemptEncryption</key>
	<false/>

Whatever the file format of the plist, don't change it when you make this edit. I use BBEdit for these kinds of file edits. It handles file write permissions and such.

9. Add a category type key to the plist

This step is not needed for local development testing. Is required for uploading to the Mac App Store.

https://youtu.be/uVWtwA4Pv28

In Info.plist one must add a value for LSApplicationCategoryType. The various possible values are listed here.

For my app, I added:

	<key>LSApplicationCategoryType</key>
	<string>public.app-category.finance</string>

10. Add a minimum system version key to the plist

There is a minimum system version key in the application plist so this step may now be obsolete. Leaving it here just in case.

In Info.plist one must add a value for LSMinimumSystemVersion. I am using LiveCode Indy 9.0.2 and according to Wikipedia, LiveCode 9.x supports 64-bit Intel macOS 10.9.x and greater.

For my app, I added:

	<key>LSMinimumSystemVersion</key>
	<string>10.9.0</string>

11. Assign unique identifiers to embedded bundles in your application: tsNet, revdb, dbsqlite, etc

Only required when submitting to the Mac App Store.

NOTE: tsNet.bundle is only included in apps that utilize internet connectivity. Skip this step if you do not have "tsNet.bundle" in Show Package Contents / Contents / MacOS / Externals / tsNet.bundle.

https://youtu.be/Dll9BqvHePM

There is a code resource within LiveCode app bundles named tsNet and your tsNet in your app needs to be "owned" by you otherwise you get a CFBundleIdentifier Collision when uploading your app. Go to Show Package Contents / Contents / MacOS / Externals / tsNet.bundle / Show Package Contents / Contents / Info.plist  If your domain is "YOURCOMPANY.com" and your app is named "YOURPRODUCT" then replace "au.com.techstrategies.external.tsNet" with "com.YOURCOMPANY.YOURPRODUCT.tsNet" in the Info.plist file in the tsNet.bundle.

For my app, I edited it to:

	<key>CFBundleIdentifier</key>
	<string>com.txfconvert.txfconvert.tsNet</string>

For the other bundles like revdb and dbsqlite:

	<key>CFBundleIdentifier</key>
	<string>sbs.com.runrev.revdb</string>

	<key>CFBundleIdentifier</key>
	<string>sbs.com.runrev.dbsqlite</string>
Click to copy

12. Remove 32-bit code from revsecurity.dylib

As of January 2024 this step is probably now obsolete.

Note: not all apps will have revsecurity.dylib 

Note: LiveCode 9.0.1 and earlier are outputting a universal version (64-bit and 32-bit) of revsecurity.dylib. Future versions might cease doing that. The number of bytes in the disallowed version is 3,892,216 and after the removal of 32-bit code the byte size is 2,085,880.

Go to Show Package Contents / Contents / MacOS / revsecurity.dylib. If revsecurity.dylib is present, you must remove the 32-bit code from that dynamic library. 

sudo lipo <path_to_revsecurity.dylib> -remove i386 -output <path_to_revsecurity.dylib>

13. Remove 32-bit code from revpdfprinter.dylib

As of January 2024 this step is probably now obsolete.

Note: not all apps will have revpdfprinter.dylib (mine does not)

Note: It is my understanding that LiveCode 9.0.1 and earlier are outputting a universal version (64-bit and 32-bit) of revpdfprinter.dylib. Future versions might cease doing that. Since my app doesn't include that code I cannot tell you how many bytes the universal and 64-bit only versions are.

I do not know where revpdfprinter.dylib is stored within the app. Perhaps it is at Go to Show Package Contents / Contents / MacOS / revpdfprinter.dylib. If revpdfprinter.dylib is present, you must remove the the 32-bit code from that dynamic library. 

sudo lipo <path_to_revpdfprinter.dylib> -remove i386 -output <path_to_revpdfprinter.dylib>

14. Close any Package Contents windows.

Close all the windows where you are examining Package Contents.

15. Change the permissions of the standalone app

As of January 2024 Mark Smith has never needed to do this so perhaps it is no longer needed.

https://youtu.be/8YNtU62FfYQ

Change ownership of all the parts and pieces of the standalone app so that you "own" tsNet. In terminal:

	sudo chmod -R u+rw <path_to_standalone_app_bundle>

16. Enable sandboxing

https://youtu.be/IuZjoLZ462U

Enable sandboxing for the Mac App Store. Create "entitlements.plist" in the same directory as the standalone application. I duplicate the Info.plist file, change the name, and replace the <dict> section with my apps' sandbox settings.

All the standard sandbox entitlement keys are documented here.

The app sandbox temporary exception entitlement keys are documented here.

https://youtu.be/Bhpne2lRK4M

My app user selects a file, opens it, reads it, and writes to another file so I need "com.apple.security.files.user-selected.read-write".

I use "get URL" and thus need "com.apple.security.network.client".

Your sandboxed and signed app automatically has a folder you can write into for preferences:

	put specialFolderPath("support") & "/<your_app_name>" into prefsfolder

You can automatically read and write to that folder. No entitlements need to be specified for that folder. For my app with an app name of "TXF Convert", prefsfolder is:

/Users/keenethery/Library/Containers/com.txfconvert.txfconvert/Data/Library/Application Support/TXF Convert

This path through "Container" is only visible to you when the app is sandboxed and signed. I write my preferences file inside the final "TXF Convert" folder inside the "Application Support" folder.

My entitlements.plist contains this dict specification.

<dict>
	<key>com.apple.security.app-sandbox</key>
	<true/>
	<key>com.apple.security.files.user-selected.read-write</key>
	<true/>
	<key>com.apple.security.network.client</key>
	<true/>
</dict>

None of the LiveCode documentation details what entitlements are required for various LiveCode functions or commands. The only way I found out what worked and what didn't was by testing the signed and sandboxed version of my app and then altering it accordingly.

Note, some entitlements are read-only with a corresponding read-write. You cannot use both. If you need read-write, do not include read-only.

Mark Smith has provided his dict specification. The last two entries he ran across while trying to get his submission accepted.

<dict>
	<key>com.apple.security.app-sandbox</key>
	<true/>
	<key>com.apple.security.files.user-selected.read-write</key>
	<true/>
	<key>com.apple.security.files.bookmarks.app-scope</key>
	<true/>
	<key>com.apple.application-identifier</key>
	<string>R54C74LFCN.com.marksmith.safesort</string>
	<key>com.apple.developer.team-identifier</key>
	<string>R54C74LFCN</string>
</dict>
Click to copy

Mark Smith provides this additional information when using TestFlight:

If you are submitting to TestFlight your app must have an embedded provisioning profile. I just went into my Apple account and in Profiles selected the option to create a profile for submission to the app store then filled in the blanks. However, if you are doing this outside Xcode there are some additional entitlements you need to include (one for the application-identifier and one for the team-identifier). Step-by-step instructions for doing this outside Xcode are provided here:

https://developer.apple.com/forums/thread/733942

In addition, if you are not submitting to TestFlight but your entitlements still include a restricted entitlement, like mine does, you need to include an embedded provisioning profile and the extra entitlements. This is also discussed in the link referenced above.

Be aware that if you include a provisioning profile it needs to be renamed “embedded.provisionprofile” and included in <app name>/contents/ (same place where the info.plist file is located). It does not need to be installed on your device.

17. Code sign executables

https://youtu.be/TmTqOVTXQMA

All of the executables in your app must be code signed with your Apple Developer ID certificate. Open the application "Keychain Access" in your Utilities folder. Select the keychain "login" and the category of "My Certificates". In the list should be two:

3rd Party Mac Developer Installer: <your_name> (<your_ID>)

3rd Party Mac Developer Application: <your_name> (<your_ID>)

For example:

3rd Party Mac Developer Installer: Kee Nethery (CEASNJ1234)

3rd Party Mac Developer Application: Kee Nethery (CEASNJ1234)

If you have "Developer ID Application: ..." and "Developer ID Installer: ..." in the "Certificates" section within "KeyChain Access", and no certificates within the "My Certificates" section, you will need to create the certificates that get stored in "My Certificates".

In developer.apple.com look for the area "Certificates, Identifiers and Profiles" also displayed as "Certificates, IDs and Profiles". Select that. In the upper left, select "macOS" to create macOS certificates. From that point the path is: macOS / Production / What type of certificate do you need? / Production / Mac App Store / [Continue] / Mac App Distribution. You'll create a CSR with your Apple ID email and company name that gets saved to disk. Continue, select the CSR, and it will create a file in your Downloads folder "mac_app.cer". Run through the process again and select the other choice "Mac Installer Distribution". You need both certificates. Continue in the web site and you'll be able to select them and have them be imported into your keychain so that they show up in "My Certificates".

You will need the "Application" portion to do the code sign. You will also need Xcode installed with it's utilities to perform the code sign. Using the above sample, in Terminal, code sign the app and all of the embedded executables inside it:

sudo codesign --verbose --deep --force --sign "3rd Party Mac Developer Application: Kee Nethery (CEASNJ1234)" <path_to_standalone_app_bundle>

18. Code sign entitlements.plist

https://youtu.be/6qa5lzNeBQI

Once that is done, a CodeSignature folder is created inside the app bundle. Then codesign the entitlements.plist:

sudo codesign --verbose --force --sign "3rd Party Mac Developer Application: Kee Nethery (CEASNJ1234)" --entitlements <path_to_entitlements.plist_file> <path_to_standalone_app_bundle>

Previous example above included a "--deep" flag and Panos Merakos suggested not to sign the embedded packages, thus dropping the "-- deep".

19. Verify the signing

https://youtu.be/MkYJMSyDb3g

Just to confirm all is well, verify the code signing:

sudo codesign --verify <path_to_standalone_app_bundle>

No response means that there were no errors and it is code signed.

20. Create the installer package

https://youtu.be/XSOI_vsBxig

Create the installer package.

sudo productbuild --component <path_to_standalone_app_bundle> /Applications --sign "3rd Party Mac Developer Installer: Kee Nethery (CEASNJ1234)" --product <path_to_standalone_app_bundle_Info.plist> <path_to_standalone_app_bundle_delete_".app">.pkg

For that last path, it is the path to the standalone application bundle with the .app suffix replaced by .pkg  

For example:

      LiveCode Projects/myApp.app

would become:

      LiveCode Projects/myApp.pkg

This will create a properly signed installer package file in the same folder as the application.

21. Test the installer

https://youtu.be/evEEjjVka-E

Test the installer.  (Note the "-target /" that comes after the path to the pkg file)

sudo installer -store -package <path_to_app_pkg_file> -target /

It will go through the installation process to confirm that the installer package is OK.

NOTE: If the app is signed for distribution to the Mac App Store the resulting app will not run locally.

22. Test the app

Now that the signed app is permanently embedded in the installer, you must do a final test of the signed app to make sure that it still works with all the sandbox permissions. Test everything. I ended up removing app features because they ceased working when the app was signed to operate in the sandbox.

NOTE: You can only test an app that has not been signed for distribution to the Mac App Store. Once you have signed it for distribution you’ll need to download it from the Mac App Store to test it.

23. Create a new version in App Store Connect

https://youtu.be/htMTB7XfH8M

New App

To create a new app, in developer.apple.com: App Store Connect / Go to App Store Connect / My Apps / + / New macOS App 

"Company Name" is the name of your company as shown on your keychain certs, in my instance "Kee Nethery"

"Name" is the name of the app without the .app appended to it.

Bundle ID: was selectable from a list (no idea where that came from) and it had the name and the bundle ID "TXF Convert - com.txfconvert.txfconvert" 

"SKU" is whatever you want it to be, it's your internal identifier. I used "txfconvert".

Once I created the new macOS app, it was assigned an Apple ID. For example, "1454474799"

Essentially you are registering a new Bundle ID so that you can then upload your .pkg file that has that Bundle ID.

Revise Existing App

To create a new version, in App Store Connect, select the previously version and hit the "(+) VERSION" button on the left side of the App Store screen. Once you've uploaded the standalone with the Application Loader, select with the (+) next to the "Build" section header to select the previously uploaded app package.

When Apple tells you to fix an error in 2.0 you'll need to increment the version number in the app (for example to 2.0.1) and in App Store Connect. You can just edit the version number in the App Store Connect data display from 2.0 to 2.0.1. Now all the app data belongs to 2.0.1.

24. Upload the app to App Store Connect

Application Loader App

https://youtu.be/H1xrzvp_lK0

"Application Loader.app" is now in Xcode. You need the most recent Xcode version to access it. Xcode menu / Open Developer Tool menu item / Application Loader.app

Little Snitch Users: I have Little Snitch installed. The Application Loader within Xcode kept failing until I allowed incoming connections to the process "ascp". For some reason Apple servers want to connect back into my machine for the application upload. Once the upload was complete, I disabled that rule in Little Snitch. 

Transporter App

From Mark Smith January 2024: I used a different process than the one Kee describes. To upload the app to the App Store, launch Transporter (available from the App Store) and drop the application package (.pkg file) onto Transporter. Transporter will do the rest. NOTE: I think you must complete Step 23 first before attempting to upload to the App Store (because Transporter picks the bundle ID out of the .pkg file you upload).

25. Add screen shots to App Store Connect

https://youtu.be/Og90dY1uF94

Screen shots uploaded into App Store Connect for the App Store need to be specific screen sizes. The fewest dpi is 1280x800 and the store allows 10 screen shots. The screen shots have to be the entire screen so I created an alternate user to get clean anonymous screen shots.

12 Comments

Dan Friedman

Thank you for these steps! It really made it much easier to understand and complete the process. I am about to submit to the App Store, but I have a question... I would also like to make my app downloadable on my website. Can I take the app after step 20 (before making the installer) and post it for downloading? Would this be advisable and fulfill all of apple's hoops that I need to jump through?

Kee Nethery

There is another article specifically for people downloading a macOS app outside of the App Store. There are many similarities, but they are not exactly the same. The code is probably going to be different in the two versions of your app. Splash screens, copy protections, and functions not allowed in the App Store come to mind. http://lessons.livecode.com/a/1088036-signing-and-notarizing-macos-apps-for-gatekeeper

Russell

We are developing a MacOS app. However we have only once managed to make a successful .pkg. We are now wishing to complete the process but seem only to make .pkg files that produce an app with zero bytes in it. The frustrating thing is the full installation process occurs “successfully” but when the app is checked it has zero bytes. We are using LiveCode 9.0.4, Mojave, 10.1 Xcode Any help gratefully received.

Elanor Buchanan

Hi Russell

At which stage does your app end up with a size of 0 bytes? Do you only see this at step 21: Create the installer package or once the app has been installed?

Kind regards

Elanor

Russell

21. The .pkg is around 255 mb (as it should be) but 22. the app installed is 0 bytes.

Russell

Hi Elanor,

Excuse my curtness.

Sent in haste.

Regards

Russell

kee nethery

Russell, Maybe send me a copy of your terminal log for all these steps to my personal email? [email protected] Perhaps there is something I'll be able to see? Kee

Elanor Buchanan

Hi Russell,

Could you possibly send your .pkg file for us to take a look at? If you could send it to [email protected] that would be helpful/

Thanks

Elanor

Russell

Hi Kee and Elanor

Thank you for your requests. We are going to make a fresh .pkg as we have thought of something else to try re. Preferences. If that does not work we will send the Terminal log and .pkg through to each of you as requested. Thank you for your assistance in this matter.

Regards

Russell

Russell

Hi Kee and Elanor

The problem is now fixed. It was due either to missing stage 15 out or simply typos. Thank you for your help with this it is much appreciated.

Regards

Russell

Kee Nethery

This step by step has bit rot. I've not tested it in over a year. Thank you to Mark Smith for forwarding this email from Apple Developer Support;

We’re reaching out because you recently used the altool command-line utility to notarize your macOS software with Apple. As announced last year at WWDC22, if you’re still using altool with the Apple notary service, you should transition to the notarytool command-line utility as soon as possible. Notarizing software with altool was deprecated in Xcode 13, and the Apple notary service will no longer accept uploads from altool as of November 1, 2023. Existing notarized software will continue to function properly.

For information on notarizing your apps, read TechNote TN3147: Migrating to the latest notarization tool.

Panos Merakos

Hello Kee,

Indeed, this lesson might be a bit outdated, but in the sense that some of these steps are now already done by LiveCode.

RE the note about the notarytool utility, note that this is for notarizing the mac app for distributing it *outside* the Mac App Store - so it does not affect this lesson.

Hope this helps.

Kind regards,
Panos
--

Add your comment

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.