google-services.json for different productFlavors
Google included support for flavors in version 2.0 of the play services plugin. Since this version of the gradle plugin com.google.gms:google-services:2.0.0-alpha3
you can do this
Step 1: add to gradle
// To auto-generate google map api key of google-services.json
implementation 'com.google.android.gms:play-services-maps:17.0.0'
Step 2: add to AndroidManifest.xml in the application tag
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="@string/google_api_key" />
Step 3: download each flavor JSON file from firebase and add it
app/src/
flavor1/google-services.json
flavor2/google-services.json
Version 3.0.0 of the plugin searches for the JSON file in these locations (considering you have a flavor
flavor1 and a build type debug
):
/app/src/debug/google-services.json
/app/src/debug/flavor1/google-services.json
/app/google-services.json
This worked for me even using flavorDimensions. I have free & paid in one dimension and Mock & Prod in the other dimension. I also have 3 buildTypes: debug, release, and staging. This is how it looks in my project for the FreeProd flavor:
How many google-services.json files will depend on your project's characteristics, but you will need at least one JSON file for every Google project.
If you want more details about what this plugin does with these JSON files, here it is:
https://github.com/googlesamples/google-services/issues/54#issuecomment-165824720
Link to the official docs:
https://developers.google.com/android/guides/google-services-plugin
Blog post with updated info: https://firebase.googleblog.com/2016/08/organizing-your-firebase-enabled-android-app-builds.html
And go here to check the latest version of this plugin: https://mvnrepository.com/artifact/com.google.gms/google-services?repo=google
configure mulitple google-services.Json for different flavours in FCM
The article you are referring to is old. A little while back Firebase
changed the implementation of supporting different flavors. There is now only one google-services.json
file generated by Firebase which holds a reference to all the flavors.
You have to add multiple apps in the same Project in the Firebase console, and download the updated google-service.json
and put in the root folder.
Follow the latest guide provided by Firebase. Read their instructions on how to add different variants:
Adding apps to a Firebase project
Add Firebase to your Android project
Edit google-services.json for different flavors in Gradle
Answer updated
First of all I must explain I'm using Jenkins to compile my application, so the build process is not exactly the same than in Android Studio. In my case Jenkins only build the release version and is not getting the flavors on the same way than the IDE. I'll explain both solutions:
In the build.gradle (Module: app)
Mine
buildscript{
...
}
android {
...
}
afterEvaluate {
android.applicationVariants.all { variant ->
preBuild.doLast {
setGoogleServicesJson(variant)
}
}
// Only for Jenkins
assembleRelease.doFirst {
deleteGoogleServicesJson()
}
}
def setGoogleServicesJson(variant) {
def originalFileName = "google-services.bak"
def newFileName = "google-services.json"
def originalFile = "./$originalFileName"
def newFile = "./$newFileName"
def applicationId = variant.applicationId
def regularExpression = "\\\"package_name\\\" : \\\"(\\w(\\.\\w)?)+\\\""
def packageName = "\\\"package_name\\\" : \\\"$applicationId\\\""
copy {
from (originalFile)
into ("./")
rename (originalFileName, newFileName)
}
ant.replaceregexp(
file: newFile,
match: regularExpression,
replace: packageName,
byLine: true)
}
def deleteGoogleServicesJson() {
file("./google-services.json").delete()
}
apply plugin: 'com.google.gms.google-services'
Jenkins is getting the google-services.json
located in the 'Project/app/' folder and it doesn't use the flavor ones, so for each variant and as soon as possible (after the preBuild
task) I'm creating a new JSON from my *.bak
file, overriding the package_name
and letting Gradle continues with the building.
When everything is done and before it release the app (assembleRelease.doFirst
) I delete the google-services.json
and I keep the *.bak
.
In my case I only want to change the package_name
value of my JSON, but this solution won't work if I want to change another value as the project_number
, the client_id
or whatever else depending on the flavor.
Alternative solution (using flavors)
afterEvaluate {
android.applicationVariants.all { variant ->
def fileName = "google-services.json"
def originalFile = "./$fileName"
def flavorName = variant.flavorName
def destinationPath = "."
// If there is no flavor we use the original path
if (!flavorName.empty) {
destinationPath = "$destinationPath/src/$flavorName/"
copy {
from file(originalFile)
into destinationPath
}
}
def regularExpression = "\\\"package_name\\\" : \\\"(\\w(\\.\\w)?)+\\\""
def packageName = "\\\"package_name\\\" : \\\"$variant.applicationId\\\""
ant.replaceregexp(
file: "./$destinationPath/$fileName",
match: regularExpression,
replace: packageName,
byLine: true)
}
}
In this solution I have the google-services.json
in the 'Project/app/' folder and I make a copy of it in each flavor folder. Then I override the package_name. In case you are working without flavors, the app will use the original JSON to compile.
You can check if another JSON exists in the flavor folder before override it, in case you have different values for the rest of the values.
Old solution
I've found a solution mixing this and this answers.
This is my build.gradle (Module: app)
right now:
afterEvaluate {
android.applicationVariants.all { variant ->
def applicationId = variant.applicationId
ant.replaceregexp(file: './google-services.json', match:'package_name_value', replace: applicationId, byLine: true)
}
}
where package_name_value
is the "regular expression" I've defined to be replaced.
The location of the google-services.json
is "MyProject/ppp/google-services.json", and I've tested that if you put another googler-services.json
inside your flavor folder, it overrides the first one.
*There is (at least) one problem when you have more than one flavor defined at the same time, because this task is always overriding the same file, so the final application id will be the last you have defined.
If you have another way, feel free to post it.
Multiple google-services.json Per Product Flavour
The only way I was able to do this was to bypass use of google-services.json
and create FirebaseApp
instance dynamically e.g.
if (<is dev>) {
apiKey = <dev api key>;
databaseUrl = <dev database url>;
} else if (<is test> {
apiKey = <>;
databaseUrl = <>;
} else // production {
apiKey = <>;
databaseUrl = <>;
}
FirebaseOptions firebaseOptions = new FirebaseOptions.Builder()
.setApiKey(apiKey)
.setApplicationId(context.getString(R.string.google_app_id))
.setDatabaseUrl(databaseUrl)
.build();
return FirebaseApp.initializeApp(context, firebaseOptions, "MyApp");
Is there any way to have no google-services.json for some of product flavors?
I think that you could just place an empty google-services.json file in those flavors.
File google-services.json is missing when combining multiple product flavors with flavor dimensions
I end up by solving this issue with a couple of extra tasks for each merged productFlavor. I added this code after android
:
afterEvaluate {
android.productFlavors.all { flavor ->
if (flavor.dimension == "vendor") {
task("copy${flavor.name.capitalize()}GoogleServicesFile", type: Copy) {
description = 'Switches to google-services.json depending on flavor' from "src/${flavor.name}"
include "google-services.json" into "."
}
task("delete${flavor.name.capitalize()}GoogleServicesFile", type: Delete) {
description = 'Delete google-services.json from base folder'
delete "./google-services.json"
}
}
}
android.applicationVariants.all { variant ->
def buildType = variant.buildType.name.capitalize()
def typeFlavorName = variant.productFlavors.get(0).name.capitalize()
def vendorFlavorName = variant.productFlavors.get(1).name.capitalize()
def copyFileTaskName = "copy${vendorFlavorName}GoogleServicesFile"
def deleteFileTaskName = "delete${vendorFlavorName}GoogleServicesFile"
def processGoogleServicesTaskName = "process${typeFlavorName}${vendorFlavorName}${buildType}GoogleServices"
tasks."${processGoogleServicesTaskName}".dependsOn "${copyFileTaskName}"
tasks."${processGoogleServicesTaskName}".finalizedBy "${deleteFileTaskName}"
}
}
This way, for each typeFlavorName
, vendorFlavorName
and buildType
variation, the google-services.json
file is copied to app/
before process{typeFlavorName}{vendorFlavorName}{buildType}GoogleServices
and deleted afterwards.
Related Topics
Programmatically Obtain the Phone Number of the Android Phone
Android Listview With Different Layouts For Each Row
How to Convert a Drawable to a Bitmap
How Do We Use Runonuithread in Android
How to Turn on Front Flash Light Programmatically in Android
How to Use the Textwatcher Class in Android
Passing a Bundle on Startactivity()
Dexindexoverflowexception Only When Running Tests
Post Multipart Request With Android Sdk
How to Capture the "Virtual Keyboard Show/Hide" Event in Android
Call an Activity Method from a Fragment