Configuring Android App Signing on React Native

Some tips on getting your React Native Android app signed for production.

Preetam D'SouzaAug 22, 2020

It's time. You've toiled away on your React Native app for months and it's finally time to deploy your baby to the world.

But first, you'll need to set up Play App Signing. Although this process isn't complicated, it's a little annoying since you have to deal with key passwords without exposing them.

At Mirai Labs, we deal with native Android and React Native apps so often that managing app signing has become a very common task for our team. After some trial and error, we found a solution that works pretty well, cleanly separating the upload key information from the rest of our app. Here's a short tutorial on how you can give our setup a try in your next app!

Step 1 — Generate your upload key

First, you'll need to generate an upload key that you'll use to sign your app when you upload it to the Play store.

To generate your key using a simple GUI within Android Studio, follow the latest instructions from the Android Developer docs.

Keystore generation

Here's a quick summary of the steps:

  1. Open up Android Studio
  2. Click Build > Generate Signed Bundle/APK
  3. Select Android Bundle or APK depending on the type of artifact you need (Android Bundle is usually the way to go) and click Next
  4. Click Create new... under Key Store Path
  5. Fill out the fields as shown in the screenshot. Note to name your keystore upload.keystore and store it in android/app to be consistent with your app's debug keystore. Set the alias to upload. Remember to note down your key passwords somewhere handy — we'll need them in the next step.
  6. Click OK
  7. Click Cancel (we will generate the signed APK later)

Step 2 — Configure your build to use the upload key

This is where the official docs aren't that great. The official docs ask you to add your key passwords to either the user-wide ~/.gradle/gradle.properties or your app's android/gradle.properties. If you work on multiple Android projects, mixing up your upload key passwords in a single user-wide file can be messy, and the alternative of storing them in the checked-in file android/gradle.properties is a no-no since the passwords are stored in plaintext.

Instead, what you can do is create a separate upload.keystore.properties file and keep it within your app's workspace, but add it to your .gitignore (or, if you're not using git, your VCS's equivalent) so you don't commit it to source control. This way, your secrets (although still in plaintext) are at least separated from the rest of your codebase.

First create android/app/upload.keystore.properties and add your keystore config:

key.store=upload.keystore
key.alias=upload
key.store.password=*********
key.alias.password=*********

Now update android/app/build.gradle to use the properties file you just created:

...
signingConfigs {
        debug {
            storeFile file('debug.keystore')
            storePassword 'android'
            keyAlias 'androiddebugkey'
            keyPassword 'android'
        }
        // ADD THE RELEASE BLOCK BELOW
        release {
            def keystorePropertiesFile = rootProject.file('app/upload.keystore.properties')
            if (keystorePropertiesFile.exists()) {
                def keystoreProperties = new Properties()
                keystoreProperties.load(new FileInputStream(keystorePropertiesFile))

                storeFile file(keystoreProperties['key.store'])
                storePassword keystoreProperties['key.store.password']
                keyAlias keystoreProperties['key.alias']
                keyPassword keystoreProperties['key.alias.password']
            }
        }
    }
    buildTypes {
        debug {
            signingConfig signingConfigs.debug
        }
        release {
            signingConfig signingConfigs.release // 'signingConfigs.debug' -> 'signingConfigs.release'
            minifyEnabled enableProguardInReleaseBuilds
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
        }
    }
...

The code reads fairly well, but what we are doing is reading in the upload key properties we have defined in app/upload.keystore.properties and telling Gradle to use them for our release builds.

We also guard against the case where the release properties file doesn't exist (perhaps someone on your team without release key access is mistakenly trying to run a release a build); you will simply see a signing failed error in this case.

Step 3 — Configure your VCS to ignore your upload key passwords

If you're using git, add a line to your .gitignore to prevent accidentally checking in your passwords stored in upload.keystore.properties:

...
# BUCK
buck-out/
\.buckd/
*.keystore
!debug.keystore
upload.keystore.properties
...

If you're not using git, check your VCS's documentation to determine how to add upload.keystore.properties to your ignore list.

Step 4 — Build a signed release

To build your release bundle run the following from the android directory:

$ ./gradlew bundleRelease

If you've set up everything correctly, your build will sign your app bundle with your new upload key, producing an app bundle at android/app/build/outputs/bundle/release/app-release.aab.

Upload your app bundle to the Google Play Console and opt in to App Signing by Google Play when prompted.

Recap

You should now have Android app signing configured for your React Native app. Your upload key passwords are still stored within your app codebase, but they are cleanly separated from the rest of your code and will not be checked into version control.

There is still one problem remaining, however: our passwords are stored in plaintext. In a future article, we will discuss how to plug this last security hole.

That's it for now! We hope you found our approach to Android app signing useful for your next React Native app!

Further Reading

Like this article?

Subscribe to receive our latest articles in your inbox.