6

I use one among many options to store my API keys in the computer/keychain rather than directly in the cloud-backed-up project code (namely gradle-credentials-plugin ). What I'd like is to be able to manage Google Maps keys in a similar way, but they're used in a different file (Manage Google Maps API Key with Gradle in Android Studio).

If anyone has a simple (or intricate, but reliable) option for me to dig into, I'd be grateful!

Kheldar
  • 5,361
  • 3
  • 34
  • 63
  • Why can't you use the combination of the two things that you linked to? Use `credentials.whateverYouCallYourMapsApiKey` to populate `resValue`. – CommonsWare Mar 17 '18 at 17:39
  • Do you think couldn't be enough having different string key for the different build variant "release" and "debug"? – shadowsheep Mar 17 '18 at 18:15
  • @shadowsheep I fail to see how that would store the keys in the computer, avoiding sending it into the public repository? – Kheldar Mar 20 '18 at 10:45
  • It should be a good solution to have let's say a file named `api.keys` in which you have your keys and that you ignore so that is not versioned and that you have only in your PC? So that to get your production key in the release build and your development key in the debug build? – shadowsheep Mar 20 '18 at 10:49
  • Ah, I see what you mean. I'll try that! – Kheldar Mar 20 '18 at 11:23

4 Answers4

10

You can use manifestPlaceholders to inject the string from your build.gradle.

  1. Inset your API key into a file like local.properties
google.maps_api_key=SECRET_KEY
  1. Make sure this file is ignored using .gitignore:
local.properties
  1. Make the API key available to your AndroidManifest.xml. Using withInputStream() ensures the InputStream is closed automatically.
android{
  defaultConfig {

    // Load credentials.
    def properties = new Properties()
    file("../local.properties").withInputStream { properties.load(it) }

    // Share the key with your `AndroidManifest.xml`
    manifestPlaceholders = [ googleMapsApiKey:"${properties.getProperty('google.maps_api_key')}"]
  1. Load the API key in your AndroidManifest.xml:
<application>

        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="${googleMapsApiKey}" />
hb0
  • 3,350
  • 3
  • 30
  • 48
  • Interesting, I'll try this out next time I encounter this situation! – Kheldar Dec 13 '20 at 12:16
  • 2
    Thank you! your recommendations worked for me! Before I found it I had tried to use recommendations by Google found at https://developers.google.com/maps/documentation/android-sdk/get-api-key, but they didn't work because they didn't say anything about "manifestPlaceholders". – porlicus Jul 22 '21 at 09:44
  • Instead of local.properties, I use gradle.properties to store the key, because local.properties file is excluded in .gitignore, and so it is loss of information to the developers. Can I use your solution? – Abhinav Saxena Oct 11 '22 at 13:51
  • @AbhinavSaxena Should work, but it's on purpose to exclude `local.properties` from git as you usually don't want to store sensitive information in the repository (here: Google Map Key). Even if you repo is private, you (or a fork of yours) might set it to public at some point and then the key can be retrieved from Git history by others. But that's no topic to be discussed in this comment section :). – hb0 Oct 12 '22 at 14:26
  • It worked! (Although the following is out of topic, still adding) The file local.properties take the path of Android and Native SDK for one machine. It does not make sense, to share it, if other developers are to contribute in the same project. Though Android Studio corrects the wrong paths itself on the start of the project, but still. Thanks. :-) – Abhinav Saxena Oct 12 '22 at 15:22
4

You can use a not versioned file called as you want, let's say api.keys with this content:

debugMapsApiKey=xxxxXXXxxxx
releaseMapsApiKey=xxxYYYxxx

Put it in your root project folder.

You read this file in your build.gradle file in a way like that:

def apiKeysFile = rootProject.file("api.keys")
def apiKeysFile = new Properties()
apiKeysFile.load(new FileInputStream(apiKeysFile))

[...]

debug {
    buildConfigField "String", MAPS_KEY, apiKeysFile['debugMapsApiKey']
}

release {
    buildConfigField "String", MAPS_KEY, apiKeysFile['releaaseMapsApiKey']
}

And you can access it in code through

BuildConfig.MAPS_KEY that if you build in debug you will have "xxxxXXxxxx" value, instead in release you will have "xxxxYYxxxx".

And if you want to access on XML you could use resValue that create a string resource.

debug {
    resValue "string", MAPS_KEY, apiKeysFile['debugMapsApiKey']
}

release {
   resValue "string", MAPS_KEY, apiKeysFile['releaseMapsApiKey']
}

In this way you could also get it in code with

getString(R.string.MAPS_KEY)
shadowsheep
  • 14,048
  • 3
  • 67
  • 77
  • Well, it does work, but it doesn't quite do what I want because it ignores the tool I've set up for other keys. Upvoted, but I'll fix things a bit differently. – Kheldar Mar 20 '18 at 11:47
  • @Kheldar Well, I don't know what tool you have set for other keys, but If this solution helped you going through the right solution if you like you can accept it as the right answer non the less. BTW it's up to you! I'm happy you did your work done! ;) – shadowsheep Mar 20 '18 at 11:51
  • thanks a bunch, it definitely helped me narrow down my reasoning ^^ – Kheldar Mar 20 '18 at 12:00
  • error The current scope already contains a variable of the name apiKeysFile @ line 4, column 5. def apiKeysFile = new Properties() – Josef Vancura Feb 18 '21 at 15:28
1

google_maps_api.xml

<resources>
    <string name="google_maps_key" templateMergeStrategy="preserve" translatable="false">GoogleMapsApiKey</string>
</resources>

manifest

<meta-data
    android:name="com.google.android.geo.API_KEY"
    android:value="@string/GoogleMapsApiKey"/>

gradle

resValue "string", "GoogleMapsApiKey", mapskey

gradle.properties

mapskey="AIza...8w" // key here
Josef Vancura
  • 1,053
  • 10
  • 18
0

Shadowsheep's solution works, but it's not really what I want to do.

What I've ended up doing.

  • First, I was under the mistaken impression it was absolutely necessary to populate google-maps-api.xml with the key, when it apparently is sufficient to set the key in the Manifest.

  • Second, I've added a <meta-data android:name="com.google.android.geo.API_KEY" android:value"@string/GoogleMapsApiKey"> line into the Manifest

  • Third, I've set mapsKey via my chosen tool (gradle-credentials-plugin by etiennestuder)

  • Finally, I've added into the app's module build.gradle buildTypes section these two lines:

def mapsKey = credentials.GOOGLE_MAPS_API_KEY ?: "Key Missing"

it.resValue "string", "GoogleMapsApiKey", mapsKey

Kheldar
  • 5,361
  • 3
  • 34
  • 63