为 Gradle 中的不同口味编辑 google-services.json
Edit google-services.json for different flavors in Gradle
已回答 。
我的应用程序中有不止一种风格,我想对所有这些都使用相同的 google-service.json
,所以我考虑过将属性 package_name
的值设置为正则表达式并在我的 build.gradle
(应用程序模块)中使用 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)
}
问题是我不知道如何访问 PackageName(代码中的myPackageName)或者是否可能。
也许我必须使用另一个任务而不是runBeforeBuild
,我对Gradle
不是很熟悉。
答案已更新
首先我必须解释一下我正在使用 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
并且它不使用风味的,所以对于每个变体,尽快尽可能(在 preBuild
任务之后)我正在从我的 *.bak
文件创建一个新的 JSON,覆盖 package_name
并让 Gradle 继续构建.
当一切都完成后,在它发布应用程序之前 (assembleRelease.doFirst
) 我删除了 google-services.json
并保留了 *.bak
.
在我的例子中,我只想更改 JSON 的 package_name
值,但如果我想更改另一个值作为 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)
}
}
在这个解决方案中,我在 'Project/app/' 文件夹中有 google-services.json
,我在每个风味文件夹中复制了它。然后我覆盖 package_name。如果您在没有风格的情况下工作,应用程序将使用原始 JSON 进行编译。
您可以在覆盖之前检查 flavor 文件夹中是否存在另一个 JSON,以防您对其余值有不同的值。
旧解
我找到了混合 this and 个答案的解决方案。
这是我现在的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
是我定义要替换的 "regular expression"。
google-services.json
的位置是 "MyProject/ppp/google-services.json",我测试过如果你把另一个 googler-services.json
放在你的 flavor 文件夹中,它会覆盖第一个。
*当你同时定义了不止一种风格时,(至少)有一个问题,因为这个任务总是覆盖同一个文件,所以最终的应用程序 ID 将是你最后定义的。
如果你有其他方法,欢迎post。
我找到了另一种方法,想分享一下。
请注意,这是我第一次使用 gradle 编写一些任务,所以代码根本不是最优的(我现在不能花更多的时间来改进它)。
说明
我做的事情很简单。
1) 在任务 processFlavorBuildTypeGoogleServices 之前,即来自 Google Services 的任务将读取 google-services.json 文件,我触发了一些将更新 google-services.json 文件的代码。
为了做到这一点:
gradle.taskGraph.beforeTask { Task task ->
if (task.name.startsWith("process") && task.name.endsWith("GoogleServices")) {
}
}
2) 从任务名称中检索当前的 flavor 和 buildType(任务名称示例:processProdReleaseGoogleServices in the form of 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。
请注意将第二行的文件路径更改为指向您的位置。
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)
}
}
已回答
我的应用程序中有不止一种风格,我想对所有这些都使用相同的 google-service.json
,所以我考虑过将属性 package_name
的值设置为正则表达式并在我的 build.gradle
(应用程序模块)中使用 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)
}
问题是我不知道如何访问 PackageName(代码中的myPackageName)或者是否可能。
也许我必须使用另一个任务而不是runBeforeBuild
,我对Gradle
不是很熟悉。
答案已更新
首先我必须解释一下我正在使用 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
并且它不使用风味的,所以对于每个变体,尽快尽可能(在 preBuild
任务之后)我正在从我的 *.bak
文件创建一个新的 JSON,覆盖 package_name
并让 Gradle 继续构建.
当一切都完成后,在它发布应用程序之前 (assembleRelease.doFirst
) 我删除了 google-services.json
并保留了 *.bak
.
在我的例子中,我只想更改 JSON 的 package_name
值,但如果我想更改另一个值作为 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)
}
}
在这个解决方案中,我在 'Project/app/' 文件夹中有 google-services.json
,我在每个风味文件夹中复制了它。然后我覆盖 package_name。如果您在没有风格的情况下工作,应用程序将使用原始 JSON 进行编译。
您可以在覆盖之前检查 flavor 文件夹中是否存在另一个 JSON,以防您对其余值有不同的值。
旧解
我找到了混合 this and
这是我现在的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
是我定义要替换的 "regular expression"。
google-services.json
的位置是 "MyProject/ppp/google-services.json",我测试过如果你把另一个 googler-services.json
放在你的 flavor 文件夹中,它会覆盖第一个。
*当你同时定义了不止一种风格时,(至少)有一个问题,因为这个任务总是覆盖同一个文件,所以最终的应用程序 ID 将是你最后定义的。
如果你有其他方法,欢迎post。
我找到了另一种方法,想分享一下。 请注意,这是我第一次使用 gradle 编写一些任务,所以代码根本不是最优的(我现在不能花更多的时间来改进它)。
说明
我做的事情很简单。
1) 在任务 processFlavorBuildTypeGoogleServices 之前,即来自 Google Services 的任务将读取 google-services.json 文件,我触发了一些将更新 google-services.json 文件的代码。 为了做到这一点:
gradle.taskGraph.beforeTask { Task task ->
if (task.name.startsWith("process") && task.name.endsWith("GoogleServices")) {
}
}
2) 从任务名称中检索当前的 flavor 和 buildType(任务名称示例:processProdReleaseGoogleServices in the form of 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。 请注意将第二行的文件路径更改为指向您的位置。
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)
}
}