Most developers don't take pleasure in resolving code signing issues and that includes me. While managing certificates and provisioning profiles has become easier over the years, it can still be challenging. If you're working in a team or use a build server to create and distribute builds, then code signing can become complex.
But there's good news. Several years ago, Felix Krause took on the challenge to make common tasks simple and automated. Many trivial tasks and everyday problems can be resolved and automated by embracing fastlane. As I mentioned in the previous episode, fastlane is a tool for mobile development that is focused on automation. Code signing is one of the tasks fastlane can handle for you. Let's revisit the project we created in the previous episode and find out how fastlane can help us.
Disabling Automatic Code Signing
Xcode 8 introduced automatic code signing. This feature handles a number of common tasks for you, including managing App IDs and provisioning profiles. When you enable automatic code signing for a target, Xcode talks to the Apple Developer Portal on your behalf. Automatic code signing is enabled by default.

Let's see what happens if we disable automatic code signing by unchecking the checkbox Automatically manage signing. We need to specify which provisioning profile should be used for each configuration.

We can build and run the application in a simulator, but we're not allowed to build and run the application on a physical device.

Manual code signing isn't something that looks appealing, but it has several advantages. If you're working in a team or use a build server to create and distribute builds, then manual code signing offers more flexibility.
Why fastlane?
I try to keep the dependencies of a project to a minimum. Every dependency is a liability, regardless of the person, team, or company maintaining the dependency. Most of the projects I work on depend on CocoaPods and fastlane. What makes these dependencies different? Why should you consider using them?
Managing third party libraries and frameworks is a pain without a robust dependency manager. I'm sure that some developers swear by Git submodules, but I'm not one of them. I've been using CocoaPods for many years and it has only gotten better and more reliable. For me, CocoaPods is the best solution to manage third party libraries and frameworks. For other developers, that might be Carthage or Git submodules. At the moment, Apple doesn't offer a first party solution to manage dependencies. That should change as the Swift Package Manager matures.
Publishing an application on the App Store is more than writing code and pushing a few buttons. It involves managing certificates and provisioning profiles, creating builds, and generating screenshots. There are countless tasks that you need to handle to get from zero to App Store. Apple doesn't offer a reliable solution to automate these tasks. fastlane does. fastlane is a tool that has gained widespread adoption in the mobile community and it has matured in a surprisingly short time. Felix Krause wrote the first lines of code for fastlane in 2014. fastlane is under active development. Features are added and issues are fixed on a weekly basis.
You should always be careful when you add a dependency. I use CocoaPods and fastlane because there are no first party solutions. CocoaPods and fastlane fit very well in my workflow and are excellent options for managing dependencies and automating tasks.
Getting Started With fastlane
Getting up to speed with fastlane can be challenging because it includes a variety of tools to automate tasks. We start with a simple setup. We update the setup as the needs of the project change. What I want to handle in this episode is creating an App ID for the Cocoacasts client and setting up code signing. This is surprisingly straightforward using fastlane.
Before we start, I want to say a few words about developer accounts, App Store Connect, and the Apple Developer Portal. I'm sure you heard that Apple is enforcing two factor or two step authentication. While this improves security, it also complicates development if you want to automate common tasks. I recommend creating a separate user in App Store Connect for interacting with fastlane and third party services, such as a continuous integration service. That user should have a limited set of permissions. The role of App Manager is sufficient. A user with role App Manager automatically receives the roles of Developer and Marketing.
I also recommend injecting sensitive information, such as credentials, as environment variables. By using that strategy, credentials are not stored in the repository and it also makes updating sensitive information easier.
This approach also works for fastlane. fastlane looks for the FASTLANE_USER and FASTLANE_PASSWORD environment variables. With two factor or two step authentication enabled, you need to generate an app-specific password and assign it to the FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD environment variable. I've already taken care of these steps.
Setting up fastlane is trivial. Open a terminal and run the fastlane init command. Don't forget to prefix the command with bundle exec as I explained in the previous episode.
bundle exec fastlane init
You have several options to set up fastlane. We choose for a manual setup. fastlane creates a folder named fastlane at the root of the project. The folder contains two files, Appfile and Fastfile. Appfile stores information about the project, which is used by fastlane and avoids the need to repeat yourself. Let's update Appfile with the bundle identifier of the application and the developer account we use to communicate with App Store Connect and the Apple Developer Portal. We also set the team identifier for the Apple Developer Portal and the team identifier for App Store Connect. This is important if the developer account is associated with multiple teams.
# https://docs.fastlane.tools/advanced/#appfile
app_identifier("be.codefoundry.cocoacasts")
apple_id(ENV["FASTLANE_USER"])
team_id "2493UGBPKJ"
itc_team_id "230533"
Fastfile contains the tasks you can execute using fastlane. These tasks are commonly referred to as lanes. The Fastfile fastlane created for us includes one lane as an example. The lane is named custom_lane. Let's print a message to illustrate how it works.
default_platform(:ios)
platform :ios do
desc "Description of what the lane does"
lane :custom_lane do
print "This is a test lane."
end
end
Open a terminal and execute the lane by running the fastlane command followed by the name of the lane.
bundle exec fastlane custom_lane
The command generates quite a bit of output. Somewhere in the output you should see the message we printed.
Creating an App ID
By disabling automatic code signing, we need to take care of a few tasks. Xcode doesn't create or update the App ID for the Cocoacasts target. That's something we need to handle. We use fastlane to create or update the App ID for the Cocoacasts target. Open Fastfile, remove the example lane, and define a new lane with name updateappid.
default_platform(:ios)
platform :ios do
lane :update_app_id do
end
end
fastlane inclues a broad selection of actions. To create a new application on App Store Connect and the Apple Developer Portal, we use the produce action. We need to pass the action several parameters, such as the username of the user that is used to sign in to Apple's developer services, the name of the application, the language, the version of the application, and a SKU.
default_platform(:ios)
platform :ios do
lane :update_app_id do
produce(
username: ENV['FASTLANE_USER'],
app_name: 'Cocoacasts',
language: 'English',
app_version: '1.0',
sku: 'be.codefoundry.cocoacasts')
end
end
Open a terminal and execute the lane. fastlane creates an App ID on App Store Connect and the Apple Developer Portal.
bundle exec fastlane update_app_id
Creating Certificates and Provisioning Profiles
We have an App ID for the Cocoacasts target, but we still can't run the application on a physical device. We need to create a development certificate and a development provisioning profile. match is a fastlane tool that handles this for you. Before we set up match, we need to create a private repository to store certificates and provisioning profiles. A Git repository makes it easy to install certificates and provisioning profiles on any machine that can access the Git repository. I already created a Git repository for this purpose. Make sure that the Git repository is private because it stores sensitive information.
The next step is running the match init command to set everything up. fastlane asks you where you'd like to store the certificates and provisioning profiles. I use Git, but fastlane also supports Google Cloud.
bundle exec fastlane match init
fastlane adds three files to the fastlane folder, Matchfile, README.md, and report.xml. README.md is a file that is automatically created by fastlane and gives an overview of the commands the project supports. report.xml shouldn't be put under source control. We need to add it to the .gitignore file of the project.
# fastlane
/fastlane/report.xml
Matchfile stores the information fastlane needs to manages the certificates and provisioning profiles, such as the location of the Git repository.
To create a certificate and provisioning profile for development, we execute the match development command.
bundle exec fastlane match development
fastlane creates the certificate if there isn't one available and updates the provisioning profile if necessary.


We can repeat these steps for distribution by executing the match appstore command.
bundle exec fastlane match appstore


The match tool is convenient, but even more convenient is the fact that fastlane stores the certificates and provisioning profiles in a Git repository. This is what the GitHub repository looks like after executing these commands.

It's important to repeat that the repository should be kept private as it contains sensitive information. The match tool also creates a README.md file that includes the steps you need to take to set everything up on a new machine.
Once you wrap your head around fastlane and the match tool, it's hard not to like it. I want to emphasize that I'm only covering the basics of fastlane and the match tool. The project we're building isn't complex. The match tool has a lot more to offer and it covers a wide range of setups and configurations.
Updating the Project
fastlane has created certificates and provisioning profiles for development and distribution. The certificates and private keys are safely stored in the keychain. fastlane put the provisioning profiles in a location Xcode expects. Everything is in place to update code signing for the Cocoacasts target.
Open the workspace CocoaPods created for us, select the project in the Project Navigator, and choose the Cocoacasts target from the list of targets.

We need to select for each configuration an eligible provisioning profile. That's it. We don't need to worry about Xcode changing anything. It won't touch code signing for the Cocoacasts target since we disabled automatic code signing.

By choosing for manual code signing we need to handle a few steps manually when we make changes to the project. Let me show you what I mean. Open the Capabilities tab at the top.

The Cocoacasts client will support push notifications at some point, which means that we need to enable the Push Notifications capability. With automatic code signing enabled, Xcode would update the App ID and provisioning profile for us behind the scenes by talking to the Apple Developer Portal. With automatic code signing disabled, we need to perform these steps manually. Fortunately, fastlane makes this trivial. It doesn't happen automatically, but it only requires a few steps. I'll show you how that works later in this series.

What's Next?
Over the years I have spent hours and hours debugging code signing issues. Code signing has improved over the years, but it continues to be a topic new developers struggle with. You need to understand the basics. There's no way around that. But once you have a good grasp of code signing, it should no longer be a hurdle if you choose for fastlane or automatic code signing.