What is app thinning, how do on-demand resources and Background Assets reduce install size, and what happened to bitcode?

21.7.1 · L3 · Interview

Predict first

Create an on-demand resource request with two tags. What do its tags and default priority report, and is the Urgent constant assignable?

import Foundation
import UIKit

let request = NSBundleResourceRequest(tags: ["level2", "level3"])
print(request.tags.sorted(), request.loadingPriority)
request.loadingPriority = NSBundleResourceRequestLoadingPriorityUrgent
print(request.loadingPriority == NSBundleResourceRequestLoadingPriorityUrgent)
  • ["level2", "level3"] 0.5, then true
  • [] 0.0, then false
  • It crashes because the tags are not in the bundle

Predict first

Does the Background Assets framework compile for iOS?

import BackgroundAssets

func startDownloads() {
    let manager = BADownloadManager.shared
    _ = manager
}
  • Yes, the API is available (it needs an extension and entitlements to actually run)
  • No, it is macOS only

Mental model. The store is a tailor who takes your one pattern and cuts a suit to the buyer’s size, and ODR is mailing the winter coat later if the buyer lives somewhere cold.

App thinning is the App Store delivering a tailored variant of your app instead of the full archive. Slicing creates a variant for each device class: only the right CPU architecture, and from asset catalogs only the image scales, colour spaces, GPU resources and device idioms that the device uses. That is why you use asset catalogs (rather than loose files in the bundle) for images and data, since only catalog assets can be sliced. The user’s download is therefore smaller than the IPA you upload, and the size Xcode’s App Thinning Size Report shows per device variant is the number to track (compressed download size versus uncompressed install size). The platform also limits what can be downloaded over cellular without asking, so a large download can reduce installs; check the current thresholds in Apple’s documentation.

Content that is not needed at first launch can be left out of the initial download. On-demand resources (ODR) tag assets (for example by game level) as initial-install, prefetched or on-demand, and the app requests tags with NSBundleResourceRequest(tags:), keeps the request alive while the content is in use and lets the system purge it afterward; the request’s loadingPriority hints at urgency (the checked values are a default of 0.5 and an Urgent constant). The newer Background Assets framework (BADownloadManager, with an extension that downloads while the app is not running, and Apple-hosted or self-hosted assets) serves the same goal with more control, and needs an extension and entitlements, so it cannot run from a plain script. Bitcode was Apple’s intermediate form the store could re-optimise and slice; it was required for watchOS and tvOS and optional on iOS, and Xcode 14 deprecated it, so new apps do not use it and the slicing that matters today is by architecture and assets.

A request is a description of what you want; nothing is fetched until you begin accessing. The default priority is 0.5, and urgent is the highest.

The API is part of the iOS SDK; downloading requires an app extension and entitlement, which is why this check only compiles.

Common traps

  • Shipping images outside an asset catalog. They cannot be sliced, so every device downloads every variant.
  • Holding an ODR request too long, or releasing it too early. Content is purged when you let go; end the request when the screen no longer needs it.

They might follow up with

  • What is bitcode now? Deprecated; Xcode 14 and later do not require or support it.
  • Which size matters for users? The compressed download for their device variant, and the installed size for storage.

Related questions

  • 21.7.2 Where does binary size come from, how do you measure and shrink it, and what do optimisation level, stripping…
  • 21.3.2 How do you build a performance culture on a team: budgets, regression gates, ownership and release guardrails?
  • 16.3.1 How do static and dynamic linking differ for an app, what do they cost at launch and in size, and what are…

Where does binary size come from, how do you measure and shrink it… →