Unity iOS Code Signing Explained
Code signing is the single biggest source of confusion in Unity iOS development. It's not actually complicated — it just involves four objects that must all match, and Apple's error messages rarely tell you which one is wrong.
The four objects involved
1. The private key
Everything starts here. When you request a certificate you generate a key pair: a private key that stays with you, and a certificate signing request (CSR) sent to Apple. The private key never leaves your control.
This explains the most common confusion in iOS signing: a certificate downloaded from Apple is useless on its own. Without the matching private key, nothing can sign with it. That's why teams exchange .p12 files (certificate + private key together) rather than .cer files.
2. The distribution certificate
Apple signs your CSR and returns a certificate — your team's verifiable identity. Two types matter:
- Development — installs on registered test devices only.
- Distribution — required for TestFlight and the App Store.
Using a development certificate where a distribution one is required produces the classic ITMS-90035 Invalid Signature rejection after upload.
3. The provisioning profile
The profile is the glue. It states: "this bundle ID may be signed by these certificates, for this distribution method." It embeds the certificates it trusts, which has two consequences developers hit constantly:
- Create a new certificate, and existing profiles won't trust it — regenerate them.
- Change your App ID's capabilities (In-App Purchase, Push Notifications), and existing profiles become
INVALIDimmediately.
4. The bundle identifier
Your app's unique reverse-DNS name, e.g. com.yourstudio.yourgame. It must match in three places: Unity Player Settings, the App ID in your Apple account, and the provisioning profile. A mismatch anywhere fails the build.
Where Unity fits in
Unity generates the Xcode project but deliberately leaves signing unconfigured. When the Xcode build runs, signing is applied to the targets. Two Unity-specific details matter enormously:
- The app target is
Unity-iPhone. That's what needs the profile. UnityFrameworkis an embedded framework and must not receive a provisioning profile — it's signed by inheritance. Applying a profile to every target (easy to do from the command line) causes a confusing "does not support provisioning profiles" error.
Manual signing vs automatic signing
Automatic signing lets Xcode create and manage profiles by talking to your Apple account. Convenient interactively, but it requires a signed-in Xcode — i.e. a Mac — and behaves poorly in headless CI.
Manual signing means you supply an explicit certificate and profile. It's more work but fully reproducible, which is why every serious CI pipeline uses it.
Doing all of this from Windows
None of the four objects above require macOS to create. Key pairs and CSRs are standard cryptography, and Apple's App Store Connect API can register bundle IDs, issue certificates and generate provisioning profiles programmatically. Only the final signing operation needs macOS, and that can run on a cloud machine.
This is precisely what MacFree automates: it generates the key pair and CSR locally, requests the distribution certificate through Apple's API, creates a matching App Store profile, assembles the .p12, and hands all of it to a cloud macOS runner that signs and uploads — from Windows or Linux, with no Keychain and no openssl.
Let the certificates handle themselves
MacFree creates your signing material and ships to TestFlight from Windows or Linux.
Get MacFree on the Unity Asset Store →Frequently asked questions
What is a provisioning profile for Unity iOS?
A file issued by Apple that links your bundle identifier, one or more signing certificates, and a distribution method such as App Store. Xcode embeds it in the app so iOS can verify the app is authorised to run. Unity's generated project doesn't include one by default.
What is an iOS distribution certificate?
The digital identity Apple issues to prove a build came from your team. It's only usable together with the private key that generated its signing request — which is why copying the certificate file alone to another machine never works.
How does iOS code signing work in Unity?
Unity exports an Xcode project without signing configured. During the Xcode build the app target is signed with a distribution certificate and matching provisioning profile. The profile must cover the exact bundle ID and embed the certificate in use.