【问题标题】:Firebase Crashlytics With UncaughtExceptionHandlerFirebase Crashlytics 与 UncaughtExceptionHandler
【发布时间】:2018-05-29 13:05:41
【问题描述】:

我已集成 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); 
  } 
}; 

} 

【问题讨论】:

  • 我也有同样的问题,你找到解决办法了吗?
  • 我建议您更新到最新版本,但您能提供给我们大文件吗?
  • @ParaskevasNtsounos 也更新到最新版本,无法正常工作:)
  • @DurgeshPatel 你在模拟器中测试应用程序吗?
  • @kevanaghera 没有。在真实设备中

标签: android firebase crashlytics


【解决方案1】:

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

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

【讨论】:

  • 如果我们这样做(添加自定义 ContentProvider),Firebase 处理程序是否不会覆盖我们的实现并且我们会丢失它?
  • 如果我们添加自定义ContentProvider来初始化一个未捕获的异常处理程序,我们的异常处理程序会先被初始化,我们会先获取所有的异常,并且不会与firebase的异常处理程序发生冲突,从而使firebase异常处理程序在我们的处理程序之后也会得到相同的异常。因此,崩溃将毫无问题地记录到 Firebase。 @Maksym
【解决方案2】:

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

您不应在 BaseActivity 中创建自定义异常处理程序。 最好在您的应用程序类中执行此操作。 在 BaseActivity 的情况下,您每次启动新活动时都会创建一个新的处理程序,这会扩展您的 BaseActivity。

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

val defaultExceptionHandler = Thread.getDefaultUncaughtExceptionHandler()

在我的例子中,它是一个

com.crashlytics.android.core.CrashlyticsUncaughtExceptionHandler

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

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
        }

        }
    }

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

override fun onCreate() {
        super.onCreate()
        Fabric.with(this, Crashlytics())
        val defaultExceptionHandler = Thread.getDefaultUncaughtExceptionHandler()
        val customExceptionHandler = DefaultExceptionHandler(defaultExceptionHandler)
        Thread.setDefaultUncaughtExceptionHandler(customExceptionHandler)
    }

【讨论】:

    【解决方案3】:

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

    代码 sn-p:

     <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.
                }
            }
        }
    

    【讨论】:

      【解决方案4】:

      在织物的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());
      

      【讨论】:

      • 我不想只集成我自己未捕获的异常。所以我可以做到这一点?
      • @Priyank Patel,正如我所说,这段代码在 BaseActivity.java 的 onCreate() 中,但没有成功或失败的回调:)
      • @kevanaghera 如果您只想使用自己的异常处理程序而不是 crashlytics,那么您只需要在应用程序类的 onCreate 方法中使用 Thread.setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler);' 即可捕获未捕获的异常。
      • @kevanaghera 我已经知道这件事了。 :) 查看我发布的问题描述。 :)
      • 这对我不起作用。我的要求是在崩溃后启动反馈活动并同时在 Crashlytics 上记录致命异常,而应用程序不会显示默认的崩溃对话框并要求重新启动应用程序。
      【解决方案5】:

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

      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'
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-10-01
        • 2019-07-23
        • 1970-01-01
        • 1970-01-01
        • 2023-03-19
        • 2018-09-17
        • 2017-11-27
        相关资源
        最近更新 更多