25

I'm currently working on an Android project, and learning how to use git. I'm blocked because of a problem with git : I have my Google Maps api key declared in my android-manifest file :

<meta-data
    android:name="com.google.android.maps.v2.API_KEY"
    android:value="HEREISMYKEY"/>

Now, I'd like to push my code in github, but I can't push my AndroidManifest, because it contains my api key (which is supposed to remain secret).

I'd like to know if there is a way to modify it before every push, or maybe modify it each time I compile my application?

Thank you for your help !

Bryan Denny
  • 27,363
  • 32
  • 109
  • 125
MagicMicky
  • 3,819
  • 2
  • 37
  • 53

4 Answers4

41

Create a new *.xml file in your res/values (call it api-keys.xml or something similar).

Change your manifest to point to this string:

 <meta-data
    android:name="com.google.android.maps.v2.API_KEY"
    android:value="@string/GoogleMapsKey"/>

When you first push your changes to the public, put in a dummy key.

Then edit the file with your real API key.

Then add the file to your .gitignore file so it doesn't get pushed again.

Bryan Denny
  • 27,363
  • 32
  • 109
  • 125
  • 6
    You should also untrack your api-keys.xml file before creating the gitignore file. Otherwise you'll still push changes. [link](https://help.github.com/articles/ignoring-files) – mez.pahlan Sep 21 '13 at 15:29
  • Just a small FYI, for some reason, IntelliJIdea does not want api-keys.xml so use api_keys.xml instead. – rup3rt Oct 04 '13 at 00:25
  • This is a great answer. For some reason I thought all string resource xml files needed to be named values by convention. Now I have learned that I can do the same thing on Android as I do for my other projects! – Mike Holler Feb 07 '14 at 06:34
  • 1
    My preferred solution to handle the modfied file is to use the command: git update-index --assumed-unchanged api-key.xml. – Martin Böschen Aug 27 '15 at 12:31
  • This is great, but can the project be built without the key file? Does not it violate the "basic" rule of version control -- only code that can be compiled should be versioned? – Barun May 24 '16 at 10:55
1

I suggest to use Gradle to dynamically load the API key for different build types and load a dummy key if none is found. This has the advantage that also a CI can build your application without the need of a real API key, but every new developer in your team has to set up the API key.

  1. create a properties file google-maps-api.properties in your root gradle folder. Ignore the file by adding this line gradle/google-maps-api.properties to your .gitignore and put in the following 2 properties:
googleMapsApiKeyDebug=[YOUR_DEBUG_GOOGLE_MAPS_API_KEY_HERE]
googleMapsApiKeyRelease=[YOUR_RELEASE_GOOGLE_MAPS_API_KEY_HERE]
  1. Next create the following google-maps-api-config.gradle file in your root gradle folder. This Gradle file will load the property file you created in step 1.
ext {
    googleMapsApiConfig = new GoogleMapsApiConfigLogic(project)
}

/*
Before you run your application, you need a Google Maps API key.

Using these values:

Package name:
at.ict4d.covid19map

SHA-1 certificate fingerprint:
DE:4A:F0:B1:F5:F4:00:88:B6:E0:03:3E:31:1F:11:88:3F:43:0D:8B

Follow the directions here:
https://developers.google.com/maps/documentation/android/start#get-key

Once you have your key (it starts with "AIza") create a file with the name "google-maps-api.properties" in the gradle folder:
gradle/google-maps-api.properties

Put in 2 properties:
googleMapsApiKeyDebug:[THE KEY YOU JUST CREATED]
googleMapsApiKeyRelease:[YOUR RELEASE GOOGLE MAPS KEY] (if you are just developing and not planning to publish then fill in "YOUR_RELEASE_KEY_HERE")

"gradle/google-maps-api.properties" example:
googleMapsApiKeyDebug=AIzaFJKLJKsdLFDDsjlkdfDFJKLdjkf
googleMapsApiKeyRelease=YOUR_RELEASE_KEY_HERE

Sync your project and build.
*/

class GoogleMapsApiConfigLogic {

    public final keyGoogleMapsApiKeyDebug = "googleMapsApiKeyDebug"
    public final keyGoogleMapsApiKeyRelease = "googleMapsApiKeyRelease"
    private final configGoogleMapsApiPropsFileName = "gradle/google-maps-api.properties"

    public final props

    private final project

    GoogleMapsApiConfigLogic(project) {
        this.project = project
        this.props = loadGoogleMapsApiProperties()
    }

    def loadGoogleMapsApiProperties() {

        Properties propertiesObj

        if ((propertiesObj = loadFromProperties("$project.rootDir/$configGoogleMapsApiPropsFileName")) != null) {
            project.logger.quiet("google-maps-api-config: use local properties file for Google Maps API")
            return propertiesObj
        } else {
            propertiesObj = new Properties()
            propertiesObj.put(keyGoogleMapsApiKeyDebug, "YOUR_KEY_HERE")
            propertiesObj.put(keyGoogleMapsApiKeyRelease, "YOUR_KEY_HERE")
        }

        project.logger.quiet("google-maps-api-config: no API key found for Google Maps")
        return propertiesObj
    }

    def loadFromProperties(fileName) {
        Properties props = new Properties()
        File propFile = new File(fileName)

        if (propFile.exists()) {
            props.load(new FileInputStream(propFile))
            if (props.get(keyGoogleMapsApiKeyDebug) != null &&
                    props.get(keyGoogleMapsApiKeyRelease) != null) {
                project.logger.quiet("google-maps-api-config: use $fileName for Google Maps API")
                return props
            }
        } else {
            project.logger.quiet("google-maps-api-config: $propFile does not exist for Google Maps API")
        }
        return null
    }
}
  1. Add the the following to your app/build.gradle file:
plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id 'kotlin-android-extensions'
    // ...
}

apply from: "$rootDir/gradle/google-maps-api-config.gradle" // handles Google Maps API key

android {

   // ...

   buildTypes {
        release {

            // other config

            resValue "string", "google_maps_key", "\"${googleMapsApiConfig.props.getProperty(googleMapsApiConfig.keyGoogleMapsApiKeyRelease)}\""
        }

        debug {
            // other config

            resValue "string", "google_maps_key", "\"${googleMapsApiConfig.props.getProperty(googleMapsApiConfig.keyGoogleMapsApiKeyDebug)}\""
        }
    }

This will create a String Resource with the key google_maps_key and the value of your API key. You can delete any other API key references, e.g. Android Studio generate the following files: app/src/debug/res/values/google_maps_api.xml and app/src/release/res/values/google_maps_api.xml - you can delete them.

  1. Add the Google Maps API Key to your manifest:
<application>

        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="@string/google_maps_key" />
Paul Spiesberger
  • 5,630
  • 1
  • 43
  • 53
0

The way I have approached similar issues in the past is by using specific branches in my git repo for pubic pushes.

Say you have a local master branch with your keys in the manifest. When you are ready to push to github (or wherever else) you can make a new "release" branch with no history. You can see a bit more about that here: How to push new branch without history git branch --orphan release. Once you do that remove all private information, commit all files and push only that branch to github git push origin release.

The issue with this is you will not have a commit history, maybe someone else can come up with something better.

Community
  • 1
  • 1
sgarman
  • 6,152
  • 5
  • 40
  • 44
0

If you create Google Maps Activity from Android Studio as a template it will add needed plugin in your build.gradle file, and then you can put your API key in local.properties file and use it as variable in Manifest file as for example: "${API_KEY}"

For more information visit https://developers.google.com/maps/documentation/places/android-sdk/secrets-gradle-plugin