Build & Release Using Github Actions
#
Continuous integration and deploymentContinuous integration is the practice of frequently committing small changes to a shared repository. This can range from once per day to multiple times per day.
Continuous deployment/delivery picks up after continuous integration. CD automates the delivery of applications to selected infrastructures (like Play Store, Firebase App distribution and App Store in our case). Most teams work with multiple environments other than the production, such as development and testing environments, and CD ensures there is an automated way to push code changes to them.
#
CI/CD WorkflowOne of the Main Advantages of using React Native is that you can build one app that works on both ios and android platforms, same thing for CI/CD we can setup App Center for automatic builds and also ensuring smooth delivery to the App Store/Play Store.
For CI we will use the same GIT Workflow, for Development each time you add a new feature or you fix a bug it should be tested and merged to main branch. If this version is stable you can generate a new github release using npm run release
#
Configure Release ProcessTo create a new app release we are going to use the same tool used to create npm packages and a preview github release.
- Add
np
andreact-native-version
package.
yarn add np react-native-version -D
- Go to
package.json
and add the following scripts
{ "name": "AwesomeProject", "version": "0.0.1", "scripts": { "np": "np --no-publish", "postversion": "react-native-version" }}
we added react-native-version
command as a postversion script because np
can't update ios and android versions. react-native-version
will help sync package.json
version with android and ios as well as incrementing the build number automatically. The default behavior work as expected but you can add more options
⚠️ Make sure to add github repo in your package.json. it's mandatory to create a github release.
- Generate an App release using(we need a simple video here):
npm run npyarn np
#
Android Github Action- Create a new github workflow
.github/workflows/android_build.yml
and add the following content
name: Android Build ## name of the workflow
on: release: types: [published] ## only run the workflow when a new release has been published
jobs: android-build: name: Android Build runs-on: ubuntu-latest # using ubuntu latest version / or you can use a specific version
steps: - name: Check out Git repository # checkout repository uses: actions/checkout@v2
- name: Set up our JDK environment # setup JDK environment: mandatory as we need to build an android project uses: actions/setup-[email protected] with: java-version: 1.8
- name: Set up Node.js ## setup node and yarn with cache uses: actions/setup-node@v2 with: node-version: 14 cache: "yarn"
- name: Install dependencies ## install project deps with --frozen-lockfile to make sure we will have the same packages version ( very recommended on running yarn install on ci) run: yarn install --frozen-lockfile
## configure cash for gradle : will help to reduce build time - name: Cache Gradle Wrapper uses: actions/cache@v2 with: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}
- name: Cache Gradle Dependencies uses: actions/cache@v2 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-caches-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }} restore-keys: | ${{ runner.os }}-gradle-caches-
- name: Make Gradlew Executable run: cd android && chmod +x ./gradlew
## make sure to generate abb instead if you wand to upload it to play store ./gradlew bundleRelease - name: Build Android App Bundle run: | cd android && ./gradlew assembleRelease --no-daemon
## sign generate apk using github secrets - name: Sign App Bundle id: sign_app uses: r0adkll/sign-android-release@v1 with: releaseDirectory: android/app/build/outputs/apk/release signingKeyBase64: ${{ secrets.ANDROID_SIGNING_KEY }} alias: ${{ secrets.ANDROID_ALIAS }} keyStorePassword: ${{ secrets.ANDROID_KEY_STORE_PASSWORD }} keyPassword: ${{ secrets.ANDROID_KEY_PASSWORD }}
## upload artifact to action - name: Upload Artifact uses: actions/upload-artifact@v2 with: name: Gakko App Bundle path: ${{steps.sign_app.outputs.signedReleaseFile}}
## Distribute app to Firebase App Distribution for testing / use google play internal track if you have a google play account - name: upload artifact to Firebase App Distribution uses: wzieba/Firebase-Distribution-Github-Action@v1 with: appId: ${{secrets.ANDROID_FIREBASE_APP_ID}} token: ${{secrets.ANDROID_FIREBASE_TOKEN}} groups: testers file: ${{steps.sign_app.outputs.signedReleaseFile}}
## upload abb to google play using https://github.com/r0adkll/upload-google-play
- Generate a keystore and add environment variables as github secrets in your repository
Android Singing Configuration for r0adkll/sign-android-release@v1 action.
You can generate keystore using the following command:
keytool -genkeypair -v -storetype PKCS12 -keystore my-upload-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000
ANDROID_SIGNING_KEY
: The base64 encoded signing key used to sign your app
This action will directly decode this input to a file to sign your release with. You can prepare your key by running this command on *nix systems.
openssl base64 < your_signing_key.jks | tr -d '\n' | tee signing_key.jks.base64.txt
Then copy the contents of the .txt file to your ANDROID_SIGNING_KEY
GH secret.
ANDROID_ALIAS
: The alias of your signing keyANDROID_KEY_STORE_PASSWORD
: The password to your signing keystoreANDROID_KEY_PASSWORD
: The private key password for your signing keystore
Firebase App distribution
if you want to distribute App to testers using firebase App distribution using wzieba/Firebase-Distribution-Github-Action@v1 you need to create a firebase application and activate App distribution then add the following Github secrets:
ANDROID_FIREBASE_APP_ID
: App id can be found on the General Settings pageANDROID_FIREBASE_TOKEN
: Upload token - see Firebase CLI Reference (tldr; runfirebase login:ci
command to get your token).
Upload to Google Play
to upload the Android Application to Google play you can add the following to you github action:
## Distribute App- name: Upload App to Google Play uses: r0adkll/upload-google-play@v1 with: serviceAccountJsonPlainText: ${{ secrets.ANDROID_SERVICE_ACCOUNT_JSON_TEXT }} packageName: com.example releaseFiles: android/app/build/outputs/bundle/release/*.aab track: internal inAppUpdatePriority: 2
First Make sure your android developer account and internal track are ready to accept new build.
Next you should generate A new service account to upload your aab
file to Google play. here's a complete guide on how to generate Android service account 👉 Generate Service account json file
⚠️ Only Owners can generate service account json files ⚠️ Make sure to to delete signing the release aab with debug credentials
Then you can json file content to Github secrets under ANDROID_SERVICE_ACCOUNT_JSON_TEXT
name.
#
IOS Github actionThe first step is to generate bundle Id, certification and Provisioning Profile for distribution and install them in your mac. check IOS code sining guide
#
Configure IOS project on xcodeOpen your project on xcode by double click on
ios/XXXX.xcworkspace
(⚠️ not.xcodeproj
file)Select project target >
Singing & Capabilities
>Release
Uncheck Automatically manage singing
In
Provisioning Profile
, import profile you already downloaded.If the certificate associated to profile is already installed on your device you should see it in
Signing Certificate
also you should see the team name appear automatically
Now your project code source is ready for github action build
#
IOS Build workflowname: IOS Build
on: release: types: [published]
jobs: ios-build: name: IOS Build runs-on: macOS-latest defaults: run: working-directory: ios
steps: - name: Cancel Previous Runs uses: styfle/cancel-workflow-[email protected] with: access_token: ${{ github.token }} - name: Check out Git repository uses: actions/checkout@v2
- name: Set up Node.js uses: actions/setup-node@v2 with: node-version: 14 cache: "yarn"
- name: Install dependencies run: yarn install --frozen-lockfile
- name: Restore buildcache uses: mikehardy/buildcache-action@v1 continue-on-error: true
- name: Setup Ruby (bundle) uses: ruby/setup-ruby@v1 with: ruby-version: 2.6 bundler-cache: true
- name: Restore Pods cache uses: actions/cache@v2 with: path: | ios/Pods ~/Library/Caches/CocoaPods ~/.cocoapods key: ${{ runner.os }}-pods-${{ hashFiles('ios/Podfile.lock') }} restore-keys: | ${{ runner.os }}-pods- - name: Install Pods run: yarn setup:ios
- name: Build IOS App uses: yukiarrr/ios-build-[email protected] with: project-path: ios/Gakko.xcodeproj p12-base64: ${{ secrets.IOS_P12_BASE64 }} mobileprovision-base64: ${{ secrets.IOS_MOBILE_PROVISION_BASE64 }} code-signing-identity: "iPhone Distribution" team-id: ${{ secrets.IOS_TEAM_ID }} certificate-password: ${{ secrets.IOS_CERTIFICATE_PASSWORD }} workspace-path: ios/Gakko.xcworkspace
- name: Upload Artifact uses: actions/upload-artifact@v2 with: name: Gakko IOS IPA path: "output.ipa"
- name: "Upload app to TestFlight" uses: apple-actions/upload-testflight-build@v1 with: app-path: "output.ipa" issuer-id: ${{ secrets.APPSTORE_ISSUER_ID }} api-key-id: ${{ secrets.APPSTORE_API_KEY_ID }} api-private-key: ${{ secrets.APPSTORE_API_PRIVATE_KEY }}
Add the following environment variable as GH secrets
Sining certs and provisioning profile for yukiarrr/ios-build-action
IOS_MOBILE_PROVISION_BASE64
: Base64 encoded Provisioning profile file.
Download it from your Apple developer portal and use the following script to generate base64
openssl base64 < MY_Profile.mobileprovision | tr -d '\n' | tee my-profile.base64.txt
P12_BASE64
: Base64 encoded.p12
file (key + cert)
After installing the certificate in your Mac, Open Keychain Access
App. Select "My Certificates" on the top, and locate the certificate you've downloaded.
Expand the certificate to see the corresponding private key.Then select the certificate and private key, then right-click for the context menu on the items and choose "Export 2 items…".
Pick a location on disk to save the file as a .p12
and choose a strong password for the file(IOS_CERTIFICATE_PASSWORD
)
Generate a base64 for the .p12
file using
openssl base64 < cert.p12 | tr -d '\n' | tee cert.base64.txt
IOS_TEAM_ID
: your apple team id https://developer.apple.com/account/#!/membership/IOS_CERTIFICATE_PASSWORD
: Password used to generate p2 certificate.
Upload to TestFlight upload-testflight-build
APPSTORE_ISSUER_ID
: Go to Users and Access > API Keys, the issuer id is something like598542-36fe-1a63-e073-0824d0166672a
APPSTORE_API_KEY_ID
: The Key ID for AppStore Connect API.APPSTORE_API_PRIVATE_KEY
: The PKCS8 format Private Key for AppStore Connect API. The content of the fileAuthKey_xxxxxx.p8
generated