Why Does iOS Require Code Signing?
Every iOS app must be cryptographically signed before it can run on a device or be distributed through the App Store. Code signing serves three purposes: it verifies the developer's identity, ensures the code has not been tampered with, and enforces Apple's app distribution rules.
If your code signing setup is wrong, Xcode will refuse to build, devices will refuse to install, and App Store Connect will reject your upload. It is one of the most common sources of frustration in iOS development.
Key Components
Signing Certificate
A signing certificate is a digital identity that proves you (or your organization) are a registered Apple developer. There are two types:
- Development certificate: Used for building and running apps on test devices
- Distribution certificate: Used for App Store, Ad Hoc, and Enterprise distribution
Each certificate consists of a public key (stored at Apple) and a private key (stored in your macOS Keychain). You can have a limited number of active distribution certificates per team.
App ID
An App ID is a unique identifier for your app, registered in the Apple Developer portal. It has two parts:
- Team ID: Your developer team's unique prefix (assigned by Apple)
- Bundle ID: A reverse-DNS string you define (e.g., com.yourcompany.yourapp)
The App ID is associated with specific capabilities (push notifications, Sign in with Apple, App Groups, etc.) called entitlements.
Provisioning Profile
A provisioning profile ties together a certificate, an App ID, and a set of rules:
- Development profile: Links a development certificate + App ID + specific device UDIDs. Only those registered devices can run the app.
- Ad Hoc profile: Like development, but for wider testing (up to 100 devices per year).
- App Store profile: Links a distribution certificate + App ID. No device restriction since distribution goes through Apple.
- Enterprise profile: For in-house distribution within an organization (requires Enterprise Program membership).
Entitlements
Entitlements are key-value pairs that grant your app specific capabilities:
- Push notifications
- iCloud / CloudKit
- App Groups (shared data between apps/extensions)
- Sign in with Apple
- Associated Domains (for universal links)
- HealthKit, HomeKit, etc.
Entitlements must match between your provisioning profile (configured in the portal) and your Xcode project's entitlements file.
How Signing Works in Practice
Automatic Signing (Xcode)
Xcode can manage signing automatically:
- Select "Automatically manage signing" in your target settings
- Choose your development team
- Xcode creates and downloads certificates and profiles as needed
This works well for individual developers and small teams doing local development. It breaks down in CI/CD environments where there is no interactive Xcode session.
Manual Signing
For CI/CD and larger teams, manual signing gives you explicit control:
- Create certificates and profiles in the Apple Developer portal
- Download them and install into your build machine's keychain
- Reference them explicitly in your Xcode build settings or xcodebuild command
Fastlane Match
The most popular team solution. Match stores your certificates and profiles in a shared location (Git repo, Google Cloud, or S3):
- One team member initializes match (generates certs and profiles)
- Other team members and CI machines run match to download and install them
- Profiles are automatically renewed before expiration
- Everyone uses the same signing identity, eliminating "works on my machine" issues
Common Problems and Fixes
"No matching provisioning profile": Your profile does not match the bundle ID, entitlements, or certificate. Regenerate the profile with the correct settings.
"Certificate not found": The private key for the certificate is missing from your keychain. You need the .p12 file that was exported when the certificate was created.
"Device not registered": For development and Ad Hoc profiles, the target device must be registered in the portal. Add the device UDID and regenerate the profile.
Profile expired: Provisioning profiles expire after one year. Regenerate in the portal or run fastlane match to auto-renew.
Best Practices
- Use Fastlane Match for teams of two or more developers
- Never share .p12 private keys over email or chat. Use an encrypted Git repo or secrets manager.
- Keep a single distribution certificate per team. Multiple certificates cause confusion.
- Rotate certificates well before expiration to avoid emergency scrambles
- In CI, install certificates into a temporary keychain that is deleted after the build