Mehdi Tmimi Mobile

Mobile Development Capsule 03 · iOS

How does iOS run an app?

Your app works on your iPhone. Then it opens the camera, and vanishes. No error, no dialog. Your code is fine. A line is missing from a file iOS reads.

The short answeriOS does what Android does: a sandbox per app, a lifecycle the system drives, permissions the user decides. Apple holds the keys: only code Apple has authorized runs, and every door is Apple's. An app the user leaves is frozen within seconds.

Same shape as Android, other keys

Three rows are the same idea, renamed. Three decide who holds the keys.

Android and iOS, side by side
Android capsule 02iOS
The packageAn APKAn .app bundle, in an .ipa
The contractAndroidManifest.xmlInfo.plist, plus entitlements: what Apple granted
The sandboxA Linux user per appA container per app
The certificateSelf-signed, no authorityIssued by Apple
The way inPlay, or an APK the user allowsApple's doors only
Work after leavingA declared foreground service, with a notificationA declared mode, or handed to iOS

On Android, no authority vouches for your certificate. On an iPhone, nothing runs unless Apple authorized it.

Go deeper Inside the signature 1 min

Before anything runs, iOS checks the code signature. It is a hash of every file, signed with a certificate Apple issued to a named developer. Change one byte, and iOS will not launch the app. This covers the app's native code. JavaScript an app downloads, such as an Expo update, is not signed by Apple; the store's rules limit what it may change. Updates are capsule 10.

The signature carries the app's entitlements: the capabilities Apple granted, such as push notifications or iCloud. A provisioning profile ties it all together: who may sign, which app, on which devices, until when, with which entitlements. The App Store signs the app once more when it distributes it.

On Android, the certificate is self-signed: no authority stands behind it. On Google Play, Google keeps the app's signing key and signs what it delivers.

Go deeper Files and secrets 1 min

At install, iOS creates a container for the app: a folder with a random name, holding Documents/, Library/ and tmp/. The app reads and writes there, and nowhere else. Sharing goes through the system: the share sheet, the document picker, iCloud.

Files in the container are encrypted by default once the user has set a passcode, and readable from the first unlock after a restart. Secrets belong in the keychain, by default readable only while the device is unlocked. Where the data lives, and which copy is the truth, is capsule 05.

Every door is Apple's

iOS runs only code Apple has authorized. So every way onto an iPhone is a way Apple provides.

  • The App Store, after App Review.
  • TestFlight, for testers you invite.
  • Your own devices, from Xcode.
  • A company's staff, employees only.

In the European Union, Japan and Brazil, a law or a regulator added other doors. The fold below lists them.

There is no “unknown sources” switch. Apple is the doorman at every door.

Go deeper Where a law or a regulator opened other doors 1 min

In the European Union, a law brought alternative app marketplaces in iOS 17.4, and a developer's own website in iOS 17.5. In Japan, a law brought marketplaces in iOS 26.2. In Brazil, an agreement with the competition regulator brought them in iOS 26.5. In Japan and Brazil, only marketplaces install from a website.

These apps skip the App Store, not Apple. Each one is notarized: a baseline review by Apple of security and privacy, whatever the channel.

TestFlight takes up to 10,000 testers, invited by email or by a public link, each build for 90 days; the first build for outside testers is reviewed. Your own devices take a build from Xcode, a few days at a time with a free Apple Account. Delivery is capsule 10.

Checkpoint

A classmate sends you their app's .ipa file. Can you install it on your iPhone by opening the file?

See the answer

There is no unknown-sources switch on iOS. An app arrives through the App Store or TestFlight, or as a build whose profile lists your device. The developer's signature alone is not enough.

No purpose string, a crash

The first use of the camera shows a dialog. iOS draws it, not your app, and quotes your purpose string. Without that string, the request fails, and iOS usually crashes the app.

  1. The app asks for the camera. iOS shows its own dialog, with the app's name and its purpose string.
  2. The user allows or refuses. iOS stores the answer in Settings, and does not ask again.
  3. No purpose string: the request fails, and the app crashes at that moment.

The user answers once, and can change it in Settings. The app must work when the answer is no.

Go deeper Notifications, reviews, privacy labels 1 min

The camera, the microphone, the location, the photos and the contacts are protected resources, among others. Notifications ask for permission too, but need no purpose string.

App Review rejects a build whose code reaches a protected resource without a purpose string, even when only a library calls the API. The App Store listing shows what data the app collects. Since May 2024, a privacy manifest must also say why the app uses certain APIs that could fingerprint a device, UserDefaults among them: self-declared, and the developer answers for it.

Leave the app, and it freezes

When the user leaves, the app gets a few seconds. Then iOS suspends it: in memory, running nothing. When memory runs short, iOS terminates it, without a callback.

  1. Not runningnever launched, or terminated
  2. Inactivea passage between states
  3. Activein front, interactive
  4. Backgrounda few seconds to finish
  5. Suspendedfrozen in memory, no CPU
  6. Terminatedno callback; back to not running

Back from suspended: instant. From terminated: a cold launch.

Save as the app leaves the foreground. Design for a cold launch at any time.

Go deeper Background modes, the hooks, and Android 2 min

Work that must go on after the user leaves needs a background mode the app declares and App Review checks: audio, location, voice over IP, fetch and processing jobs the system schedules, pushes that wake the app briefly. Or it is handed to the system: a background URLSession transfers files even while the app is suspended. Since iOS 26, an app can also ask to finish one job the user started, visibly and cancellably. A general “keep running” does not exist.

Where to save: scenePhase .inactive then .background in SwiftUI; sceneWillResignActive then sceneDidEnterBackground in UIKit; AppState “inactive” then “background” in React Native; the visibilitychange event in a web app. Since iOS 13, these states belong to each scene, each window of the app.

Android now freezes too: since Android 14, a cached process is frozen about ten seconds after the user leaves, on phones that support it. The difference is the way out: on Android, a foreground service, declared with its type and shown as a notification, keeps the app running. On iOS, nothing general does.

Before the lab

Seeing it needs no Mac; building it does

Xcode and the iOS simulators run only on macOS. To build an iOS app, you need a Mac: yours, or one in the cloud. To see your app on an iPhone, you may not.

What each family needs to run on an iPhone
FamilySee it on an iPhone, no MacBuild it for the App Store
Native, SwiftNoA Mac with Xcode, yours or one in the cloud
ExpoYes: Expo Go, within its limitsEAS Build, on Expo's Macs
Ionic + CapacitorThe web build, in SafariA Mac with Xcode, yours or one in the cloud
PWAYes: Safari opens itNo build: it is a website

To build for the App Store, the certificate and the profile must be yours: a paid Apple Developer Program membership.

Go deeper Expo Go's limits, and the cloud 1 min

Expo Go comes from the App Store. It runs your project only on the same SDK version, only with the native libraries it ships, and only when you are logged in to Expo both in the CLI and in the app. Anything else needs a development build.

EAS Build and Codemagic build on their Macs and hand you the signed .ipa. Xcode Cloud too, but you first set it up from Xcode, on a Mac. The membership costs 99 USD a year; an accredited school can ask Apple for a fee waiver.

With knowledge · in class

The AI gets the paperwork wrong

An assistant writes Swift as fluently as Kotlin. It gets the paperwork wrong. It forgets the purpose string and the keychain, iOS's safe for secrets. It switches on background modes you did not ask for.

Paste first, whatever the family

assume iOS can freeze the app seconds after the user leaves and terminate it without warning: save the draft as the app leaves the foreground, restore it on a cold launch, and enable no background mode unless I ask

All families

Say it in the prompt

for every protected resource the app uses, add its iOS purpose string with a one-sentence reason a user would accept, and tell me in which file or setting you put it

Where the purpose strings live

  • Native: the target's Signing & Capabilities and Info panes. A new Xcode project has no Info.plist file.
  • Expo: app.json, in ios.infoPlist or a module's config plugin.
  • Ionic: ios/App/App/Info.plist, a real file after npx cap add ios.
  • PWA: nothing to declare. Safari asks the user for you.

Native

Say it in the prompt

for every protected resource the app uses, add its usage description (in Info.plist, or as an INFOPLIST_KEY_ build setting if the project has no Info.plist file) with a one-sentence reason a user would accept; store the session token in the Keychain, never in UserDefaults

Check the project

Expo

Say it in the prompt

set each iOS purpose string through the module's config plugin or ios.infoPlist in app.json, with a one-sentence reason a user would accept; store the session token with expo-secure-store

Check the project

Ionic

Say it in the prompt

after npx cap add ios, add to ios/App/App/Info.plist the usage description each plugin's documentation lists, with a one-sentence reason a user would accept

Check the project

PWA

Say it in the prompt

ask for the camera only when the user taps a button that needs it, and keep every other feature working when the answer is no

Check the project

Review reads these settings too. Guideline 2.5.4: background services only for their intended purposes, such as VoIP, audio, location, task completion and local notifications. Guideline 5.1.1: ask only for data relevant to the app's core functionality.

Try it on your phone · 10 minutes

See the sandbox from the user's side, no Mac needed

On any iPhone; no iPhone, pair with a classmate. Each “You should see” follows Apple's own guide, linked.

  1. The answer lives in Settings. Settings → Privacy & Security → Camera.

    You should see The apps that asked for the camera, each with its own switch. Apps that never asked are not listed. iPhone User Guide

    This proves The answer belongs to the user and the system, not to the app.

  2. The bundle and the container. Settings → General → iPhone Storage → an app.

    You should see Its storage in detail, then two actions: offload the app, or delete it. Offloading frees the app's storage but keeps its documents and data. Apple Support

    This proves The app and its data are two things: the bundle, and its container.

  3. Who works in the background. Settings → Battery → View All Battery Usage, then a day, then an app.

    You should see For each app, two times: “On screen” and “Background”. iPhone User Guide

    This proves The system counts background time, app by app. It is not free.

Go deeper Two more places, and homework 2 min

Files → Browse → On My iPhone. A folder appears for an app only when it chose to share its Documents folder with the user. Every other container stays invisible, even to you.

Settings → General → VPN & Device Management. A company's own app, installed by hand outside the App Store, opens only once the user trusts its developer here. Apple Support

Homework for capsule 09. Settings → Privacy & Security → App Privacy Report: turn it on for a week. It shows when each app accessed data or sensors, and which domains it contacted. Apple Support

Quick check

Capsule 02 On Android, your notes app is cached, and memory runs short. What runs in your code before the process dies?

See the answer

A killed process runs nothing, not even onDestroy. iOS does the same to a suspended app: it terminates it with no callback, so on both you save on the way out, not at the end.

Capsule 02 Who vouches for the certificate that signs an app, on Android and on iOS?

See the answer

An Android certificate is self-signed, from a key the developer generates; on iOS, nothing runs unless Apple issued the certificate to a named developer. Play App Signing means Google keeps a key, not that it vouches for one.

The first time your app asks for the camera, a dialog appears. Who draws it, and whose sentence does it show?

See the answer

iOS draws the dialog, not your app, with your app's name and the purpose string it declares. Apple writes no default sentence: without that string, the request fails and the app usually crashes.

Your app's upload is at 40% when the user switches to another app for twenty minutes. The app declares no background mode. When the user comes back, the upload…

See the answer

Without a declared mode, the app gets a few seconds and is then suspended, upload included; if memory ran short meanwhile, iOS terminated it with no callback. To finish a transfer while suspended, hand it to iOS: a background URLSession.

Last week the user tapped “Don’t Allow” for the camera. Today your app asks again. What happens?

See the answer

iOS asks once and keeps the answer: the request now reports no access, with no dialog. A refusal crashes nothing; the app must keep working, and can point the user to Settings.

Your iOS app will use the camera. Which line belongs in your prompt to the assistant?

See the answer

Without a purpose string, the camera request fails and the app usually crashes. Background modes are what assistants switch on unasked, and the camera is asked for when the user taps the button that needs it, not at launch.

In Expo Go, your app opens the camera without a problem. Are your own purpose strings right?

See the answer

In Expo Go, your project runs inside Expo Go's app, with Expo Go's purpose strings: Settings shows Expo Go. Yours ship only in a native build, such as eas build, so test the camera there; android.permissions is Android's list anyway.

An assistant stores the user's session token in UserDefaults. What do you ask it to change?

See the answer

A file in the container, UserDefaults included, is readable from the first unlock after a restart; a keychain item, by default, only while the device is unlocked. Documents/ holds files too, and the user can even see them when the app shares that folder.

Settings → General → iPhone Storage → an app → Offload App. What happens?

See the answer

Offloading frees the app's own storage but keeps its documents and data; deleting would remove both. The app and its data are two things: the bundle, and its container.

You have no Mac, and your lab is the Expo app. How can you see it running on your iPhone?

See the answer

Expo Go, an App Store app, runs your project when it uses the same SDK and only the native libraries Expo Go ships. The simulator runs only on macOS, and a build for the App Store can come from Expo's Macs, with EAS Build.

Recap

  1. Same shape as Android. A sandbox, a lifecycle, permissions. Apple holds the keys.
  2. Authorized by Apple. Nothing runs unless Apple's chain of signatures allows it.
  3. Every door is Apple's. App Store, TestFlight, your own devices. No side door.
  4. A purpose string, or a crash. The user decides, and can change it in Settings.
  5. Frozen within seconds. Terminated without a callback. Save as the app leaves the foreground.
  6. A Mac to build. Expo Go and Safari let you see it without one.

Sources

← All capsules