Android 由于磁盘加密,Crashlytics 在直接启动时失败

Android Crashlytics fails on direct boot due to disk encryption

Android Crashlytics 在 android 上直接启动时无法初始化。问题是在 Android 中支持上下文的默认存储是加密的,直到用户输入他们的凭据:

https://developer.android.com/reference/android/content/Context.html#createDeviceProtectedStorageContext()

您会在日志中看到一堆信息,例如

07-17 16:47:18.083 1897-1982/XXX E/SharedPreferencesImpl: Couldn't create directory for SharedPreferences file /data/user/0/com.xxx.xxx/shared_prefs/com.crashlytics.sdk.android:answers:settings.xml

也通过使用 Fabric.Builder

注册 initializationCallback 进行验证

有没有办法通过 createDeviceProtectedStorageContext 存储将 crashlytics 配置为使用共享首选项后端?

问题是,如果应用程序以这种方式在启动时启动,那么 crashlytics 将无法在应用程序的整个生命周期内工作。这可能会导致遗漏大量崩溃报告。

基本上它会失败,因为像 Crashlytics 这样的库会调用 getBaseContext,这会使 createDeviceProtectedStorageContext 无效。对于 Crashlytics,它还期望 getApplicationContext 到 return 和 Application。这是完整的解决方法。

执行以下 class:(将其翻译成 Java 应该不难)

@SuppressLint("Registered")
@TargetApi(24)
class DeviceStorageApp(context: Context) : Application() {
    init {
        attachBaseContext(context.createDeviceProtectedStorageContext())
    }

    /**
     * Thou shalt not get the REAL underlying application context which would no
     * longer be operating under device protected storage.
     */
    override fun getApplicationContext(): Context = this
}

AndroidManifest.xml 中禁用自动初始化:

<meta-data android:name="firebase_crashlytics_collection_enabled"
           android:value="false"/>

然后在您的真实 Application.onCreate 中执行此操作:(Android 省略 SDK 版本检查)

Fabric.with(DeviceStorageApp(this), Crashlytics())

完整样本:https://github.com/Mygod/VPNHotspot/commit/2578c1c6ec67a8b9c7274c6f0e0f47ed030a6813

编辑:如果您想使用远程配置等 Firebase 功能,您可能还需要将这些添加到您的 AndroidManifest.xml 中。 (你可能想要添加它,因为这只是一个存根服务)

<service android:name="com.google.firebase.components.ComponentDiscoveryService"
         android:directBootAware="true"/>