Crashlytics Android SDK - 自定义UncaughtExceptionHandler

34

在一个应用中,是否可以将自定义的UncaughtExceptionHandler与crashlytics结合使用?如果可以-如何实现?


这个问题解决了吗?我也遇到了新的遗留问题。发现代码无法进一步链接未捕获的异常。 - Seph Remotigue
@SephRemotigue 请尝试此解决方案 https://dev59.com/5F8e5IYBdhLWcg3w7-Fz#56990688 - Александр Кундрюков
7个回答

35

更新

请参考@kmityak的答案,因为Crashlytics/Fabric初始化现在是异步的,所以下面的解决方案已不再有效。

原始答案

您可以设置自定义的UncaughtExceptionHandler,只要它将异常传递给默认的UncaughtExceptionHandler以便稍后通过Crashlytics处理。

以下代码是在Application子类中实现的:

private static Thread.UncaughtExceptionHandler mDefaultUEH;
private static Thread.UncaughtExceptionHandler mCaughtExceptionHandler = new Thread.UncaughtExceptionHandler() {
    @Override 
    public void uncaughtException(Thread thread, Throwable ex) {
        // Custom logic goes here

        // This will make Crashlytics do its job
        mDefaultUEH.uncaughtException(thread, ex);
    }
};

@Override
public void onCreate() {
    super.onCreate();

    // Order is important!
    // First, start Crashlytics
    Crashlytics.start(this);

    // Second, set custom UncaughtExceptionHandler
    mDefaultUEH = Thread.getDefaultUncaughtExceptionHandler();
    Thread.setDefaultUncaughtExceptionHandler(mCaughtExceptionHandler);
}

第二个选项是在设置自定义UncaughtExceptionHandler之后注册Crashlytics - 然后所有未捕获的异常都将被Crashlytics报告为致命错误,并在此之后传递给您的自定义处理程序。


3
我无法调用Crashlytics.start(this)方法。我正在使用crashlytics:2.5.1版本。我希望在退出应用程序的同时将故障报告发送到Fabric。请问该怎么做? - SweetWisher ツ
1
请使用Fabric.with(this, Crashlytics())代替Crashlytics.start(this) - Tej
请问代码应该放在哪里?我不理解“...在Application子类内部”是什么意思。谢谢! - Mr. B.
1
你需要创建一个自定义的Application类。你可以通过创建android.app.Application的子类并在AndroidManifest.xml中注册它来实现。更多信息请参见:https://developer.android.com/reference/android/app/Application.html - jskierbi

19

由于最近版本的Crashlytics进行异步初始化,因此最好使用Fabric的初始化回调:

private static Thread.UncaughtExceptionHandler mDefaultUEH;
private static Thread.UncaughtExceptionHandler mCaughtExceptionHandler = 
   new Thread.UncaughtExceptionHandler() {
     @Override 
public void uncaughtException(Thread thread, Throwable ex) {
        // Custom logic goes here

        // This will make Crashlytics do its job
        mDefaultUEH.uncaughtException(thread, ex);
    }
};

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) {
                    mDefaultUEH = Thread.getDefaultUncaughtExceptionHandler();
                    Thread.setDefaultUncaughtExceptionHandler(mCaughtExceptionHandler);
                }

                @Override
                public void failure(Exception e) {

                }
            })
            .build());

2
从CrashlyticsCore(v2.9.4)中我所看到的,CrashlyticsController.enableExceptionHandling()在onPreExecute()内被调用。因此,这仍然在同一个线程中完成。此外,CrashlyticsUncaughtExceptionHandler(控制器使用的)确保将异常传递给任何默认处理程序。因此,初始化Fabric和自己的异常处理程序的顺序并不重要,只要你做相同的事情即可。 - black
3
我在我的Application类中尝试了这个,对于我的情况,failure(Exception e)函数会收到一个异常回调:“com.crashlytics.sdk.android.crashlytics-core Initialization was cancelled”。你认为这是为什么? - Rahul Gurnani
2
我正在尝试这个,但是 InitializationCallback 没有被调用。有什么想法吗? - Blitz

3

如果那些解决方案都对我无效,我会按照以下方式进行操作:

// Setup handler for uncaught exceptions.
Thread.setDefaultUncaughtExceptionHandler (new Thread.UncaughtExceptionHandler()
{
    @Override
    public void uncaughtException (Thread thread, Throwable e)
    {
        //Send Report to Crashlytics. Crashlytics will send it as soon as it starts to work
        Crashlytics.logException(e);

        //Your custom codes to Restart the app or handle this crash
        HandleCrashes(thread, e);
    }
});

以下是我的自定义方法,用于重新启动应用程序:

private void HandleCrashes(Thread t, Throwable e) {

    Intent i = new Intent(mContext, frmLogin.class);
    i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
    i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    i.putExtra("JustLogin", true);
    startActivity(i);

    System.exit(1);
}

4
这个解决方案的问题在于,Crashlytics 会将此崩溃报告为非致命错误而不是一般的崩溃。 - Vito Valov
2
@VitoValov 有没有什么方法可以解决这个问题?仍然发送致命崩溃并重新启动应用程序? - Guillaume

3
是的,这是可能的。
在您的 Application 类中:
@Override
public void onCreate() {
    super.onCreate();
    Crashlytics.start(this);
    initUncaughtExceptionHandler();
}

private void initUncaughtExceptionHandler() {
    final ScheduledThreadPoolExecutor c = new ScheduledThreadPoolExecutor(1);
    c.schedule(new Runnable() {
        @Override
        public void run() {
            final UncaughtExceptionHandler defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
            Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
                @Override
                public void uncaughtException(Thread paramThread, Throwable paramThrowable) {
                    // do my amazing stuff here 
                    System.err.println("Error!");
                    //then pass the job to the previous handler
                    defaultHandler.uncaughtException(paramThread, paramThrowable);
                }
            });
        }
    }, 5, TimeUnit.SECONDS);
}

我之所以将它设置为5秒后执行,是因为Crashlytics需要一些时间来进行设置。我正在使用这段代码并且它运行得非常完美。当然,如果你的应用在启动时崩溃了,那很抱歉,无法使用自定义处理程序;)


3
  1. 关闭自动收集

    将以下内容添加到您的AndroidManifest.xml文件中

<meta-data
     android:name="firebase_crashlytics_collection_enabled"
     android:value="false" />
  1. 注册您的自定义UncaughtExceptionHandler
Thread.setDefaultUncaughtExceptionHandler(customerUncaughtExceptionHandler)
  1. 在注册UncaughtExceptionHandler后手动启动Crashlytics
Fabric.with(this, new Crashlytics());

重新构建并重新安装您的应用程序。

1

我找到了 Fabric 2.10.1 的解决方案:

Thread.setDefaultUncaughtExceptionHandler(yourExceptionHandler)
Fabric.with(this, Crashlytics())

0
    Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
    @Override
    public void uncaughtException(Thread thread, Throwable throwable) {
        // Delegate to the default uncaught exception handler provided by the system
        Thread.getDefaultUncaughtExceptionHandler().uncaughtException(thread, throwable);
    }
});

// Initialize Firebase Crashlytics
FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(true);

// Set Firebase Crashlytics as the default uncaught exception handler
Thread.setDefaultUncaughtExceptionHandler(FirebaseCrashlytics.getInstance().getUncaughtExceptionHandler());

1
FirebaseCrashlytics API的.getUncaughtExceptionHandler()方法适用于哪个版本? - Chisko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接