在Gradle中为不同的品味编辑google-services.json

3

答案在这里

我在我的应用程序中有多种版本,我想要使用相同的google-service.json文件来运行所有版本,因此我考虑将属性package_name的值设置为正则表达式,并使用build.gradle(app模块)中的task进行替换。

我的版本是按照以下方式定义的:

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

问题是我不知道如何访问包名(代码中的myPackageName),甚至不确定是否可能访问。
也许我需要使用另一个任务而不是runBeforeBuild,因为我对Gradle不是很熟悉。

将 myPackageName 声明为一个变量,其值取决于您运行的版本。 - Fakher
2个回答

4
我发现了另一种做法,并且想要分享一下。 请注意,这是我第一次使用gradle编写任务,因此代码并不完美(我现在无法花更多时间来改进它)。
说明
我所做的事情非常简单。
1)在处理FlavorBuildTypeGoogleServices进程之前,也就是来自Google服务的读取google-services.json文件的任务,我触发了一些代码来更新google-services.json文件。 为了完成这个目标:
gradle.taskGraph.beforeTask { Task task ->
    if (task.name.startsWith("process") && task.name.endsWith("GoogleServices")) {
    }
}

2) 从任务名称中获取当前风味和构建类型(任务名称示例:processProdReleaseGoogleServices,格式为 process'Flavor''BuildType'GoogleServices)

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

3) 从currentFlavor变量中删除buildType。为了做到这一点,我只需遍历项目中的所有buildTypes,并将它们从currentFlavor变量中删除。

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

此时,变量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)
    }
}

最佳解决方案! - Hasanaga

2

回答已更新

首先,我必须解释一下我正在使用Jenkins来编译我的应用程序,因此构建过程与Android Studio不完全相同。在我的情况下,Jenkins仅构建发布版本,并且没有以与IDE相同的方式获取flavor。我将解释两种解决方案:

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”,并且不使用flavor ones,因此对于每个变量和尽快(在preBuild任务之后),我都会从我的*.bak文件创建一个新的JSON,覆盖package_name,并让Gradle继续构建。
当所有事情都完成并且在发布应用程序之前(assembleRelease.doFirst)时,我删除google-services.json并保留*.bak。
在我的情况下,我只想更改JSON的package_name值,但是如果我想更改另一个值,例如project_number,client_id或任何其他取决于flavor的值,则此解决方案将无法工作。
替代解决方案(使用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)
    }
}

在这个解决方案中,我把google-services.json放在'Project/app/'文件夹中,并在每个flavor文件夹中复制一份。然后我覆盖了package_name。如果你没有使用flavors,应用程序将使用原始JSON进行编译。
在覆盖之前,你可以检查flavor文件夹中是否存在另一个JSON,在这种情况下,你可能有不同的值。

旧解决方案

我发现了一个解决方案,混合了这个这个答案。

这是我的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将是您定义的最后一个。

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


2
preBuild已经过时,必须用preBuildProvider.get().doLast {...}来替换。感谢你的解决方案,效果非常好。 - user4752077

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