# CustomActivityOnCrash
**Repository Path**: blm1314/CustomActivityOnCrash
## Basic Information
- **Project Name**: CustomActivityOnCrash
- **Description**: Android library that allows launching a custom activity when your app crashes, instead of showing the hated "Unfortunately, X has stopped" dialog.
- **Primary Language**: Unknown
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 1
- **Created**: 2020-07-23
- **Last Updated**: 2021-11-06
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Custom Activity On Crash library
This library allows launching a custom activity when the app crashes, instead of showing the hated "Unfortunately, X has stopped" dialog.

## How to use
### One-step install
Add the following dependency to your build.gradle:
```gradle
dependencies {
compile 'cat.ereza:customactivityoncrash:2.3.0'
}
```
...and you are done!
**You can combine this library with other crash handlers such as Crashlytics or ACRA.**
If you are using Crashlytics, there's nothing to do, just use it normally.
If you are using ACRA, you should initialize it inside `Application.onCreate` instead of `Application.attachBaseContext`, and enable `alsoReportToAndroidFramework`, otherwise, it will not work.
### Try it
Force an app crash by throwing an uncaught exception, using something like this in your code:
```java
throw new RuntimeException("Boom!");
```
### Advanced setup
You can customize the behavior of this library in several ways by setting its configuration at any moment.
However, it's recommended to do it on your `Application` class so it becomes available as soon as possible.
Add a snippet like this to your `Application` class:
```java
@Override
public void onCreate() {
super.onCreate();
CaocConfig.Builder.create()
.backgroundMode(CaocConfig.BACKGROUND_MODE_SILENT) //default: CaocConfig.BACKGROUND_MODE_SHOW_CUSTOM
.enabled(false) //default: true
.showErrorDetails(false) //default: true
.showRestartButton(false) //default: true
.logErrorOnRestart(false) //default: true
.trackActivities(true) //default: false
.minTimeBetweenCrashesMs(2000) //default: 3000
.errorDrawable(R.drawable.ic_custom_drawable) //default: bug image
.restartActivity(YourCustomActivity.class) //default: null (your app's launch activity)
.errorActivity(YourCustomErrorActivity.class) //default: null (default error activity)
.eventListener(new YourCustomEventListener()) //default: null
.apply();
}
```
## Customization options
### Custom behavior
**Here is a more detailed explanation of each option that can be set using `CaocConfig.Builder`:**
```java
launchWhenInBackground(int);
```
> This method defines if the error activity should be launched when the app crashes while on background.
> There are three modes:
> - `CaocConfig.BACKGROUND_MODE_SHOW_CUSTOM`: launch the error activity even if the app is in background.
> - `CaocConfig.BACKGROUND_MODE_CRASH`: launch the default system error when the app is in background.
> - `CaocConfig.BACKGROUND_MODE_SILENT`: crash silently when the app is in background.
>
> The default is `CaocConfig.BACKGROUND_MODE_SHOW_CUSTOM`.
```java
enabled(boolean);
```
> Defines if CustomActivityOnCrash crash interception mechanism is enabled.
> Set it to `true` if you want CustomActivityOnCrash to intercept crashes,
> `false` if you want them to be treated as if the library was not installed.
> This can be used to enable or disable the library depending on flavors or buildTypes.
> The default is `true`.
```java
showErrorDetails(boolean);
```
> This method defines if the error activity must show a button with error details.
> If you set it to `false`, the button on the default error activity will disappear, thus disabling the user from seeing the stack trace.
> The default is `true`.
```java
trackActivities(boolean);
```
> This method defines if the library must track the activities the user visits and their lifecycle calls.
> This is displayed on the default error activity as part of the error details.
> The default is `false`.
```java
showRestartButton(boolean);
```
> This method defines if the error activity must show a "Restart app" button or a "Close app" button.
> If you set it to `false`, the button on the default error activity will close the app instead of restarting.
> If you set it to `true` and your app has no launch activity, it will still display a "Close app" button!
> The default is `true`.
```java
logErrorOnRestart(boolean);
```
> This controls if the stack trace must be relogged when the custom error activity is launched.
> This functionality exists because the Android Studio default Logcat view only shows the output for the
> current process. This makes it easier to see the stack trace of the crash. You can disable it if you
> don't want an extra log.
> The default is `true`.
```java
minTimeBetweenCrashesMs(boolean);
```
> Defines the time that must pass between app crashes to determine that we are not in a crash loop.
> If a crash has occurred less that this time ago, the error activity will not be launched and the system
> crash screen will be invoked.
> The default is `3000`.
```java
errorDrawable(Integer);
```
> This method allows changing the default upside-down bug image with an image of your choice.
> You can pass a resource id for a drawable or a mipmap.
> The default is `null` (the bug image is used).
```java
restartActivity(Class extends Activity>);
```
> This method sets the activity that must be launched by the error activity when the user presses the button to restart the app.
> If you don't set it (or set it to null), the library will use the first activity on your manifest that has an intent-filter with action
> `cat.ereza.customactivityoncrash.RESTART`, and if there is none, the default launchable activity on your app.
> If no launchable activity can be found and you didn't specify any, the "restart app" button will become a "close app" button,
> even if `showRestartButton` is set to `true`.
>
> As noted, you can also use the following intent-filter to specify the restart activity:
> ```xml
>
>
>
>
> ```
```java
errorActivity(Class extends Activity>);
```
> This method allows you to set a custom error activity to be launched, instead of the default one.
> Use it if you need further customization that is not just strings, colors or themes (see below).
> If you don't set it (or set it to null), the library will use the first activity on your manifest that has an intent-filter with action
> `cat.ereza.customactivityoncrash.ERROR`, and if there is none, a default error activity from the library.
> If you use this, the activity **must** be declared in your `AndroidManifest.xml`, with `process` set to `:error_activity`.
>
> Example:
> ```xml
> android:name="cat.ereza.customactivityoncrash.sample.CustomErrorActivity"
> android:label="@string/error_title"
> android:process=":error_activity" />
> ```
>
> As noted, you can also use the following intent-filter to specify the error activity:
> ```xml
>
>
>
>
> ```
```java
eventListener(EventListener);
```
> This method allows you to specify an event listener in order to get notified when the library shows the error activity, restarts or closes the app.
> The EventListener 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 event listener will be invoked.
> The default is `null`.
### Customization of the default activity
You can override several resources to customize the default activity:
**Theme:**
The activity uses your application theme by default. It must be a child of `Theme.AppCompat` or a default one will be used.
If you want to specify a specific theme only for the error activity, you can do so by redeclaring it on your manifest like this:
```xml
```
**Image:**
By default, an image of a bug is displayed. You can change it to any image by using the provided `errorDrawable(int)` method.
You can also do it the old way and create a `customactivityoncrash_error_image` drawable on all density buckets (mdpi, hdpi, xhdpi, xxhdpi and xxxhdpi).
**Strings:**
You can provide new strings and translations for the default error activity strings by overriding the following strings:
```xml
An unexpected error occurred.\nSorry for the inconvenience.
Restart app
Close app
Error details
Error details
Close
Copy to clipboard
Copied to clipboard
Error information
```
*There is a `sample` project module with examples of these overrides. If in doubt, check the code in that module.*
### Completely custom error activity
If you choose to create your own completely custom error activity, you can use these methods:
```java
CustomActivityOnCrash.getStackTraceFromIntent(getIntent());
```
> Returns the stack trace that caused the error as a string.
```java
CustomActivityOnCrash.getAllErrorDetailsFromIntent(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.
```java
CustomActivityOnCrash.getConfigFromIntent(getIntent());
```
> Returns the config of the library when the crash happened. Used to call some methods.
```java
CustomActivityOnCrash.restartApplication(activity, config);
```
> Kills the current process and restarts the app again with a `startActivity()` to the passed intent.
> You **MUST** call this to restart the app, or you will end up having several `Application` class instances and experience multiprocess issues.
```java
CustomActivityOnCrash.restartApplicationWithIntent(activity, intent, config);
```
> The same as `CustomActivityOnCrash.restartApplication`, but allows you to specify a custom intent.
```java
CustomActivityOnCrash.closeApplication(activity, eventListener);
```
> Closes the app and kills the current process.
> You **MUST** call this to close the app, or you will end up having several Application class instances and experience multiprocess issues.
**The `sample` project module includes an example of a custom error activity. If in doubt, check the code in that module.**
## Using Proguard?
No need to add special rules, the library should work even with obfuscation.
## Inner workings
This library relies on the `Thread.setDefaultUncaughtExceptionHandler` method.
When an exception is caught by the library's `UncaughtExceptionHandler` it does the following:
1. Captures the stack trace that caused the crash
2. Launches a new intent to the error activity in a new process passing the crash info as an extra.
3. Kills the current process.
The inner workings are based on [ACRA](https://github.com/ACRA/acra)'s dialog reporting mode with some minor tweaks. Look at the code if you need more detail about how it works.
## Incompatibilities
* CustomActivityOnCrash will not work with any custom `UncaughtExceptionHandler` set after initializing the library that does not call back to the original handler.
* If your app initialization or error activity crash, there is a possibility of entering an infinite restart loop (this is checked by the library for the most common cases, but could happen in rarer cases).
* The library has not been tested with multidex enabled. It uses Class.forName() to load classes, so maybe that could cause some problem in API<21. If you test it with such configuration, please provide feedback!
* The library has not been tested with multiprocess apps. If you test it with such configuration, please provide feedback too!
## Disclaimers
* This will not avoid ANRs from happening.
* This will not catch native errors.
* There is no guarantee that this will work on every device.
* This library will not make you toast for breakfast :)
## Contributing & license
Any contribution in order to make this library better will be welcome!
The library is licensed under the [Apache License 2.0](https://github.com/Ereza/CustomActivityOnCrash/blob/master/LICENSE).
The bug image used in the default error activity is licensed under CC-BY by Riff: https://www.sketchport.com/drawing/6119265933459456/lady-bug
If you use the image in your app, don't forget to mention that!