Distributing your iOS app with an arm64e slice

[Update] Xcode 10.2 Beta 1 does not change the behavior that is described below.

Learn how to distribute your iOS app with the arm64e CPU architecture slice.


Introduction

This year’s incarnation of Apple’s iOS devices features the new Apple A12 Bionic CPU. Performance improvements aside, it is the first commercially available 7nm silicone, and the first CPU with the arm64e CPU architecture (as usual, AnandTech covers Apple’s new CPU extensively). Its new security extensions might require you to make adjustments to your code. Apple explains the various usecases and provides necessary steps in their documentation. The new pointer authentication requirements of arm64e resulted in additional work for my team at App Center as well.
It turns out to be quite challenging to distribute an app with an arm64e slice today. While Xcode 10.1 added support for developers to test their app with new architecture, it is not possible to submit an app to the App Store or TestFlight. In fact, the arm64e architecture will be stripped away if you use Xcode’s Organizer window. This happens even when exporting for AdHoc or Enterprise distribution (see the Xcode 10.1 release notes), and even when exporting from the commandline via xcodebuild.

In this post, I will show you how you can circumvent this limitation and export an iOS app with the arm64e slice. You can distribute it to your testers (using one of the alternatives to TestFlight of course).


Export the .xcarchive with the new architecture

First, you need Xcode 10.1 installed on your machine. Open your app’s project or workspace in Xcode 10.1 and add the arm64e architecture as described in the documentation.

Image1

Once you have done that, archive your application the same way you normally would.

This assumes that your app’s dependencies support the arm64e architecture. We recently added arm64e support to the App Center SDK for iOS. I plan on covering our journey in another post.

After Xcode has finished archiving the app, the Organizer window will open. Right-click on the archive that you just created and select “Show in Finder”.

Image2

I prefer to copy the .xcarchive package somewhere where I can find it easily. For my example, I’m choosing a folder on the desktop. To check if the binary in your .xcarchive package contains the slice for the arm64e architecture, run

lipo -info $PATH_TO_THE_BINARY_INSIDE_THE_XCARCHIVE.

The easiest way to get the path to the binary is: right-click on the .xcarchive package that you created, select “Show Package Contents”, and locate your .app package inside Products/Applications/. Then right-click on the .app package, select “Show Package Contents” once more, and find your app’s binary.

In my example, I need to run:

lipo -info /Users/benny/Desktop/AwesomeApp/AwesomeApp.xcarchive/Products/Applications/AwesomeApp.app/AwesomeApp.

This prints out the following:

Architectures in the fat file: /Users/benny/Desktop/AwesomeApp/AwesomeApp.xcarchive/Products/Applications/AwesomeApp.app/AwesomeApp are: arm64 arm64e

Awesome, the .xcarchive already contains the arm64e slice!


Create the .ipa file

The next step is to create the .ipa file that you can install on your new iPhone/iPad.

My initial idea was to switch back to Xcode 9.4.1, run xcodebuild -exportArchive -archivePath ./AwesomeApp.xcarchive/ -exportPath ./ -exportOptionsPlist ExportOptions.plist, and trick xcodebuild into exporting an .ipa file which contains the arm64e slice.

Unfortunately, this doesn’t work; signing the .dylibs and .frameworks will fail because Xcode 9.4.1’s code_sign tool will not be able to do it’s job – the .xcarchive was created in Xcode 10.1, after all.

Luckily, I learned about the ditto tool from a co-worker the other day. cd into the folder that contains your app’s .xcarchive and create a temporary directory structure:

mkdir -p tmp/app/Payload.

Copy your .app package into the directory using:

ditto AwesomeApp.xcarchive/Products/Applications/AwesomeApp.app tmp/app/Payload/AwesomeApp.app,

followed by:

ditto -ck --rsrc --sequesterRsrc --keepParent tmp/app/Payload/ AwesomeApp.ipa


Congratulations, you’re pretty much done. Use lipo -info on the app’s binary inside the .ipa package (unzip the .ipa, then use “Show Package Contents” ) to verify that it contains the arm64e architecture. It should print something like this:

/Users/benny/Desktop/AwesomeApp/Payload/AwesomeApp.app/AwesomeApp is architecture: arm64 arm64e

Now, go distribute your .ipa with the new arm64e architecture to your testers and squash all those bugs!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s