I hope you have been following this CI/CD blog series right from Part 1. If not, you can read Part 1 here and Part 2 here.
In this blog, I am going to focus mainly on Android-related steps, like JDK set, building aab, and uploading to the Play store.
Let’s get started with setting up the JDK environment!
– name: JDK environment Set-Up
uses: actions/setup-java@v1.4.3 with: java-version: 11.0.15 |
- name: Decode Keystore for Nitor # decode keystore and generate jks/keystore file if: ${{ github.event.inputs.target == 'Nitor' || (github.event.inputs.target == 'NitorPro' && github.event.inputs.flavor == 'staging' ) }} id: decode_keystore_for_Nitor uses: timheuer/base64-to-file@v1 with: fileName: "Nitor.jks" encodedString: ${{ secrets.ANDROID_SIGNING_KEY }} |
- name: "move keystore Nitor" if: ${{ github.event.inputs.target == 'Nitor' || (github.event.inputs.target == 'NitorPro' && github.event.inputs.flavor == 'staging') }} run: | mv ${{steps.decode_keystore_for_Nitor.outputs.filePath}} android/app ls android/app |
- name: Make Gradlew Executable run: cd android && chmod +x ./gradlew |
def getVersionName = { -> def name = project.hasProperty('versionName') ? versionName : "1.0" return name } def getVersionCode = { -> def code = project.hasProperty('versionCode') ? versionCode.toInteger() : 1 return code } |
defaultConfig { applicationId "your.app.id" minSdkVersion 15 targetSdkVersion 23 versionCode getVersionCode() versionName geVersionName() -------- -------- } |
./gradlew assembleDebug -PversionCode=483 -PversionName=4.0.3 |
You can read more about it here: https://web.archive.org/web/20160119183929/https://robertomurray.co.uk/blog/2013/gradle-android-inject-version-code-from-command-line-parameter/
- name: Generate App Bundle for Nitor / staging if: ${{ github.event.inputs.target == 'Nitor' && github.event.inputs.flavor == 'staging' }} run: | cd android ./gradlew bundleNitorstagingRelease -PversionCode=${{ github.event.inputs.minorversion }} -PversionName=${{ github.event.inputs.majorversion }} |
- name: Sign APK For Nitor / staging if: ${{ github.event.inputs.target == 'Nitor' && github.event.inputs.flavor == 'staging' }} id: sign_app_Nitor_staging uses: r0adkll/sign-android-release@v1 with: releaseDirectory: android/app/build/outputs/bundle/NitorstagingRelease/ signingKeyBase64: ${{ secrets.ANDROID_SIGNING_KEY }} alias: ${{ secrets.ANDROID_ALIAS }} keyStorePassword: ${{ secrets.ANDROID_KEY_STORE_PASSWORD }} keyPassword: ${{ secrets.ANDROID_KEY_PASSWORD }} |
- name: Upload App to Google Play Nitor / staging if: ${{ github.event.inputs.target == 'Nitor' && github.event.inputs.flavor == 'staging' }} uses: r0adkll/upload-google-play@v1 with: serviceAccountJsonPlainText: ${{ secrets.ANDROID_SERVICE_ACCOUNT_JSON_TEXT }} packageName: com.Nitor.Nitor.staging releaseFiles: android/app/build/outputs/bundle/NitorstagingRelease/*.aab track: internal status: completed inAppUpdatePriority: 2 |
To upload the app to Google Play, we will largely follow the same procedure, but we will utilize the .aab bundle rather than the APK.
You must create a new service account in order to upload your .aab to Google Play. Remember:
⚠️ ️Delete the signing of the release aab with the debug credentials from the android/app/build.gradle file.
⚠️ Only Owners have the ability to produce service account JSON files.
The process of creating an Android service account is explained in detail here – Generate Service account JSON file
The content of the JSON file can then be uploaded to GitHub secrets with the name ANDROID SERVICE ACCOUNT JSON TEXT.
****************************************************************
Here’s a useful link: https://www.obytes.com/blog/react-native-ci-cd-github-action
Explore how you can add a self-hosted-runner here: https://docs.github.com/en/actions/hosting-your-own-runners/adding-self-hosted-runners
Kindly refer to the following .yml file which I have used as an example.
name: Android Build Deployment on: workflow_dispatch: # manually triggers with inputs inputs: target: description: "Target" required: true default: "Nitor" type: choice options: - Nitor - NitorPro flavor: description: "Environment" required: true default: "staging" type: choice options: - staging - development - production minorversion: description: "Minor Version" #versionCode required: true majorversion: description: "Major Version" #versionName required: true jobs: android: name: Publish App To Play Store runs-on: self-hosted # [ubuntu-latest, macOS-latest, self-hosted] steps: - name: Check out Git repository uses: actions/checkout@v2 with: persist-credentials: false # make it false if you are going to clone private repositories in yarn - name: JDK environment Set Up uses: actions/setup-java@v1.4.3 with: java-version: 11.0.15 - name: Decode Keystore for Nitor # decode keystore and generate jks/keystore file if: ${{ github.event.inputs.target == 'Nitor' || (github.event.inputs.target == 'NitorPro' && github.event.inputs.flavor == 'staging' ) }} id: decode_keystore_for_Nitor uses: timheuer/base64-to-file@v1 with: fileName: "Nitor.jks" encodedString: ${{ secrets.ANDROID_SIGNING_KEY }} - name: Decode Keystore for NitorPro # decode keystore and generate jks/keystore file if: ${{ github.event.inputs.target == 'NitorPro' && (github.event.inputs.flavor == 'development' || github.event.inputs.flavor == 'production') }} id: decode_keystore_for_NitorPro uses: timheuer/base64-to-file@v1 with: fileName: "NitorPro.jks" encodedString: ${{ secrets.NITORPRO_RELEASE_STORE_FILE }} - name: Decode build.gradle # decode build.gradle and generate build.gradle file id: decode_app_build_gradle uses: timheuer/base64-to-file@v1 with: fileName: "build.gradle" encodedString: ${{ secrets.GRADLE}} - name: Decode .env.Nitor.staging # decode .env.Nitor.staging and generate .env.Nitor.staging file if: ${{ github.event.inputs.target == 'Nitor' && github.event.inputs.flavor == 'staging'}} id: decode_Nitor_staging uses: timheuer/base64-to-file@v1 with: fileName: ".env" encodedString: ${{ secrets.NITOR_STAGING}} - name: Decode .env.Nitor.development # decode .env.Nitor.development and generate .env.Nitor.development file if: ${{ github.event.inputs.target == 'Nitor' && github.event.inputs.flavor == 'development'}} id: decode_Nitor_development uses: timheuer/base64-to-file@v1 with: fileName: ".env" encodedString: ${{ secrets.NITOR_DEVELOPMENT}} - name: Decode .env.Nitor.production # decode .env.Nitor.production and generate .env.Nitor.production file if: ${{ github.event.inputs.target == 'Nitor' && github.event.inputs.flavor == 'production'}} id: decode_Nitor_production uses: timheuer/base64-to-file@v1 with: fileName: ".env" encodedString: ${{ secrets.NITOR_PRODUCTION}} - name: Decode .env.NitorPro.staging # decode .env.NitorPro.stagingand generate .env.NitorPro.staging file if: ${{ github.event.inputs.target == 'NitorPro' && github.event.inputs.flavor == 'staging'}} id: decode_NitorPro_staging uses: timheuer/base64-to-file@v1 with: fileName: ".env" encodedString: ${{ secrets.NITORPRO_STAGING}} - name: Decode .env.NitorPro.development # decode .env.NitorPro.development and generate .env.NitorPro.development file if: ${{ github.event.inputs.target == 'NitorPro' && github.event.inputs.flavor == 'development'}} id: decode_NitorPro_development uses: timheuer/base64-to-file@v1 with: fileName: ".env" encodedString: ${{ secrets.NITORPRO_DEVELOPMENT}} - name: Decode .env.NitorPro.production # decode .env.NitorPro.production and generate .env.NitorPro.production file if: ${{ github.event.inputs.target == 'NitorPro' && github.event.inputs.flavor == 'production'}} id: decode_NitorPro_production uses: timheuer/base64-to-file@v1 with: fileName: ".env" encodedString: ${{ secrets.NITORPRO_PRODUCTION}} # - name: move "jks" to android/app - name: "move keystore Nitor" if: ${{ github.event.inputs.target == 'Nitor' || (github.event.inputs.target == 'NitorPro' && github.event.inputs.flavor == 'staging') }} run: | mv ${{steps.decode_keystore_for_Nitor.outputs.filePath}} android/app ls android/app - name: "move keystore NitorPro" if: ${{ github.event.inputs.target == 'NitorPro' && (github.event.inputs.flavor == 'development' || github.event.inputs.flavor == 'production')}} run: | mv ${{steps.decode_keystore_for_NitorPro.outputs.filePath}} android/app ls android/app - name: "move build gradle" run: | mv ${{steps.decode_app_build_gradle.outputs.filePath}} android/app ls cat android/app/build.gradle - name: "move Nitor_staging" if: ${{ github.event.inputs.target == 'Nitor' && github.event.inputs.flavor == 'staging'}} run: | mv ${{steps.decode_Nitor_staging.outputs.filePath}} ./ pwd cat .env - name: "move Nitor_development" if: ${{ github.event.inputs.target == 'Nitor' && github.event.inputs.flavor == 'development'}} run: | mv ${{steps.decode_Nitor_development.outputs.filePath}} ./ pwd cat .env - name: "move Nitor_production" if: ${{ github.event.inputs.target == 'Nitor' && github.event.inputs.flavor == 'production'}} run: | mv ${{steps.decode_Nitor_production.outputs.filePath}} ./ pwd cat .env - name: "move NitorPro_staging" if: ${{ github.event.inputs.target == 'NitorPro' && github.event.inputs.flavor == 'staging'}} run: | mv ${{steps.decode_NitorPro_staging.outputs.filePath}} ./ pwd cat .env - name: "move NitorPro_development" if: ${{ github.event.inputs.target == 'NitorPro' && github.event.inputs.flavor == 'development'}} run: | mv ${{steps.decode_NitorPro_development.outputs.filePath}} ./ pwd cat .env - name: "move NitorPro_production" if: ${{ github.event.inputs.target == 'NitorPro' && github.event.inputs.flavor == 'production'}} run: | mv ${{steps.decode_NitorPro_production.outputs.filePath}} ./ pwd cat .env - name: git config with PAT_GITHUB run: git config --global url.https://${{ secrets.PAT_GITHUB }}@github.com/.insteadOf https://github.com - name: Set up our node configuration uses: actions/setup-node@v1 with: node-version: 16.x - name: Get yarn cache directory path id: yarn-cache-dir-path run: echo "::set-output name=dir::$(yarn cache dir)" - name: yarn Install dependencies if: | steps.cache-yarn-cache.outputs.cache-hit != 'true' || steps.cache-node-modules.outputs.cache-hit != 'true' run: | yarn install --network-concurrency 1 - name: Make Gradlew Executable run: cd android && chmod +x ./gradlew # Generate App Bundle for Nitor / staging - name: Generate App Bundle for Nitor / staging if: ${{ github.event.inputs.target == 'Nitor' && github.event.inputs.flavor == 'staging' }} run: | cd android ./gradlew bundleNitorstagingRelease -PversionCode=${{ github.event.inputs.minorversion }} -PversionName=${{ github.event.inputs.majorversion }} # Generate App Bundle for Nitor / development - name: Generate App Bundle for Nitor / development if: ${{ github.event.inputs.target == 'Nitor' && github.event.inputs.flavor == 'development' }} run: | cd android ./gradlew bundleNitordevelopmentRelease -PversionCode=${{ github.event.inputs.minorversion }} -PversionName=${{ github.event.inputs.majorversion }} # Generate App Bundle for Nitor / production - name: Generate App Bundle for Nitor / production if: ${{ github.event.inputs.target == 'Nitor' && github.event.inputs.flavor == 'production' }} run: | cd android ./gradlew bundleNitorRelease -PversionCode=${{ github.event.inputs.minorversion }} -PversionName=${{ github.event.inputs.majorversion }} # Generate App Bundle for NitorPro / staging - name: Generate App Bundle for NitorPro / staging run: | cd android ./gradlew bundleNitorProstagingRelease -PversionCode=${{ github.event.inputs.minorversion }} -PversionName=${{ github.event.inputs.majorversion }} if: ${{ github.event.inputs.target == 'NitorPro' && github.event.inputs.flavor == 'staging' }} # Generate App Bundle for NitorPro / development - name: Generate App Bundle for NitorPro / development run: | cd android ./gradlew bundleNitorProdevelopmentRelease -PversionCode=${{ github.event.inputs.minorversion }} -PversionName=${{ github.event.inputs.majorversion }} if: ${{ github.event.inputs.target == 'NitorPro' && github.event.inputs.flavor == 'development' }} # Generate App Bundle for NitorPro / production - name: Generate App Bundle for NitorPro / production run: | cd android ./gradlew bundleNitorProRelease -PversionCode=${{ github.event.inputs.minorversion }} -PversionName=${{ github.event.inputs.majorversion }} if: ${{ github.event.inputs.target == 'NitorPro' && github.event.inputs.flavor == 'production' }} # sign generated aab for Nitor / staging - name: Sign APK For Nitor / staging if: ${{ github.event.inputs.target == 'Nitor' && github.event.inputs.flavor == 'staging' }} id: sign_app_Nitor_staging uses: r0adkll/sign-android-release@v1 with: releaseDirectory: android/app/build/outputs/bundle/NitorstagingRelease/ signingKeyBase64: ${{ secrets.ANDROID_SIGNING_KEY }} alias: ${{ secrets.ANDROID_ALIAS }} keyStorePassword: ${{ secrets.ANDROID_KEY_STORE_PASSWORD }} keyPassword: ${{ secrets.ANDROID_KEY_PASSWORD }} # sign generated aab for Nitor / development - name: Sign APK For Nitor / development if: ${{ github.event.inputs.target == 'Nitor' && github.event.inputs.flavor == 'development' }} id: sign_app_Nitor_development uses: r0adkll/sign-android-release@v1 with: releaseDirectory: android/app/build/outputs/bundle/NitordevelopmentRelease/ signingKeyBase64: ${{ secrets.ANDROID_SIGNING_KEY }} alias: ${{ secrets.ANDROID_ALIAS }} keyStorePassword: ${{ secrets.ANDROID_KEY_STORE_PASSWORD }} keyPassword: ${{ secrets.ANDROID_KEY_PASSWORD }} # sign generated aab for Nitor / production - name: Sign APK For Nitor / production if: ${{ github.event.inputs.target == 'Nitor' && github.event.inputs.flavor == 'production' }} id: sign_app_Nitor_production uses: r0adkll/sign-android-release@v1 with: releaseDirectory: android/app/build/outputs/bundle/NitorRelease/ signingKeyBase64: ${{ secrets.ANDROID_SIGNING_KEY }} alias: ${{ secrets.ANDROID_ALIAS }} keyStorePassword: ${{ secrets.ANDROID_KEY_STORE_PASSWORD }} keyPassword: ${{ secrets.ANDROID_KEY_PASSWORD }} # sign generated aab for NitorPro / staging - name: Sign APK For NitorPro / staging if: ${{ github.event.inputs.target == 'NitorPro' && github.event.inputs.flavor == 'staging' }} id: sign_app_NitorPro_staging uses: r0adkll/sign-android-release@v1 with: releaseDirectory: android/app/build/outputs/bundle/NitorProstagingRelease/ signingKeyBase64: ${{ secrets.ANDROID_SIGNING_KEY }} alias: ${{ secrets.ANDROID_ALIAS }} keyStorePassword: ${{ secrets.ANDROID_KEY_STORE_PASSWORD }} keyPassword: ${{ secrets.ANDROID_KEY_PASSWORD }} # sign generated aab for NitorPro / development - name: Sign APK For NitorPro / development if: ${{ github.event.inputs.target == 'NitorPro' && github.event.inputs.flavor == 'development' }} id: sign_app_NitorPro_development uses: r0adkll/sign-android-release@v1 with: releaseDirectory: android/app/build/outputs/bundle/NitorProdevelopmentRelease/ signingKeyBase64: ${{ secrets.NITORPRO_RELEASE_STORE_FILE }} alias: ${{ secrets.NITORPRO_RELEASE_KEY_ALIAS }} keyStorePassword: ${{ secrets.NITORPRO_RELEASE_STORE_PASSWORD }} keyPassword: ${{ secrets.NITORPRO_RELEASE_KEY_PASSWORD }} # sign generated aab for NitorPro / production - name: Sign APK For NitorPro / production if: ${{ github.event.inputs.target == 'NitorPro' && github.event.inputs.flavor == 'production' }} id: sign_app_NitorPro_production uses: r0adkll/sign-android-release@v1 with: releaseDirectory: android/app/build/outputs/bundle/NitorProRelease/ signingKeyBase64: ${{ secrets.NITORPRO_RELEASE_STORE_FILE }} alias: ${{ secrets.NITORPRO_RELEASE_KEY_ALIAS }} keyStorePassword: ${{ secrets.NITORPRO_RELEASE_STORE_PASSWORD }} keyPassword: ${{ secrets.NITORPRO_RELEASE_KEY_PASSWORD }} #Upload App to Google Play For Nitor / staging - name: Upload App to Google Play Nitor / staging if: ${{ github.event.inputs.target == 'Nitor' && github.event.inputs.flavor == 'staging' }} uses: r0adkll/upload-google-play@v1 with: serviceAccountJsonPlainText: ${{ secrets.ANDROID_SERVICE_ACCOUNT_JSON_TEXT }} packageName: com.Nitor.Nitor.staging releaseFiles: android/app/build/outputs/bundle/NitorstagingRelease/*.aab track: internal status: completed inAppUpdatePriority: 2 #Upload App to Google Play For Nitor / development - name: Upload App to Google Play Nitor / development if: ${{ github.event.inputs.target == 'Nitor' && github.event.inputs.flavor == 'development' }} uses: r0adkll/upload-google-play@v1 with: serviceAccountJsonPlainText: ${{ secrets.ANDROID_SERVICE_ACCOUNT_JSON_TEXT }} packageName: com.Nitor.Nitor.dev releaseFiles: android/app/build/outputs/bundle/NitordevelopmentRelease/*.aab track: internal status: completed inAppUpdatePriority: 2 #Upload App to Google Play For Nitor / production - name: Upload App to Google Play Nitor / production if: ${{ github.event.inputs.target == 'Nitor' && github.event.inputs.flavor == 'production' }} uses: r0adkll/upload-google-play@v1 with: serviceAccountJsonPlainText: ${{ secrets.ANDROID_SERVICE_ACCOUNT_JSON_TEXT }} packageName: com.Nitor.Nitor releaseFiles: android/app/build/outputs/bundle/NitorRelease/*.aab track: internal status: completed inAppUpdatePriority: 2 #Upload App to Google Play For NitorPro / staging - name: Upload App to Google Play NitorPro / staging if: ${{ github.event.inputs.target == 'NitorPro' && github.event.inputs.flavor == 'staging' }} uses: r0adkll/upload-google-play@v1 with: serviceAccountJsonPlainText: ${{ secrets.ANDROID_SERVICE_ACCOUNT_JSON_TEXT }} # please update this with NitorPro android serviceAccountJsonPlainText: ${{ secrets.ANDROID_SERVICE_ACCOUNT_JSON_TEXT }} packageName: com.Nitor.NitorPro.staging releaseFiles: android/app/build/outputs/bundle/NitorProstagingRelease/*.aab track: internal status: draft inAppUpdatePriority: 2 #Upload App to Google Play For NitorPro / development - name: Upload App to Google Play NitorPro / development if: ${{ github.event.inputs.target == 'NitorPro' && github.event.inputs.flavor == 'development' }} uses: r0adkll/upload-google-play@v1 with: serviceAccountJsonPlainText: ${{ secrets.ANDROID_SERVICE_ACCOUNT_JSON_TEXT }} # please update this with NitorPro android serviceAccountJsonPlainText: ${{ secrets.ANDROID_SERVICE_ACCOUNT_JSON_TEXT }} packageName: com.Nitor.NitorPro.dev releaseFiles: android/app/build/outputs/bundle/NitorProdevelopmentRelease/*.aab track: internal status: completed inAppUpdatePriority: 2 #Upload App to Google Play For NitorPro / production - name: Upload App to Google Play NitorPro / production if: ${{ github.event.inputs.target == 'NitorPro' && github.event.inputs.flavor == 'production' }} uses: r0adkll/upload-google-play@v1 with: serviceAccountJsonPlainText: ${{ secrets.ANDROID_SERVICE_ACCOUNT_JSON_TEXT }} # please update this with NitorPro android serviceAccountJsonPlainText: ${{ secrets.ANDROID_SERVICE_ACCOUNT_JSON_TEXT }} packageName: com.Nitor.NitorPro releaseFiles: android/app/build/outputs/bundle/NitorProRelease/*.aab track: internal status: completed inAppUpdatePriority: 2 |
So, this is how you can go about the Android setup of CI/CD with GitHub Actions! Mail us with your thoughts about this setup and visit us at Nitor Infotech to learn about our offerings.
Subscribe to our fortnightly newsletter!