DEV Community

Code Salley
Code Salley

Posted on

React Native CI/CD with Fastlane (iOS)

React-Native app CI/CD to increment build number, build, and publish. This part is focused on iOS to keep things simple.


Requirements

  • React Native App
  • Fastlane
  • Apple developer account

The plan is to rely on the app store connect API, to avoid 2FA nightmare. First, we need to create an API key for our Fastlane script.

Create an API key

Go to app store connect and click on users and access select integrations tab and add a new team key (give it a name and set access to App Manager).
Download the key and take note of the (Key Id and Issuer Id)
In total, we have 3 env variables here

Table 1.0

Name Value Description
APPSTORE_KEY_PATH /certs/example.p8 path to key file
APPSTORE_ISSUER_ID 1234-5454-test..... Issuer ID under team keys
APPSTORE_KEY_ID 3B3XXS9XXX Key id from generated key

Now let's head over to our project and install fastlane, check out fastlane docs for the best way to install. I will go with Bundler,

STEP1 (only if you are using bundler)
If you don't have a Gemfile in the root of your project, create one and add fastlane

Gemfile

# Gemfile
source "https://rubygems.org"

gem "fastlane"
Enter fullscreen mode Exit fullscreen mode

Then run bundle install, now we have fastlane installed. Keep in mind, if you install fastlane with bundler you have to run fastlane with bundle exec fastlane if you're using homebrew no need to prepend bundle exec.

STEP 2.
Initialize fastlane by running the below command, this will create a folder and a fastfile for you.

bundle exec fastlane init
Enter fullscreen mode Exit fullscreen mode

This will generate a fastlane folder with a Fastfile and Appfile.

Now we need a way to generate and manage certificates securely, I recommend using match and git(GitHub)
Let's add match to our workflow by running

bundle exec fastlane match init
Enter fullscreen mode Exit fullscreen mode

match initialization

this will generate a Matchfile which will house match configurations.
add your git repo, app_identifier, and app store username to the Matchfile. it will look something like this

# fastlane/Matchfile
#
# create a private GitHub repo and paste the URL here.
# you can create a classic GitHub API key and have your repo looking like 
# git_url("https://GIT_BASIC_AUTHORIZATION@github.com/username/awesome-app-certs.git")
git_url("https://github.com/username/awesome-app-certs.git")

storage_mode("git")

app_identifier("com.example")
username("username@example.com")
Enter fullscreen mode Exit fullscreen mode

Time to automate our lanes to run straight, we are following these simple steps

  1. create a keychain db
  2. connect to app store connect and get an API key using envs in Table 1.0
  3. codesigning with match
  4. Increment build number (optional)
  5. Build app
  6. push to Testflight

1.create a keychain db

# I recommend passing keychain-name and keychain-password through env.
# delete old keychain if one exists
delete_keychain(
  name: keychain-name
) if File.exist? File.expand_path("~/Library/Keychains/keychain-name-db")

  # create a new keychain, take note of the name and password
create_keychain(
  name: keychain-name,
  password: keychain-password,
  default_keychain: true,
  unlock: true,
  timeout: 3600
)
Enter fullscreen mode Exit fullscreen mode

2.connect to app store connect and get an API using envs in Table 1.0

api_key = app_store_connect_api_key(
  key_id: ENV['APPSTORE_KEY_ID'], # from table 1.0
  issuer_id: ENV['APPSTORE_ISSUER_ID'],  # from table 1.0
  key_filepath: ENV['APPSTORE_KEY_PATH'],  # from table 1.0
  in_house: false
)
Enter fullscreen mode Exit fullscreen mode

3 codesigning with match

match(
  type: "appstore", # use development | appstore | ad-hoc
  app_identifier: 'com.example', # if you have other extensions like oneginal then pass an array [com.example, com.example.OneSignalNotificationServiceExtension]
  verbose: true,
  api_key: api_key,
  keychain_name: keychain-name,
  keychain_password: keychain-password
)
Enter fullscreen mode Exit fullscreen mode

4 Increment build number

# getting app version number
# [https://docs.fastlane.tools/actions/get_version_number/]
version = get_version_number(
  xcodeproj: "ios/ExampleApp.xcodeproj", # path to xcodeproj 
  target: "exampleApp" # Target name
 )

# get the current build number of a version from Testflight using api_key from step 2.
# [https://docs.fastlane.tools/actions/latest_testflight_build_number]
current_build_number = latest_testflight_build_number(version: version, api_key: api_key, app_identifier: "com.exmaple")

# [https://docs.fastlane.tools/actions/increment_build_number/]
increment_build_number(
  xcodeproj: "ios/exampleApp.xcodeproj",
  build_number: current_build_number + 1
 )
Enter fullscreen mode Exit fullscreen mode

5 Build app docs

# build app with gym
 build_app(
   scheme: "exampleApp",
   workspace: "ios/exampleApp.xcworkspace",
   export_method: "app-store",
   clean: true,
   verbose: true,
     export_options: {
       export_method: "app-store",
       team_id: '123TEAM_ID',
     }
 )
Enter fullscreen mode Exit fullscreen mode

6 Publish to Testflight

upload_to_testflight(
  skip_waiting_for_build_processing: true,
  api_key: api_key,
  changelog: "New Build"
)
Enter fullscreen mode Exit fullscreen mode

By putting all these together, we have enough steps to build and publish our app. To Keep things short, below is the link to the complete Faslane file.
Fastlane gist

Top comments (0)