Unless the device is Jailbroken, all the apps that run on iOS devices need to be signed by trusted developers who have a valid certificate from Apple. Code signing is the process of digitally signing any form of the code to confirm the author of code and guarantee that the code has not been changed or corrupted since it was signed. There are various security terms involved in the process of code signing, such as a public key, private key, certificates and digital signatures.
Why code sign iOS apps?
Code signing makes the user feel safe whilst using the app, providing the app has been developed by trusted developers. Every developer or organisation who wants to develop iOS apps needs a certificate from Apple to make apps. Code signing ensures that nothing has been changed since the developer signed the code, meaning there is no chance of an attacker changing the code when it has been written by the developer. In summary, code signing makes the apps secure for users. However, there are some limitations as well. Code signing does not protect users against attacks from dynamic content, e.g. when the app is loading data from various third-party sources.
What is required to code sign apps?
There are various things we need to code sign our iOS apps. We will briefly address each one.
CSR (Certificate Signing Request)
This is the very first step in code signing iOS apps. The developer needs to create a Certificate signing request (CSR) from their local machine, with some basic details confirming the developer’s identity. The CSR needs to be sent to the Certificate Authority (CA), which is Apple for the iOS platform. Apple then confirms the developer’s identity and issues a certificate to the developer. Anyone can create a CSR from their local macOS machine using the Keychain:
- Choose Keychain Access > Certificate Assistant > Request a Certificate from a Certificate Authority.
- Fill in your details (email, name, country, etc.). Simply follow all the instructions on screen.
- Select the option Save to disk.
- Specify a filename and click Save.
- Click Continue and the Certificate Assistant generates a CSR and saves the file to your computer.
At the end of this process, you will have a CSR on your local machine.
In order to get the certificate from Apple, we need to have a developer membership with Apple. You can enrol in the development programme using this link. Apple will charge a fee of approx. $99/year for the developer membership. You can get different types of certificates too, e.g. development, distribution, enterprise. Once you get the Apple developer membership, you will be able to access the developer portal, from which you can create a certificate for iOS development.
The process is very simple and straightforward. You can find the step by step guide here to create a certificate. As a developer, you can create a certificate for development or distribution. The development certificate is used to develop apps internally, which are deployed on internal devices. However, distribution certificates are used to release apps to the App Store that can run on any device. iOS development certificates are usually associated with private keys. You can export the certificate from keychain to the Personal Information Exchange a.k.a. the P12 format to store both the certificate and private key together. You can find the entire process of exporting the certificate mentioned in this post here.
The provisioning profile is a combination of the Team ID, Bundle ID, App ID, Device ID and Entitlements. Provisioning profiles define the rule for running the app inside the device. Its role is to confirm:
- a specific app with an App ID
- that an app with that app ID can run on certain devices included in the provisioning profile. Development provisioning profiles have the list of devices included, whilst distribution provisioning profiles do not.
- that the app should only have those entitlements defined in the provisioning profile.
- that the app can only run trust based on the certificate embedded in the provisioning profile.
The process for creating a provisioning profile can be found here.
Provisioning profiles can also be created for development as well as distribution certificates. Once the provisioning profile has been created, we are able to sign the iOS apps.
Apple has very comprehensive documentation on the entire code signing process here. Whilst code signing an iOS app, all components, including bundles, resources, frameworks, tools, scripts, libraries, plugins, Info.plist files, assets and all other codes, need to be code signed along with the individual components of the apps.
Xcode code signing
Xcode uses the codesign command line tool to sign the app once it’s built. We can use the codesign tool to sign the app without Xcode as well. The codesign tool is used to create and verify the code signature. Xcode uses automated code signing to code sign iOS apps, but we can also use customised signing for better control. Apple announced automated code signing in Xcode 8; we have the new setting in the General tab of the build target to enable automatic code signing. We simply need to let Xcode know our development team and Xcode will handle all code signing tasks, such as certificates, provisioning profiles, etc., automatically.
In the process of manual signing, we have to explicitly specify the code signing identity and provisioning profile in the build setting.
There is an awesome guide on code signing on Xcode 8, you can read it here if you need more information about manual and automatic signing. Once we code sign iOS apps, we can get the code-signed IPA file from Xcode by archiving the app. You can archive an iOS app by going to Xcode > Product > Archive. You must select the device destination as Generic iOS Device to archive an iOS app.
Once the archive build is successful, Xcode will open an organiser window to validate or distribute the app.
At this point, we can distribute iOS apps to the Apple App Store. We need to have a bundle identifier and version number available in the App Store Connect portal.
Publishing Apps with Xcode
In order to publish an iOS app, we need to create a new app on the App Store Connect portal. In the My Apps tab, we can add a new app by specifying all the required information.
You can create a new version or use the existing one for publishing iOS apps. Your App Store Connect portal page should look like this.
You will also need screenshots and icons as per the App Store publishing guidelines to publish apps to the App Store.
Once we have all this information in the App Store Connect portal, we can go back to the Xcode organiser window and click Distribute App to upload the app to the App Store. Select the distribution method as App Store and the appropriate production provisioning profile. Finally, click the Upload button to upload the app binary to the App Store.
Xcode will take some time to upload the binary to the App Store Connect portal. Once everything is OK, you will see that the binary has been uploaded to the App Store Connect portal.
In the App Store Connect portal, if you click the TestFlight tab, you can see that the build is processing on the App Store Connect portal. Once the build is processed, you need to provide the compliance information before you can start internal testing. Your build will then be ready for testing on TestFlight.
Once the processing is finished, you can distribute apps to the internal testers using TestFlight. You have now successfully published the app to TestFlight using Xcode.
Codemagic: Code signing and publishing
In a previous post, we explored how Codemagic code signs and distributes iOS apps. Codemagic allows both manual and automatic code signing features. When we are ready to distribute the apps, we can easily set up CI/CD for the app using Codemagic (see the Getting Started Guide). On Codemagic, we can enable iOS code signing from the Publish section by uploading the certificate and the provisioning profile we downloaded from the Apple Developer portal. In the Codemagic app, navigate to Settings > Publish > iOS code signing > Manual and upload your certificate and provisioning profile there.
While building the app with Codemagic, we need to select release mode so that the app can be distributed to the App Store.
In the Codemagic app settings, we need to provide the App Store Connect portal email and password and the bundle ID of the app in order to upload the app to the App Store.
Once Codemagic generates the build artifacts, we can build to the App Store Connect portal, formerly known as iTunesConnect, following the App Store guidelines and submit the app for review. We can follow the same process above to distribute apps to TestFlight.
Xcode vs. Codemagic Distribution
We have now covered the iOS app distribution method using Xcode and Codemagic. In the process of releasing an app from Xcode, we have seen that there are various configuration and manual steps required for submitting an app to the App Store Connect portal. Also remember that an engineer cannot work on anything else whilst Xcode is performing all these tasks. We need to have certificates in the local mac and the user needs to be logged in to Xcode with their App Store credentials. Most importantly, the user needs to have a macOS machine.
With Codemagic, however, we simply need to provide our certificate, profiles and App Store credentials and the rest of the app distribution work is done by Codemagic. Engineers do not have to babysit the distribution process. The most important thing is that you do not need to have a macOS machine.
You can use either local Xcode or a CI/CD tool for distributing apps to the App Store Connect portal. With Codemagic, we released the iOS version of the Flutter app to TestFlight in just a few steps, without a mac, saving the engineers time. Codemagic has support for automatic signing or, if you want better control over provisioning profiles, it also supports customised signing.