In previous posts I have covered how to set up and use access key with App Store API and later how to automatically generate certificate and profiles using the access key. Let’s crank it up to 11 and have automated app uploads to App Store using GitHub Actions so we never ever have to see Xcode’s archiving steps again. For this to work, 2 tasks need to be done (given fastlane is available):

  • Create fastlane action with release flow
  • Create GitHub workflow based on preferred events

For the first task, the following action is added to Fastfile:

app_store_connect_api_key

lane :release do
	if is_ci
		setup_ci
	end
	sync_certs
	build_app
	upload_to_testflight
end

First, setup_ci needs to be called to setup temporary keychain to ensure sync_certs works correctly on any CI provider. To prevent setup_ci from running locally, in case it is triggered on your local machine, is_ci check is required.

sync_certs function comes from iOS: automate certificate and profile creation using fastlane post. Essentially, it can be replaced with fastlane’s match action directly. It will ensure that certificates and profiles are downloaded and installed on CI machine’s keychain for later signing.

build_app and upload_to_testflight actions most likely look familiar to you. It simply builds, signs and uploads generated .ipa file to the App Store. Refer to fastlane docs for more information about available lanes and possible arguments for further possible configurations.

Note: Remember to add app_store_connect_api_key to Fastfile. This will ensure App Store API keys are correctly loaded before executing release action.

For the GitHub workflow, the following .yml file is added under .github/workflows directory:

name: Upload build to App Store

on:
  workflow_dispatch

jobs:
  upload-build:
    runs-on: macos-latest
    env:
      APP_STORE_CONNECT_API_KEY_KEY_ID: ${{ secrets.APP_STORE_KEY_ID }}
      APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ secrets.APP_STORE_ISSUER_ID }}
      APP_STORE_CONNECT_API_KEY_KEY: ${{ secrets.APP_STORE_ACCES_KEY }}
      APP_STORE_CONNECT_API_KEY_IS_KEY_CONTENT_BASE64: true
      MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
      MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.MATCH_GIT_BASIC_AUTHORIZATION }} 
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Upload to App Store
        run: fastlane release

3 important parts:

  • on trigger. In this case, workflow_dispatch is used which is part of manual events and can be triggered via GitHub API or via GitHub web interface. However, there are different options as well which can suit your needs better, such as recurring weekly builds. Have a look at GitHub documentation.
  • env values. These values are important and have to be configured similarly to values used in .env file as in earlier post on access keys. There are few additional values - MATCH_PASSWORD and MATCH_GIT_BASIC_AUTHORIZATION:
    • MATCH_PASSWORD - secret value used by fastlane match to encrypt/decrypt certificates and profiles within private remote repository.
    • MATCH_GIT_BASIC_AUTHORIZATION - access token which fastlane match will use to download certificates from private remote repository. It can be generated by accessing Personal access tokens page on GitHub. At minimum repo scope has to be granted to allow access to private repositories.

    All of the actual secrets must be added to Repository secrets which is under Settings -> Secrets

    Note: Environment keys under env section in .yml file need to be exactly as shown above. These keys are directly used by fastlane to load values. For more information, refer to fastlane’s match action documentation

  • steps section. It simply contains 2 steps - checkout the code and trigger fastlane action that was created previously. This can be extended with more steps, e.g. to notify others about new builds.

And voilà, if done correctly, you should be able to automatically and consistently upload iOS builds to App Store using GitHub Actions.