[android] google-services.json for different productFlavors

Update: GCM is deprecated, use FCM

I'm implementing the new Google Cloud Messaging following the guides from the Google Developers page here

I've successfully run and test it. But my problem now is I have different product flavors with different applicationId/packageName and different Google Cloud Messaging Project Id. The google-services.json have to be put at the /app/google-services.json not the flavors folder.

Is there any way to make the google-services.json config different for many flavors?

The answer is


I'm currently using two GCM Project Id in the same app package. I put the google-service.json of my first GCM project but I switch from the first to the second one only changing the SENDER_ID:

    String token = instanceID.getToken(SENDER_ID,GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);

(At this point I think that the google-services.json isn't mandatory )


1.) What does google-services.json really do?

Follow this : https://stackoverflow.com/a/31598587/2382964

2.) How does google-services.json file affects your android studio project?

Follow this : https://stackoverflow.com/a/33083898/2382964

just in short for second url, if you add google-services.json in your project there must be a auto-generated google-services folder for debug variant in this path

app/build/generated/res/google-services/debug/values/values.xml

3.) What to do, to make it done?

add google-services dependency in project_level build.gradle, you can also use version 3.0.0 if you are using app_compact library.

// Top-level build.gradle file
classpath 'com.google.gms:google-services:2.1.2'

now in app_level build.gradle you have to add at the bottom.

// app-level build.gradle file
apply plugin: 'com.google.gms.google-services'

4.) Where to put google-service.json file in your structure.

case 1.) if you have no build_flavor just put it in inside /app/google-service.json folder.

case 2.) if you have multiple build_flavor and you have different-different google_services.json files put inside app/src/build_flavor/google-service.json.

case 3.) if you have multiple build_flavor and you have single google_services.json file put inside app/google-service.json.


We have a different package name for debug builds (*.debug) so I wanted something that works based on flavor and buildType, without having to write anything flavor-related in the pattern of processDebugFlavorGoogleServices.

I created a folder named "google-services" in each flavor, containing both the debug version and the release version of the json file :

enter image description here

In the buildTypes section of your gradle file, add this :

    applicationVariants.all { variant ->
            def buildTypeName = variant.buildType.name
            def flavorName = variant.productFlavors[0].name;

            def googleServicesJson = 'google-services.json'
            def originalPath = "src/$flavorName/google-services/$buildTypeName/$googleServicesJson"
            def destPath = "."

            copy {
                if (flavorName.equals(getCurrentFlavor()) && buildTypeName.equals(getCurrentBuildType())) {
                    println originalPath
                    from originalPath
                    println destPath
                    into destPath
                }
            }
    }

It will copy the right json file at the root of your app module automatically when you'll switch build variant.

Add the two methods called to get the current flavor and current build type at the root of your build.gradle

def getCurrentFlavor() {
    Gradle gradle = getGradle()
    String  tskReqStr = gradle.getStartParameter().getTaskRequests().toString()

    Pattern pattern;

    if( tskReqStr.contains( "assemble" ) )
        pattern = Pattern.compile("assemble(\\w+)(Release|Debug)")
    else
        pattern = Pattern.compile("generate(\\w+)(Release|Debug)")

    Matcher matcher = pattern.matcher( tskReqStr )

    if( matcher.find() ) {
        println matcher.group(1).toLowerCase()
        return matcher.group(1).toLowerCase()
    }
    else
    {
        println "NO MATCH FOUND"
        return "";
    }
}

def getCurrentBuildType() {
    Gradle gradle = getGradle()
    String  tskReqStr = gradle.getStartParameter().getTaskRequests().toString()

        if (tskReqStr.contains("Release")) {
            println "getCurrentBuildType release"
            return "release"
        }
        else if (tskReqStr.contains("Debug")) {
            println "getCurrentBuildType debug"
            return "debug"
        }

    println "NO MATCH FOUND"
    return "";
}

That's it, you don't have to worry about removing/adding/modifying flavors from your gradle file, and it get the debug or the release google-services.json automatically.


According to ahmed_khan_89's answer, you can put you "copy code" inside product flavors.

productFlavors {
    staging {
        applicationId = "com.demo.staging"

        println "Using Staging google-service.json"
        copy {
            from 'src/staging/'
            include '*.json'
            into '.'
        }
    }
    production {
        applicationId = "com.demo.production"

        println "Using Production google-service.json"
        copy {
            from 'src/production/'
            include '*.json'
            into '.'
        }
    }
}

Then you don't have to switch settings manually.


  1. remove the existing google-services.json from your project.
  2. Build > Clean Project
  3. compile and run your app
  4. look at the error message that comes up to figure out where you can put your google-services.json..mine looked like this
    File google-services.json is missing. The Google Services Plugin cannot function without it. 
     Searched Location: 
    C:\Users\username\Desktop\HelloWorld\app\src\devSuffixYes_EnvQaApistaging_\google-services.json
    C:\Users\username\Desktop\HelloWorld\app\src\debug\google-services.json
    C:\Users\username\Desktop\HelloWorld\app\src\devSuffixYes_EnvQaApistaging_Debug\google-services.json
    C:\Users\username\Desktop\HelloWorld\app\src\dev\google-services.json
    C:\Users\username\Desktop\HelloWorld\app\src\devDebug\google-services.json
    C:\Users\username\Desktop\HelloWorld\app\src\devSuffixYes_EnvQaApistaging_\debug\google-services.json
    C:\Users\username\Desktop\HelloWorld\app\src\debug\devSuffixYes_EnvQaApistaging_\google-services.json
    C:\Users\username\Desktop\HelloWorld\app\src\dev\debug\google-services.json
    C:\Users\username\Desktop\HelloWorld\app\src\dev\suffix\google-services.json
    C:\Users\username\Desktop\HelloWorld\app\src\dev\suffixDebug\google-services.json
    C:\Users\username\Desktop\HelloWorld\app\src\dev\suffix\debug\google-services.json
    C:\Users\username\Desktop\HelloWorld\app\src\dev\suffix\yes_\google-services.json
    C:\Users\username\Desktop\HelloWorld\app\src\dev\suffix\yes_Debug\google-services.json
    C:\Users\username\Desktop\HelloWorld\app\src\dev\suffix\yes_\debug\google-services.json
    C:\Users\username\Desktop\HelloWorld\app\src\dev\suffix\yes_\env\google-services.json
    C:\Users\username\Desktop\HelloWorld\app\src\dev\suffix\yes_\envDebug\google-services.json
    C:\Users\username\Desktop\HelloWorld\app\src\dev\suffix\yes_\env\debug\google-services.json
    C:\Users\username\Desktop\HelloWorld\app\src\dev\suffix\yes_\env\qa\google-services.json
    C:\Users\username\Desktop\HelloWorld\app\src\dev\suffix\yes_\env\qaDebug\google-services.json
    C:\Users\username\Desktop\HelloWorld\app\src\dev\suffix\yes_\env\qa\debug\google-services.json
    C:\Users\username\Desktop\HelloWorld\app\src\dev\suffix\yes_\env\qa\apistaging_\google-services.json
    C:\Users\username\Desktop\HelloWorld\app\src\dev\suffix\yes_\env\qa\apistaging_Debug\google-services.json
    C:\Users\username\Desktop\HelloWorld\app\src\dev\suffix\yes_\env\qa\apistaging_\debug\google-services.json
    C:\Users\username\Desktop\HelloWorld\app\google-services.json
    

NOTE: it also cares about the order of the declaratios in the flavorDimensions. mine was flavorDimensions "dev_suffix", "environment"


I have found that the google-services plugin is quite useless for projects that want to add GCM. It only generates the following file which simply adds your project ID as a string resource:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- Your API key would be on the following line -->
    <string name="gcm_defaultSenderId">111111111111</string>
</resources>

It appears that you only need it if you copied the sample code verbatim directly from the Cloud Messaging for Android guide. Here is the example line:

String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId),              GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);

Solution

If you want to be able to switch API projects for different build types or product flavors you can just define your own constants and choose the appropriate one when calling the getToken() API.

private static final String SENDER_ID = "111111111111";
private static final String SANDBOX_SENDER_ID = "222222222222";

String token = instanceID.getToken(
        BuildConfig.DEBUG ? SENDER_ID : SANDBOX_SENDER_ID,
        GoogleCloudMessaging.INSTANCE_ID_SCOPE,
        null);

For Product Flavors

The above code works for switching between debug and release builds. For product flavors you would define different API keys in a java source file and place the files in their corresponding product flavor directory. For reference: Gradle Build Variants


The point of the google-services plugin is to simplify integration of Google features.

Since it only generates android-resources from the google-services.json file, over-complicated gradle-logic negates this point, I think.

So if the Google-docs don’t say which resources are needed for specific Google-features, I would suggest to generate the JSON-file for each relevant buildtype/flavor, see what resources get generated by the plugin and then put those resources manually into their respective src/buildtypeORflavor/res directories.

Delete the references to google-services plugin and the JSON-file after that, and you are done.

For detailed information about the inner workings of google-services gradle-plugin see my other answer:

https://stackoverflow.com/a/33083898/433421


I'm using the google-services.json file, created from here: https://developers.google.com/mobile/add?platform=android&cntapi=gcm&cnturl=https:%2F%2Fdevelopers.google.com%2Fcloud-messaging%2Fandroid%2Fclient&cntlbl=Continue%20Adding%20GCM%20Support&%3Fconfigured%3Dtrue

In the JSON-structure there is a JSON-array called clients. If you have multiple flavors, just add the different properties here.

{
  "project_info": {
    "project_id": "PRODJECT-ID",
    "project_number": "PROJECT-NUMBER",
    "name": "APPLICATION-NAME"
  },
  "client": [
    {
      "client_info": {
        "mobilesdk_app_id": "1:PROJECT-NUMBER:android:HASH-FOR-FLAVOR1",
        "client_id": "android:PACKAGE-NAME-1",
        "client_type": 1,
        "android_client_info": {
          "package_name": "PACKAGE-NAME-1"
        }
      },
      "oauth_client": [],
      "api_key": [],
      "services": {
        "analytics_service": {
          "status": 1
        },
        "cloud_messaging_service": {
          "status": 2,
          "apns_config": []
        },
        "appinvite_service": {
          "status": 1,
          "other_platform_oauth_client": []
        },
        "google_signin_service": {
          "status": 1
        },
        "ads_service": {
          "status": 1
        }
      }
    },
    {
      "client_info": {
        "mobilesdk_app_id": "1:PROJECT-NUMBER:android:HASH-FOR-FLAVOR2",
        "client_id": "android:PACKAGE-NAME-2",
        "client_type": 1,
        "android_client_info": {
          "package_name": "PACKAGE-NAME-2"
        }
      },
      "oauth_client": [],
      "api_key": [],
      "services": {
        "analytics_service": {
          "status": 1
        },
        "cloud_messaging_service": {
          "status": 2,
          "apns_config": []
        },
        "appinvite_service": {
          "status": 1,
          "other_platform_oauth_client": []
        },
        "google_signin_service": {
          "status": 1
        },
        "ads_service": {
          "status": 1
        }
      }
    }
  ],
  "client_info": [],
  "ARTIFACT_VERSION": "1"
}

In my project I'm using the same project-id and when I'm adding the second package-name in the above url, google provides me with a file containing multiple clients in the json-data.


According to Firebase docs you can also use string resources instead of google-services.json.

Because this provider is just reading resources with known names, another option is to add the string resources directly to your app instead of using the Google Services gradle plugin. You can do this by:

  • Removing the google-services plugin from your root build.gradle
  • Deleting the google-services.json from your project
  • Adding the string resources directly
  • Deleting apply plugin: 'com.google.gms.google-services' from your app build.gradle

Example strings.xml:

<string name="google_client_id">XXXXXXXXX.apps.googleusercontent.com</string>
<string name="default_web_client_id">XXXX-XXXXXX.apps.googleusercontent.com</string>
<string name="gcm_defaultSenderId">XXXXXX</string>
<string name="google_api_key">AIzaXXXXXX</string>
<string name="google_app_id">1:XXXXXX:android:XXXXX</string>
<string name="google_crash_reporting_api_key">AIzaXXXXXXX</string>
<string name="project_id">XXXXXXX</string>

Inspired by @ahmed_khan_89 answer above. We can directly keep like this in gradle file.

android{

// set build flavor here to get the right Google-services configuration(Google Analytics).
    def currentFlavor = "free" //This should match with Build Variant selection. free/paidFull/paidBasic

    println "--> $currentFlavor copy!"
    copy {
        from "src/$currentFlavor/"
        include 'google-services.json'
        into '.'
    }
//other stuff
}

Hey Friends also looks for name use only lowercase then u don't get this error


No need for any additional gradle scripting.

Google started adding different package name in the name of 'android_client_info'. It looks like below in google-services.json

"android_client_info": {
      "package_name": "com.android.app.companion.dev"
    }

so, following steps are enough to have different google-services.json selection.

  1. Have 2 flavours
  2. Add a new dev flavour's package to google analystics configuration page and download google-services.json.
  3. Notice in the new configuration file, both of your flavour's package ids are there
  4. Prepare any of your flavour build.

That is it!..


Short answer:

  • Implementation: By default, you should copy google-services.json to app dir.

For other flavor, copy google-services.json to app/src/{flavor-name} dir

  • Test: Try to build, open Build tab, then check output message with Parsing json file:.....

    ...
    gradle.taskGraph.beforeTask { Task task ->
        if (task.name ==~ /process.*GoogleServices/) {
            android.applicationVariants.all { variant ->
                if (task.name ==~ /(?i)process${variant.flavorName}(Debug|Release)GoogleServices/) {
                    copy {
                        from "src/tenants/${variant.flavorName}"
                        include 'google-services.json'
                        into '.'
                    }
                }
            }
        }
    }

    gradle.taskGraph.afterTask { Task task ->
        if (task.name ==~ /process.*GoogleServices/) {
            android.applicationVariants.all { variant ->
                if (task.name ==~ /(?i)process${variant.flavorName}(Debug|Release)GoogleServices/) {
                    delete fileTree(".").matching {
                        include 'google-services.json'
                    }
                }
            }
        }
    }

Well I am running into the same problem and couldn't get any perfect solution. It's just a workaround. I am wondering how Google didn't think about flavors...? And i hope they will propose soon a better solution.

What I am doing:

I have two flavors, in each one I put the corresponding google-services.json : src/flavor1/google-services.json and src/flavor2/google-services.json .

Then in build gradle I copy the file depending on the flavor to the app/ directory:

android {

// set build flavor here to get the right gcm configuration.
//def myFlavor = "flavor1"
def myFlavor = "flavor2"

if (myFlavor.equals("flavor1")) {
    println "--> flavor1 copy!"
    copy {
        from 'src/flavor1/'
        include '*.json'
        into '.'
    }
} else {
    println "--> flavor2 copy!"
    copy {
        from 'src/flavor2/'
        include '*.json'
        into '.'
    }
}

// other stuff
}

Limitation: you will have to change myFlavor manually in gradle each time you want to run for a different flavor (because it's hardcoded).

I tried many ways to get the current build flavor like afterEvaluate close... couldn't get any better solution until now.

Update, Another solution: one google-services.json for all the flavors:

You can also, have different package names for each flavor and then in the google developer console you don't have to create two different apps for each flavor, but just two different clients in the same app. Then you will have only one google-services.json that contains your both clients. Of course, this depends on how you're implementing the backend of your flavors. If they're not separated then this solution will not help you.


Place your "google-services.json" file under app/src/flavors respectively then in build.gradle of app, under android add below code

gradle.taskGraph.beforeTask { Task task ->
        if (task.name ==~ /process.*GoogleServices/) {
            android.applicationVariants.all { variant ->
                if (task.name ==~ /(?i)process${variant.name}GoogleServices/) {
                    copy {
                        from "/src/${variant.flavorName}"
                        into '.'
                        include 'google-services.json'
                    }
                }
            }
        }
    }

google-services.json file is unnecessary to receive notifications. Just add a variable for each flavour in your build.gradle file:

buildConfigField "String", "GCM_SENDER_ID", "\"111111111111\""

Use this variable BuildConfig.GCM_SENDER_ID instead of getString(R.string.gcm_defaultSenderId) while registering:

instanceID.getToken(BuildConfig.GCM_SENDER_ID, GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);

Firebase now supports multiple application ids with one google-services.json file.

This blog post describes it in detail.

You'll create one parent project in Firebase that you'll use for all of your variants. You then create separate Android applications in Firebase under that project for each application id that you have.

When you created all of your variants, you can download a google-services.json that supports all of your applications ids. When it's relevant to see the data separately (i.e. Crash Reporting) you can toggle that with a dropdown.


UPDATE: The following explanation is for one Android Studio project, with one Firebase Project and different Firebase Apps inside that project. If the aim is to have different JSON files for different Firebase Apps in different Firebase Projects inside the same Android Studio project, (or if you don't know what's the difference) look here..

You need one Firebase App per Android Application ID (usually package name). Is common to have one Application ID per Gradle build variant (This is gonna be likely if you use Gradle build types and Gradle build flavours)


As of Google Services 3.0 and using Firebase it's not necessary to create different files for different flavours. Creating different files for different flavours can be not clear or straightforward in case you have productFlavours and Build types which compose with each other.

In the same file you'll have the all the configurations you need for all your build types and flavours.

In the Firebase console you need to add one app per package name. Imagine that you have 2 flavours (dev and live) and 2 build types (debug and release). Depending on your config but it's likely that you have 4 different package names like:

  • com.stackoverflow.example (live - release)
  • com.stackoverflow.example.dev (live - dev)
  • com.stackoverflow.example.debug (debug - release)
  • com.stackoverflow.example.dev.debug (debug - dev)

You need 4 different Android Apps in the Firebase Console. (On each one you need to add the SHA-1 for debug and live for each computer you are using)

When you download the google-services.json file, actually it doesn't really matter from what app you download it, all of them contain the same info related to all your apps.

Now you need to locate this file in app level (app/).

enter image description here

If you open that file you'll see that if contains all the information for all your package names.

A pain point use to be the plugin. In order to get it working you need to locate the plugin at the bottom of your file. So this line..

apply plugin: 'com.google.gms.google-services'

...needs to be on the bottom of your app build.gradle file.

For most of the said here, it applies to previous versions as well. I've never had different files for different configs, but now with the Firebase console is easier because they provide one single file with everything you need for all you configs.


Wrote a Medium post on this issue.

Had the a similar problem (using BuildTypes instead of Flavors), and fixed it like so.

Take advantage of Gradle's dependency management system. I created two tasks, switchToDebug and switchToRelease. Require that any time assembleRelease is run, that switchToRelease is also run. Same for debug.

def appModuleRootFolder = '.'
def srcDir = 'src'
def googleServicesJson = 'google-services.json'

task switchToDebug(type: Copy) {
    def buildType = 'debug'
    description = 'Switches to DEBUG google-services.json'
    from "${srcDir}/${buildType}"
    include "$googleServicesJson"
    into "$appModuleRootFolder"
}

task switchToRelease(type: Copy) {
    def buildType = 'release'
    description = 'Switches to RELEASE google-services.json'
    from "${srcDir}/${buildType}/"
    include "$googleServicesJson"
    into "$appModuleRootFolder"
}

afterEvaluate {
    processDebugGoogleServices.dependsOn switchToDebug
    processReleaseGoogleServices.dependsOn switchToRelease
}

EDIT: use processDebugFlavorGoogleServices/processReleaseFlavorGoogleServices task to modify it at a per-flavor level.


You have many flavor, so it mean you will have many difference package id, right? So, just go to the page where you setup/generate your json file and config for each package name. All of it will add to json file.

I'm verry lazy to post picture now, but basically:

  • go to https://developers.google.com/mobile/add
  • select platform
  • select your app
  • IMPORTANT: type your flavor package name to field "android package name"
  • ... continue to get your configuration file. Download it!

When config the file, you can see that google show you the Server API Key + Sender ID. And it is same for all package (flavors)

At the end, you just need only one json file for all flavors.

One more question here that you have to test when you register to get Registration Token, check if is difference for each flavor. I don't touch on it but it think it should be difference. Too late now and i so sleepy :) Hope it help!


UPDATED:

In terms of Firebase setup with build variants, please refer to this blog which has detailed instructions.


Based on @ZakTaccardi's answer, and assuming you don't want a single project for both flavors, add this to the end of your build.gradle file:

def appModuleRootFolder = '.'
def srcDir = 'src'
def googleServicesJson = 'google-services.json'

task switchToStaging(type: Copy) {
    outputs.upToDateWhen { false }
    def flavor = 'staging'
    description = "Switches to $flavor $googleServicesJson"
    delete "$appModuleRootFolder/$googleServicesJson"
    from "${srcDir}/$flavor/"
    include "$googleServicesJson"
    into "$appModuleRootFolder"
}

task switchToProduction(type: Copy) {
    outputs.upToDateWhen { false }
    def flavor = 'production'
    description = "Switches to $flavor $googleServicesJson"
    from "${srcDir}/$flavor/"
    include "$googleServicesJson"
    into "$appModuleRootFolder"
}

afterEvaluate {
    processStagingDebugGoogleServices.dependsOn switchToStaging
    processStagingReleaseGoogleServices.dependsOn switchToStaging
    processProductionDebugGoogleServices.dependsOn switchToProduction
    processProductionReleaseGoogleServices.dependsOn switchToProduction
}

You need to have the files src/staging/google-services.json and src/production/google-services.json. Replace the flavor names for the ones you use.


Indeed, juste one google-services.json in MyApp/app/ directory is good, no need for aditional script with com.google.gms:google-services:3.0.0. But be careful to delete the file google-services.json from the app directory MyApp/app/src/flavor1/res/ to avoid the error type Execution failed for task ':app:processDebugGoogleServices'. > No matching client found for package


So if you want to programmatically copy google-services.json file from all your variants into your root folder. When you switch to a specific variant here's a solution for you

android {
  applicationVariants.all { variant ->
    copy {
        println "Switches to $variant google-services.json"
        from "src/$variant"
        include "google-services.json"
        into "."
    }
  }
}

There's a caveat to this approach that is you need to have google-service.json file in each of your variants folder here's an example. variant image


Simplifying what @Scotti said. You need to create Multiples apps with different package name for a particular Project depending on the product flavor.

Suppose your Project is ABC having different product flavors X,Y where X has a package name com.x and Y has a package name com.y then in the firebase console you need to create a project ABC in which you need to create 2 apps with the package names com.x and com.y. Then you need to download the google-services.json file in which there will be 2 client-info objects which will contain those pacakges and you will be good to go.

Snippet of the json would be something like this

{
  "client": [
    {
      "client_info": {
        "android_client_info": {
          "package_name": "com.x"
        }

    {
      "client_info": {
        "android_client_info": {
          "package_name": "com.y"
        }
      ]

    }

Examples related to android

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How to implement a simple scenario the OO way My eclipse won't open, i download the bundle pack it keeps saying error log getting " (1) no such column: _id10 " error java doesn't run if structure inside of onclick listener Cannot retrieve string(s) from preferences (settings) strange error in my Animation Drawable how to put image in a bundle and pass it to another activity FragmentActivity to Fragment A failure occurred while executing com.android.build.gradle.internal.tasks

Examples related to google-cloud-messaging

Google Play Services GCM 9.2.0 asks to "update" back to 9.0.0 Firebase cloud messaging notification not received by device Error:Conflict with dependency 'com.google.code.findbugs:jsr305' Where can I find the API KEY for Firebase Cloud Messaging? How to send push notification to web browser? google-services.json for different productFlavors INSTALL_FAILED_DUPLICATE_PERMISSION... C2D_MESSAGE Android: Test Push Notification online (Google Cloud Messaging) How to get RegistrationID using GCM in android Why do I get "MismatchSenderId" from GCM server side?

Examples related to google-play-services

com.google.android.gms:play-services-measurement-base is being requested by various other libraries Error: fix the version conflict (google-services plugin) Google Play Services GCM 9.2.0 asks to "update" back to 9.0.0 updating Google play services in Emulator How to unpublish an app in Google Play Developer Console Android Studio Gradle: Error:Execution failed for task ':app:processDebugGoogleServices'. > No matching client found for package Error "File google-services.json is missing from module root folder. The Google Services Plugin cannot function without it" com.android.build.transform.api.TransformException How to add google-services.json in Android? google-services.json for different productFlavors