iOS: CI/CD Integration via FastLane & Firebase using Gitlab : Part – 2
In the first part of the blog, we covered the Fastlane setup/Installation with multiple files like Appfile, Gymfile, and Fastfile. Now we are moving to the next part of this series where we will use CI/CD workflow via Fastlane & Firebase on the local machine.
We will use the next step of the Code Signing approach via the match import command. This will create a separate repository and upload your private keys and certificates in a Gitlab repo for syncing them across the machines. This approach is secure.
Code Signing approach: Using Fastlane match
The concept of match command is described in the codesigning guide.
Import: Prepare Certificates Using Match(Only one-time setup)
To import and encrypt a certificate (.cer), the private key (.p12), and the provisioning profiles (.mobileprovision or .provisionprofile) into the match repo run:
$ fastlane match import
You will be prompted for the certificate (.cer), the private key (.p12), and the provisioning profiles (.mobileprovision or .provisionprofile) paths. match will first validate the certificate (.cer) against the Developer Portal before importing the certificate, the private key, and the provisioning profiles into the specified match repository.
However, if there is no access to the developer portal but there are certificates, private keys, and profiles provided, you can use the skip_certificate_matching option to tell match not to verify the certificates. Like this:
$ fastlane match import --skip_certificate_matching true
The default type is ‘development’. So we need to specify the type explicitly.
$ fastlane match import --type enterprise --skip_certificate_matching true
This step will skip login to the Apple Developer Portal and will import the provided certificate, private key, and profile directly to the certificates Gitlab repo.
We need to be careful when using this option and ensure the certificates and profiles match the type (development, adhoc, appstore, enterprise, developer_id) and are not revoked or expired.
4. Matchfile- Please follow the steps while initializing the match command with prompted options.
Step-1. Initialize Match in your iOS project by running the command fastlane match init in the root directory of your project.
Step-2. Fastlane Match supports multiple storage modes and will ask you to select the one you want to use like options 1, 2, and so on. In this blog, We have selected option 1 which is ‘git‘.
Step-3. The system will ask you for the URL of the Git Repo then Enter the EMPTY GIT-CETIFICATE URL (it’s added on prerequisites new to provide a separate shared repository ).
Now Match file will be created on your root Directory-
git_url("EMPTY GIT-CETIFICATE Repoistory")
storage_mode("git")
type("enterprise") # The default type, can be: appstore, adhoc, enterprise or development
ENV["MATCH_PASSWORD"] = "MATCH_PASSWORD"
Setup Fastfile actions- In the Fastlfile Actions, We will set up all the actions like custom variables, and lanes to execute the set of tasks in a sequential manner.
Add the Below Script on the Fastlane File-
# This file contains the fastlane.tools configuration
# You can find the documentation at https://docs.fastlane.tools
#
# For a list of all available actions, check out
#
# https://docs.fastlane.tools/actions
#
# For a list of all available plugins, check out
#
# https://docs.fastlane.tools/plugins/available-plugins
#
# Uncomment the line if you want fastlane to automatically update itself
# update_fastlane
#Variables
APP_BUNDLE_ID = "com.test.iOS"
#APP_BUNDLE_ID_NSE = "com.test.iOS.Todo_ios-NSE"
#APP_BUNDLE_ID_NCE = "com.test.iOS.Todo_ios-NCE"
APP_PROVISION_TITLE = "AdhocDistribution"
#APP_PROVISION_TITLE_NSE = "Todo_ios Adhoc NSE"
#APP_PROVISION_TITLE_NCE = "Todo_ios Adhoc NCE"
#App Method support list
#["app-store", "validation", "ad-hoc", "package", "enterprise", "development", "developer-id", "mac-application"]
APP_METHOD = "enterprise"
# The default type, can be: appstore, adhoc, enterprise or development
MATCH_METHOD = "enterprise"
PROJECT_SCHEMA_QA = 'Todo_ios'
PROJECT_WORKSPACE = 'Todo_ios.xcworkspace'
PROJECT_XCODEPROJ = 'Todo_ios.xcodeproj'
IPA_FILE_NAME = "Todo_ios"
BUILD_PATH = "./builds"
INCLUDE_BITCODE = false
INCLUDE_SYMBOLS = false
FIREBASE_APP_ID = "FIREBASE_APP_ID"# i.e, "1:58453............"
TESTER_LIST = "test@gmail.com" # Add with coma separated
RELEASE_NOTES_FILE_PATH = "./fastlane/release-notes.txt"
MY_TEAM = "MY_TEAM" # i.e, "RT......"
GIT_URL_CERTIFICATES = "GIT_URL_CERTIFICATES"# i.e, "https:........./todo_ios_certificate"
#Fetch values from environmental variables
username = ENV['USERNAME']
personal_github_access_token = "PERSONAL_GITHUB_ACCESS_TOKEN" # i.e, "gl.........."
authorization_token_str = "#{username}:#{personal_github_access_token}"
basic_authorization_token = Base64.strict_encode64(authorization_token_str)
#Key chain passcode of MacOS machine
KEYCHAIN_PASSWORD = "KEYCHAIN_PASSWORD" # i.e, "Raj........."
default_platform(:ios)
platform :ios do
desc "Sync certificates"
lane :sync_certificates do
#read-only disables match from overriding the existing certificates.
match(type: MATCH_METHOD,
app_identifier: APP_BUNDLE_ID,
git_url: GIT_URL_CERTIFICATES,
git_basic_authorization: basic_authorization_token,
keychain_password: KEYCHAIN_PASSWORD,
readonly: true,
skip_certificate_matching: true,
verbose: true)
end
desc "Update project provisioning"
lane :update_provisioning do
CERTIFICATE_NAME = ENV["sigh_#{APP_BUNDLE_ID}_#{MATCH_METHOD}_certificate-name"]
APP_PROVISION_PROFILE_PATH = ENV["sigh_#{APP_BUNDLE_ID}_#{MATCH_METHOD}_profile-path"]
update_project_provisioning(
xcodeproj: PROJECT_XCODEPROJ,
profile: APP_PROVISION_PROFILE_PATH,
build_configuration: "QA",
code_signing_identity: CERTIFICATE_NAME
)
end
desc "Disable automatic code signing"
lane :disable_auto_code_sign do
# more advanced manual code signing
update_code_signing_settings(
use_automatic_signing: false,
path: "./#{PROJECT_XCODEPROJ}",
team_id: MY_TEAM,
bundle_identifier: APP_BUNDLE_ID,
code_sign_identity: "",
profile_name: ""
)
end
desc "QA Build"
lane :qa_build do
APP_PROVISION_PROFILE_NAME = ENV["sigh_#{APP_BUNDLE_ID}_#{MATCH_METHOD}_profile-name"]
#EXPORT_TEAM_ID = ENV["sigh_#{APP_BUNDLE_ID}_#{MATCH_METHOD}_team-id"]
gym(scheme: PROJECT_SCHEMA_QA,
workspace: PROJECT_WORKSPACE,
clean: true,
silent: false,
include_bitcode: INCLUDE_BITCODE,
include_symbols: INCLUDE_SYMBOLS,
xcargs: {
BUNDLE_IDENTIFIER: APP_BUNDLE_ID,
#PROVISIONING_PROFILE_SPECIFIER: APP_PROVISION_PROFILE_NAME,
DEVELOPMENT_TEAM: MY_TEAM,
CODE_SIGN_STYLE: "Manual"
},
export_xcargs: "-allowProvisioningUpdates",
skip_profile_detection: true,
export_options: {
method: APP_METHOD,
provisioningProfiles: {
APP_BUNDLE_ID => APP_PROVISION_TITLE,
}
},
configuration: 'Release',
output_name: IPA_FILE_NAME,
output_directory:BUILD_PATH,
skip_codesigning: false,
#export_team_id: EXPORT_TEAM_ID,
verbose: true)
end
desc "Increament build version"
lane :increment_version do
LATEST_VERSION = 0
latest_release = firebase_app_distribution_get_latest_release(
app: FIREBASE_APP_ID
)
if latest_release != nil
LATEST_VERSION = latest_release[:buildVersion].to_i
end
increment_build_number({ build_number: LATEST_VERSION + 1 })
end
desc "clean"
lane :clean do
clear_derived_data(derived_data_path: BUILD_PATH)
end
desc "Create ipa"
lane :build do
#clean derived data for path
clean
# Disable automatic code signing
#disable_auto_code_sign
#match certificate & profile
sync_certificates
#update project provisioning
#update_provisioning
# Creates a signed file
qa_build
end
end
Note: Please update your own detail in the above script i.e,.
APP_BUNDLE_ID,
APP_PROVISION_TITLE,
FIREBASE_APP_ID,
TESTER_LIST,
MY_TEAM,
GIT_URL_CERTIFICATES,
PERSONAL_GITHUB_ACCESS_TOKEN,
KEYCHAIN_PASSWORD.
Now run fastlane ios build command,
Result:- The above command will generate the .ipa file using above configuration setup with the fastlane summary.
Trouble Shoot:-
-
- Validate Bundle Identifiers on FastFile.
- Validate that Schema and Project names are Proper.
- Make Sure You have disabled automatic Sign-in and manually add profiles.
- Make sure that your iOS project is properly set up Locally on Xcode and you are able to archive and export to the app store by disabling automatic signing.
Upload to firebase
Next, you need to set up the Firebase App Distribution plugin. This tool allows you to upload to Firebase from Fastlane with an action. From the Terminal, run the following command to add the App Distribution plugin to your Fastlane installation:
$ fastlane add_plugin firebase_app_distribution
If for some reason, plugins are not installed, try again after disabling the VPN.
The next step is to log in to Firebase. Follow the steps mentioned on the website.
https://firebase.google.com/docs/cli
Now open Fastfile in a text editor, and paste the code below fastlane lane:
desc "Upload build to Firebase"
lane :upload_build_to_firebase do
firebase_app_distribution(
ipa_path: "#{BUILD_PATH}/#{IPA_FILE_NAME}.ipa",
app: FIREBASE_APP_ID, testers: TESTER_LIST,
#groups: "",
#release_notes_file: RELEASE_NOTES_FILE_PATH,
release_notes: "Testing build upload")
end
Also, add the code below the fastlane build lane
desc "Create ipa"
............
......
# Increases the build number by 1
#increment_version
# Creates a signed file
qa_build
# Build upload to firebase
upload_build_to_firebase
end
After all these setups, run the following command from Terminal: fastlane ios build.
Result:- This will generate the .ipa file and upload to Firebase App Distribution on Firebase Console.
Uploaded build link:
Concluding that we have covered the CI/CD workflow via Fastlane & Firebase on the local machine in Part – 2. We’ll cover in the next part how to use CI/CD workflow via Fastlane & Firebase with Gitlab Actions. Stay tuned!