Search This Blog

Tuesday 8 September 2020

Fastlane tutorial for production use

 Fastlane is a set of open sources tools(written in ruby) for automating various aspects like generating build for iOS, Android, running unit tests etc.

Here is how I did fastlane set up & integration to the existing CI-Jenkins. We have used fastlane for the CD part of CI/CD pipeline.

Commands

  • these are few commands I have used. a lot are there.

  • fastlane init 

    • creates FastFile, AppFile

    • Firsttime for a new acc, failed due to lack of certs, provisioning profiles. this will take apple id, password.

  • fastlane cert - to create a distribution profile using above acc

  • fastlane sigh - to create/get provisioning profile for the above to appstore. not for adhoc

  • fastlane beta - init will create a betalane, now running this command will archieve & export .ipa & push to TestFlight.

  • fastlane pilot upload - to push to store can use

  • fastlane match - to use existing certificates. its pushes/pulls certs required for iOS from a git repo and do the job.

Setting up fastlane

  • Install: brew install fastlane

  • in source code folder go to each platform run: 

    • fastlane init

      • this will ask what we want to do- select 2, Automate push to TestFlight

      • next, choose the right target - App

      • give a different appname whichc is not in your account

    • run fastlane beta

      • But, we need to get certs from apple developer portal & need to be used by everyone. for that, we need to use match (a fastlane tool)

      • run fastlane match init

      • it will ask for a priavte git repo. created and gave.

      • it will create a matchfile

      • it will ask for apple username, password.

      • Based on the current project id, it will create the required certificates, provisioning profile

      • for test flight, ran: fastlane match appstore.

      • the above will create the cert if not there.

      • in our case, we have exceeded max no.of Dist certs so, it throwed an error. so, now setting up a git repo with certs and profiles that fastlane and all of us can use.

      • to use the existing certs, there is no direct tool. we need to use irb(interactive ruby tool or a ruby script to fetch the certs), encrypt, decrypt them.

      • wrote a script beforePlacingManualCerts.rb for fetching the certs & placing it in required folder and to upload.

      • to get id, need to use spaceship cli command. Ref: https://medium.com/@jonathancardoso/using-fastlane-match-with-existing-certificates-without-revoking-them-a325be69dac6

      • Then, fastlane match appstore —readonly. (this is giving error as of now.)

      • Add run script phase to remove unused architectures: 

      • create an App specific password 

      • setup ssh for match git repo

      • Gym-for building iOS.

      • 1st time, it may ask for accessing login key chain, enter password and always allow. this steps need to be checked on automating.

      • React-native-config - no space, commans, quotes etc.

      • https://stackoverflow.com/a/40661027/4065202 for libRealmJS not found etc. adding a new Config need to do these. "$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)"

      • need to input password once firstime building and always allow.

Fastlane iOS implementation to push to AppStore is completed. here are the things that were done.

AppStore:

  • created a gmail account(your apple account), registered as developer in apple developer portal.

Fastlane:
  • created a lane called beta to push/run the set of commands/actions to push to TestFlight.

  • First, will check for required certificates, provisioning profile

    • This will be carried out by Match.

    • Created a match file.

    • For easy sharing and use of certificated across the team, created a private git repo.

    • All the Certificates & profiles will be here & All will be encrypted.

    • Access to the git repo is restricted. not all of you will have access. it will be provide on a need basis for safety.

    • Here, as we need to use existing certificates, no direct fastlane tool is there to do this job. So, wrote a Ruby script for automating the manual job of running few terminal commands to get the existing certificates and place them in to the git repo with encryption. t

    • Checked in this automation as well with name UseExistingCertsProfiles_Fastlane.rb.

  • Match will fetch certs and install it in local keychain. It will ensure everytime certificates are upto date with certificates in apple portal.

  • This will make sure that all required certificates for the app are there.

  • Automations for store builds:

    • For majority of the required automations, i have used react-native-config plugin.

    • All the required config variables are moved to config file called .env & .env.production. Config variables are

      • DEFAULT_ENV in Config.js

      • DEV_FEATURES in Constants.js

      • NEWRELICE_AGENT_KEY - appdelegate.m

      • REALM_SCHEMA_VERSION - offlineServices.js

      • For firebase GoogleServices-info.plist i have created a Build Phase: Copy Firebase GoogleService-Info.plist - which runs a shell script to place the file in build folder based on Configuration selected.

      • For removing unused architectures required for JWPlayer, created another Build Phase: Remove Unused architectures - (JW iOS SDK.framework signing issue resolution) - which runs a shell script to identify and remove unused architectures.

      • For the above purpose to not to be effected by regular dev builds, created a new Scheme: app.production & Configuration: Store.

      • Added pre-build step to set the ENVFILE required for react-native-config

      • Manual tasks

        • I left two of the items to be manual as automation will complicate than simplifying. they are:

          • Version: 1.8.3 etc. This follow semantic versioning: major.minor.patch

          • To let fastlane increment correctly, we need to pass the above bump type. I can’t default it to any. So, left it.

          • Realm Schema

            • This is required in a JS file OfllineServices.js

            • Need to use Git hook to update the version value in .env file. but that comes under keyword expansion. 

            • Git suggests not to do it as it may lead to merge conflicts.

            • Doing that using Git is also an overkill. So, left it.

          • We need to make sure to update the Version number, Schema version correctly in the release/master branch.

  • Jenkins

    • Installed required libraries Fastlane, bundler etc

    • created a job in Jenkins (in a separate folder) to run the above fastlane script.

    • Added Lang environment variable in Jenkins which is required for fastlane.

Note:

  • Only when running for the first time, we need to provide login key chain password and click on Always allow. This is required fot accessing the certificate for signing.

Ofcourse, resolved many certificate issue, building/linker issues (it iOS).
Slack integration & iOS

  • Android:

    • Supply - upload_to_play_store

    • should be in json format

    • app-fastlane-service-acc - API service acc name - android management user

    • key id: xxxxxxxxxxxxxxxxxx

    • newrelic key change - done

    • Google services json - done

    • Slack -

    • Job with progress

  1. created a google account and got invited by playstore admin

  2. With PlayStore owner credentials created a service account for pushing the builds to play store.

  3. added fastlane to android

  4. Config and constants are taken care in iOS, so not required to be done here.

  5. for new relic using react-native-congfig, added step to read from .env file

  6. placed the google-services.json file in android/app/src/release folder. Firebase plugin will pick from the dev/release folders respectively.

  7. added slack notifications by using weblinks.

    1. For this, created an app in slack and get it approved by admin (Shiva)

    2. created a weblink to #mobile-pipeline

    3. using that in Fastfile to send messages

Ref:
  • https://medium.com/react-native-training/fastlane-for-react-native-ios-android-app-devops-8ca85bee614e
  • https://rollout.io/blog/react-native-developer-series-deploy-ios-and-android-pipelines-with-fastlane-and-jenkins/
  • https://docs.fastlane.tools/best-practices/continuous-integration/jenkins/
  • https://www.macadamian.com/learn/automating-ios-certificate-and-profile-syncing-with-fastlane/
  • https://medium.com/@hohey670/ios-multiple-configurations-with-fastlane-8cbaff7d2fa8
  • https://medium.com/@jonathancardoso/using-fastlane-match-with-existing-certificates-without-revoking-them-a325be69dac6
  • https://medium.com/ios-development-tips-and-tricks/slack-fastlane-%EF%B8%8F-about-one-of-continuous-integration-puzzles-6ca03576003e

UseExistingCertsProfiles_Fastlane
##############------SMALL AUTOMATION-------##########
# instead of doing the job of uploading existing certificates via irb (interactive Ruby) manually, this helps in automating
# to use it, give your git_url(where you are storing your cert, profiles for match), match_password below and keep the folder stucture as mentioned below
#-------------------FOLDER-STRUCTURE------------------
# to use this automation follow the folder structure mentioned here:
# Fastlane match keeps certificates in cert directory, provisioning profiles in profiles directory
# for different envs like development, distribution certificates will be kept in respective folders under certs folder. i.e.
# - certs/development for dev; certs/distribution for dist;
# - profiles/appstore for appstore; profiles/adhoc for adhoc etc.
# keep your certs and profiles then same way inside fastlane folder (can be any but keeping in fastlane folder for ease)
# so fodler structure is: fastlane/certs/distribution, fastlane/certs/development. fastlane/profiles/appstore etc.
#--------------------RUNNING--------------------------
# ruby UseExistingCertsProfiles_Fastlane.rb
#

require 'match'
git_url = 'https://github.xxxxxxx.xxxx/xxx/xxxxxxx.git'
shallow_clone = false
ENV["MATCH_PASSWORD"]='xxxxxxxx'
branch = 'master'
storage = Match::Storage.for_mode('git', { git_url: git_url, shallow_clone: shallow_clone, git_branch: branch, clone_branch_directly: false})
storage.download
encryption = Match::Encryption.for_storage_mode('git', { git_url: git_url, working_directory: storage.working_directory})
encryption.decrypt_files
# copy file
puts __dir__+"/certs"
FileUtils.copy_entry(__dir__+"/certs", storage.working_directory+"/certs")
FileUtils.copy_entry(__dir__+"/profiles", storage.working_directory+"/profiles")
puts(storage.working_directory)
encryption.encrypt_files
files_to_commit = Dir[File.join(storage.working_directory, "**", "*.{cer,p12,mobileprovision}")]
storage.save_changes!(files_to_commit: files_to_commit)


###************NOTE***********######
# this can be completly automated using Ruby.
# First check if certs & profiles folders exist and has subfolder required or not.
# accept git_url, password, may be branch as well in case multiple apps as commandline arguments
# rest works fine.
# Because of lack of time, not doing it now, other can take it up & contribut to opensource

1 comment:

  1. Thank you for the fantastic Blog; I thoroughly loved reading it! You'll find out whether or not you're ready to run a store. Because Suffescom solutions operate in a high-contagion environment, developing a reliable security system, such as in-app development and other services, Suffescom Solutions is critical to enable customers to purchase products from your app without fear of being taken advantage of.

    ReplyDelete