Manage Google Maps API Key with Gradle in Android Studio
Asked Answered
N

4

54

I know Gradle is powerful and I would like to manage the API keys for development/produciton of Google Maps

Currently I always need to manually comment one line and uncomment the other to make it work. Is there a way to do it automatically in Gradle with some custom release configuration ?

<!-- MapView v2 API -->
<uses-library android:name="com.google.android.maps" />
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="[MY_DEV_KEY]" />
<!-- PROD
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="[MY_PROD_KEY]" />
-->
Neurasthenic answered 30/9, 2014 at 15:13 Comment(0)
W
120

Since you are using gradle you can do the following:

build.gradle

android {
  .. .. ...
    buildTypes {
       debug {
          resValue "string", "google_maps_api_key", "[YOUR DEV KEY]"
       }
       release {
           resValue "string", "google_maps_api_key", "[YOUR PROD KEY]"
       }
    }
  }

And in your AndroidManifest.xml

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

This way you only have one AndroidManifest.xml and you set value based on your build type.

Wheatley answered 6/1, 2015 at 19:37 Comment(6)
This solution works like a charm with the latest Android Studio version (1.1 Beta 2)! Thanks for sharing.Glabrescent
I ended up adding resValue to each one of my various product flavors and it worked great.Nichols
Is it safe to store them like this?Daphne
@GokhanArik, yes it is safe to store it like this.Wheatley
@GokhanArik safe in terms of making your api keys available to everyone who has access to the code, no. Safe regarding whether it would work and nothing will mess up, yes.Savoy
@Wheatley I need to fetch the API keys from gradle.properties depending upon different buildType.. any solution regarding that?Pantheas
S
27

You can achieve this with manifest placeholder feature: http://tools.android.com/tech-docs/new-build-system/user-guide/manifest-merger#TOC-Placeholder-support

in build.gradle file:

buildTypes {
    debug {
        manifestPlaceholders = [ google_map_key:"your_dev_key"]
    }
    release {
        manifestPlaceholders = [ google_map_key:"prod_key"]
    }
}

and then in manifest:

<meta-data
    android:name="com.google.android.maps.v2.API_KEY"
    android:value="${google_map_key}"/>

That's exact thing for different keys for different flavors and this is cleaner solution than using string resources.

P.S. On the other hand I would better consider getting api keys from backend and do not hardcode them on the client. This is more secure and more flexible approach.

Strobila answered 6/2, 2015 at 19:51 Comment(5)
How can we access this google_map_key in activity(Java file)?Fluorite
Try this: ApplicationInfo ai = getPackageManager().getApplicationInfo(activity.getPackageName(), PackageManager.GET_META_DATA); String myApiKey = ai.metaData.getString("com.google.android.maps.v2.API_KEY");Strobila
For me this only worked when defining manifestPlaceholders in android.defaultConfig as explained in the docu for some reasons.Allanite
PS. If you getting api keys from backend, do you still have to hard code your backend url somewhere, and secret key to call that api? Now you need to store the new credentials somewhere.Dastardly
@babyishTank it depends. One good option could be to have endpoint which returns short living secrets which requires authorization (not suitable for every app). Not every service supports short living secrets, but IMO it's best option to prevent someone to misuse your paid service(s) account. But definitely from now on I would suggest to never hardcode any secrets into the app, just retrieve it from your backend if you need it.Strobila
C
14

In Android Studio (checked with version 0.8.11) you can add Google Maps Activity (New->Google->Google Maps Activity) to your project and Android studio will generate necessary files for you, you only have to insert your keys. There are also instructions generated. Look for google_maps_api.xml files in your debug/res/values/ and release/res/values folders.

Chuckchuckfull answered 30/9, 2014 at 15:59 Comment(1)
Yes this applies to newer versions of Android and using Android Studio: res > values > google_map_api.xml and a <string name="google_maps_key" ... And your layout xml file will contain a fragment in it.Goop
R
11

In Android Studio, there's the concept of build types and flavors, and you can use these to get what you need. Build types are different versions of the app that are functionally identical but may differ in debugging code. By default, all Android Gradle projects have debug and release build types.

Flavors are versions of your app that are functionally different; you can have free and paid, for example. By default your Android Gradle projects don't have any flavors, but you can add them.

Build types and flavors are combined (into what's called a variant) when you do a build; in this example, you can have freeDebug, freeRelease, paidDebug, and paidRelease builds.

The build system lets you easily override a number of things in each type/flavor/variant; one of the things you can do is to override parts of the AndroidManifest.xml file. The build system merges together the different eligible bits of manifests into one master manifest when it builds a particular variant.

With that background in hand, in your case you might want to have a different API key in the debug version of your app vs. the release version. The debug version is what you'll use in your day-to-day development, debugging and testing, and the release version is what you'd deploy to users.

To do this, do not put the Google Maps API key in the main app's AndroidManifest.xml file in src/main; instead, add two new folders, src/debug and src/release and add stub AndroidManifest.xml files there. Don't include full information in those new manifests, but only what's unique about what's needed for that particular variant. Your source files will look like this:

Screenshot of project directory structure showing multiple manifest files

Your src/debug/AndroidManifest.xml file will contain this:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="[MY_DEV_KEY]" />
</manifest>

and src/release/AndroidManifest.xml will have this:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="[MY_PROD_KEY]" />
</manifest>

To reiterate, don't put any API key in the src/main/AndroidManifest.xml file.

If for some reason you don't want to use build types to differentiate you could set up dev and prod flavors and split it that way instead; the manifest overriding works in the same way.

Rodi answered 30/9, 2014 at 16:11 Comment(1)
Thanks for all the explanation. I've upvote your answer for the great explanation, but I found the Okas solution more elegant as it avoids the duplication of manifest and put the key in a XML resource string. I know the principle is the same as your explanation.Neurasthenic

© 2022 - 2024 — McMap. All rights reserved.