Crashlytics Firebase с UncaughtExceptionHandler

Я интегрировал Firebase Crashlytics версии 2.9.1 для выявления сбоев, чтобы обеспечить производительность и стабильность моего приложения.

Сбои не регистрируются в консоли сбоев firebase, если у приложения есть собственный UncaughtExceptionHandler.

В моем приложении есть 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); 
  } 
}; 

} 

У меня такая же проблема, как и вы нашли решение?

Kevan Aghera 29.05.2018 15:27

Я рекомендую вам обновить последнюю версию, но не могли бы вы предоставить нам файлы Gradle?

Paraskevas Ntsounos 29.05.2018 15:32

@ParaskevasNtsounos тоже обновился до последней версии, не работает :)

Durgesh Patel 30.05.2018 07:47

@DurgeshPatel у тестового приложения в эмуляторе?

Kevan Aghera 30.05.2018 13:43

@kevanaghera нет. в реальном устройстве

Durgesh Patel 30.05.2018 15:03

@DurgeshPatel, потому что я получил ошибку в эмуляторе не на реальных устройствах. и в приложении-эмуляторе приложение заходит в бесконечный цикл и каждый раз генерирует один и тот же журнал ошибок.

Kevan Aghera 30.05.2018 15:26

Обратитесь к stackoverflow.com/questions/44771420/…

DavidSon Nguyen 28.12.2018 10:36

та же проблема, сбой, не регистрирующийся на реальном устройстве с последней конфигурацией при использовании настраиваемого UncaughtExceptionHandler, даже при запуске mDefaultUncaughtExceptionHandler? .uncaughtException (thread, ex)

Killer 23.09.2020 10:14
12
8
3 364
5

Ответы 5

Вы пытались обновить последнюю версию:

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

И сервисы Google (уровень проекта):

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

Убедитесь, что все обновлено. Это последнее обновление в библиотеках 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'

Установите свой собственный обработчик исключений внутри 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());

Я не хочу интегрировать крашлитику firebase, только мое собственное неперехваченное исключение. так я могу этого добиться?

Kevan Aghera 30.05.2018 05:45

@Priyank Patel, поскольку я поставил этот код в onCreate () BaseActivity.java, но нет обратного вызова успеха или неудачи :)

Durgesh Patel 30.05.2018 07:58

@kevanaghera, если вы хотите использовать только свой собственный обработчик исключений вместо аварийной обработки, вам просто нужно использовать Thread.setDefaultUncaughtExceptionHandler(UncaughtExceptionH‌​andler); 'в методе onCreate класса приложения, чтобы поймать неперехваченное исключение.

Priyank Patel 30.05.2018 08:01

@kevanaghera, я уже знал это. :) см. описание моего вопроса. :)

Durgesh Patel 30.05.2018 08:07

У меня это не работает. Мое требование - запустить действие обратной связи после сбоя и одновременно зарегистрировать фатальное исключение в Crashlytics, при этом приложение не будет отображать диалоговое окно сбоя по умолчанию и запрашивать перезапуск приложения.

Rahul Gurnani 10.10.2018 08:33

Хорошо, я исследовал этот вопрос.

Вы не должны создавать собственный обработчик исключений внутри BaseActivity. Лучше сделать это в своем классе Application. В случае 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)
    }

Для последней версии firebase crashlytics 17.x.x они настраивают обработчик неперехваченных исключений внутри Content Provider, чтобы разработчик не передавал контекст и вручную инициализировал. Это сделано для автоматической инициализации firebase при запуске приложения. Таким образом, даже если мы настроим наш обработчик неперехваченных исключений в классе Application oncreate, наша реализация переопределяет firebase, и о сбоях не будет сообщаться обработчику исключений firebase.

Исправление: чтобы исправить это, мы должны написать настраиваемого поставщика контента и установить для него максимальный приоритет в нашем приложении. Затем инициализируйте наш обработчик неперехваченных исключений внутри oncreate поставщика контента вместо того, чтобы делать это в классе приложения. Таким образом, наш будет инициализирован первым и не будет переопределять firebase.

Если мы это сделаем (добавим собственный ContentProvider), не переопределит ли обработчик Firebase нашу реализацию, и мы потеряем ее?

Maksym 25.10.2020 18:47

Если мы добавим настраиваемый ContentProvider для инициализации обработчика неперехваченных исключений, наш обработчик исключений будет инициализирован первым, и мы сначала получим все исключения, и он не будет конфликтовать с обработчиком исключений firebase, так что обработчик исключений firebase также получает те же исключения сразу после наш обработчик. Таким образом, сбой будет зарегистрирован в firebase без проблем. @Maksym

Niyas 02.11.2020 10:36

У меня тоже была такая же проблема в моем приложении. Как было предложено @niyas, я также использовал то же решение, и оно отлично работает для меня. Firebase использует поставщика контента для инициализации sdk firebase crashlytics и его обработчика неперехваченных исключений. Поэтому, если вы зарегистрируете свой обработчик неперехваченных исключений у настраиваемого поставщика контента с более высоким приоритетом, чем у firebase. Затем порядок получения обратного вызова обработчику меняется на обратный. Сначала обратный вызов отправляется обработчику Firebase, а затем вашему обработчику. Таким образом, firebase собирает трассировку стека для сбоев, и вы также получаете обратный вызов в обработчике для перезапуска приложения / или любого другого варианта использования. Я нашел это решение на github Вот ссылка!

Фрагмент кода:

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

Другие вопросы по теме