Let start with the most important question: Why we need a provisioning profile?
The short answer is: Because we want to run our shiny new app on a physical device.
So, if you never ever want to run your ode on a physical device, then you don’t need a provisioning profile. That’s it. If the simulator is enough for you to run your app, then you will never face the issues with the provisioning profiles.
The 2 mostly used techniques how to run your code on a physical device are:
- Connect a physical device to your Xcode session and run the code from there. For this purpose you will need a Developer provisioning profile.
- Distribute the app via the App Store, so anyone who downloads it can run on her physical device. For this you need a Distribution / App Store provisioning profile.
Creating Provisioning profiles
You can manage your Provisioning profiles in the Apple Developer site: https://apple.co/37B5YUU. Clicking on the small circle with the plus will start the registration of a new provisioning profile. There are 2 sections in the first screen, where you need to select from the Development profiles and the Distribution profiles. The naming are a bit misleading, since there is a Development profile called “iOS App Development”, while in the Distribution the respective profile type name is “App Store”. Those 2 are used for the iOS Development and the iOS App distribution.
First you need to select which App identifier you want to use for this profile.
If the profile is a development profile, then the developers certificates need to be selected. Those certificates will be included in the provisioning profile. In the next step you need to select the devices to include in the profile.
In case of a Distribution provisioning profile, you need to only provide the Distribution certificate (only one), which will be embedded in the profile.
Downloading the profiles
You have 2 options to download the provisioning profile files:
The first is to go to the Apple Developer portal, and download it from the web. Double clicking on the file will import the profile into Xcode. However, if you intend to use the profile from command line, like on a CI/CD pipeline, you will need the file itself.
The second (and maybe more convenient) solution is to set up your development Apple ID in Xcode (Xcode menu -> Preferences -> Accounts), and when you added an Apple ID you will have the Download Manual Profiles button. Please note that this option is only installing the profile in your local Xcode instance.
Pro tip: If you login with Xcode, you can also manage the different certificate from the same Accounts screen ;). Just one click to generate the respective certificate, but you still need to export it out from the Keychain Access.
What is inside the file?
Essentially a provisioning profile file is a xml ehem… plist file, and quite easy to understand. The fundamental difference between the Development and the Distribution profile content is the fact is in the Development profile you can find the uniques identifiers of the devices that you added (see the previous post), while the Distribution profile doesn’t have this list.
There are parts which are common in both files, the main (and interesting ones) are the following:
- App ID Name (the is not the same as the app bundle id).
- The Team ID
- The Team name
- The platform (ie iOS)
- Expiration date
- Name of the provisioning profile (this can be used as a preference, when you are creating your own ExportOptions.plist. Further info about this can be found here: https://bit.ly/3L7O9LD)
However, the fundamental differences between the Development and the Distribution profile are not just about how the binary is distributed (from Xcode vs via App Store), but also the content of the provisioning profile.
In case of Development profile:
- Individual Developer Certificate
- Device UUIDs
In case of Distribution profile:
- App Store Distribution Certificate
*The only exception in the Distribution profiles is the Ad-Hoc Distribution. In this profile the App Store distribution certificate and the eligible Device UUIDs are included in the profile. With this combination you can essentially distribute the app outside of the App Store, but only for the devices that listed in the profile.
Both the Development and the Distribution profile includes certificates. The Distribution obviously only includes the App Store Distribution Certificate , while the Developer one is including all of the developers’ certificate that included in the provisioning profile, during its creation (or update) in the
DeveloperCertificates node of the plist file.
The development (and the Ad-Hoc Distribution) profiles are also including the eligible devices UUID list under the
ProvisionedDevices key in the plist file.
How to use them…?
… from Xcode
Finally, we have the provisioning profiles imported into our beloved Xcode. As I mentioned in the beginning, the whole hassle is because the Automatically manage signing button is not ticked on the app target Signing and Capabilities screen:
If we managed well the import of the provisioning profile as described in the previous point, we can now have options to select the provisioning profile in the same screen, based on the target bundle identifier. We have the option to select the used provisions profile for each build configuration (usually you have Debug and Release by default) for the target.
Here the things can run out of control easily, so let’s just recap how it is usually works.
By default with the Release build configuration we use a Distribution profile. The Debug build configuration in the other hand the Development profile is the default. So far so good.
The scheme for target is usually set up to use the Release configuration for Archiving, and the Debug configuration both for Running and Testing. That means that we can run our precious app on a physical device, and also we can trigger the tests on the same device.
However… Xcode can be easily confused on the installed certificates (at least this is my experience). If you have more than one certificates in your Keychain Access with the private key from the same team, Xcode sometimes says that certain certificates are not included. It can happen on both certificates types, since both the Development and the Distribution certificates are bound to either the developer, or the organization, and you are allowed to create multiple certificates on each Certificate category. The assignment to your Xcode project, (i.e. which certificates should be used in that particular project) is actually happening in the Provisioning profile.
One important note is that you can only run your app from Xcode on a physical device connected to your machine, which has device UUIDs included. *In this sense the Ad-Hoc profile is a bit of an exception. Based on my tests the app runs on the device, but he Xcode gave me a “Could not launch” Error.
… from Command Line
Using form command line is less complicated (compared to the Xcode), since usually that’s the case of the CI/CD builds, when we are using he xcodebuild command to produce an app archive (or an .ipa file) for further distribution. The default case is here to build an archive, therefore almost all of the cases a Distribution profile should be used. There are some further consideration here, since you don’t have control over the Keychain Access on the remote machine. For that reason most of the cases the Distribution Certificate that we want to use needs to be injected to the CI/CD pipeline. That happens with the help of the .p12 files (an exported certificate, see my previous post here), and the accompanied password. Apart from the certificate we still need to pass the provisioning profile file to the CI/CD server.
Usually the challenge is here that how to pass the Information during the xcodebuild archive command, that which profile should be used?
That magic happens in the ExportOptions.plist file. Here is an example: https://bit.ly/3Ks3F45, where the important points are:
signingStyleshould be manual
- You need to pass the
signingCertificate(see the reason above)
- You can pass even a list of Provisioning profiles, not just one (Which can be required if you have extensions or WatchKit App with separate Bundle ID in your project).
If you managed to create your ExportOptions.plist file, you just need to supply to your CI/CD command line with the
-exportOptionsPlist parameter. You can have more than one .plist file, according to your need. For example use separate files on the same project for different environments.
My favorite Developer Support advocate, Quinn “the Eskimo” actually built a very compact How-To on the same topic as above. If you want some extra information, you can find it on that link: https://apple.co/37tXTkZ.
Ok, so it was quite long, but whoever managed to read through until this point deserves a refresher, here it is 😉 : 🥤. The Part 4 will be all about the troubleshooting and the management tasks occurring with the profiles (and all of their ingredients).