UDIDs, certificates and profiles, explained once
3 min readDistributionGetting started
iOS code signing has four moving parts and they are usually explained in the order Apple’s UI presents them, which is not the order that makes sense. Here they are in the order that does.
The four pieces
A certificate says who you are. It is issued by Apple to a developer or a team, it lives in a keychain with a private key, and it expires — typically after a year. Losing the private key means the certificate is dead and you issue a new one.
An App ID says which app. It is the bundle identifier plus the list of capabilities that app is allowed to use — push, App Groups, HealthKit, associated domains, and so on.
A device is a UDID: a unique identifier for one physical phone or tablet. Apple’s development programme allows a limited number of registered devices per type per year.
A provisioning profile binds the other three together: this certificate may sign this App ID and install it on these devices. It expires. It is embedded inside the IPA at build time.
That last sentence is the one worth remembering.
Why editing the profile does nothing
The profile is baked into the build. Adding a device UDID to the profile in the developer portal does not change any IPA that already exists — the file on your disk still contains the old profile with the old device list.
So the sequence is always: add the UDID → regenerate the profile → rebuild → redistribute. Teams lose hours to this every year, usually by adding a device, handing over the same build, and being confused when it still fails.
Where the UDID comes from
The UDID is a property of the device, not of an account. You need it from the physical phone.
Do not take it from a spreadsheet that somebody maintained in 2023. Half the “why will this not install” tickets I have seen resolved into a UDID that belonged to a device the team no longer owned, typed in from a list nobody had checked.
Profile types, and what each allows
| Profile | Signs with | Installs on |
|---|---|---|
| Development | Development certificate | Registered devices only |
| Ad Hoc | Distribution certificate | Registered devices, up to 100 per type |
| Enterprise | Enterprise certificate | Any device, after the user trusts it |
| App Store | Distribution certificate | Nothing directly — store submission only |
Two consequences worth internalising:
- An App Store build cannot be sideloaded. Ever. It is not a bug and there is no flag.
- Enterprise distribution is for your own organisation. Using it to distribute to the public is a violation that ends with the certificate being revoked, which bricks every install of every app signed with it.
Why builds stop working on a Tuesday
Because something expired, and expiry is a date rather than an event, so nothing warns you.
- Certificate expired. Every profile using it becomes invalid. All builds stop installing at once.
- Profile expired. That app’s builds stop installing.
- Certificate revoked. Same as expired, but immediate and usually deliberate — somebody cleaning up the portal.
The signature is always: yesterday it worked, nobody changed anything, and it broke on every device simultaneously. If it broke on one device, it is a UDID problem instead.
The trust step
An installed development or enterprise build will not launch until the user trusts the certificate on the device: Settings → General → VPN & Device Management.
This catches people because the install succeeded. Nothing failed; the app is on the home screen. It just refuses to run. Once per certificate per device.
Keeping this from being a recurring problem
Three habits, each about five minutes:
- A device list that matches reality. Read UDIDs off the physical devices when they join the fleet, not from memory.
- A note of expiry dates. Certificates and profiles, in a calendar. The whole class of “it broke on Tuesday” disappears.
- An audit when a device joins or leaves. Which profiles are installed on it, and are any of them ones you did not put there.
None of it is interesting work. All of it is cheaper than the afternoon it replaces.
