CustomActivityOnCrash


Source link: https://github.com/Ereza/CustomActivityOnCrash

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:

dependencies {

  compile 'cat.ereza:customactivityoncrash:2.1.0' 
}

...and you are done!

Of course, you can combine this library with any other crash handler such as Crashlytics, ACRA or Firebase, just set them up as you would normally.

Try it

Force an app crash by throwing an uncaught exception, using something like this in your code:

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:

@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:

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.

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.

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.

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.

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.

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.

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.

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

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:

<intent-filter>
  <!-- ... -->
  <action android:name="cat.ereza.customactivityoncrash.RESTART" /> </intent-filter>
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:

<activity
  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:

<intent-filter>
  <!-- ... -->
  <action android:name="cat.ereza.customactivityoncrash.ERROR" /> </intent-filter>
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:

<activity
  android:name="cat.ereza.customactivityoncrash.activity.DefaultErrorActivity"
  android:theme="@style/YourThemeHere"
  android:process=":error_activity" />

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:

<string name="customactivityoncrash_error_activity_error_occurred_explanation">An unexpected error occurred.\nSorry for the inconvenience.</string> <string name="customactivityoncrash_error_activity_restart_app">Restart app</string> <string name="customactivityoncrash_error_activity_close_app">Close app</string> <string name="customactivityoncrash_error_activity_error_details">Error details</string> <string name="customactivityoncrash_error_activity_error_details_title">Error details</string> <string name="customactivityoncrash_error_activity_error_details_close">Close</string> <string name="customactivityoncrash_error_activity_error_details_copy">Copy to clipboard</string> <string name="customactivityoncrash_error_activity_error_details_copied">Copied to clipboard</string> <string name="customactivityoncrash_error_activity_error_details_clipboard_label">Error information</string>

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:

CustomActivityOnCrash.getStackTraceFromIntent(getIntent());

Returns the stack trace that caused the error as a string.

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.

CustomActivityOnCrash.getConfigFromIntent(getIntent());

Returns the config of the library when the crash happened. Used to call some methods.

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.

CustomActivityOnCrash.restartApplicationWithIntent(activity, intent, config);

The same as CustomActivityOnCrash.restartApplication, but allows you to specify a custom intent.

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'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 in these cases:
    • With any custom UncaughtExceptionHandler set after initializing the library, that does not call back to the original handler.
    • With ACRA enabled and reporting mode set to TOAST or DIALOG.
  • 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.

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!

Resources

Inspired by cwac-adapter, RecyclerAdapterWrapper allows you to add more functionalities into an existing RecyclerView.Adapter. The wrapper delegates all behaviors to the wrapped object, you just need to override the specific behaviors you need.

A major bug in Play Services could be the reason GCM messages that you send aren't reaching your users. Pacemaker helps patch this bug by doing for Play Services what it should be doing on its own.

When showing a really enchanting explanatory animation to your users, but you know that after a while it'll get tedious and would stop users wanting to use your app. QuickSand is here to solve that problem.

Automatically manipulates the duration of animations depending on how many times the user has viewed them.

EndlessRecyclerViewAdapter support for RecyclerView.Adapter.

Fast Google Cloud Messaging (GCM) integration library for Android. Includes Topic Messaging.

A sliding tabs layout implemented with the RecyclerView.

Topics


2D Engines   3D Engines   9-Patch   Action Bars   Activities   ADB   Advertisements   Analytics   Animations   ANR   AOP   API   APK   APT   Architecture   Audio   Autocomplete   Background Processing   Backward Compatibility   Badges   Bar Codes   Benchmarking   Bitmaps   Bluetooth   Blur Effects   Bread Crumbs   BRMS   Browser Extensions   Build Systems   Bundles   Buttons   Caching   Camera   Canvas   Cards   Carousels   Changelog   Checkboxes   Cloud Storages   Color Analysis   Color Pickers   Colors   Comet/Push   Compass Sensors   Conferences   Content Providers   Continuous Integration   Crash Reports   Credit Cards   Credits   CSV   Curl/Flip   Data Binding   Data Generators   Data Structures   Database   Database Browsers   Date &   Debugging   Decompilers   Deep Links   Dependency Injections   Design   Design Patterns   Dex   Dialogs   Distributed Computing   Distribution Platforms   Download Managers   Drawables   Emoji   Emulators   EPUB   Equalizers &   Event Buses   Exception Handling   Face Recognition   Feedback &   File System   File/Directory   Fingerprint   Floating Action   Fonts   Forms   Fragments   FRP   FSM   Functional Programming   Gamepads   Games   Geocaching   Gestures   GIF   Glow Pad   Gradle Plugins   Graphics   Grid Views   Highlighting   HTML   HTTP Mocking   Icons   IDE   IDE Plugins   Image Croppers   Image Loaders   Image Pickers   Image Processing   Image Views   Instrumentation   Intents   Job Schedulers   JSON   Keyboard   Kotlin   Layouts   Library Demos   List View   List Views   Localization   Location   Lock Patterns   Logcat   Logging   Mails   Maps   Markdown   Mathematics   Maven Plugins   MBaaS   Media   Menus   Messaging   MIME   Mobile Web   Native Image   Navigation   NDK   Networking   NFC   NoSQL   Number Pickers   OAuth   Object Mocking   OCR Engines   OpenGL   ORM   Other Pickers   Parallax List   Parcelables   Particle Systems   Password Inputs   PDF   Permissions   Physics Engines   Platforms   Plugin Frameworks   Preferences   Progress Indicators   ProGuard   Properties   Protocol Buffer   Pull To   Purchases   Push/Pull   QR Codes   Quick Return   Radio Buttons   Range Bars   Ratings   Recycler Views   Resources   REST   Ripple Effects   RSS   Screenshots   Scripting   Scroll Views   SDK   Search Inputs   Security   Sensors   Services   Showcase Views   Signatures   Sliding Panels   Snackbars   SOAP   Social Networks   Spannable   Spinners   Splash Screens   SSH   Static Analysis   Status Bars   Styling   SVG   System   Tags   Task Managers   TDD &   Template Engines   Testing   Testing Tools   Text Formatting   Text Views   Text Watchers   Text-to   Toasts   Toolkits For   Tools   Tooltips   Trainings   TV   Twitter   Updaters   USB   User Stories   Utils   Validation   Video   View Adapters   View Pagers   Views   Watch Face   Wearable Data   Wearables   Weather   Web Tools   Web Views   WebRTC   WebSockets   Wheel Widgets   Wi-Fi   Widgets   Windows   Wizards   XML   XMPP   YAML   ZIP Codes