diff --git a/appbase/build.properties b/appbase/build.properties
index c6b702b..1abad11 100644
--- a/appbase/build.properties
+++ b/appbase/build.properties
@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
-#Mon May 11 16:56:31 HKT 2026
+#Mon May 11 18:51:30 CST 2026
stageCount=7
libraryProject=libappbase
baseVersion=15.20
publishVersion=15.20.6
-buildCount=0
+buildCount=12
baseBetaVersion=15.20.7
diff --git a/libappbase/build.properties b/libappbase/build.properties
index ba0efde..1abad11 100644
--- a/libappbase/build.properties
+++ b/libappbase/build.properties
@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
-#Mon May 11 16:56:19 HKT 2026
+#Mon May 11 18:51:30 CST 2026
stageCount=7
libraryProject=libappbase
baseVersion=15.20
publishVersion=15.20.6
-buildCount=0
+buildCount=12
baseBetaVersion=15.20.7
diff --git a/libappbase/src/main/java/cc/winboll/studio/libappbase/utils/CrashHandleNotifyUtils.java b/libappbase/src/main/java/cc/winboll/studio/libappbase/utils/CrashHandleNotifyUtils.java
index 578e8c0..2b8832b 100644
--- a/libappbase/src/main/java/cc/winboll/studio/libappbase/utils/CrashHandleNotifyUtils.java
+++ b/libappbase/src/main/java/cc/winboll/studio/libappbase/utils/CrashHandleNotifyUtils.java
@@ -11,6 +11,7 @@ import android.text.TextUtils;
import cc.winboll.studio.libappbase.CrashHandler;
import cc.winboll.studio.libappbase.LogUtils;
+import cc.winboll.studio.libappbase.R;
/**
* 应用崩溃处理通知实用工具集(类库兼容版)
@@ -36,6 +37,21 @@ public class CrashHandleNotifyUtils {
private static final int FLAG_IMMUTABLE = 0x00000040;
/** 通知内容最大行数(控制在3行,超出部分省略) */
private static final int NOTIFICATION_MAX_LINES = 3;
+ /** 通知摘要最大长度 */
+ private static final int SUMMARY_MAX_LENGTH = 200;
+ /** 展开按钮广播Action */
+ private static final String ACTION_EXPAND = "cc.winboll.studio.libappbase.ACTION_EXPAND_CRASH";
+
+ private static Context sHostContext = null;
+ private static String sHostPackageName = "";
+ private static String sHostAppName = "";
+ private static Class> sReportCrashActivity = null;
+
+ // ====================== 正则表达式定义 ======================
+ private static final String REGEX_EXCEPTION_TYPE = "([\\w.]+Exception|[\\w.]+Error)";
+ private static final String REGEX_EXCEPTION_MESSAGE = "(?<=:\\s)(.+?)(?=\\n|\\r|$)";
+ private static final String REGEX_STACK_TRACE = "\\s+at\\s+([\\w.$]+)\\.([\\w<>]+)\\(([^:]+\\.java):(\\d+)\\)";
+ private static final String REGEX_CAUSE = "(?<=Caused by:\\s)" + REGEX_EXCEPTION_TYPE + "\\s*:";
// ====================== 对外核心方法 ======================
/**
@@ -104,11 +120,11 @@ public class CrashHandleNotifyUtils {
* @param errorLog 崩溃日志
* @param reportCrashActivity 跳转Activity
*/
- private static void sendCrashNotification(final Context hostContext,
- final String hostPackageName,
- final String hostAppName,
- final String errorLog,
- final Class> reportCrashActivity) {
+private static void sendCrashNotification(final Context hostContext,
+ final String hostPackageName,
+ final String hostAppName,
+ final String errorLog,
+ final Class> reportCrashActivity) {
final NotificationManager notificationManager =
(NotificationManager) hostContext.getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager == null) {
@@ -125,7 +141,7 @@ public class CrashHandleNotifyUtils {
LogUtils.e(TAG, "构建跳转PendingIntent失败");
return;
}
- final Notification notification = buildNotification(hostContext, hostAppName, errorLog, jumpIntent);
+ final Notification notification = buildNotification(hostContext, hostPackageName, hostAppName, errorLog, jumpIntent);
notificationManager.notify(CRASH_NOTIFY_ID, notification);
LogUtils.d(TAG, "崩溃通知发送成功,宿主包名:" + hostPackageName);
}
@@ -171,7 +187,7 @@ public class CrashHandleNotifyUtils {
if (Build.VERSION.SDK_INT >= API_LEVEL_ANDROID_12) {
flags |= FLAG_IMMUTABLE;
}
- return PendingIntent.getActivity(
+return PendingIntent.getActivity(
hostContext,
CRASH_NOTIFY_ID,
crashIntent,
@@ -186,6 +202,7 @@ public class CrashHandleNotifyUtils {
/**
* 构建Notification通知实例
* @param hostContext 宿主上下文
+ * @param hostPackageName 宿主包名
* @param hostAppName 宿主应用名
* @param errorLog 崩溃日志
* @param jumpIntent 点击跳转意图
@@ -193,6 +210,7 @@ public class CrashHandleNotifyUtils {
*/
@SuppressWarnings("deprecation")
private static Notification buildNotification(final Context hostContext,
+ final String hostPackageName,
final String hostAppName,
final String errorLog,
final PendingIntent jumpIntent) {
@@ -200,15 +218,15 @@ public class CrashHandleNotifyUtils {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
builder.setChannelId(CRASH_NOTIFY_CHANNEL_ID);
}
+ String briefInfo = extractBriefInfo(errorLog);
Notification.BigTextStyle bigTextStyle = new Notification.BigTextStyle();
- bigTextStyle.setSummaryText("日志已省略,下拉查看完整内容");
- bigTextStyle.bigText(errorLog);
bigTextStyle.setBigContentTitle(hostAppName + " 崩溃");
+ bigTextStyle.bigText(briefInfo);
+ bigTextStyle.setSummaryText("点击查看详情");
builder.setStyle(bigTextStyle);
-
builder.setSmallIcon(hostContext.getApplicationInfo().icon)
.setContentTitle(hostAppName + " 崩溃")
- .setContentText(getShortContent(errorLog))
+ .setContentText(briefInfo.split("\n")[0])
.setContentIntent(jumpIntent)
.setAutoCancel(true)
.setWhen(System.currentTimeMillis())
@@ -226,12 +244,76 @@ public class CrashHandleNotifyUtils {
* @param content 原始日志
* @return 缩略文案
*/
- private static String getShortContent(final String content) {
- if (content == null || content.isEmpty()) {
+ private static String getShortContent(final String errorLog) {
+ if (errorLog == null || errorLog.isEmpty()) {
return "无崩溃日志";
}
- final int maxLength = 80;
- return content.length() <= maxLength ? content : content.substring(0, maxLength) + "...";
+ String brief = extractBriefInfo(errorLog);
+ String firstLine = brief.split("\n")[0];
+ if (firstLine.length() > 80) {
+ firstLine = firstLine.substring(0, 80) + "...";
+ }
+ return firstLine;
+ }
+
+ /**
+ * 使用正则表达式从崩溃日志中提取简要信息
+ * @param crashLog 完整崩溃日志
+ * @return 简要崩溃信息
+ */
+ private static String extractBriefInfo(final String crashLog) {
+ if (crashLog == null || crashLog.isEmpty()) {
+ return "无崩溃日志";
+ }
+ StringBuilder brief = new StringBuilder();
+ try {
+ java.util.regex.Pattern exceptionPattern = java.util.regex.Pattern.compile(REGEX_EXCEPTION_TYPE);
+ java.util.regex.Matcher exceptionMatcher = exceptionPattern.matcher(crashLog);
+ if (exceptionMatcher.find()) {
+ brief.append(exceptionMatcher.group(1));
+ }
+ java.util.regex.Pattern messagePattern = java.util.regex.Pattern.compile(REGEX_EXCEPTION_MESSAGE);
+ java.util.regex.Matcher messageMatcher = messagePattern.matcher(crashLog);
+ if (messageMatcher.find()) {
+ String message = messageMatcher.group(1).trim();
+ if (message.length() > 100) {
+ message = message.substring(0, 100) + "...";
+ }
+ if (brief.length() > 0) {
+ brief.append(" - ");
+ }
+ brief.append(message);
+ }
+ java.util.regex.Pattern causePattern = java.util.regex.Pattern.compile(REGEX_CAUSE);
+ java.util.regex.Matcher causeMatcher = causePattern.matcher(crashLog);
+ if (causeMatcher.find()) {
+ if (brief.length() > 0) {
+ brief.append("\n");
+ }
+ brief.append("原因: ").append(causeMatcher.group(1));
+ }
+ java.util.regex.Pattern stackPattern = java.util.regex.Pattern.compile(REGEX_STACK_TRACE);
+ java.util.regex.Matcher stackMatcher = stackPattern.matcher(crashLog);
+ int lineCount = 0;
+ while (stackMatcher.find() && lineCount < 3) {
+ if (brief.length() > 0) {
+ brief.append("\n");
+ }
+ brief.append(" at ").append(stackMatcher.group(1)).append(".")
+ .append(stackMatcher.group(2)).append("(")
+ .append(stackMatcher.group(3)).append(":")
+ .append(stackMatcher.group(4)).append(")");
+ lineCount++;
+ }
+ if (brief.length() == 0) {
+ brief.append(crashLog.length() > SUMMARY_MAX_LENGTH ? crashLog.substring(0, SUMMARY_MAX_LENGTH) + "..." : crashLog);
+ }
+ } catch (Exception e) {
+ LogUtils.e(TAG, "提取崩溃简要信息失败", e);
+ brief.setLength(0);
+ brief.append(crashLog.length() > SUMMARY_MAX_LENGTH ? crashLog.substring(0, SUMMARY_MAX_LENGTH) + "..." : crashLog);
+ }
+ return brief.toString();
}
/**
diff --git a/libappbase/src/main/res/layout/notification_crash.xml b/libappbase/src/main/res/layout/notification_crash.xml
new file mode 100644
index 0000000..6fbe3e3
--- /dev/null
+++ b/libappbase/src/main/res/layout/notification_crash.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libappbase/src/main/res/layout/notification_crash_expanded.xml b/libappbase/src/main/res/layout/notification_crash_expanded.xml
new file mode 100644
index 0000000..0a1a118
--- /dev/null
+++ b/libappbase/src/main/res/layout/notification_crash_expanded.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
\ No newline at end of file