Skip to content

Commit

Permalink
Upgrade dependencies and code for newest Gradle version, close #71, c…
Browse files Browse the repository at this point in the history
…lose #75 (via documentation)
  • Loading branch information
Ereza committed May 29, 2022
1 parent e98590a commit 0da0e89
Show file tree
Hide file tree
Showing 12 changed files with 148 additions and 183 deletions.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ dependencies {

...and you are done!

**You can combine this library with other crash handlers such as Crashlytics or ACRA.**
**You can combine this library with other crash handlers such as Firebase Crashlytics or ACRA.**

If you are using Crashlytics, there's nothing to do, just use it normally.
If you are using Firebase Crashlytics, you **must** call `FirebaseApp.initializeApp(this);` inside `onCreate` in your `Application` class.

If you are using ACRA, you should initialize it inside `Application.onCreate` instead of `Application.attachBaseContext`, and enable `alsoReportToAndroidFramework`, otherwise, it will not work.
If you are using ACRA, you **must** initialize it inside `onCreate` in your `Application` class, instead of `attachBaseContext`, and enable `alsoReportToAndroidFramework`, otherwise, CustomActivityOnCrash will not work.

### Try it

Expand Down Expand Up @@ -54,6 +54,8 @@ public void onCreate() {
.errorActivity(YourCustomErrorActivity.class) //default: null (default error activity)
.eventListener(new YourCustomEventListener()) //default: null
.apply();

//If you use Firebase Crashlytics or ACRA, please initialize them here as explained above.
}
```

Expand Down
6 changes: 3 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@

buildscript {
repositories {
jcenter()
mavenCentral()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.3'
classpath 'com.android.tools.build:gradle:7.2.0'
}
}

allprojects {
repositories {
jcenter()
mavenCentral()
google()
}
}
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
14 changes: 6 additions & 8 deletions library/build.gradle
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
apply plugin: 'com.android.library'

android {
compileSdkVersion 29
buildToolsVersion "29.0.3"
compileSdkVersion 32
resourcePrefix 'customactivityoncrash_'

defaultConfig {
minSdkVersion 14
targetSdkVersion 29
versionCode 12
versionName "2.3.1-SNAPSHOT"
minSdkVersion 16
targetSdkVersion 32
}
namespace 'cat.ereza.customactivityoncrash'
}

ext {
PUBLISH_GROUP_ID = 'cat.ereza'
PUBLISH_ARTIFACT_ID = 'customactivityoncrash'
PUBLISH_VERSION = android.defaultConfig.versionName
PUBLISH_VERSION = '2.4.0-SNAPSHOT'
}

apply from: "publish-mavencentral.gradle"

dependencies {
api 'androidx.appcompat:appcompat:1.1.0'
api 'androidx.appcompat:appcompat:1.4.1'
}
3 changes: 1 addition & 2 deletions library/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cat.ereza.customactivityoncrash">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<application>
<activity
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,92 +109,93 @@ public static void install(@Nullable final Context context) {
application = (Application) context.getApplicationContext();

//We define a default exception handler that does what we want so it can be called from Crashlytics/ACRA
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(@NonNull Thread thread, @NonNull final Throwable throwable) {
if (config.isEnabled()) {
Log.e(TAG, "App has crashed, executing CustomActivityOnCrash's UncaughtExceptionHandler", throwable);
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
if (config.isEnabled()) {
Log.e(TAG, "App has crashed, executing CustomActivityOnCrash's UncaughtExceptionHandler", throwable);

if (hasCrashedInTheLastSeconds(application)) {
Log.e(TAG, "App already crashed recently, not starting custom error activity because we could enter a restart loop. Are you sure that your app does not crash directly on init?", throwable);
if (oldHandler != null) {
oldHandler.uncaughtException(thread, throwable);
return;
}
} else {
setLastCrashTimestamp(application, new Date().getTime());

Class<? extends Activity> errorActivityClass = config.getErrorActivityClass();

if (hasCrashedInTheLastSeconds(application)) {
Log.e(TAG, "App already crashed recently, not starting custom error activity because we could enter a restart loop. Are you sure that your app does not crash directly on init?", throwable);
if (errorActivityClass == null) {
errorActivityClass = guessErrorActivityClass(application);
}

if (isStackTraceLikelyConflictive(throwable, errorActivityClass)) {
Log.e(TAG, "Your application class or your error activity have crashed, the custom activity will not be launched!");
if (oldHandler != null) {
oldHandler.uncaughtException(thread, throwable);
return;
}
} else {
setLastCrashTimestamp(application, new Date().getTime());

Class<? extends Activity> errorActivityClass = config.getErrorActivityClass();

if (errorActivityClass == null) {
errorActivityClass = guessErrorActivityClass(application);
} else if (config.getBackgroundMode() == CaocConfig.BACKGROUND_MODE_SHOW_CUSTOM || !isInBackground
|| (lastActivityCreatedTimestamp >= new Date().getTime() - TIME_TO_CONSIDER_FOREGROUND_MS)) {

final Intent intent = new Intent(application, errorActivityClass);
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
throwable.printStackTrace(pw);
String stackTraceString = sw.toString();

//Reduce data to 128KB so we don't get a TransactionTooLargeException when sending the intent.
//The limit is 1MB on Android but some devices seem to have it lower.
//See: http://developer.android.com/reference/android/os/TransactionTooLargeException.html
//And: http://stackoverflow.com/questions/11451393/what-to-do-on-transactiontoolargeexception#comment46697371_12809171
if (stackTraceString.length() > MAX_STACK_TRACE_SIZE) {
String disclaimer = " [stack trace too large]";
stackTraceString = stackTraceString.substring(0, MAX_STACK_TRACE_SIZE - disclaimer.length()) + disclaimer;
}
intent.putExtra(EXTRA_STACK_TRACE, stackTraceString);

if (isStackTraceLikelyConflictive(throwable, errorActivityClass)) {
Log.e(TAG, "Your application class or your error activity have crashed, the custom activity will not be launched!");
if (oldHandler != null) {
oldHandler.uncaughtException(thread, throwable);
return;
}
} else if (config.getBackgroundMode() == CaocConfig.BACKGROUND_MODE_SHOW_CUSTOM || !isInBackground
|| (lastActivityCreatedTimestamp >= new Date().getTime() - TIME_TO_CONSIDER_FOREGROUND_MS)) {

final Intent intent = new Intent(application, errorActivityClass);
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
throwable.printStackTrace(pw);
String stackTraceString = sw.toString();

//Reduce data to 128KB so we don't get a TransactionTooLargeException when sending the intent.
//The limit is 1MB on Android but some devices seem to have it lower.
//See: http://developer.android.com/reference/android/os/TransactionTooLargeException.html
//And: http://stackoverflow.com/questions/11451393/what-to-do-on-transactiontoolargeexception#comment46697371_12809171
if (stackTraceString.length() > MAX_STACK_TRACE_SIZE) {
String disclaimer = " [stack trace too large]";
stackTraceString = stackTraceString.substring(0, MAX_STACK_TRACE_SIZE - disclaimer.length()) + disclaimer;
}
intent.putExtra(EXTRA_STACK_TRACE, stackTraceString);

if (config.isTrackActivities()) {
StringBuilder activityLogStringBuilder = new StringBuilder();
while (!activityLog.isEmpty()) {
activityLogStringBuilder.append(activityLog.poll());
}
intent.putExtra(EXTRA_ACTIVITY_LOG, activityLogStringBuilder.toString());
if (config.isTrackActivities()) {
StringBuilder activityLogStringBuilder = new StringBuilder();
while (!activityLog.isEmpty()) {
activityLogStringBuilder.append(activityLog.poll());
}
intent.putExtra(EXTRA_ACTIVITY_LOG, activityLogStringBuilder.toString());
}

if (config.isShowRestartButton() && config.getRestartActivityClass() == null) {
//We can set the restartActivityClass because the app will terminate right now,
//and when relaunched, will be null again by default.
config.setRestartActivityClass(guessRestartActivityClass(application));
}
if (config.isShowRestartButton() && config.getRestartActivityClass() == null) {
//We can set the restartActivityClass because the app will terminate right now,
//and when relaunched, will be null again by default.
config.setRestartActivityClass(guessRestartActivityClass(application));
}

intent.putExtra(EXTRA_CONFIG, config);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
if (config.getEventListener() != null) {
intent.putExtra(EXTRA_CONFIG, config);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
if (config.getEventListener() != null) {
try {
config.getEventListener().onLaunchErrorActivity();
} catch (Throwable t) {
Log.e(TAG, "An unknown error occurred while invoking the event listener's onLaunchErrorActivity. Please check your implementation.", t);
}
application.startActivity(intent);
} else if (config.getBackgroundMode() == CaocConfig.BACKGROUND_MODE_CRASH) {
if (oldHandler != null) {
oldHandler.uncaughtException(thread, throwable);
return;
}
//If it is null (should not be), we let it continue and kill the process or it will be stuck
}
//Else (BACKGROUND_MODE_SILENT): do nothing and let the following code kill the process
}
final Activity lastActivity = lastActivityCreated.get();
if (lastActivity != null) {
//We finish the activity, this solves a bug which causes infinite recursion.
//See: https://github.com/ACRA/acra/issues/42
lastActivity.finish();
lastActivityCreated.clear();
application.startActivity(intent);
} else if (config.getBackgroundMode() == CaocConfig.BACKGROUND_MODE_CRASH) {
if (oldHandler != null) {
oldHandler.uncaughtException(thread, throwable);
return;
}
//If it is null (should not be), we let it continue and kill the process or it will be stuck
}
killCurrentProcess();
} else if (oldHandler != null) {
oldHandler.uncaughtException(thread, throwable);
//Else (BACKGROUND_MODE_SILENT): do nothing and let the following code kill the process
}
final Activity lastActivity = lastActivityCreated.get();
if (lastActivity != null) {
//We finish the activity, this solves a bug which causes infinite recursion.
//See: https://github.com/ACRA/acra/issues/42
lastActivity.finish();
lastActivityCreated.clear();
}
killCurrentProcess();
} else if (oldHandler != null) {
oldHandler.uncaughtException(thread, throwable);
}
});
application.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
Expand Down Expand Up @@ -373,7 +374,11 @@ public static void restartApplicationWithIntent(@NonNull Activity activity, @Non
intent.addCategory(Intent.CATEGORY_LAUNCHER);
}
if (config.getEventListener() != null) {
config.getEventListener().onRestartAppFromErrorActivity();
try {
config.getEventListener().onRestartAppFromErrorActivity();
} catch (Throwable t) {
Log.e(TAG, "An unknown error occurred while invoking the event listener's onRestartAppFromErrorActivity. Please check your implementation.", t);
}
}
activity.finish();
activity.startActivity(intent);
Expand All @@ -395,7 +400,11 @@ public static void restartApplication(@NonNull Activity activity, @NonNull CaocC
*/
public static void closeApplication(@NonNull Activity activity, @NonNull CaocConfig config) {
if (config.getEventListener() != null) {
config.getEventListener().onCloseAppFromErrorActivity();
try {
config.getEventListener().onCloseAppFromErrorActivity();
} catch (Throwable t) {
Log.e(TAG, "An unknown error occurred while invoking the event listener's onCloseAppFromErrorActivity. Please check your implementation.", t);
}
}
activity.finish();
killCurrentProcess();
Expand Down Expand Up @@ -485,7 +494,7 @@ private static String getBuildDateAsString(@NonNull Context context, @NonNull Da
buildDate = 0;
}

if (buildDate > 312764400000L) {
if (buildDate > 631152000000L) {
return dateFormat.format(new Date(buildDate));
} else {
return null;
Expand Down
Loading

0 comments on commit 0da0e89

Please sign in to comment.