有没有办法使用 Firebase App Distribution 为每个 Android 构建变体配置单独的 serviceCredentialsFile?
Is there a way to configure separate serviceCredentialsFile for each Android build variant with Firebase App Distribution?
我们有几个 Firebase 项目,它们通过构建类型和风格共享相同的代码库。我们的目标是通过 Gradle 使用应用程序分发并使用服务帐户凭据进行身份验证。
在docs中显示firebaseAppDistribution
块可以用来配置参数,服务凭证文件路径就是其中之一。由于每个变体都是一个 Firebase 项目,并且每个项目都有自己的服务凭证,据我所知,我们需要在 Gradle 配置中指向单独的服务凭证文件路径。
我尝试根据变体使用 gradle 任务更新文件路径,但无法使其工作。当前构建文件如下所示:
...
apply plugin: 'com.google.firebase.appdistribution'
class StringExtension {
String value
StringExtension(String value) {
this.value = value
}
public void setValue(String value) {
this.value = value
}
public String getValue() {
return value
}
}
android {
...
productFlavors.whenObjectAdded {
flavor -> flavor.extensions.create("service_key_prefix", StringExtension, '')
}
productFlavors {
flavor1 {
...
service_key_prefix.value = "flavor1"
}
flavor2 {
...
service_key_prefix.value = "flavor2"
}
}
buildTypes {
debug {
firebaseAppDistribution {
releaseNotesFile = file("internal_release_notes.txt").path
groupsFile = file("group_aliases_debug_fb.txt").path
}
}
release {
firebaseAppDistribution {
releaseNotesFile = file("release_notes.txt").path
groupsFile = file("group_aliases_prod_fb.txt").path
}
}
}
}
...
android.applicationVariants.all { variant ->
task("firebaseCredentials${variant.name.capitalize()}", overwrite: true) {
variant.productFlavors.each { flavor ->
doLast {
firebaseAppDistribution {
def serviceKeyFile = file(
"../${flavor.service_key_prefix.value}-${variant.buildType.name}-service-key.json")
if (serviceKeyFile != null) {
serviceCredentialsFile = serviceKeyFile.path
}
}
}
}
}
}
android.applicationVariants.all { variant ->
def distTask = tasks.named("appDistributionUpload${variant.name.capitalize()}")
def configTask = tasks.named("firebaseCredentials${variant.name.capitalize()}")
distTask.configure {
dependsOn(configTask)
}
}
apply plugin: 'com.google.gms.google-services'
任务似乎 运行 正确,但我猜文件路径没有更新,因为当我 运行 appDistributionUpload
:
时它仍然给出以下错误
Could not find credentials. To authenticate, you have a few options:
Set the serviceCredentialsFile
property in your gradle plugin
Set a refresh token with the FIREBASE_TOKEN environment variable
Log in with the Firebase CLI
Set service credentials with the GOOGLE_APPLICATION_CREDENTIALS environment variable
关于如何实现这种分布配置有什么想法吗?
真的需要为每个Variant定义不同的serivceAccount文件吗?还是每个 flavor/buildType 有单独的文件就足够了?
因为 buildType
和 productFlavors
在通过 android.applicationVariants
访问时是只读的,这将在评估阶段后执行。但是你可以在 gradle.
配置阶段直接设置 BuildType 或 Flavor 的值
目前这是我让它为我工作的唯一方法。
构建类型:
android.buildTypes.all{
File serviceAccountFile = file("/path/to/file-${it.name}.json")
if (serviceAccountFile.exists()) {
it.firebaseAppDistribution {
serviceCredentialsFile = serviceAccountFile.path
}
}
}
口味:
android.productFlavors.all{
File serviceAccountFile = file("/path/to/file-${it.name}.json")
if (serviceAccountFile.exists()) {
it.firebaseAppDistribution {
serviceCredentialsFile = serviceAccountFile.path
}
}
}
联系支持团队后,我了解到此配置尚未开箱即用,目前作为功能请求存在。
以下是 Firebase 支持团队的解决方法,它会在每次上传任务开始时修改内存中的相关环境变量:
android {
applicationVariants.all { variant ->
final uploadTaskName = "appDistributionUpload${variant.name.capitalize()}"
final uploadTask = project.tasks.findByName(uploadTaskName)
if (uploadTask != null) {
uploadTask.doFirst {
resetCredentialsCache()
final value = "$projectDir/src/${variant.name}/app-distribution-key.json"
setEnvInMemory('GOOGLE_APPLICATION_CREDENTIALS', value)
}
}
}
}
private static void setEnvInMemory(String name, String val) {
// There is no way to dynamically set environment params, but we can update it in memory
final env = System.getenv()
final field = env.getClass().getDeclaredField("m")
field.setAccessible(true)
field.get(env).put(name, val)
}
private static void resetCredentialsCache() {
// Google caches credentials provided by environment param, we are going to reset it
final providerClass = Class.forName(
'com.google.firebase.appdistribution.buildtools.reloc.com.google.api.client.googleapis.auth.oauth2.DefaultCredentialProvider')
final providerCtor = providerClass.getDeclaredConstructor()
providerCtor.setAccessible(true)
final provider = providerCtor.newInstance()
final credsClass = Class.forName(
'com.google.firebase.appdistribution.buildtools.reloc.com.google.api.client.googleapis.auth.oauth2.GoogleCredential')
final field = credsClass.getDeclaredField('defaultCredentialProvider')
field.setAccessible(true)
field.set(null, provider)
}
编辑:上述解决方案仅适用于应用分发插件版本 1.3.1。
我没有进一步联系支持人员,而是在 Jenkins CI 上使用了 GOOGLE_APPLICATION_CREDENTIALS
环境变量,如 here
所述
我们有几个 Firebase 项目,它们通过构建类型和风格共享相同的代码库。我们的目标是通过 Gradle 使用应用程序分发并使用服务帐户凭据进行身份验证。
在docs中显示firebaseAppDistribution
块可以用来配置参数,服务凭证文件路径就是其中之一。由于每个变体都是一个 Firebase 项目,并且每个项目都有自己的服务凭证,据我所知,我们需要在 Gradle 配置中指向单独的服务凭证文件路径。
我尝试根据变体使用 gradle 任务更新文件路径,但无法使其工作。当前构建文件如下所示:
...
apply plugin: 'com.google.firebase.appdistribution'
class StringExtension {
String value
StringExtension(String value) {
this.value = value
}
public void setValue(String value) {
this.value = value
}
public String getValue() {
return value
}
}
android {
...
productFlavors.whenObjectAdded {
flavor -> flavor.extensions.create("service_key_prefix", StringExtension, '')
}
productFlavors {
flavor1 {
...
service_key_prefix.value = "flavor1"
}
flavor2 {
...
service_key_prefix.value = "flavor2"
}
}
buildTypes {
debug {
firebaseAppDistribution {
releaseNotesFile = file("internal_release_notes.txt").path
groupsFile = file("group_aliases_debug_fb.txt").path
}
}
release {
firebaseAppDistribution {
releaseNotesFile = file("release_notes.txt").path
groupsFile = file("group_aliases_prod_fb.txt").path
}
}
}
}
...
android.applicationVariants.all { variant ->
task("firebaseCredentials${variant.name.capitalize()}", overwrite: true) {
variant.productFlavors.each { flavor ->
doLast {
firebaseAppDistribution {
def serviceKeyFile = file(
"../${flavor.service_key_prefix.value}-${variant.buildType.name}-service-key.json")
if (serviceKeyFile != null) {
serviceCredentialsFile = serviceKeyFile.path
}
}
}
}
}
}
android.applicationVariants.all { variant ->
def distTask = tasks.named("appDistributionUpload${variant.name.capitalize()}")
def configTask = tasks.named("firebaseCredentials${variant.name.capitalize()}")
distTask.configure {
dependsOn(configTask)
}
}
apply plugin: 'com.google.gms.google-services'
任务似乎 运行 正确,但我猜文件路径没有更新,因为当我 运行 appDistributionUpload
:
Could not find credentials. To authenticate, you have a few options:
Set the
serviceCredentialsFile
property in your gradle pluginSet a refresh token with the FIREBASE_TOKEN environment variable
Log in with the Firebase CLI
Set service credentials with the GOOGLE_APPLICATION_CREDENTIALS environment variable
关于如何实现这种分布配置有什么想法吗?
真的需要为每个Variant定义不同的serivceAccount文件吗?还是每个 flavor/buildType 有单独的文件就足够了?
因为 buildType
和 productFlavors
在通过 android.applicationVariants
访问时是只读的,这将在评估阶段后执行。但是你可以在 gradle.
目前这是我让它为我工作的唯一方法。
构建类型:
android.buildTypes.all{
File serviceAccountFile = file("/path/to/file-${it.name}.json")
if (serviceAccountFile.exists()) {
it.firebaseAppDistribution {
serviceCredentialsFile = serviceAccountFile.path
}
}
}
口味:
android.productFlavors.all{
File serviceAccountFile = file("/path/to/file-${it.name}.json")
if (serviceAccountFile.exists()) {
it.firebaseAppDistribution {
serviceCredentialsFile = serviceAccountFile.path
}
}
}
联系支持团队后,我了解到此配置尚未开箱即用,目前作为功能请求存在。
以下是 Firebase 支持团队的解决方法,它会在每次上传任务开始时修改内存中的相关环境变量:
android {
applicationVariants.all { variant ->
final uploadTaskName = "appDistributionUpload${variant.name.capitalize()}"
final uploadTask = project.tasks.findByName(uploadTaskName)
if (uploadTask != null) {
uploadTask.doFirst {
resetCredentialsCache()
final value = "$projectDir/src/${variant.name}/app-distribution-key.json"
setEnvInMemory('GOOGLE_APPLICATION_CREDENTIALS', value)
}
}
}
}
private static void setEnvInMemory(String name, String val) {
// There is no way to dynamically set environment params, but we can update it in memory
final env = System.getenv()
final field = env.getClass().getDeclaredField("m")
field.setAccessible(true)
field.get(env).put(name, val)
}
private static void resetCredentialsCache() {
// Google caches credentials provided by environment param, we are going to reset it
final providerClass = Class.forName(
'com.google.firebase.appdistribution.buildtools.reloc.com.google.api.client.googleapis.auth.oauth2.DefaultCredentialProvider')
final providerCtor = providerClass.getDeclaredConstructor()
providerCtor.setAccessible(true)
final provider = providerCtor.newInstance()
final credsClass = Class.forName(
'com.google.firebase.appdistribution.buildtools.reloc.com.google.api.client.googleapis.auth.oauth2.GoogleCredential')
final field = credsClass.getDeclaredField('defaultCredentialProvider')
field.setAccessible(true)
field.set(null, provider)
}
编辑:上述解决方案仅适用于应用分发插件版本 1.3.1。
我没有进一步联系支持人员,而是在 Jenkins CI 上使用了 GOOGLE_APPLICATION_CREDENTIALS
环境变量,如 here