A provisioning profile is a signed plist Apple gives you to bundle inside your app. It tells iOS, iPadOS, tvOS, watchOS, and visionOS three things at once: who is allowed to sign this app, which devices can run it, and which capabilities (push, App Groups, HealthKit, Sign in with Apple, etc.) the app may use. Without a matching profile installed on the device or embedded in the IPA, the operating system refuses to launch the build.
The four types
- Development
- For installing on the developer's own registered devices. Tied to one or more Apple Development certificates and a fixed device list.
- Ad Hoc
- For installing on up to 100 specific devices per device class per year. Tied to an Apple Distribution certificate and the device list.
- App Store
- For TestFlight and App Store distribution. Tied to an Apple Distribution certificate. No device list.
- In-House (Enterprise)
- Only available with an Apple Developer Enterprise Program membership. Distributes signed builds inside your own organization without going through the App Store.
What is inside
- The exact App ID (e.g. `com.example.app`) or wildcard (`com.example.*`) the profile covers.
- The Team ID that owns the profile.
- One or more developer certificates (the public halves) the profile authorizes to sign.
- Entitlements the profile grants (push, App Groups, iCloud, etc.).
- An expiration date, usually one year after creation.
- For Development and Ad Hoc, a list of UDIDs.
Where it goes at build time
xcodebuild copies the chosen profile into the .app bundle as `embedded.mobileprovision` (or `embedded.provisionprofile` for macOS). When the user launches the app, iOS checks that the embedded profile is signed by Apple, has not expired, matches the binary's bundle ID and entitlements, and was signed by the same certificate as the .app itself.