App thinning, Bitcode, Slicing: tutorial (iOS app)

How it works?

Apple has released several models of the iPhones/iPads/Apple Tvs, having different CPU architectures, screen resolutions and the screen sizes. Here we will mainly talk about iPhone. Though the same process will be applicable to iPad and Apple Tv as well.

Architectures like armv6 (older iPhones), armv7 (iPhone 4, 4S), armv7s (iPhone 5, 5c), arm64(iPhone 5S and later). The different resolution requires different image versions like @2x (iPhone 4, 4s, 5, 6, 6s, 7, 7s, 8, XF), @3x (Plus size iPhones, X, Xs, XS Max).

Apps have to support all of the architectures and the screens when released to the market. A Universal binary must be generated which supports all of the variants. No matter which device you install the app on, the universal binary will be downloaded to your device, definitely, the size of the binary will be big. One can clearly see that the binary is not optimized. A larger size causes more Data consumption, larger size on disk and might restrict “over the air” download.

Apple came up with an optimization (called App thinning) and with this, App Store will tailor the binary for all the possible device configurations and a thin binary will be downloaded on a particular iPhone.

How it works:

Slicing: Here is what Apple document says about it.

Slicing is the process of creating and delivering variants of the app bundle for different target devices. A variant contains only the executable architecture and resources that are needed for the target device. You continue to develop and upload full versions of your app to App Store Connect. The App Store will create and deliver different variants based on the devices your app supports. This works only on iOS 9 and later, the older will still be getting the Universal binary.

Bitcode:

Bitcode is an intermediate representation of a compiled program, something similar to Bytecode in JAVA. When you archive an application with bitcode enabled, the compiler produces binaries containing bitcode rather than machine code. Once the binary has been uploaded to the App Store, the bitcode is compiled down to machine code. The App Store may compile the bitcode again in the future, to take advantage of future compiler improvements without any action on your part.

Confused? Bitcode, slicing and app thinning are little confusing terms. Let me explain them a bit. App thinning is the whole process of delivering a tailored binary to the devices. It includes App Store + Operating System, both together works towards enabling the download and use the thin binaries. It manages future updates too. Slicing is performed by the App Store (TestFlight and Xcode can also do that for testing). The App Store receives a bitcode enabled fat binary from the developer and slices it into small binaries. The number of binaries will be equal to the number of device variations supported by the app. A thin binary is generated for a particular architecture and contains only the required assets. The binary will contain either @2x or @3x images based on the iOS device. Bitcode is a pre-requisite of slicing. You enable bitcode in Xcode. Unless until you enable the bitcode, Xcode won’t generate a bitcode binary and so the app store won’t be able to recompile it to generate smaller binaries and the slicing won’t happen.

What do we need to do:

  1. Use the Asset Catalog to the store assets like images. If you are supporting iPhone 4 and above and not supporting iPad 2 or earlier, you don’t need the 1x images at all.

2. Enable Bitcode for the project. You have to enable it for all the 3rd party frameworks. If the current frameworks are not bitcode enabled, you have to download their bitcode enabled version.

Errors:

You might get the following error for a framework integrated in your project like

bitcode bundle could not be generated because ‘/ the location of the SDK’ was built without full bitcode.

There are 2 steps to enable a bitcode for 3rd party projects

2.1 : Turn On the ENABLE_BITCODE flag into the Project Build Settings.

2.2: Add -fembed-bitcode as a compiler flag under Other C Flags into the Project Build Settings.

If you get the following error, the reason could be a framework is bitcode compiled using the different version of Xcode than the one you are using for compiling now. In my case, one of my frameworks was compiled using Xcode 9.4.1 while I was using Xcode 9.2

3. On-demand resources.

On-demand resources are resources — such as images and sounds — that you can tag with keywords and request in groups, by tag. The App Store hosts the resources on Apple servers and manages the downloads for you. The App Store also slices on-demand resources, further optimizing variants of the app.

Getting app size report:

Once the code changes are done, we have to generate the report. There are the following ways of seeing the report before you go live.

  1. Xcode report: Export the archive, select “All Compatible device variants” from App Thinning dropdown and check the “Rebuild from Bitcode” checkbox.

It will take some time and generate all the different ipa files for the supported iPhones. It will also generate an App Size report.

2. Testflight report: Once you upload the bitcode enabled binary to the testflight, the test flight shows the summary like below once it’s reviewed and available for testing. You can tap on a link “App Store File Sizes” and get the report. It will show a report detailing the sizes for all the possible iOS devices.

NOTE: The app slicing process takes place at the App Store. Since the Enterprise apps are not uploaded to the app store, you might choose to keep the bitcode disabled for them. However, for Enterprise builds, Xcode can generate sliced binaries on your mac itself. In that case, the users have to install the appropriate binary by themselves.

The dSYMs:

As we saw earlier, that the Bitcode enabled binary generated by Xcode contains bitcode and not the machine code. App Store recompiles the binary from bitcode to machine code. So the actual dSYMs will be generated at this point by App Store. Your Xcode does have dSYMs but that is for the bitcode binary. They can’t be used to de-symbolicate the crash reports for the crashes faced by real customers.

So, once your app is reviewed and ready to be released, you have to download the dSYMs and keep it somewhere for records (You might want to upload it to Crashlytics/Fabric/Firebase).

Testflight provides a link to download the dSYMs as shown in the image above “Download dSYM”.

Downloading the dSYM files from the iTunes Connect website

  1. Open the App Details page.
  2. Click Activity.
  3. From the list of All Builds, select a version.
  4. Click the Download dSYM link.

This is a very powerful feature which every app which is larger in size should adopt. Current, over the air download limit for iOS apps, is 150 MB that means if the size of the app is larger than this App Store won’t allow the download over LTE/4G. While the device disk size is not a big concern for iPhone users these days, reducing the size will still help in faster app updates.

In this tutorial, mostly I have shared what I have to do to support app thinning in an older project.

Thanks for reading this. Let me know your feedback.

Happy coding!

works @Globallogic