Crashlytics (Fabric) 为应用程序变体(构建类型、产品风格)分离组织

Crashlytics (Fabric) separate organizations for application variants (build types, product flavors)

这是一个自我回答的问题,用于分享我的知识。

我有一个包含多种产品风格的项目,我想为每种产品风格使用单独的组织来集成 Fabric。

我尝试使用 Android Studio Fabric 插件集成 Fabric。它增加了

<meta-data
    android:name="io.fabric.ApiKey"
    android:value="DEFAULT_ORGANIZATION_API_KEY" />

进入 main 个源集的 AndroidManifest.xml

我决定在特定于应用程序变体的源集中重写此条目:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <application>
        <meta-data
            android:name="io.fabric.ApiKey"
            android:value="SECOND_ORGANIZATION_API_KEY"
            tools:replace="android:value" />
    </application>
</manifest>

然后我发现 Fabric Gradle 插件在构建期间生成带有 fabric api 秘密(也称为构建秘密)的 crashlytics.properties 文件,我应该将此文件包含到源代码管理中。但是每次我构建特定的应用程序变体时,这个文件都会被覆盖,因为 api 秘密对于每个应用程序都是唯一的。

如何为每个应用程序变体使用单独的组织来集成 Fabric?

在构建过程中调用 fabricGenerateResources 任务,它会查找名为 fabric.properties 的文件,其中包含以下内容:

apiSecret=YOUR_BUILD_SECRET
apiKey=YOUR_API_KEY

所以我们只需要在此之前生成 fabric.properties 文件。

我发现 this solution 并稍微修改它以完全支持应用程序变体,而不仅仅是构建类型。

将此代码添加到 build.gradleandroid 部分:

File crashlyticsProperties = new File("${project.projectDir.absolutePath}/fabric.properties")
applicationVariants.all { variant ->
    variant.productFlavors.each { flavor ->
        def variantSuffix = variant.name.capitalize()
        def generatePropertiesTask = task("fabricGenerateProperties${variantSuffix}") << {
            Properties properties = new Properties()
            properties.put("apiKey", flavor.fabricApiKey)
            properties.put("apiSecret", flavor.fabricApiSecret)
            properties.store(new FileWriter(crashlyticsProperties), "")
        }

        def generateResourcesTask = project.tasks.getByName("fabricGenerateResources${variantSuffix}")
        generateResourcesTask.dependsOn generatePropertiesTask
        generateResourcesTask.doLast {
            println "Removing fabric.properties"
            crashlyticsProperties.delete()
        }
    }
}

它迭代应用程序变体,并为每个应用程序变体创建生成 fabric.properties 文件的任务和在 Fabric Gradle 插件生成应用程序资源后删除此文件的任务。

您现在所需要做的就是定义产品风味或特定构建类型 fabricApiKeyfabricApiSecret:

productFlavors {
    flavor1 {
        ext.fabricApiKey = "FLAVOR1_API_KEY"
        ext.fabricApiSecret = "FLAVOR1_API_SECRET"
    }
}

ext 是一个 ExtraPropertiesExtention object provided by every ExtensionAware 对象。它允许将新属性添加到现有对象。在我的例子中 flavor1ExtensionAware 对象,它可以通过使用 ext.someProperty = "value" 语法用新属性扩展,以后这些属性可以用作 flavor.someProperty, flavor.fabricApiKey.

另外最好把fabric.properties包括到.gitignore

如果您在调试期间使用它来禁用 Crashlytics,请不要忘记从调试构建类型中删除 ext.enableCrashlytics = false。您可以在 Application.onCreate:

中禁用它
Fabric.with(this, new Crashlytics.Builder().core(
    new CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build()).build());

如果您不反对使用应用程序 ID 后缀,则不需要单独的组织。崩溃和答案将被视为单独的应用程序。

例如,假设我的应用程序 ID 是 io.example

在你的 build.gradle:

buildTypes {
  debug {
    applicationIdSuffix ".debug"
  }
  release {
    //options
  }
}

将调试版本部署到设备或模拟器后,您将在 Fabric 站点上看到两个应用程序:

  • io.example
  • io.example.debug

这种方法的一个优点是您还可以单独跟踪其他构建风格:io.exmaple.freeio.exmaple.paidio.example.exterprise 等。

一个更简单的解决方案,也与 Gradle 5.x+ 兼容,是为每个需要独特结构的构建变体创建单独的 fabric.properties 文件 [=31= 】 钥匙和秘密。将 fabric.properties 个文件创建为:

#Contains API Secret used to validate your application. Commit to internal source control; avoid making secret public.
apiSecret=YOUR_API_SECRET
apiKey=YOUR_API_KEY

YOUR_API_SECRET 替换为构建变体的 API 秘密,将 YOUR_API_KEY 替换为构建变体的 API 密钥。

然后将每个变体的 fabric.properties 放在项目 src/variant 文件夹下,例如app/src/debugapp/src/releaseSee documentation 有关构建变体的更多详细信息。

在构建时,将使用正在构建的变体的 fabric.properties