# iOS Playbook <!-- omit in toc -->

This playbook is meant to provide developers with all the information needed to get a CI/CD pipeline up and running for the iOS side of a React Native application.

## Table of Contents

<!-- TOC -->

- [Table of Contents](#table-of-contents)
- [Apple Account](#apple-account)
  - [API Key Usage and Setup](#api-key-usage-and-setup)
- [Match](#match)
  - [Using Match](#using-match)
  - [Creating AWS Match Resources](#creating-aws-match-resources)
- [CircleCI](#circleci)
- [Messaging](#messaging)
- [Certificate and Profile Management](#certificate-and-profile-management)
  - [Adding Entitlements/Capabilities:](#adding-entitlementscapabilities)
  - [Updating your profile / regenerating your certificates:](#updating-your-profile--regenerating-your-certificates)
    - [You'll need the following environment variables added to your local environment:](#youll-need-the-following-environment-variables-added-to-your-local-environment)
    - [Updating your certificates with match:](#updating-your-certificates-with-match)
    - [Make sure it all works](#make-sure-it-all-works)
- [Gotchas](#gotchas)
<!-- /TOC -->

## Apple Account

For a fully fledged deployment process you need an [apple developer account](https://developer.apple.com/programs/) setup and working. In addition, there are a couple of best practices getting everything working as well as possible.

1. Access to the [App Store Connect API](https://developer.apple.com/app-store-connect/api/). Please see section below for more details on this.
2. A user with the App Manager role on the Apple account.

### API Key Usage and Setup

The Fastfile for iOS makes use of the App Store Connect API as stated above, which is a much better way to manage access, and avoids 2FA issues prevalent with setting up a user specifically for Fastlane. You can read about the benefits of this approach [here](https://docs.fastlane.tools/app-store-connect-api/)

In order to get an App Store Connect API key, the Account Holder of the Apple Developer account/team will need to request access on App Store Connect.

The process to achieve this is as follows:

1. Log in to App Store Connect
2. Click the “Users and Access” icon
3. Click the Keys tab at top of the page.
4. You see the message “Permission is required to access the App Store Connect API. You can request access on behalf of your organisation”, along with a Request Access button.
5. Click Request Access.
6. Review the terms and, if acceptable, click the checkbox and then submit.

Access should be granted automatically, and you should be able to create a key immediately once the Account Holder has requested access. When creating an API key remember to only provide the minimum access needed — in most cases the Developer role should suffice.

Your API key will be in the form of a private key (saved as a p8 file).

Once you have downloaded it and stored it securely (e.g. in something such as LastPass), you will need to base64 encode it. You can achieve this on a \*nix system with:

`cat KeyFileName.p8 | base64`

You will then want to add the following environment variables to whichever environment makes use of the Fastfile (CI or your machine):

APP_STORE_CONNECT_KEY_ID — The Key ID is available on the [API Keys](https://appstoreconnect.apple.com/access/api) page on the corresponding API key generated.
APP_STORE_CONNECT_ISSUER_ID — The Issuer ID is available on the [API Keys](https://appstoreconnect.apple.com/access/api) page.
APP_STORE_CONNECT_API_KEY_BASE64 — The Base64 encoded value of the key from the command above.

Thanks to [Alastair Hendricks](https://alihen.xyz/posts/2020-12-12-fastlane-match-app-store-connect-api) for outlining this process so comprehensively in the linked article.

**[⬆ back to top](#table-of-contents)**

## Match

### Using Match

[Match](https://docs.fastlane.tools/actions/match/) is only concerned with handling certificates and profiles for iOS. Match needs a couple of things to do its job.

1. An apple user with at least the Developer role with access to the relevant app.
2. There are two options(that are catered for) for storing certificates and profiles. Best practice in future will be to use the s3 bucket.
   - A private git repository.
   - An AWS S3 bucket. This tool allows easy creation of this bucket for you. see [Creating AWS Match Resources](#creating-aws-match-resources)

With this information at hand you can start the match process. Make sure to read the [docs](https://docs.fastlane.tools/actions/match/) in its [entirety](https://en.wikipedia.org/wiki/RTFM).

Once you have completed the certificate and profile creation you will need to set it in [Xcode](https://docs.fastlane.tools/codesigning/xcode-project/#xcode-8). Be sure to read through the docs if any of the code signing processes do not make sense.

**[⬆ back to top](#table-of-contents)**

### Creating AWS Match Resources

This tool allows the easy creation of an S3 Bucket to store your match certificates, and an IAM user with read permissions on the bucket, allowing you or whatever CI tool you are using to retrieve these easily and securely.

You can achieve this by running `npx @nona-creative/react-native-ci-utils aws creatematchresources` to start the process.

If you have the environment variables AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION exported in your environment these will be picked as defaults.

You may enter any other user credentials as well. These credentials should have the ability to create an S3 bucket, create an IAM User in your account, and to grant that user read permissions on the bucket. Answer all the questions. Assuming everything worked, something that looks like the following should be printed out to your terminal:

```bash
IAM Username: fast-lane-user
Access Key: AKIAIOSFODNN7EXAMPLE)
Secret Access Key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY)
Match S3 Bucket Name: fastlane-test
```

Store these details securely for use with your CI/CD tool of choice

**[⬆ back to top](#table-of-contents)**

## CircleCI

While this playbook is written with CircleCI in mind, most of the information can be transferred to other CI/CD tools. There are a couple of important environment variables that you need for CircleCI to deploy your application:

1. Please refer to the [docs](https://docs.fastlane.tools/best-practices/continuous-integration/#environment-variables-to-set) on recommended environment variables.
2. It is best practice to have a CI user that has access to your repositories(app, match etc.) and your Apple account that will be used to checkout code and deploy the app.
3. It is best practice to use CircleCI [contexts](https://circleci.com/docs/2.0/contexts/) where relevant. Be sure to check what [contexts](https://app.circleci.com/settings/organization/github/Nona-Creative/contexts) Nona has set up when working within the Nona GitHub account.

**[⬆ back to top](#table-of-contents)**

## Messaging

The fastlane template that gets generated will assume that there is a slack webhook setup. This process of setting up messaging is a two-step process.

1. Set up a [slack webhook](https://api.slack.com/messaging/webhooks). It is good practice to use one webhook per project (iOS and android).
2. Set the `SLACK_URL` environment variable in CircleCI for your project.

**[⬆ back to top](#table-of-contents)**

## Certificate and Profile Management

### Adding Entitlements/Capabilities:

1. navigate to [developer.apple.com](https://developer.apple.com)
2. from your account, select `Certificates, Identifiers & Profiles` from the left-hand side menu
3. Select `Identifiers`, then your project.
4. Add whatever Capabilities you need to add, and save.

### Updating your profile / regenerating your certificates:

#### You'll need the following environment variables added to your local environment:

1. **App Store Connect**: To run the match command (you should have generated all of these in the steps above, or they'll be available in **App Store Connect**)

   - `APP_STORE_CONNECT_KEY_ID`
   - `APP_STORE_CONNECT_ISSUER_ID`
   - `APP_STORE_CONNECT_API_KEY_BASE64`

2. **AWS**: You'll need credentials for a user that has `write access` to the S3 bucket that holds the `match` credentials.
   - `AWS_ACCESS_KEY_ID`
   - `AWS_SECRET_ACCESS_KEY`

#### Updating your certificates with match:

1. For this we'll be using the terminal. Have a look in your `package.json` or `ios/Fastfile` to find the correct command. You're wanting something that regenerates your certificates. For our project, it's these two:

   - `develop_certificates`
   - `appstore_certificates`

2. You'll need to ensure your environment is setup correctly - so export the values in _'Things you'll need' #1 & #2_ above into your environment.

3. Next, you'll want to run each of the lanes set in _#1_ above:

   `bundle exec fastlane develop_certificates readonly:false` .

   _The `readonly:false` command makes sure that the updated profiles will be saved to your S3 bucket._

4. Finally, repeat the above with the `appstore_certificates` command:

   `bundle exec fastlane appstore_certificates readonly:false`

If both commands ran successfully, then your profiles should have been updated. Bravo! 🎉

#### Make sure it all works

To make sure everything has been updated successfully:

1. Open [developer.apple.com](https://developer.apple.com) again, then
2. Open the `Profiles` tab
3. Click on your dev and prod profiles (for us it's "Ad hoc" and "App Store" respectively) and make sure that your entitlement/capabilities changes have been made.

**[⬆ back to top](#table-of-contents)**

## Gotchas

It is important to note that sometimes there are [nondeterministic failures](https://circleci.com/blog/xcodebuild-exit-code-65-what-it-is-and-how-to-solve-for-ios-and-macos-builds/) when building the mobile applications on CircleCI. Rerunning a build might be all that is needed most times before looking for other issues. That being said, there are some general things to look out for:

1. Slow build times are common (can be improved somewhat by choosing a bigger [resource class](https://circleci.com/docs/2.0/configuration-reference/#resource_class) on CircleCi).
2. When using a git repository for your match setup you need to use a user SSH key that has access to both the application code repository and the match repository.

**[⬆ back to top](#table-of-contents)**
