使用自定义 UncaughtExceptionHandler 升级 Firebase Crashlytics

Upgrade Firebase Crashlytics with custom UncaughtExceptionHandler

Update your apps to use latest Firebase Crashlytics SDKs before November 15, 2020 上工作时,在我激活自定义 UncaughtExceptionHandler 后,它不会再向 Crashlytics 发送崩溃。

下面的代码我将它设置在 ApplicationonCreate() 内。

        FirebaseCrashlytics crashlytics = FirebaseCrashlytics.getInstance();
        crashlytics.setCrashlyticsCollectionEnabled(!BuildConfig.DEBUG); // only release able to send.
        crashlytics.sendUnsentReports(); // send reports
        Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
            FirebaseCrashlytics.getInstance().recordException(e); // record exception.
            // below things are restart app when crash appeared.
            PackageManager packageManager = getPackageManager();
            Intent intent = packageManager.getLaunchIntentForPackage(getPackageName());
            if (intent != null) {
                ComponentName componentName = intent.getComponent();
                Intent mainIntent = Intent.makeRestartActivityTask(componentName);
                startActivity(mainIntent);
                Runtime.getRuntime().exit(0);
            }
        });

当我删除自定义 UncaughtExceptionHandler 时,它能够向 Crashlytics 报告。

以下代码在使用 Fabric 库时运行良好。 ()

        CrashlyticsCore core = new CrashlyticsCore.Builder()
                .disabled(BuildConfig.DEBUG)
                .build();
        Fabric.with(new Fabric.Builder(this).kits(new Crashlytics.Builder()
                .core(core).build()).initializationCallback(new InitializationCallback<Fabric>() {
            @Override
            public void success(Fabric fabric) {
                Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
                    LogWrapper.logException(e);
                    PackageManager packageManager = getPackageManager();
                    Intent intent = packageManager.getLaunchIntentForPackage(getPackageName());
                    if (intent != null) {
                        ComponentName componentName = intent.getComponent();
                        Intent mainIntent = Intent.makeRestartActivityTask(componentName);
                        startActivity(mainIntent);
                        Runtime.getRuntime().exit(0);
                    }
                });
            }

            @Override
            public void failure(Exception e) {
                e.printStackTrace();
            }
        }).build());

有什么解决办法吗?任何帮助将不胜感激。非常感谢。

您需要调用 getUncaughtExceptionHandler 并挂起,然后设置您自己的 uncaughtexceptionhandler 并在退出前调用我们的。

解决方案是 posted here。我会将修改后的代码粘贴到此处以供寻找它的任何人使用:

下面的代码写在Java。 Kotlin请访问原文post.

public class NewCrashHandlerContentProvider extends ContentProvider {
    public static final String TAG = "NewCrashHandler";
    static long PRE_DELAY_MILLIS = 3000L;
    static long POST_DELAY_MILLIS = 3000L;

    public static void initializeAfterFirebaseContentProvider() {
        Thread.setDefaultUncaughtExceptionHandler(new PreFirebaseCrashHandler(Thread.getDefaultUncaughtExceptionHandler()));
    }

    @Override
    public boolean onCreate() {
        try {
            Log.i(TAG, "+onCreate()");
            Thread.setDefaultUncaughtExceptionHandler(new PostFirebaseCrashHandler(Thread.getDefaultUncaughtExceptionHandler()));
            return true;
        }finally {
            Log.i(TAG, "-onCreate()");
        }
    }

    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
        return null;
    }

    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        return null;
    }

    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
        return null;
    }

    @Override
    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
        return 0;
    }

    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
        return 0;
    }


    static class PreFirebaseCrashHandler implements Thread.UncaughtExceptionHandler {
        Thread.UncaughtExceptionHandler previousUncaughtExceptionHandler;
        public static final String TAG = "PreFirebaseCrashHandler";

        public PreFirebaseCrashHandler(Thread.UncaughtExceptionHandler previousUncaughtExceptionHandler) {
            this.previousUncaughtExceptionHandler = previousUncaughtExceptionHandler;
        }

        @Override
        public void uncaughtException(@NonNull Thread t, @NonNull Throwable e) {
            LogWrapper.logException(e);
            try {
                // my own logic
                Thread.sleep(PRE_DELAY_MILLIS);
            }catch (Throwable throwable) {
                LogWrapper.e(TAG, throwable.getLocalizedMessage());
            } finally {
                previousUncaughtExceptionHandler.uncaughtException(t,e);
            }
        }
    }

    static class PostFirebaseCrashHandler implements Thread.UncaughtExceptionHandler {
        Thread.UncaughtExceptionHandler previousUncaughtExceptionHandler;
        public static final String TAG = "PostFirebaseCrashHandler";

        public PostFirebaseCrashHandler(Thread.UncaughtExceptionHandler previousUncaughtExceptionHandler) {
            this.previousUncaughtExceptionHandler = previousUncaughtExceptionHandler;
        }

        @Override
        public void uncaughtException(@NonNull Thread t, @NonNull Throwable e) {
            LogWrapper.e(TAG, "+uncaughtException($thread, $throwable)");
            try {
                Thread.sleep(POST_DELAY_MILLIS);
            }catch (Throwable throwable) {
                LogWrapper.e(TAG, throwable.getLocalizedMessage());
            }finally {
                previousUncaughtExceptionHandler.uncaughtException(t,e);
            }
            LogWrapper.e(TAG, e.getLocalizedMessage());
        }
    }

}

在Application文件中,在onCreate()方法中写入:

NewCrashHandlerContentProvider.initializeAfterFirebaseContentProvider();

也别忘了更新manifests

<provider
            android:authorities="${applicationId}"
            android:name=".utils.NewCrashHandlerContentProvider"
            android:exported="false"
            android:initOrder="101"
            android:grantUriPermissions="false"/>