Publishing to the App Store with Fastlane and GitHub Actions

Akshat Tiwari
7 min readJun 23, 2022

--

In this article, we’ll learn to automate tasks for deploying our iOS App to the App Store using Fastlane and GitHub Actions.

Why Fastlane?

  • Fastlane is the easiest way to automate beta deployments and releases for your iOS and Android apps. 🚀
  • It handles all tedious tasks, like generating screenshots, dealing with code signing, and releasing your application.

You can tag along the following steps to do this setup.

Generating App Store Connect API key

In order to use the App Store Connect API, fastlane requires the following:

  • App Store Connect API key filepath or content
  • Issuer ID
  • Key ID

Creating an App Store Connect API Key

To create a key, you need to have Admin permissions in your App Store Connect account. Here are the steps you need to follow:

  1. Log in to App Store Connect
  2. Navigate to Users and Access
  1. Select the Keys tab
  1. Click Generate API Key button
  1. Enter a name for the key.
  1. Select at least one role. Remember to provide the minimum level of access needed.
  2. Click Generate

The key will appear on the page once created successfully.

The API Key will be in .p8 format. You might consider using a base64-encoded version to avoid running into this known issue.

To encode your key, run the command below:

cat [YOUR_KEY_NAME].p8 | base64

Now you have everything you need to authenticate against the App Store Connect API.

Storing your secrets

In order to authenticate with the ASC API, we’ll need an API key along with a couple of other details. These are considered sensitive, which means we’ll need to store them securely in a place where they can be accessed by our GitHub workflows. We’ll be storing all our sensitive keys in repository secrets using GitHub’s encrypted secrets, making them automatically accessible to our GitHub Actions workflows.

Creating & storing your App Store Connect API Key

We’ll be adding the Issuer ID, the Key ID, and the p8 private key to GitHub’s encrypted secrets.

To add a new secret to GitHub’s encrypted secrets, first navigate to the iOS repo which you’ll be adding the GitHub workflow to. On the far right, click “Settings”.

Then, click “Secrets” from the list in the left menu.

From here, click “New repository secret” to add a new secret:

When you click “New repository secret”, you’ll see a form that will prompt you to enter a name for your new secret, and the value.

Finally, add all the required secrets.

GitHub secrets only accepts strings, so for certain credentials (any .p8 or .p12 files for example), you’ll first need to convert the file to a base64-encoded string before adding it to GitHub secrets as we did before.

Please note that you should store a backup copy of your secrets securely in another location (somewhere that is not GitHub encrypted secrets), as you won’t be able to export or access the credentials again from GitHub after you’ve added them.

With these secrets added to GitHub’s repository secrets, we can authenticate with the ASC API within the GitHub workflow we’ll create to run our builds.

Storing your App Store distribution certificate & private key

In order to properly sign App Store distribution builds on CI, the workflow will need access to a valid App Store distribution certificate and private key pair. You’ll need to add the App Store distribution signing certificate & private key (.p12) to your repository secrets:

  • IOS_DIST_SIGNING_KEY — the text version of the .p12 distribution certificate
  • IOS_DIST_SIGNING_KEY_PASSWORD — the password used during export of the certificate

With these secrets added to GitHub’s repository secrets, we’re ready to set up our GitHub Actions workflow to run our builds.

Set up your GitHub Actions workflow .yml file

Let’s set up our iOS GitHub actions workflow .yml file — it’ll define the steps we’ll run as part of our workflow. Within these steps, we’ll call our fastlane lanes.

Paste the following code into your build-upload-ios.yml file:

name: iOS binary build & upload

on:
workflow_dispatch:

jobs:
deploy:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2

- name: Set up ruby env
uses: ruby/setup-ruby@v1
with:
ruby-version: 2.7.2
bundler-cache: true

- name: Import Code-Signing Certificates
uses: Apple-Actions/import-codesign-certs@v1
with:
p12-file-base64: ${{ secrets.IOS_DIST_SIGNING_KEY }}
p12-password: ${{ secrets.IOS_DIST_SIGNING_KEY_PASSWORD }}

- name: Build & upload iOS binary
run: bundle exec fastlane ios build_upload_testflight
env:
ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
ASC_KEY: ${{ secrets.ASC_PRIVATE_KEY }}
KEYCHAIN_PATH: ~/Library/Keychains/signing_temp.keychain-db

- name: Upload app-store ipa and dsyms to artifacts
uses: actions/upload-artifact@v2
with:
name: app-store ipa & dsyms
path: |
${{ github.workspace }}/example-iOS.ipa
${{ github.workspace }}/*.app.dSYM.zip

Our workflow defines a single job, called “deploy”, which runs on the latest macOS machine version supported by GitHub workflows. The job has a series of steps, marked with a dash “-”. Some of these steps will use predefined “actions”, which can either be provided by GitHub (e.g. actions/checkout@v2), or available as open source actions created and supported by the community through GitHub’s Marketplace.

jobs:
deploy:
runs-on: macos-latest
steps:

The first step is checking out the codebase using GitHub’s checkout action. Then, we install our dependencies. Since we’re using fastlane, which is a Ruby gem, we’ll define a Ruby environment with the option bundler-cache: true, which will automatically run bundle install and cache installed gems. bundle install will install fastlane and any other Ruby dependencies in your project.

- uses: actions/checkout@v2

- name: Set up ruby env
uses: ruby/setup-ruby@v1
with:
ruby-version: 2.7.2 # omit if .ruby-version file exists in project, or replace with your team’s supported ruby version
bundler-cache: true

Next, we’ll need to import our distribution code signing certificate into the machine’s keychain. We’ll do this using an open source GitHub action called “import-codesign-certs”, and passing in our base64-encoded App Store distribution code signing certificate (and its corresponding password) which are stored in GitHub’s repository secrets. This will allow us to properly sign the build we’ll be creating in the next step.

- name: Import Code-Signing Certificates
uses: Apple-Actions/import-codesign-certs@v1
with:
p12-file-base64: ${{ secrets.IOS_DIST_SIGNING_KEY }}
p12-password: ${{ secrets.IOS_DIST_SIGNING_KEY_PASSWORD }}

Finally, we can call our main fastlane action, “build_upload_testflight”, passing in the required ASC API key information (also stored in GitHub’s repository secrets), and the keychain path where the signing certificate was stored in the previous step. Our fastlane action will take care of downloading the necessary provisioning profiles, updating the build number, building the app, and uploading the resulting .ipa to TestFlight.

- name: Build & deploy iOS release
run: bundle exec fastlane ios build_upload_testflight
env:
ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
ASC_KEY: ${{ secrets.ASC_PRIVATE_KEY }}
KEYCHAIN_PATH: ~/Library/Keychains/signing_temp.keychain-db

The last step in the workflow uploads the produced artifacts (the .ipa file and its associated dSYM files) so they can be viewed in GitHub as part of the workflow. If you don’t have any use for the build’s artifacts, you can remove this step from the workflow.

Now, you can commit and push up your newly created GitHub workflow file. It’ll show up on your repo under the “Actions” tab.

Running your build

Once you’ve pushed up your GitHub workflow file, you’ll be able to trigger your workflow directly from GitHub’s UI. Simply find your workflow in the “Actions” tab, and click “Run workflow”:

And that’s it!

Using fastlane combined with GitHub Actions, we’ve put together a simple CI pipeline that increments build numbers, creates a distribution .ipa, and uploads the .ipa to TestFlight.

Anyone that has access to your GitHub repository can now trigger the workflow directly from GitHub, or you can set a workflow trigger to automatically kick off a workflow run any time pushes are made to certain branches.

With a basic build & deploy CI pipeline now in place, anyone on the team is empowered to create and upload builds, removing a common bottleneck while also increasing reliability and consistency.

Write some code👨‍💻, push 🚀 and chill! 😎

I hope you liked this article. If you find this article helpful then share it with everyone. Maybe it’ll help someone who needs it 😃.

Feel free to connect with me on LinkedIn and check out my GitHub profile.

Thank you!

--

--

Akshat Tiwari
Akshat Tiwari

Written by Akshat Tiwari

Coding Geek, Open Source Enthusiast.

No responses yet