代码之家  ›  专栏  ›  技术社区  ›  Óscar

编辑谷歌服务。Gradle中不同风格的json

  •  2
  • Óscar  · 技术社区  · 7 年前

    回答 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 .

    2 回复  |  直到 7 年前
        1
  •  4
  •   nah0y    6 年前

    我找到了另一种方法,并想与大家分享。 请注意,这是我第一次使用gradle编写一些任务,因此代码根本不是最优的(目前我无法花更多时间来改进它)。

    解释

    我所做的很简单。

    1) 就在任务流程FlavorBuildTypeGoogleServices之前,这是来自Google Services的任务,它将读取Google服务。json文件,我触发一些代码来更新google服务。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) 从我的构建中定义的风格中检索包名称。格拉德尔

    在我的构建中。gradle,我为每种口味指定了包装名称:

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

    我这样检索它: (包名返回时带有[],因此我必须删除它们。例如,我将检索[PackageName 1])

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

    5) 现在我有了当前构建的包名,我只需要打开当前的google服务。json文件,并更新其中的包名称。为此,我添加了一个方法updategogleservicesjsonfile。 请小心更改第二行上的文件路径以指向您的位置。

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

    这里有一些更新谷歌服务的代码。在执行读取任务之前的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
  •  2
  •   Óscar    7 年前

    答案已更新

    首先,我必须解释一下,我使用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'
    

    詹金斯得到了 google-services.json 位于 '项目/应用程序/' 文件夹,它不使用味道的,所以对于每个变体,请尽快(在 preBuild 任务)我正在从 *.bak 文件,重写 package_name 让Gradle继续建造。

    当一切都完成后,在它发布应用程序之前( assembleRelease.doFirst )我删除 谷歌服务。json 我保留 *.bak公司 .

    就我而言,我只想改变 package\u名称 我的JSON的值,但如果我想将另一个值更改为 project_number 这个 client_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)
        }
    }
    

    在这个解决方案中,我有 谷歌服务。json '项目/应用程序/' 文件夹,我在每个flavor文件夹中复制它。然后我覆盖 package\u名称 . 如果您没有使用flavors,应用程序将使用原始JSON进行编译。

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


    旧解决方案

    我找到了一种混合溶液 this this 答案。

    这是我的 建筑gradle(模块:应用程序) 马上:

    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 是我定义要替换的“正则表达式”。

    的位置 谷歌服务。json “MyProject/ppp/google services.json” ,我已经测试过如果你再放一个 googler-services.json 在您的flavor文件夹中,它会覆盖第一个文件夹。

    *如果同时定义了多个flavor,则(至少)会出现一个问题,因为此任务总是覆盖同一文件,因此最终的应用程序id将是您最后定义的。

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