Our mobile team is small and operates in-house. All work from development, testing to distribution is discussed and handled directly between team members. App building is done on the local machine and then installed directly to testers via cable.
However, as the project expands, the need to share the build with testers in many regions, or send it to customers for review/accept before release becomes important. Continuing to build locally by installing directly becomes manual, does not guarantee the version, code quality and is time-consuming.
Therefore, setting up CI/CD to deliver builds quickly, synchronously, with clear versioning and easy to send to testers/customers is a must.
1. Current team conditions
Criteria |
Describe |
Source code management system |
GitLab Enterprise |
Development Platform |
iOS and Android |
Number of developers |
< 5 people |
Resource CI/CD |
No private server to build |
Current needs |
Need to share quick build with tester/customer |
Target |
Build automation, reduce manual operations, versioning management, easy to maintain |
2. Compare popular CI/CD options
Criteria |
GitLab CI (self-hosted) |
Bitrise |
GitHub Actions + Fastlane |
Mobile friendly |
Have |
Very easy |
Good |
Initial configuration |
Difficult (requires separate runner) |
Very suitable |
Easy |
Free Package |
Unclear (self-hosting is resource intensive) |
Limit 200 min/month |
2000 minutes/month for private repo |
Easy to maintain |
Difficult if the team is small |
Very easy |
Easy |
Automate cert/profile |
Need to do it manually |
Integrated |
Good support with Match |
TestFlight/Firebase Integration |
Depending on configuration |
Available |
Can be easily integrated |
- With or without runner is fine → flexible for future scaling
- Easy to understand interface, full documentation
- Support detailed workflow, easy to customize
- Good integration with Fastlane → sync cert, build, upload TestFlight
- Free package is suitable for small teams, no need to upgrade in the first stage
4. Scope of implementation
- iOS: distribute builds to TestFlight
- Android: distribute builds to Firebase App Distribution
Devs push code as usual to GitLab (the project's main source control). This is the first step in the CI/CD chain without changing the team's habits.
GitLab is configured to automatic mirror source code to GitHub repository every time there is a new commit.
➔ Copy the token you just created (note, this token is only displayed once so remember to save it carefully)
➔ Finally, setup runner to run mirror
Runs on server or local (macOS, Linux, Windows are all fine):
You will be asked:
Prompt |
Example answer |
Enter the GitLab instance URL: |
https://gitlab.comor self-hosted GitLab URL |
Enter the registration token: |
Get token inSettings > CI/CD > Runners |
Enter a description for the runner: |
mirror-runner |
Enter tags for the runner (comma-separated): |
mirror |
Enter executor: |
shell |
Note:
Now, you can test by pushing the code on GitLab and monitor if there are updates on GitHub.
3. Fastlane runtest and build iOS app
After successfully mirroring the code from GitLab to GitHub, the GitHub Actions workflow will build and upload the iOS app to TestFlight via Fastlane. The entire process is divided into the following steps:
Create bundle ID for test app, for example: com.sanan.setup.cicd
4. Distribute build to testers
Install Fastlane for project (macos):brew install fastlane
fastlane init
fastlane match init
Next, open Appfile:
Next, open Matchfile: Edit your respective git_url and username
export ASC_KEY_ID="<key_id_appstore_connect_api>"
export ASC_ISSUER_ID="<isuer_id_appstore_connect_api>"
export ASC_KEY_CONTENT="<content_appstore_connect_api>"
export MATCH_PASSWORD="<your_setup>"
export FASTLANE_APPLE_ID="<your_apple_id>"
export DEVELOPER_PORTAL_TEAM_ID="<your_apple_developer_account_id>"
export TEMP_KEYCHAIN_USER="<your_setup>"
export TEMP_KEYCHAIN_PASSWORD="<your_setup>"
Then run: bundle exec fastlane beta_prod
Successful run result:
Successfully uploaded the new binary to App Store Connect
1. ACTIONS_DEPLOY_KEY
2. ASC_KEY_ID
3. ASC_ISSUER_ID
4. ASC_KEY_CONTENT
5. MATCH_PASSWORD
6. FASTLANE_APPLE_ID
7. DEVELOPER_PORTAL_TEAM_ID
8. TEMP_KEYCHAIN_USER
9. TEMP_KEYCHAIN_PASSWORD
Note: ACTIONS_DEPLOY_KEY is the private key when you setup regular ssh for the ios-certificates repository
Finally, push the code and test it. Go to the Actions tab.
With the detailed instructions above, we have gradually implemented the CI/CD process for iOS projects from the real situation of a small team:
Adopting CI/CD not only saves time, but also increases stability and better control over distributions – especially as the number of members and testing environments starts to expand.
______________________________________________________________
In part 2, we will continue to extend this process to Android, use Firebase App Distribution Combine with Fastlane and GitHub Actions to create a similar distribution process for your Android app.
If you have never implemented CI/CD before, try applying this iOS part right in your personal project or staging – you will see a clear difference in your daily workflow.