【问题标题】:Edit google-services.json for different flavors in Gradle在 Gradle 中为不同的风格编辑 google-services.json
【发布时间】:2017-12-12 11:36:16
【问题描述】:

已回复here

我的应用程序中有不止一种风格,我想对所有这些风格都使用相同的 google-service.json,所以我考虑将属性 package_name 的值设置为正则表达式并使用task 在我的build.gradle(应用模块)中。

我的口味是这样定义的:

android {
    productFlavors {
        FirstFlavor {
            applicationId "com.thisapp.first"
            versionCode = 1
            versionName "1.0"
        }
        SecondFlavor {
            applicationId "com.myapp.second"
            versionCode = 1
            versionName "1.0"
        }
    }
}

我的想法是这样的:

task runBeforeBuild(type: Exec) {
    def google_json = file('./google-services.json')
    google_json.getText().replace('${package_name_value}', myPackageName)
}

问题是我不知道如何访问 PackageName(代码中的myPackageName),甚至不知道如何访问。

也许我必须使用另一个任务而不是runBeforeBuild,我对Gradle不是很熟悉。

【问题讨论】:

  • 将 myPackageName 设为变量,取值取决于您运行的风格

标签: android android-gradle-plugin build.gradle google-play-services


【解决方案1】:

我找到了另一种方法,并想分享它。 请注意,这是我第一次使用 gradle 编写一些任务,所以代码根本不是最优的(我现在不能花更多的时间来改进它)。

说明

我所做的很简单。

1) 就在任务 processFlavorBuildTypeGoogleServices 之前,即来自 Google 服务的将读取 google-services.json 文件的任务,我触发了一些将更新 google-services.json 文件的代码。 为了做到这一点:

gradle.taskGraph.beforeTask { Task task ->
    if (task.name.startsWith("process") && task.name.endsWith("GoogleServices")) {
    }
}

2) 从任务名称中获取当前的flavor和buildType(任务名称示例:processProdReleaseGoogleServices,形式为process'Flavor''BuildType'GoogleServices)

String currentFlavor = task.name.replace("process", "").replace("GoogleServices", "")
currentFlavor = currentFlavor.toLowerCase()

3) 从 currentFlavor 变量中删除 buildType。为此,我只需遍历项目中的所有 buildType,并将它们从 currentFlavor 变量中删除

android.applicationVariants.all { variant ->
    currentFlavor = currentFlavor.replace(variant.buildType.name, "")
}

此时,变量currentFlavor具有currentFlavor(例如“prod”)

4) 从我的 build.gradle 中定义的风味中检索包名称

在我的 build.gradle 中,我为每种风味指定了 packageName:

productFlavors {
    prod {
        applicationId 'packageName1'
    }
    rec {
        applicationId 'packageName2'
    }
}

我这样检索它: (包名是用[]返回的,所以我必须删除它们。例如我会检索[packageName1])

String currentApplicationId;
android.applicationVariants.all { variant ->
    if (variant.flavorName == currentFlavor) {
        currentApplicationId = variant.productFlavors.applicationId.toString().replace("[", "").replace("]", "")
    }
}

5) 现在我有了当前构建的包名,我只需要打开当前的 google-services.json 文件,并更新里面的包名。为此,我添加了一个方法 updateGoogleServicesJsonFile。 请注意将第二行的 filePath 更改为指向您的位置。

def updateGoogleServicesJsonFile(applicationId) {
    File file = new File(getProjectDir(), "/google-services.json")
    if (!file.exists())
    {
        project.logger.log(LogLevel.ERROR, "Error updating the google-services.json because the file doesn't exists...")
        return
    }

    List<String> lineList = file.readLines()
    for (int i = 0; i < lineList.size(); i++)
    {
        if (lineList.get(i).trim().startsWith("\"package_name\": \""))
        {
            String line = lineList.get(i)
            line = line.substring(0, line.indexOf(":") + 1)
            line += " \"" + applicationId + "\""

            lineList.set(i, line)
        }
    }

    file.write(lineList.join("\n"))
}

你有它,一些代码在读取它的任务执行之前更新 google-services.json 文件。


代码

def updateGoogleServicesJsonFile(applicationId) {
    File file = new File(getProjectDir(), "/google-services.json")
    if (!file.exists())
    {
        project.logger.log(LogLevel.ERROR, "Error updating the google-services.json because the file doesn't exists...")
        return
    }

    List<String> lineList = file.readLines()
    for (int i = 0; i < lineList.size(); i++)
    {
        if (lineList.get(i).trim().startsWith("\"package_name\": \""))
        {
            String line = lineList.get(i)
            line = line.substring(0, line.indexOf(":") + 1)
            line += " \"" + applicationId + "\""

            lineList.set(i, line)
        }
    }

    file.write(lineList.join("\n"))
}

gradle.taskGraph.beforeTask { Task task ->
    // Before the task processFlavorBuildTypeGoogleServices (such as processProdReleaseGoogleServices), we update the google-services.json
    if (task.name.startsWith("process") && task.name.endsWith("GoogleServices")) {
        // Getting current flavor name out of the task name
        String currentFlavor = task.name.replace("process", "").replace("GoogleServices", "")
        currentFlavor = currentFlavor.toLowerCase()

        android.applicationVariants.all { variant ->
            currentFlavor = currentFlavor.replace(variant.buildType.name, "")
       }

        // Getting current application id that are defined in the productFlavors
        String currentApplicationId;
        android.applicationVariants.all { variant ->
            if (variant.flavorName == currentFlavor) {
                currentApplicationId = variant.productFlavors.applicationId.toString().replace("[", "").replace("]", "")
            }
        }

       updateGoogleServicesJsonFile(currentApplicationId)
    }
}

【讨论】:

  • 最佳解决方案!
【解决方案2】:

答案已更新

首先我必须说明我正在使用 Jenkins 来编译我的应用程序,因此构建过程与 Android Studio 中的构建过程并不完全相同。就我而言,Jenkins 只构建了发布版本,并没有以与 IDE 相同的方式获得风味。我将解释这两种解决方案:

build.gradle (Module: app)

我的

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 正在获取位于 'Project/app/' 文件夹中的 google-services.json,并且它不使用风味的,因此对于每个变体并尽快(在 @ 987654326@ 任务)我正在从我的 *.bak 文件创建一个新的 JSON,覆盖 package_name 并让 Gradle 继续构建。

一切完成后,在应用发布之前 (assembleRelease.doFirst),我删除了 google-services.json,并保留了 *.bak

在我的情况下,我只想更改我的 JSON 的 package_name 值,但如果我想更改另一个值,如 project_numberclient_id 或其他取决于味道。

替代解决方案(使用风味)

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)
    }
}

在此解决方案中,我在 'Project/app/' 文件夹中有 google-services.json,并在每个风味文件夹中制作了一份副本。然后我覆盖 package_name。如果您没有使用各种风格,应用程序将使用原始 JSON 进行编译。

您可以在覆盖之前检查风味文件夹中是否存在另一个 JSON,以防其余值的值不同。


旧解决方案

我找到了一个混合 thisthis 答案的解决方案。

这是我现在的build.gradle (Module: app)

afterEvaluate {
    android.applicationVariants.all { variant ->
        def applicationId = variant.applicationId
        ant.replaceregexp(file: './google-services.json', match:'package_name_value', replace: applicationId, byLine: true)
    }
}

package_name_value 是我定义的要替换的“正则表达式”。

google-services.json 的位置是 “MyProject/ppp/google-services.json”,我已经测试过,如果你在你的风味文件夹中放另一个 googler-services.json,它会覆盖第一个。

*当您同时定义多个风格时(至少)存在一个问题,因为此任务总是覆盖同一个文件,因此最终的应用程序 ID 将是您定义的最后一个。

如果您有其他方法,请随时发布。

【讨论】:

  • preBuild 已过时,必须用 preBuildProvider.get().doLast {...} 替换
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-07-11
  • 1970-01-01
  • 1970-01-01
  • 2019-11-27
  • 2012-12-24
  • 1970-01-01
  • 2018-05-13
相关资源
最近更新 更多