不同 productFlavors 的 google-services.json

574

更新:GCM已被弃用,请使用FCM

我正在按照谷歌开发者页面此处的指南实现新的Google Cloud Messaging。

我已经成功运行和测试了它。但是我的问题是,我有不同的产品风味,具有不同的applicationId/packageName和不同的Google Cloud Messaging项目ID。 google-services.json必须放在/app/google-services.json而不是风味文件夹中。

是否有任何方法使google-services.json配置对于许多风味不同?


对于Maven,我们使用Maven配置文件和为每个配置文件单独创建的属性文件实现了类似的功能。 - sakis kaliakoudas
1
如果您只想使用sender_id,则可以在Google控制台中生成不带任何包名的密钥。 - Murtaza Khursheed Hussain
在Gradle文件中的apply plugin: 'com.google.gms.google-services'行似乎会将gcm字符串放入app/build/generated/res/google-services/debug/values/values.xml - Alexander Farber
我找到的最佳答案是在这个问题上 - Estel
1
请务必阅读此文:https://firebase.googleblog.com/2016/08/organizing-your-firebase-enabled-android-app-builds.html 它涵盖了所有可能性和权衡。 - Albert Vila Calvo
迄今为止我发现的答案是:https://stackoverflow.com/a/66739849/3970630 - Ric17101
28个回答

595
谷歌在Play服务插件的2.0版本中增加了对“flavors”的支持。自此版本以来,您可以使用Gradle插件com.google.gms:google-services:2.0.0-alpha3完成以下操作:
步骤1:将其添加到Gradle中。
// To auto-generate google map api key of google-services.json
implementation 'com.google.android.gms:play-services-maps:17.0.0'

第二步:在应用程序标签中添加到AndroidManifest.xml
<meta-data
    android:name="com.google.android.geo.API_KEY"
    android:value="@string/google_api_key" />

第三步:从Firebase下载每个口味的JSON文件并添加。
app/src/
    flavor1/google-services.json
    flavor2/google-services.json

插件的3.0.0版本在以下位置搜索JSON文件(假设你有一个flavor flavor1和一个构建类型debug):

/app/src/debug/google-services.json
/app/src/debug/flavor1/google-services.json
/app/google-services.json

这对我很有帮助,即使使用了flavorDimensions。我在一个维度中有免费和付费,另一个维度中有模拟和生产。我还有3个buildTypes:debug、release和staging。这是在FreeProd flavor中的项目外观:

enter image description here

你的项目需要多少个google-services.json文件取决于其特性,但至少需要一个JSON文件用于每个Google项目。
如果您想了解此插件如何使用这些JSON文件的更多详细信息,请参考以下链接:https://github.com/googlesamples/google-services/issues/54#issuecomment-165824720 官方文档链接如下:https://developers.google.com/android/guides/google-services-plugin 此处有更新信息的博客文章:https://firebase.googleblog.com/2016/08/organizing-your-firebase-enabled-android-app-builds.html 请前往此处检查此插件的最新版本:https://mvnrepository.com/artifact/com.google.gms/google-services?repo=google

15
由于某些原因,这不适用于我 - 我收到了Gradle构建错误:“模块根文件夹缺少google-services.json文件。Google服务插件无法正常运行。”因此,我将通过构建脚本每次将口味文件复制到根文件夹来解决这个问题。 - dodgy_coder
198
googl-services.json是一个可怕的东西... 管理一个疯狂的json文件怎么会比只插入API密钥和发送方ID更容易?请Google停止这种荒谬的行为。 - Greg Ennis
27
配置文件生成器的最新版本将多个属性放在同一个配置文件中,只需要在应用程序级别再次使用一个配置文件,而不是在口味级别分开使用。您只需要确保两个配置都在同一个“应用程序名称”字段下生成即可。 - runfaj
6
从 Android Studio 3.1.4 开始,使用 /app/src/flavor1/google-services.json 的方法已经无法工作。现在必须将文件放置在 /app/src/flavor1/debug/google-services.json 和 /app/src/flavor1/release/google-services.json 中。 - nurider
4
现在该插件会在以下位置查找json文件:`/app/src/flavor1/google-services.json /app/src/debug/google-services.json /app/src/flavor1Debug/google-services.json /app/src/flavor1/debug/google-services.json /app/src/debug/flavor1/google-services.json /app/google-services.json`PS:gradle版本需为3.5或更高。 - fatih ergin
显示剩余16条评论

99

更新:以下说明适用于一个Android Studio项目,其中有一个Firebase项目和不同的Firebase应用程序。

如果目标是在同一个Android Studio项目中的不同Firebase项目的不同Firebase应用程序中拥有不同的JSON文件(或者您不知道有什么区别),请看这里

您需要为每个Android应用程序ID(通常是包名称)创建一个Firebase应用程序。每个Gradle构建变体通常都有一个应用程序ID(如果使用Gradle构建类型和Gradle构建风味,则很可能会出现这种情况)


自从Google服务3.0和使用Firebase后,无需为不同的风味创建不同的文件。 对于具有相互组合的productFlavours和Build类型的情况,为不同的风味创建不同的文件可能并不清晰或直截了当。

在同一个文件中,您将拥有所有构建类型和风味所需的所有配置。

在Firebase控制台中,您需要为每个包名称添加一个应用程序。假设您有2种风味(dev和live)和2种构建类型(debug和release)。根据您的配置,但很可能您有4个不同的包名称,如:

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

您需要在Firebase控制台中创建4个不同的Android应用程序。(在每个应用程序中,您需要为每台计算机的调试和实时版本添加SHA-1)

当您下载google-services.json文件时,实际上并不重要从哪个应用程序下载它,它们所有应用程序都包含与所有应用程序相关的相同信息。

现在,您需要在应用程序级别(app /)中找到此文件。

enter image description here

如果您打开该文件,则会发现该文件包含所有包名称的信息。

插件是一个痛点。为了使其工作,您需要将插件定位在文件底部。所以这行..

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

......需要在您的应用程序 build.gradle 文件的底部。

对于这里大多数的内容,之前的版本也适用。我以前从未为不同的配置使用不同的文件,但现在使用 Firebase 控制台更容易了,因为它们提供一个单一的文件,包含您所有配置所需的一切。


9
这是一个非常好的回答,应该是这个问题唯一正确的答案。 - Fernando Velazquez
1
当我遇到与您上面描述的完全相同的问题时,我自己发现了这一点。我来到这里只是为了提交一个永久的答案,结果发现您已经完成了。使用3.0.0版本,这绝对是最好的答案。 - Tash Pemhiwa
我有同样的问题,非常感谢您提供的答案!现在,我有一个问题。如果我想要两个Firebase项目,一个用于实时环境,另一个用于其他构建类型/风格,我应该把两个google-services.json文件放在哪里? - Ye Lin Aung
10
请注意,这仅在所有的 Firebase 配置都在同一项目中时起作用。如果使用多个项目(我倾向于将开发和测试环境放在一个 Firebase 项目中,将生产环境放在另一个不同的 Google 账号下的专用生产项目中),则需要遵循 Yair Kukielka 提出的解决方案。实际上,该插件似乎支持多种路径——在构建期间,您将得到有关插件在何处查找 google-services.json 文件的提示:"Could not find google-services.json while looking in [src/prod/debug, src/debug/prod, src/prod, src/debug, src/prodDebug]" - JHH
1
可惜我只能点赞一次。对于 Firebase 控制台 UI 暗示 google-services.json 是特定于应用程序的,我要给 Google 打个大大的负分。 - William T. Mallard
显示剩余4条评论

49

我写了一篇Medium文章来讨论这个问题。

我曾经遇到过一个类似的问题(使用BuildTypes而不是Flavors),并通过以下方式解决:

利用Gradle的依赖管理系统。我创建了两个任务,switchToDebugswitchToRelease。要求每次运行 assembleRelease 时都运行 switchToRelease,调试也是同理。

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
}

编辑:使用processDebugFlavorGoogleServices/processReleaseFlavorGoogleServices任务在每个变体级别上修改它。


但是这适用于buildTypes,而不适用于OP发布的flavors。 - bryant1410
1
@bryant1410 如果你正在使用一个 flavor - 我猜你可以钩入 processDebugFlavorGoogleServices 任务。 - ZakTaccardi
你能否提供一个完整的示例?它不应该包括 processReleaseFlavorGoogleServices 吗? - bryant1410
1
@bryant1410 逻辑基本上对于口味或构建类型都是相同的。你应该能够弄清楚。 - ZakTaccardi
1
@IgorGanapolsky 是的,有两个版本。 - ZakTaccardi
显示剩余8条评论

23

根据ahmed_khan_89的回答, 你可以将"复制代码"放在产品口味内。

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 '.'
        }
    }
}

那么您就不需要手动切换设置了。


2
@ZakTaccardi 但问题是针对口味而不是构建类型。 - bryant1410
1
这不是一个像 https://medium.com/@ZakTaccardi/automatic-per-variant-google-services-json-configurations-with-gradle-d3d3e40abc0e 那样好的解决方案。 - ZakTaccardi
8
无效。无论是哪种构建类型,这都会运行两个复制命令,因此生产环境的JSON文件始终在应用程序目录中。 - Isaac
它适用于不同的版本。在 build.gradle 文件中不需要手动切换变量。 - Vito Valov

17

我遇到了同样的问题,但找不到完美的解决方法。这只是一个临时办法。 我在想谷歌为什么没有考虑过flavor呢?希望他们能尽快提出更好的解决方案。

我的做法:

我有两个flavor,在每个flavor中放入相应的google-services.json:src/flavor1/google-services.jsonsrc/flavor2/google-services.json

然后在build.gradle中,根据flavor复制文件到app/目录下:

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
}

限制:每次想要运行不同的风味时(因为它是硬编码),您将不得不在gradle中手动更改myFlavor

我尝试了许多方法来获取当前的构建风味,例如afterEvaluate等... 但直到现在我仍找不到更好的解决方案。

更新,另一种解决方案:所有风味使用一个google-services.json文件:

您还可以为每个风味设置不同的包名称,然后在Google开发人员控制台中,您不必为每个风味创建两个不同的应用程序,而只需在同一应用程序中创建两个不同的客户端。 然后,您将只有一个包含两个客户端的google-services.json文件。 当然,这取决于您如何实现您的风味的后端。如果它们没有分开,则此解决方案将无法帮助您。


你的意思是如果后端分离了,那么这对你来说就行不通了,我相信。 - ZakTaccardi
一切都取决于您对客户端和服务器两侧的定义方式。在我的情况下,不同的包名称、不同的服务器 URL 和不同的数据库。因此,服务器将向相应的数据库中的用户发送通知。用户 A 对于 flavor1 有令牌 1,对于 flavor2 有令牌 2。如果您有不同的数据库条目,则不会有任何问题。 - ahmed_khan_89
我尝试创建复制任务并在特定的调试进程或发布进程上调用它们,想到这个方法真的可以行得通。但愿之前能够发布这个方法。 - humblerookie
1
使用一个 google-services.json 文件来同时支持 releasedebug 对我而言是可行的,就像你在更新中提到的那样。如果你只是想要分离你的 debug 构建,我认为这是最简单的解决方案。参考文献:你可以在这里生成该文件:https://developers.google.com/mobile/add?platform=android - yuval

15
我正在使用从这里创建的google-services.json文件: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
在JSON结构中,有一个叫做clients的JSON数组。如果你有多个flavors,只需在此处添加不同的属性。
{
  "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"
}

在我的项目中,我正在使用相同的项目ID,当我在上述网址中添加第二个包名时,谷歌会向我提供一个包含多个客户端的JSON数据文件。


1
如果您正在使用多个项目,则此方法无法正常工作。 - MobileMon
如何获取我的口味的哈希值? - Ahmed Elsayed

15

1.) google-services.json究竟是什么?

请参考此链接:https://dev59.com/SVwZ5IYBdhLWcg3wVO5U#31598587

2.) google-services.json文件如何影响你的Android Studio项目?

请参考此链接:https://dev59.com/SVwZ5IYBdhLWcg3wVO5U#33083898

简单来说,如果你将google-services.json添加到你的项目中,就会在以下路径下自动生成一个名为google-services的文件夹,用于debug模式的变体。

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

3.) 如何完成?

project_level build.gradle文件中加入google-services依赖项,如果你正在使用app_compat库,也可以使用版本3.0.0

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

现在在app_level的build.gradle文件中,您需要将以下内容添加到底部

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

注意: 在gradle文件的底部添加此行非常重要。否则,Gradle构建不会给出任何错误,但它将无法正常工作。

4.) Google-service.json文件应该放在哪里?

情况1:如果没有build_flavor,只需将其放置在/app/google-service.json文件夹中。

情况2:如果有多个build_flavor,并且您有不同的google_services.json文件,请将其放在app/src/build_flavor/google-service.json中。

情况3:如果有多个build_flavor,并且您只有一个google_services.json文件,请将其放在app/google-service.json中。


对我来说,重要的是在 Gradle 文件的末尾添加这个 Gradle 行 // app-level build.gradle file apply plugin: 'com.google.gms.google-services',这样就可以解决问题了。 - Randika Vishman

8

google-services.json文件不必要用于接收通知。只需在build.gradle文件中为每个flavour添加一个变量即可:

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

在注册时,请使用变量BuildConfig.GCM_SENDER_ID,而不是getString(R.string.gcm_defaultSenderId):

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

8
  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
    

注意: 它还关心flavorDimensions中声明的顺序。我的是 flavorDimensions "dev_suffix", "environment"


似乎只有当flavor名称为全部小写字母的同时,其对应的源集也是如此,并且它还匹配目录名称(没有“setRoot”覆盖)时,才能正常工作。只有这样,这些目录才会被包含在搜索列表中! - Anton Breusov

7
我知道,你对于是否将google-services.json文件放在根目录下的app文件夹中存放存在疑虑,是吗?我来解开这个迷思 - 不一定。你也可以将google-services.json文件放在flavor文件夹中,就像这样:enter image description here

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接