Using local.properties file to avoid API Keys check-in into Version Control System

One of the best benefits of being an Android Developer is that we can create and contribute to open source projects! We can share our code with millions of developers around the globe. Thanks to code hosting platforms like GitHub!

Now, when we make our code available as public repositories, we should ensure we take care of some things such as the sharing of private API keys, restricted URLs, etc., How can we achieve this by using the “local.properties” file in our root project? Let’s find out in this article.

Welcome to our MindOrks blog on Using local.properties file to avoid API Keys check-in into Version Control System.

Every time, we create a new project in Android Studio, we see a file created with the name “local.properties” containing the following content:

## This file is automatically generated by Android Studio.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file should *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
#
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
sdk.dir=The Sdk Directory path

So local.properties is a file that is generated by Android Studio and it is recommended not to include this in the version control system.

So, if we take a look at our gitignore files in general, we have:

*.iml
.gradle
/local.properties
/.idea
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
/buildSrc/build/*

We can see that local.properties file is excluded in the version control system.

Tip: Updating the gitignore files with the relevant extensions and file folders is really important for creating an open-source project. Since the “local.properties” file is not shared in the version control system, we can use this for declaring our local user-specific variables or private variables such as API keys or restricted base URLs, etc.,

Let’s take a use case. Let’s consider our recently released open-source project on GitHub:

https://github.com/MindorksOpenSource/ridesharing-uber-lyft-app

This project helps to build a ride-sharing Android Taxi Clone App like Uber, Lyft. You can fork it and learn many awesome functionalities. Please go through the Readme file for details of the project.

Now, since our use case is a ride-sharing application, we will be using google maps in it. To use Google Maps, the developer should have an associated API Key. Let’s see how we can achieve this by using “local.properties” file.

First of all, let’s append a parameter in the local.properties file:

sdk.dir=The sdk directory //already existing parameter
apiKey = Your MAPS API Key

Now, let’s extract this value and use it in our app-level Gradle file through a variable.

def localProperties = new Properties()
localProperties.load(new FileInputStream(rootProject.file("local.properties")))
android {
 ......
}

In order to access our API key, we can use:

localProperties['apiKey'] (or) 
localProperties.getProperty("apiKey")

There are some files that get generated during build time such as gradleResValues.xml, BuildConfig.java, etc. Let’s make the use of these files to store the value of our API key. How can we add values to files that are generated during the build process? We shall use our buildTypes section in our app-level build.gradle file

android {
    .....
    buildTypes {
        debug {
            resValue("string", "google_maps_key", localProperties['apiKey'])
        }
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

Now once we add this in our build.gradle file, we rebuild our project and we can see a file named gradleResValues.xml is generated in the res(generated) folder.

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <!-- Automatically generated file. DO NOT MODIFY -->

    <!-- Values from build type: debug -->
    <string name="google_maps_key" translatable="false">MAPS_API_KEY</string>

</resources>

In order to use this value inside the application, we can try extracting the values like follows:

resources.getString(R.string.google_maps_key)

If we wish to store the value in the BuildConfig.java file, we can replace the resValue with buildConfigField in the app-level build.gradle file as follows:

android {
    .....
    buildTypes {
        debug {
            buildConfigField("String", "API_KEY", "\"" + localProperties['apiKey'] + "\"")
        }
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

After changing the build.gradle file, let’s rebuild the project and take a look at our BuildConfig.java file:

// Fields from build type: debug
public static final String API_KEY = your api key;

Now, we can access this parameter anywhere in the code like

BuildConfig.API_KEY

Now, you can happily share this code as a public repository by adding a TODO statement in the readme file that the required build config parameters or the gradleResValuess.xml parameters should be declared in the local.properties file in order to access them. Since this local.properties file is not a part of the version control system as discussed earlier, the values of these user-specific fields will never be shared by the other developers accessing the public repo!

This way, we can avoid the concept of hardcoding strings at the app-level code and make use of local.properties file to declare local, user-specific parameters or restricted URLs.

We hope that this article has helped you understand how to use the local.properties file in the most effective way for specific use cases.

Thank you so much for your time.

Keep Learning, Keep Sharing!

Team MindOrks.