diff --git a/README.md b/README.md index b8fa82e..45e31a5 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ public void onCreate() { .restartActivity(YourCustomActivity.class) //default: null (your app's launch activity) .errorActivity(YourCustomErrorActivity.class) //default: null (default error activity) .eventListener(new YourCustomEventListener()) //default: null + .customCrashDataCollector(new YourCustomCrashDataCollector()) //default: null .apply(); //If you use Firebase Crashlytics or ACRA, please initialize them here as explained above. @@ -181,6 +182,15 @@ eventListener(EventListener); > If you set it to `null`, no event listener will be invoked. > The default is `null`. +```java +customCrashDataCollector(CustomCrashDataCollector); +``` +> This method allows you to specify a custom crash data collector that will be invoked when a crash occurs. +> This additional data will be added to the "error details" view on the default error activity, or you can use it in your custom error activity. +> The CustomCrashDataCollector you provide can not be an anonymous or non-static inner class, because it needs to be serialized by the library. The library will throw an exception if you try to set an invalid class. +> If you set it to `null`, no custom crash data will be collected. +> The default is `null`. + ### Customization of the default activity You can override several resources to customize the default activity: @@ -223,15 +233,25 @@ You can provide new strings and translations for the default error activity stri If you choose to create your own completely custom error activity, you can use these methods: +```java +CustomActivityOnCrash.getAllErrorDetailsFromIntent(getIntent()); +``` +> Returns several error details including the stack trace that caused the error, the activity log (if available) and the custom crash data (if available), as a string. This is used in the default error activity error details dialog. + ```java CustomActivityOnCrash.getStackTraceFromIntent(getIntent()); ``` > Returns the stack trace that caused the error as a string. ```java -CustomActivityOnCrash.getAllErrorDetailsFromIntent(getIntent()); +CustomActivityOnCrash.getActivityLogFromIntent(getIntent()); +``` +> Returns the activity log as a string if `trackActivities` was enabled, `null` otherwise. + +```java +CustomActivityOnCrash.getCustomCrashDataFromIntent(getIntent()); ``` -> Returns several error details including the stack trace that caused the error, as a string. This is used in the default error activity error details dialog. +> Returns the custom crash data collected with your `CustomCrashDataCollector` if `customCrashDataCollector` was enabled, `null` otherwise. ```java CustomActivityOnCrash.getConfigFromIntent(getIntent()); diff --git a/library/src/main/java/cat/ereza/customactivityoncrash/CustomActivityOnCrash.java b/library/src/main/java/cat/ereza/customactivityoncrash/CustomActivityOnCrash.java index 36b2350..db4dbdc 100644 --- a/library/src/main/java/cat/ereza/customactivityoncrash/CustomActivityOnCrash.java +++ b/library/src/main/java/cat/ereza/customactivityoncrash/CustomActivityOnCrash.java @@ -59,9 +59,9 @@ public final class CustomActivityOnCrash { //Extras passed to the error activity private static final String EXTRA_CONFIG = "cat.ereza.customactivityoncrash.EXTRA_CONFIG"; - private static final String EXTRA_CUSTOM_CRASH_DATA = "cat.ereza.customactivityoncrash.EXTRA_CUSTOM_CRASH_DATA"; private static final String EXTRA_STACK_TRACE = "cat.ereza.customactivityoncrash.EXTRA_STACK_TRACE"; private static final String EXTRA_ACTIVITY_LOG = "cat.ereza.customactivityoncrash.EXTRA_ACTIVITY_LOG"; + private static final String EXTRA_CUSTOM_CRASH_DATA = "cat.ereza.customactivityoncrash.EXTRA_CUSTOM_CRASH_DATA"; //General constants private static final String INTENT_ACTION_ERROR_ACTIVITY = "cat.ereza.customactivityoncrash.ERROR"; @@ -154,11 +154,15 @@ public static void install(@Nullable final Context context) { } intent.putExtra(EXTRA_STACK_TRACE, stackTraceString); - CustomCrashDataCollector collector = config.getCustomCrashDataCollector(); - if (collector != null) { - intent.putExtra(EXTRA_CUSTOM_CRASH_DATA, collector.onCrash(intent)); + CustomCrashDataCollector collector = config.getCustomCrashDataCollector(); + if (collector != null) { + try { + intent.putExtra(EXTRA_CUSTOM_CRASH_DATA, collector.onCrash()); + } catch (Throwable t) { + Log.e(TAG, "An unknown error occurred while invoking the custom crash data collector's onCrash. Please check your implementation.", t); } - + } + if (config.isTrackActivities()) { StringBuilder activityLogStringBuilder = new StringBuilder(); while (!activityLog.isEmpty()) { @@ -284,7 +288,7 @@ public static String getStackTraceFromIntent(@NonNull Intent intent) { } /** - * Given an Intent, returns the custom collector trace extra from it. + * Given an Intent, returns the custom crash data extra from it. * * @param intent The Intent. Must not be null. * @return The custom collector trace, or null if not provided. @@ -366,10 +370,10 @@ public static String getAllErrorDetailsFromIntent(@NonNull Context context, @Non errorDetails += activityLog; } - String customTrace = getCustomCrashDataFromIntent(intent); - if (customTrace != null) { - errorDetails += "\nCustom trace: \n"; - errorDetails += customTrace; + String customCrashData = getCustomCrashDataFromIntent(intent); + if (customCrashData != null) { + errorDetails += "\nAdditional data: \n"; + errorDetails += customCrashData; } return errorDetails; @@ -755,9 +759,9 @@ public interface EventListener extends Serializable { } /** - * Interface to be called to register a custom crash data collector + * Interface to be called to collect additional crash data when a crash occurs. */ public interface CustomCrashDataCollector extends Serializable { - String onCrash(Intent intent); + String onCrash(); } } diff --git a/library/src/main/java/cat/ereza/customactivityoncrash/config/CaocConfig.java b/library/src/main/java/cat/ereza/customactivityoncrash/config/CaocConfig.java index c3bbd01..6d22b83 100644 --- a/library/src/main/java/cat/ereza/customactivityoncrash/config/CaocConfig.java +++ b/library/src/main/java/cat/ereza/customactivityoncrash/config/CaocConfig.java @@ -295,23 +295,6 @@ public Builder errorActivity(@Nullable Class errorActivityCl return this; } - /** - * Sets the custom error data collector class to launch when a crash occurs. - * If null, the default error activity will be used. - * - * @param collector The data collector. - * @throws IllegalArgumentException if the collector is an inner or anonymous class - */ - @NonNull - public Builder customCrashDataCollector(@Nullable CustomActivityOnCrash.CustomCrashDataCollector collector) { - if (collector != null && collector.getClass().getEnclosingClass() != null && !Modifier.isStatic(collector.getClass().getModifiers())) { - throw new IllegalArgumentException("The event listener cannot be an inner or anonymous class, because it will need to be serialized. Change it to a class of its own, or make it a static inner class."); - } else { - config.customCrashDataCollector = collector; - } - return this; - } - /** * Sets the main activity class that the error activity must launch when a crash occurs. * If not set or set to null, the default launch activity will be used. @@ -341,6 +324,23 @@ public Builder eventListener(@Nullable CustomActivityOnCrash.EventListener event return this; } + /** + * Sets the custom data collector class to invoke when a crash occurs. + * If not set or set to null, no custom data will be collected. + * + * @param collector The custom data collector. + * @throws IllegalArgumentException if the collector is an inner or anonymous class + */ + @NonNull + public Builder customCrashDataCollector(@Nullable CustomActivityOnCrash.CustomCrashDataCollector collector) { + if (collector != null && collector.getClass().getEnclosingClass() != null && !Modifier.isStatic(collector.getClass().getModifiers())) { + throw new IllegalArgumentException("The custom data collector cannot be an inner or anonymous class, because it will need to be serialized. Change it to a class of its own, or make it a static inner class."); + } else { + config.customCrashDataCollector = collector; + } + return this; + } + @NonNull public CaocConfig get() { return config; diff --git a/sample/src/main/java/cat/ereza/customactivityoncrash/sample/SampleCrashingApplication.java b/sample/src/main/java/cat/ereza/customactivityoncrash/sample/SampleCrashingApplication.java index cfee2bf..bd8922c 100644 --- a/sample/src/main/java/cat/ereza/customactivityoncrash/sample/SampleCrashingApplication.java +++ b/sample/src/main/java/cat/ereza/customactivityoncrash/sample/SampleCrashingApplication.java @@ -73,7 +73,10 @@ public void onCreate() { // .errorActivity(CustomErrorActivity.class) //This sets a EventListener to be notified of events regarding the error activity, //so you can, for example, report them to Google Analytics. -// .eventListener(new CustomEventListener()) +// .eventListener(new MyCustomEventListener()) + //This sets a CustomCrashDataCollector that is invoked when a crash occurs. This allows you to add more + //data to the error details. +// .customCrashDataCollector(new MyCustomCrashDataCollector()) .apply(); //Initialize your other error handler as normal. @@ -85,7 +88,7 @@ public void onCreate() { //enable alsoReportToAndroidFramework=true when initializing it or CustomActivityOnCrash will not work. } - private static class CustomEventListener implements CustomActivityOnCrash.EventListener { + private static class MyCustomEventListener implements CustomActivityOnCrash.EventListener { @Override public void onLaunchErrorActivity() { Log.i(TAG, "onLaunchErrorActivity()"); @@ -101,4 +104,11 @@ public void onCloseAppFromErrorActivity() { Log.i(TAG, "onCloseAppFromErrorActivity()"); } } + + private static class MyCustomCrashDataCollector implements CustomActivityOnCrash.CustomCrashDataCollector { + @Override + public String onCrash() { + return "This is additional data that will be shown in the error details."; + } + } }