How did I integrate Fastlane and GitlabCI to automate BUILD app ReactNative?
Table of Contents
Besure you was installed Fastlane before. If you not, please follow guide from Fastlane Doc: https://docs.fastlane.tools/
In ReactNative, you need init Fastlane for each
android
folder andios
folder. This Post write about ReactNative, with native project may have some difference.
1# — Android Fastlane — Config Android
1.1# — Init Fastlane
With Android, just go to /android
folder and init Fastlane:
cd android
fastlane init
Some information you need to input in this step:
- Package name: you can find it in
app/build.gradle
- Json file: it’s an access way for fastlane connect Google Play and get your app metadata. You can follow Fastlane guide to create this file https://docs.fastlane.tools/actions/supply/ (This is very important step to decide you can automate upload Google Play or not, so just follow guide of Fastlane carefully)
After Fastlane init finish, you can see folder fastlane
in your folder android
. In fastlane
folder will have 2 file Appfile
and Fastfile
and a folder metadata
Appfile
— is contains your link to JSON file, and package name
Fastfile
— You need to take care about this file, you will define your lane in this file for run build App and upload to Google Play Store.
metadata
— contains title, description, images about your App, get from Google Play
1.2# — Add plugin in Fastlane of Android folder
With Android, you need to add increment_version_code to automate increase version number in next step
cd android
fastlane add_plugin increment_version_code
Now in folder fastlane
will see like this
Pluginfile
— contains name of plugins you add before.
2# — Android Fastlane — Code for Fastfile
- With Fastlane, I just need upload source to Internal Testing, if you need upload to other, you can use this code below
upload_to_play_store(
track: 'internal',
# internal: usefor Internal Testing
# alpha: usefor Alpha Testing
# beta: usefor Beta Testing
# production: usefor Production
)
So in my case, I will do some task:
- Get current version code from App on Google Play Store
- Increment version code for App on Local
- Clean
- Build
- Upload to Play Store
This is my code:
lane :upload_internal do
previous_build_number = google_play_track_version_codes(
package_name: "com.myapprn",
track: "internal",
)[0]
current_build_number = previous_build_number + 1
increment_version_code(version_code: current_build_number) # Increment the build number of the application
gradle(task: "clean") # run the task clean
gradle(
task: "bundle",
build_type: 'release') # compile a release bundle application app.aab
upload_to_play_store(
track: 'internal',
skip_upload_metadata: true,
skip_upload_images: true,
skip_upload_screenshots: true,
)
end
if your Appfile correct, You can run build App by yourself and check on Google Play Store
# in android folder
fastlane upload_internal
# upload_internal is name of lane in Fastlane android
3# — Fastlane — Config iOs
With iOs, like Android, you can go to ios
folder and init Fastlane:
cd iOs
init Fastlane
Fastlane will show 4 choices:
- 1 — Automate screenshots
- 2 — Automate beta distribution to TestFlight
- 3 — Automate App Store distribution
- 4 — Manual setup — manually setup your project to automate your task
With my task is “Automate upload to TestFlight”, I chose number 2.
Just follow step in number 2, you will finished setup. Fastlane will require you input account development Appstore, this is very important for upload app after.
After init finished, in folder ios
you can see 2 file like android
:
Appfile
— now contains app_identifier
, apple_id
, itc_team_id
, team_id
Fastfile
— define lane for build App
4# — Fastlane — Sign & Certificate iOs
With iOs, you have Fastlane action call “Match” to Code Signing in Apple Store, Why “Match”?
When deploying an app to the App Store, beta testing service or even installing it on a device, most development teams have separate code signing identities for every member. This results in dozens of profiles including a lot of duplicates.
You have to manually renew and download the latest set of provisioning profiles every time you add a new device or a certificate expires. Additionally this requires spending a lot of time when setting up a new machine that will build your app.
With “Match”, this can help you save Code Signing at a Place like git, and everytime build App, it will sign from this place.
In ios
folder, start using match
fastlane init match
You’ll be asked if you want to store your code signing identities inside a Git repo, Google Cloud or Amazon S3. I chose Git repo, and I create a Gitlab Repo for Save Code Signing (be sure this repo is private).
After init finished, let generate new certificates and profiles:
fastlane match appstore
When finished, your Git Repo will be like this:
5# — iOs Fastlane — Code for Fastfile
- Now with Fastlane, my task will build App and upload to TestFlight. So I will using this code in Fastlane:
upload_to_testflight
My Fastlane iOs will have list Task:
- Load App Store Connect API token to use for Fastlane tools and actions below
app_store_connect_api_key
- Run
pod install
because my App using cocoapods
cocoapods
- Use
match
to signing (if you don’t init match you can’t run this step)
match(
app_identifier: ["com.myapprn"], # [target 1, target 2] if you have multiple target need to Sign
type: 'appstore', # because init match appstore so this line must be appstore
readonly: true, # only fetch existing certificates and profiles from GIT, don't generate new ones
git_basic_authorization: '<project access token from Git Repo contains Cer and Profiles', # example aWlvb2xsOmdscAJ0LOVEYOUFOREVERALLMYLIFEyc0FT
)
git_basic_authorization
: you can get this by go to Gitlab >> choose Git Repo contains Cert >> Settings >> Access Tokens . Be sure check to api
- Configures Xcode’s Codesigning options of all targets in the project
update_code_signing_settings(
use_automatic_signing: true,
)
- Increase build number of App
increment_build_number(
xcodeproj: "MyAppRN.xcodeproj",
build_number: latest_testflight_build_number + 1
)
latest_testflight_build_number
: Fetches most recent build number from TestFlight
- Build App
build_app(
export_method: 'app-store',
scheme: "MyAppRN",
workspace: "MyAppRN.xcworkspace",
configuration: "Release"
)
- Upload to TestFlight
upload_to_testflight(skip_waiting_for_build_processing: true)
This is all code:
lane :beta do
app_store_connect_api_key
cocoapods
match(
app_identifier: ["com.myapprn"], # [target 1, target 2] if you have multiple target need to Sign
type: 'appstore', # because init match appstore so this line must be appstore
readonly: true, # only fetch existing certificates and profiles from GIT, don't generate new ones
git_basic_authorization: '<project access token from Git Repo contains Cer and Profiles', # example aWlvb2xsOmdscAJ0LOVEYOUFOREVERALLMYLIFEyc0FT
)
update_code_signing_settings(
use_automatic_signing: true,
)
increment_build_number(
xcodeproj: "MyAppRN.xcodeproj",
build_number: latest_testflight_build_number + 1
)
build_app(
export_method: 'app-store',
scheme: "MyAppRN",
workspace: "MyAppRN.xcworkspace",
configuration: "Release"
)
upload_to_testflight(skip_waiting_for_build_processing: true)
end
Now you can use Fastlane to build app and upload to TestFlight
# in ios folder
fastlane ios beta
# beta is name of lane in Fastlane ios
6# — CI/CD — Gitlab
If you just want to use Fastlane for reduce time Build App at local. You don’t need to keep reading. But if you want to use CI/CD on Git for automate Build and Upload App. Keep Reading.
Before using Gitlab CI/CD, you need gitlab-runner, If you don’t have a runner:
- Install GitLab Runner on your local machine.
- Register the runner for your project. Choose the
shell
executor.
When install correct, you can see in Gitlab Project >> Settings >> Expand Runners like this:
After that, I created 2 branch for run automate:
staging-ios
for run Fastlane iOs Appstaging-android
for run Fastlane Android App
6.1# — Gitlab Integrations
To use Gitlab for automate Build and Upload App, Gitlab have two things for you, just go to your Gitlab Project (source of this App, not Git Repo Cert) >> Settings >> Integrations:
6.1.1# — Apple App Store Connect
Upload your AuthKey file p8
and “Save”
This will help Fastlane iOs connect to App Store
6.1.2# — Google Play
Upload your json
file (you was created it from “Init Fastlane android” before) and “Save”
This will help Fasstlane Android connect to Google Play
6.1.3# — Another Variables
To automate build and upload, and you need secure some properties from another developer in your team, so go to Gitlab project >> Settings >> CI/CD >> Expand Variables, and add some Variables like this:
PLAY_STORE_UPLOAD_KEYSTORE_FILE_BASE64
- Android need a keystore file for build App, so I was converted this file to base64_string. In your local, go to folder contains keystore file and run:
cd keystore_folder
base64 -w 0 myfile.keystore -o outputFile.txt
Open outputFile.txt
and I add this base64_string to Gitlab Variables
PLAY_STORE_UPLOAD_KEYSTORE_PASSWORD
- Password for keystore file
PLAY_STORE_UPLOAD_KEYSTORE_ALIAS
- Keystore alias
PLAY_STORE_UPLOAD_KEY_PASSWORD
- Key password
MATCH_PASSWORD
- This is “Fastlane Match Passphare”, when you run
fastlane init match
Fastlane will require you input this, now you need add this for CI/CD can read Signing.
IOS_MATCH_GIT_BASIC_AUTHORIZATION
- This is “project access token” of Git Repo contains Cert and Profile, you have it at step
fastlane init match
All Variables like this, be sure you choose Attributes is protected
and Expanded
:
6.1.4# — gitlab-ci.yml
Now in you root
folder on local, you need create .gitlab-ci.yml
and config:
image: node:16.20.1
stages:
- deployiOS
- deployAndroid
variables:
LC_ALL: "en_US.UTF-8"
LANG: "en_US.UTF-8"
ios:upload_testflight: # use for upload TestFight
dependencies: []
stage: deployiOS
only:
- staging-ios # run only branch staging-ios
before_script:
- yarn install
script:
- cd ios
- gem install bundler
- bundle install
- export IOS_MATCH_GIT_BASIC_AUTHORIZATION=${IOS_MATCH_GIT_BASIC_AUTHORIZATION}
- export MATCH_PASSWORD=${MATCH_PASSWORD}
- bundle exec fastlane ios beta # launch the lane beta
tags:
- ios # tag to launch your specific gitlab runner
when: manual # use manual to review on gitlab before run
android:upload_internal: # use for upload Google Play
dependencies: []
stage: deployAndroid
only:
- staging-android # run only branch staging-android
before_script:
- yarn install
- echo -n ${PLAY_STORE_UPLOAD_KEYSTORE_FILE_BASE64} | base64 -d > ./android/app/myfile.keystore
- echo "keystorePath=myfile.keystore" > ./android/signing.properties
- echo "keystorePassword=${PLAY_STORE_UPLOAD_KEYSTORE_PASSWORD}" >> ./android/signing.properties
- echo "keyAlias=${PLAY_STORE_UPLOAD_KEYSTORE_ALIAS}" >> ./android/signing.properties
- echo "keyPassword=${PLAY_STORE_UPLOAD_KEY_PASSWORD}" >> ./android/signing.properties
- echo "sdk.dir=/<dir_to_android_sdk>/Android/sdk" >> ./android/local.properties
script:
- node -v
- cd android
- gem install bundler
- bundle install
- bundle exec fastlane android upload_internal # launch the lane upload_internal
artifacts:
paths:
- ./android/app/upload.keystore
- ./android/signing.properties
expire_in: 10 mins
tags:
- android
when: manual # use manual to review on gitlab before run
6.1.3# — Gitlab Jobs
Now when you push source to gitlab, and create “merge request” to staging-ios
and staging-android
, you will see 2 job
is manual
in Gitlab Project >> Build >> Jobs
Click “Play” and Gitlab will automate Fastlane for you.
- ios
- android
7# — Conclusion
When using Fastlane and Gitlab CI, I was reduced many time for build and upload app, really cool to use it.
More Fastlane: https://docs.fastlane.tools/
More Gitlab CI: https://docs.gitlab.com/ee/topics/build_your_application.html