Update ๐šŠ๐š—๐š๐š›๐š˜๐š’๐š/๐šŠ๐š™๐š™/๐š‹๐šž๐š’๐š•๐š.๐š๐š›๐šŠ๐š๐š•๐šŽ to complete Release pipeline

Part ษชษชษช: Automate App release to Google Play | Story 3 - ๐šŠ๐š—๐š๐š›๐š˜๐š’๐š/๐šŠ๐š™๐š™/๐š‹๐šž๐š’๐š•๐š.๐š๐š›๐šŠ๐š๐š•๐šŽ file updates to complete Release pipeline

Bharat Tiwari
Automating React Native App release to Google play store
7 min readJul 27, 2020

--

Image by WikiImages from Pixabay

In the previous posts of this part of the series, we created a Google Play Service account and then configured Gitlab CI/CD variables and .๐š๐š’๐š๐š•๐šŠ๐š‹-๐šŒ๐š’.๐šข๐š–๐š• to script the release pipeline automation.

What remains now is to update the ๐šŠ๐š—๐š๐š›๐š˜๐š’๐š/๐š‹๐šž๐š’๐š•๐š.๐š๐š›๐šŠ๐š๐š•๐šŽ and ๐šŠ๐š—๐š๐š›๐š˜๐š’๐š/๐šŠ๐š™๐š™/๐š‹๐šž๐š’๐š•๐š.๐š๐š›๐šŠ๐š๐š•๐šŽ files to complete the pipeline automation setup.

๐šŠ๐š—๐š๐š›๐š˜๐š’๐š/๐š‹๐šž๐š’๐š•๐š.๐š๐š›๐šŠ๐š๐š•๐šŽ file

As we are going to use Gradle Play Publisher (GPP) to automate the app bundling and release, we need to add that as dependency in the android/build.gradle file. Open the file in code editor, under buildscript.dependencies, add classpath for the GPP as below:

buildscript {
โ€ฆ
dependencies {
classpath("com.android.tools.build:gradle:4.0.0")
classpath("com.github.triplet.gradle:play-publisher:2.8.0")
...
}
}

These are the stable versions as of the writing of this post. Look for the latest versions (GPP and Android build gradle tools) and update accordingly.

With above changes, the file should look something like below ๐Ÿ‘‡

gist url

๐Ÿ‘† line#16, we added classpath(โ€œcom.github.triplet.gradle:play-publisher:2.8.0โ€) as one of the dependency.

Also updated the version of com.android.tools.build:gradle to 4.0.0 : classpath(โ€œcom.android.tools.build:gradle:4.0.0โ€).

๐šŠ๐š—๐š๐š›๐š˜๐š’๐š/๐š๐š›๐šŠ๐š๐š•๐šŽ.๐š™๐š›๐š˜๐š™๐šŽ๐š›๐š๐š’๐šŽ๐šœ file

If you have been following this series, in Part II - at the time of manual bundling and publishing of the Android app, we added the Upload keystore file name and its credentials/alias as app level vars android/gradle.properties.

But now that we have these values moved to to Gitlab CI/CD variables, we can remove those from ๐š๐š›๐šŠ๐š๐š•๐šŽ.๐š™๐š›๐š˜๐š™๐šŽ๐š›๐š๐š’๐šŽ๐šœ.

Open the file ~/.gradle/gradle.properties or android/gradle.properties, in code editor, and remove the following variables.

MYAPP_UPLOAD_STORE_FILE=rnTSgitlabCICDExample-upload.keystore
MYAPP_UPLOAD_KEY_ALIAS= rnTSgitlabCICDExample-upload
MYAPP_UPLOAD_STORE_PASSWORD=*****
MYAPP_UPLOAD_KEY_PASSWORD=*****

๐šŠ๐š—๐š๐š›๐š˜๐š’๐š/๐šŠ๐š™๐š™/๐š‹๐šž๐š’๐š•๐š.๐š๐š›๐šŠ๐š๐š•๐šŽ file

Next, we will edit the ๐šŠ๐š™๐š™/๐š‹๐šž๐š’๐š•๐š.๐š๐š›๐šŠ๐š๐š•๐šŽ file which the gradlew command would use to create the build, bundle the app and publish the bundle to our Google Play store account. Update ๐šŠ๐š™๐š™/๐š‹๐šž๐š’๐š•๐š.๐š๐š›๐šŠ๐š๐š•๐šŽ file as below:

  1. Just below the top apply plugin: "com.android.application" statement in the file, we need to add below line of code to apply GPP plugin:
apply plugin: "com.github.triplet.play"

2. Earlier, in our .gitlab-ci.yml file, we added steps to read Gitlab-CICD environment variables to a dynamically created json file named globalSettings.json.

Now in our ๐šŠ๐š™๐š™/๐š‹๐šž๐š’๐š•๐š.๐š๐š›๐šŠ๐š๐š•๐šŽ file, we will add a function named getSettings, to read variables from this globalSettings.json file. The input parameter to this function would be the setting/variable name. We will use JsonSlurper utility to parse the json and get and return the value of the setting/variable provided by the input parameter.

For this, first add the below line of code just below the existing import statement in the file ( below import com.android.build.OutputFile)

import com.android.build.OutputFile
import groovy.json.JsonSlurper // <-- add this new import statement

Now, add a getSetting function definition below the import statements:

def getSetting(setting) {
def inputFile = file("globalSettings.json")
def settingsJson = new JsonSlurper().parseText(inputFile.text)
return settingsJson[setting]
}

3. Next, update the release signingConfig as below:

...
android {
...
defaultConfig { ... }
signingConfigs {
debug {
...
}
release {
storeFile file('uploadRelease.keystore')
storePassword getSetting("PLAY_STORE_UPLOAD_KEYSTORE_PASSWORD")
keyAlias getSetting("PLAY_STORE_UPLOAD_KEYSTORE_ALIAS")
keyPassword getSetting("PLAY_STORE_UPLOAD_KEY_PASSWORD")
}
}
}
...

๐Ÿ‘†in the release signingConfig, we are now reading the values of our appโ€™s Upload key's storePassword, keyAlias and keyPassword from the globalSettings.json using the getSetting function we defined above.

Also, the upload keystore storeFile has been specified as uploadRelease.keystore. This is the file name that we specified in the .gitlab-ci.yml script, that will be created dynamically during the pipeline run using the keystoreโ€™s base64 string added in Gitlabโ€™s CICD variables .

4. Make sure you have the above signingConfig specified for release build under buildTypes:

...
android {
...
defaultConfig { ... }
signingConfigs {...}
buildTypes {
release {
...
signingConfig signingConfigs.release
...
}
}
}
...

5. Add below play section, below the files android or dependencies section. This new play section specifies the configuration that GPP would use when releasing/publishing our app to Google Play store:

...
android {
...
}
play {
defaultToAppBundles = true
track = "internal" // 'alpha', 'beta', 'rollout' or 'production'
serviceAccountCredentials = file("serviceAccess.json")
resolutionStrategy = "auto"
}
...
  • defaultToAppBundles: makes sure to package app as AAB (Android App Bundle) instead of APK
  • track: tells to which release track the bundle is to be published, in this case itโ€™s the internal track ( other options are beta, alpha, production)
  • serviceAccountCredentials: The location of the Play Store JSON file. This again, as we specified in out .gitlab-ci.yml file, we are creating dynamically in our pipeline, reading its value from Gitlab CI/CD variable to output to android/app/serviceAccess.json file.
  • resolutionStrategy = "auto": automatically updates the appโ€™s version code to match the next available number required so itโ€™s published

๐Ÿ’Ž There are many other useful configuration options GPP provides.

That completes the changes we need to make in android/app/build.gradle file. With above changes, the file should look something like here ๐Ÿ‘‡

Ok, now we are ready with all the configuration needed on Google play console and code changes needed to allow GPP to publish our app bundle.

Letโ€™s update the release version before we commit and push our changes to Gitlab: yarn version. The post-version script we added earlier in Part I of the series to our package.json would automatically update the versions for iOS and Android file and commit the changes.

Push the branch to our Gitlabโ€™s remote repository and create a PR to merge changes to master. Now that we have .gitlab-ci.yml file in the repository, we would expect the pipeline to trigger when we merge changes to master.

(click over image to zoom)

Oops, looks like our first attempt failed.
The error we got is ๐˜”๐˜ช๐˜ฏ๐˜ช๐˜ฎ๐˜ถ๐˜ฎ ๐˜ด๐˜ถ๐˜ฑ๐˜ฑ๐˜ฐ๐˜ณ๐˜ต๐˜ฆ๐˜ฅ ๐˜Ž๐˜ณ๐˜ข๐˜ฅ๐˜ญ๐˜ฆ ๐˜ท๐˜ฆ๐˜ณ๐˜ด๐˜ช๐˜ฐ๐˜ฏ ๐˜ช๐˜ด 6.1.1. ๐˜Š๐˜ถ๐˜ณ๐˜ณ๐˜ฆ๐˜ฏ๐˜ต ๐˜ท๐˜ฆ๐˜ณ๐˜ด๐˜ช๐˜ฐ๐˜ฏ ๐˜ช๐˜ด 6.0.1. GPPโ€™s most recent version (2.8.0) needs Gradle version to be โ‰ฅ 6.1.1. Thus we need the Gradle version in our React-Native appโ€™s Android project.

Upgrading Gradle version

GPPโ€™s most recent version as of the writing of this post is GPP 2.8.0. This version requires our React-Native appโ€™s Android projectโ€™s Gradle version โ‰ฅ 6.1.1 and Android tools build gradle version โ‰ฅ 4.0.

Check your React-Native Android project Gradle version from the distributionUrl in your React-native android projectโ€™s gradle-wrapper-.properties file ๐Ÿ‘‡

(click over image to zoom)

If your Android projectโ€™s Gradle version is < 6.1.1, update it as below:

  1. Update the distributionUrl in the above file to latest Gradle versionโ€™s zip file like below:
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip

2. Add multiDexEnabled false to defaultConfig properties of the android/app/build.gradle file.

4. On terminal, cd to android folder of your react-nativeโ€™s project

./gradlew wrapper --gradle-version=6.5 --distribution-type=ALL

The above gradlew command may fail but thatโ€™s okay, its probably because it doesnโ€™t have the values that we are reading from Gitlab CI/CD variables in the app/build.gradle file.

5. Clean the project build

./gradlew clean

Also open the project in android studio, once Build sync completes, clean (Main menu โ†’ Build โ†’ Clean Build) and rebuild (Main menu โ†’ Build โ†’ Rebuild Build) the project. Again, the build may still fail because of the unavailability of Gitlab CI/CD variables when building locally, but thatโ€™s okay.

6. Commit and push the changes to the remote branch, merge to master and the pipeline should trigger.

This time the Gitlab pipeline completed successfully, got the appโ€™s build created and published to Google Play.

Check out Google Play console , we should see the new version (1.0.0 that we earlier set using yarn version) be released.

Awesome, we got our React-native Android App build and release pipeline automated using GPP and Gitlab CI-CD.

Now, we can just focus on the development of the app, and when ready with testing the new changes, push and merge the changes to master branch. This would trigger the pipeline to release the new version of app to Internal testing track.

Once the Internal test app version is tested and you feel your app is ready, you can promote the app to Alpha, Beta and finally to production by just click of a button from Google Play console.
Or you can set up additional pipeline jobs/stages in .gitlab-ci.yml file to publish the app to different tracks. Trigger those pipelines either manually or based on some branch or any other repository triggers.

There you have it! Your step-by-step guide for setting a Gitlab CI-CD pipeline to automate publishing your React-Native app on Google Play.

I hope you would find this series helpful to automate your React-Native appโ€™s Android build and release pipeline.
Thank you!!! Feedback, comments and suggestions are welcome.

โ†Prev: Gitlab CI/CD varsโ”ˆ ๐Ÿ 

--

--