使用UncaughtExceptionHandler的Firebase Crashlytics

时间:2018-05-29 13:05:42

标签: android firebase crashlytics

我已经集成了Firebase Crashlytics版本2.9.1来挖掘崩溃,以涵盖我的应用程序的性能和稳定性。

如果应用程序拥有自己的UncaughtExceptionHandler,则不会在firebase crashlytics控制台上记录崩溃。

我的应用中有BaseActivity。 在onCreate()方法中我根据项目要求注册了自定义UncaughtExceptionHandler。

每当应用因任何原因而崩溃时,都应将用户重定向到初始屏幕(MainActivity.java)。

public class BaseActivity extends FragmentActivity{ 

@Override 
protected void onCreate(Bundle arg0) { 
   // Enable global crash handler. 
   Thread.setDefaultUncaughtExceptionHandler(handleAppCrash); 
} 

/*** 
* @Purpose Called when any crash occurs in the application. 
***/ 
private Thread.UncaughtExceptionHandler handleAppCrash = new Thread.UncaughtExceptionHandler() { 
@Override 
public void uncaughtException(Thread thread, Throwable ex) { 

   Intent intent = new Intent(context, MainActivity.class); //redirect to Splash screen
   intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 
   context.startActivity(intent); 
   System.exit(0); 
  } 
}; 

} 

5 个答案:

答案 0 :(得分:3)

对于最新的firebase crashlytics 17.x.x,他们在Content Provider中设置了未捕获的异常处理程序,因此他们不需要开发人员传递上下文并手动初始化。这样做是为了在应用启动时自动初始化Firebase。因此,即使我们在Application类的oncreate上设置了未捕获的异常处理程序,我们的实现也会覆盖firebase的异常,并且崩溃不会报告给firebase异常处理程序。

修复:要解决此问题,我们必须编写一个自定义的内容提供程序,并将其优先级设置为我们的应用程序中的最大值。然后在内容提供者的oncreate内初始化我们未捕获的异常处理程序,而不是在应用程序类中进行初始化。这样,我们的将首先被初始化,并且不会覆盖firebase的。

答案 1 :(得分:0)

您是否尝试升级最新版本:

implementation 'com.crashlytics.sdk.android:crashlytics:2.9.3'

谷歌服务(项目级别):

classpath 'com.google.gms:google-services:4.0.1'

确保一切都是最新的。这是基于此link的firebase库中的最新更新,您可以在下面查看:

implementation 'com.google.firebase:firebase-core:16.0.0'
implementation 'com.google.firebase:firebase-ads:15.0.1'
implementation 'com.google.firebase:firebase-analytics:16.0.0'
implementation 'com.google.firebase:firebase-appindexing:15.0.1'
implementation 'com.google.firebase:firebase-auth:16.0.1'
implementation 'com.google.firebase:firebase-firestore:17.0.1'
implementation 'com.google.firebase:firebase-functions:16.0.1'
implementation 'com.google.firebase:firebase-messaging:17.0.0'
implementation 'com.google.firebase:firebase-storage:16.0.1'
implementation 'com.google.firebase:firebase-crash:16.0.0'
implementation 'com.google.firebase:firebase-invites:16.0.0'
implementation 'com.google.firebase:firebase-perf:16.0.0'
implementation 'com.google.firebase:firebase-database:16.0.1'
implementation 'com.google.firebase:firebase-config:16.0.0'

答案 2 :(得分:0)

在面料的InitializationCallback内设置自定义异常处理程序,如下面的代码。

    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) {
                // Get default exception handler
                final Thread.UncaughtExceptionHandler defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
                // Set your custom exception handler   
                Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
                    @Override
                    public void uncaughtException(Thread thread, Throwable ex) {
                        // redirect to Splash screen
                        Intent intent = new Intent(context, MainActivity.class);
                        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                        context.startActivity(intent);
                        // pass exception to default handler
                        defaultHandler.uncaughtException(thread, ex);
                    }
                };);
            }

            @Override
            public void failure(Exception e) {

            }
        }).build());

答案 3 :(得分:0)

好的,我已经调查了这个问题。

您不应在BaseActivity中创建自定义异常处理程序。 最好在Application类中执行此操作。 如果使用BaseActivity,则每次启动新活动时都会使用新的处理程序,从而扩展了BaseActivity。

因此,在您的应用程序类onCreate()方法中,您可以获取默认的应用程序处理程序

quanteda::corpus()

就我而言,它是

的一个实例
val defaultExceptionHandler = Thread.getDefaultUncaughtExceptionHandler()

您将使用此“ defaultExceptionHandler”向Firebase发送正确的错误。 然后,您可以创建自己的异常处理程序,但需要在此处保留此“ defaultExceptionHandler”。

com.crashlytics.android.core.CrashlyticsUncaughtExceptionHandler

最后,firebase将根据需要显示崩溃。 应用onCreate()示例

class DefaultExceptionHandler (private val  defaultExceptionHandler:Thread.UncaughtExceptionHandler?) : Thread.UncaughtExceptionHandler {
override fun uncaughtException(thread: Thread, ex: Throwable) {
        try {       
            // here you restore your activity and do other things
            // and of course you deal with defaultExceptionHandler
            // without it firebase will not work       
            defaultExceptionHandler?.uncaughtException(thread, ex)
            // only after firebase dealed with an exception, you can exit
            System.exit(0)
        } catch (e: IOException) {
            // just catch
        }

        }
    }

答案 4 :(得分:0)

我的应用程序中也遇到了同样的问题。正如@niyas所建议的,我也使用了相同的解决方案,它对我来说很好用。 Firebase使用内容提供程序初始化firebase crashlytics sdk及其未捕获的异常处理程序。因此,如果您将未捕获的异常处理程序注册到具有更高优先级的自定义内容提供程序中,则将使用firebase。然后,接收到处理程序的回调的顺序将颠倒。首先,回调将转到Firebase处理程序,然后转到您的处理程序。这样,firebase会收集崩溃的堆栈跟踪,并且您还将在处理程序中获得回调以重新启动应用程序/或任何其他用例。我在github上找到了此解决方案,这里是a link

代码段:

 <application>
        ...
        <!-- Firebase SDK initOrder is 100. Higher order init first -->
        <provider
            android:name=".UncaughtExceptionHandlerContentProvider"
            android:authorities="${applicationId}"
            android:exported="false"
            android:initOrder="101"
            android:grantUriPermissions="false" />
        ... 
    </application>

 public class UncaughtExceptionHandlerContentProvider extends ContentProvider {
    @Override
    public boolean onCreate() {
        MyCustomCrashHandler myHandler = new MyCustomCrashHandler(Thread.getDefaultUncaughtExceptionHandler());
        Thread.setDefaultUncaughtExceptionHandler(myHandler);
        return true;
    }

    @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; }
}


public class MyCustomCrashHandler implements UncaughtExceptionHandler {
    @Nullable 
    private final UncaughtExceptionHandler defaultHandler;
    
    public MyCustomCrashHandler(@Nullable UncaughtExceptionHandler defaultHandler)(){
         this.defaultHandler = defaultHandler;
    }

    @Override
    public void uncaughtException(@NonNull Thread thread, @NonNull Throwable ex) {
        // We are now safely being called after Crashlytics does its own thing. 
        // Whoever is the last handler on Thread.getDefaultUncaughtExceptionHandler() will execute first on uncaught exceptions.
        // Firebase Crashlytics will handle its own behavior first before calling ours in its own 'finally' block.
        // You can choose to propagate upwards (it will kill the app by default) or do your own thing and propagate if needed.
        
        try { 
            //do your own thing.
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (defaultHandler != null) {
                defaultHandler.uncaughtException(thread, ex) 
                // propagate upwards. With this workaround (and also without any other similar UncaughtExceptionHandler based on ContentProvider), 
                // defaultHandler should now be an instance of com.android.internal.os.RuntimeInit.KillApplicationHandler
                // hence properly killing the app via framework calls.
            }
        }
    }