Compare commits

..

8 Commits

Author SHA1 Message Date
ZhanGSKen 0368f7c7b9 <libappbase>Library Release 15.21.7 2026-08-25 05:25:30 +08:00
ZhanGSKen ceaaea60cc <appbase>APK 15.21.7 release Publish. 2026-08-25 05:25:06 +08:00
MiMo dcb73e6d93 feat(appbase): 优化快捷方式配置与崩溃日志分享功能
1. 快捷方式改为静态XML配置(仅beta渠道)
   - 新增 res/xml/shortcuts.xml 定义静态快捷方式
   - AndroidManifest.xml 添加 meta-data 引用
   - MainActivity.setupShortcuts() 移除动态注册代码

2. 崩溃日志分享功能增强
   - CrashHandleNotifyUtils: 新增 appAPKName/emailTo 参数
   - ShareLogActivity: 添加邮件接收者(EXTRA_EMAIL)支持
   - 邮件标题格式: {应用名} - 崩溃日志
   - 邮件内容添加应用版本号和设备运行环境信息
   - 通知按钮名称改为: 发送日志给开发组

3. 调用方适配
   - App.java: 传入 APPBase 和 studio@winboll.cc
2026-08-25 05:16:28 +08:00
ZhanGSKen fc7b6a9b01 <libappbase>Library Release 15.21.6 2026-08-20 05:44:48 +08:00
ZhanGSKen bc8fcbc818 <appbase>APK 15.21.6 release Publish. 2026-08-20 05:43:20 +08:00
ZhanGSKen 03b47f0897 <libappbase>Library Release 15.21.5 2026-08-20 05:37:23 +08:00
ZhanGSKen d75a45712e <appbase>APK 15.21.5 release Publish. 2026-08-20 05:37:04 +08:00
ZhanGSKen 4e0e32d6c1 <libappbase>Library Release 15.21.4 2026-07-23 19:08:17 +08:00
9 changed files with 119 additions and 46 deletions
+4 -4
View File
@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Thu Jul 23 19:07:39 HKT 2026 #Tue Aug 25 05:25:26 HKT 2026
stageCount=5 stageCount=8
libraryProject=libappbase libraryProject=libappbase
baseVersion=15.21 baseVersion=15.21
publishVersion=15.21.4 publishVersion=15.21.7
buildCount=0 buildCount=0
baseBetaVersion=15.21.5 baseBetaVersion=15.21.8
+8
View File
@@ -10,6 +10,14 @@
tools:replace="android:icon" tools:replace="android:icon"
android:icon="@drawable/ic_winboll_beta"> android:icon="@drawable/ic_winboll_beta">
<activity
android:name=".MainActivity"
android:exported="true">
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/shortcuts"/>
</activity>
</application> </application>
</manifest> </manifest>
+3
View File
@@ -2,5 +2,8 @@
<resources> <resources>
<string name="app_name">APPBase+</string> <string name="app_name">APPBase+</string>
<string name="shortcut_exception_mail_settings_short">邮件设置</string>
<string name="shortcut_exception_mail_settings_long">异常邮件接收设置</string>
<string name="shortcut_exception_mail_settings_disabled">快捷方式不可用</string>
</resources> </resources>
+16
View File
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
<shortcut
android:shortcutId="exception_mail_settings"
android:shortcutShortLabel="@string/shortcut_exception_mail_settings_short"
android:shortcutLongLabel="@string/shortcut_exception_mail_settings_long"
android:shortcutDisabledMessage="@string/shortcut_exception_mail_settings_disabled"
android:enabled="true"
android:icon="@drawable/ic_winboll_beta">
<intent
android:action="android.intent.action.VIEW"
android:targetPackage="cc.winboll.studio.appbase.beta"
android:targetClass="cc.winboll.studio.appbase.develop.APPExcetionMailSettingsActivity"/>
<categories android:name="android.shortcut.conversation"/>
</shortcut>
</shortcuts>
@@ -55,7 +55,9 @@ public class App extends GlobalApplication {
this, this,
getPackageName(), getPackageName(),
stackTraceStr, stackTraceStr,
CrashActivity.class CrashActivity.class,
"APPBase",
"studio@winboll.cc"
); );
} }
} }
@@ -1,12 +1,8 @@
package cc.winboll.studio.appbase; package cc.winboll.studio.appbase;
import android.app.Activity; import android.app.Activity;
import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
import android.graphics.drawable.Icon;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.view.Menu; import android.view.Menu;
@@ -69,31 +65,11 @@ public class MainActivity extends Activity {
/** /**
* 注册桌面图标静态快捷方式 * 注册桌面图标静态快捷方式
* 长按桌面图标后显示快捷菜单,点击可直接打开异常邮件接收设置页面 * 长按桌面图标后显示快捷菜单,点击可直接打开异常邮件接收设置页面
* 静态快捷方式已通过 res/xml/shortcuts.xml 配置,此处无需动态注册
*/ */
private void setupShortcuts() { private void setupShortcuts() {
if (!"cc.winboll.studio.appbase.beta".equals(getPackageName())) { // 静态快捷方式仅在 beta 渠道生效,通过 AndroidManifest.xml 中的 meta-data 配置
return; // beta 渠道使用 res/xml/shortcuts.xml 定义快捷方式
}
ShortcutManager shortcutManager = getSystemService(ShortcutManager.class);
if (shortcutManager == null) {
return;
}
Intent intent = new Intent(this, APPExcetionMailSettingsActivity.class);
intent.setAction(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ShortcutInfo shortcut = new ShortcutInfo.Builder(this, "exception_mail_settings")
.setShortLabel("邮件设置")
.setLongLabel("异常邮件接收设置")
.setIcon(Icon.createWithResource(this, R.drawable.ic_winboll))
.setIntent(intent)
.build();
shortcutManager.setDynamicShortcuts(
java.util.Arrays.asList(shortcut)
);
} }
/** /**
+4 -4
View File
@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Thu Jul 23 19:07:39 HKT 2026 #Tue Aug 25 05:25:06 HKT 2026
stageCount=5 stageCount=8
libraryProject=libappbase libraryProject=libappbase
baseVersion=15.21 baseVersion=15.21
publishVersion=15.21.4 publishVersion=15.21.7
buildCount=0 buildCount=0
baseBetaVersion=15.21.5 baseBetaVersion=15.21.8
@@ -67,11 +67,15 @@ public class CrashHandleNotifyUtils {
* @param hostPackageName 宿主应用包名 * @param hostPackageName 宿主应用包名
* @param errorLog 崩溃日志内容 * @param errorLog 崩溃日志内容
* @param reportCrashActivity 崩溃详情跳转Activity类 * @param reportCrashActivity 崩溃详情跳转Activity类
* @param appAPKName 应用APK名称(用于邮件标题)
* @param emailTo 邮件接收者地址
*/ */
public static void handleUncaughtException(final android.app.Application hostApp, public static void handleUncaughtException(final android.app.Application hostApp,
final String hostPackageName, final String hostPackageName,
final String errorLog, final String errorLog,
final Class<?> reportCrashActivity) { final Class<?> reportCrashActivity,
final String appAPKName,
final String emailTo) {
LogUtils.d(TAG, "handleUncaughtException 进入方法"); LogUtils.d(TAG, "handleUncaughtException 进入方法");
if (hostApp == null || TextUtils.isEmpty(hostPackageName) || TextUtils.isEmpty(errorLog)) { if (hostApp == null || TextUtils.isEmpty(hostPackageName) || TextUtils.isEmpty(errorLog)) {
LogUtils.e(TAG, "handleUncaughtException 参数为空校验不通过"); LogUtils.e(TAG, "handleUncaughtException 参数为空校验不通过");
@@ -87,7 +91,14 @@ public class CrashHandleNotifyUtils {
sCrashLogCacheFilePath = crashLogFilePath; sCrashLogCacheFilePath = crashLogFilePath;
final Intent shareIntent = new Intent(hostApp, ShareLogActivity.class); final Intent shareIntent = new Intent(hostApp, ShareLogActivity.class);
shareIntent.putExtra(ShareLogActivity.EXTRA_CRASH_LOG_FILEPATH, crashLogFilePath); shareIntent.putExtra(ShareLogActivity.EXTRA_CRASH_LOG_FILEPATH, crashLogFilePath);
shareIntent.putExtra(ShareLogActivity.EXTRA_CRASH_LOG_SUBJECT, "崩溃日志"); String subject = "崩溃日志";
if (appAPKName != null && !appAPKName.isEmpty()) {
subject = appAPKName + " - 崩溃日志";
}
shareIntent.putExtra(ShareLogActivity.EXTRA_CRASH_LOG_SUBJECT, subject);
if (emailTo != null && !emailTo.isEmpty()) {
shareIntent.putExtra(ShareLogActivity.EXTRA_CRASH_LOG_EMAIL_TO, emailTo);
}
shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
final PendingIntent sharePendingIntent = createSharePendingIntent(hostApp, shareIntent); final PendingIntent sharePendingIntent = createSharePendingIntent(hostApp, shareIntent);
sendCrashNotification(hostApp, hostPackageName, hostAppName, errorLog, reportCrashActivity, sharePendingIntent); sendCrashNotification(hostApp, hostPackageName, hostAppName, errorLog, reportCrashActivity, sharePendingIntent);
@@ -109,7 +120,21 @@ public class CrashHandleNotifyUtils {
LogUtils.w(TAG, "未携带宿主包名,默认使用应用自身包名"); LogUtils.w(TAG, "未携带宿主包名,默认使用应用自身包名");
} }
final String errorLog = intent.getStringExtra(CrashHandler.EXTRA_CRASH_LOG); final String errorLog = intent.getStringExtra(CrashHandler.EXTRA_CRASH_LOG);
handleUncaughtException(hostApp, hostPackageName, errorLog, reportCrashActivity); handleUncaughtException(hostApp, hostPackageName, errorLog, reportCrashActivity, null, null);
}
/**
* 重载兼容方法:适配原有调用方式
* @param hostApp 宿主Application实例
* @param hostPackageName 宿主应用包名
* @param errorLog 崩溃日志内容
* @param reportCrashActivity 崩溃详情跳转Activity类
*/
public static void handleUncaughtException(final android.app.Application hostApp,
final String hostPackageName,
final String errorLog,
final Class<?> reportCrashActivity) {
handleUncaughtException(hostApp, hostPackageName, errorLog, reportCrashActivity, null, null);
} }
/** /**
@@ -355,7 +380,7 @@ public class CrashHandleNotifyUtils {
.setWhen(System.currentTimeMillis()) .setWhen(System.currentTimeMillis())
.setPriority(Notification.PRIORITY_DEFAULT); .setPriority(Notification.PRIORITY_DEFAULT);
if (shareIntent != null) { if (shareIntent != null) {
builder.addAction(android.R.drawable.ic_menu_send, "分享日志", shareIntent); builder.addAction(android.R.drawable.ic_menu_send, "发送日志给开发组", shareIntent);
} }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
return builder.build(); return builder.build();
@@ -2,6 +2,9 @@ package cc.winboll.studio.libappbase.utils;
import android.app.Activity; import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.widget.Toast; import android.widget.Toast;
@@ -21,6 +24,7 @@ public class ShareLogActivity extends Activity {
public static final String TAG = "ShareLogActivity"; public static final String TAG = "ShareLogActivity";
public static final String EXTRA_CRASH_LOG_FILEPATH = "crash_log_filepath"; public static final String EXTRA_CRASH_LOG_FILEPATH = "crash_log_filepath";
public static final String EXTRA_CRASH_LOG_SUBJECT = "crash_log_subject"; public static final String EXTRA_CRASH_LOG_SUBJECT = "crash_log_subject";
public static final String EXTRA_CRASH_LOG_EMAIL_TO = "crash_log_email_to";
@Override @Override
protected void onCreate(final Bundle savedInstanceState) { protected void onCreate(final Bundle savedInstanceState) {
@@ -43,10 +47,40 @@ public class ShareLogActivity extends Activity {
} }
final String subject = intent.getStringExtra(EXTRA_CRASH_LOG_SUBJECT); final String subject = intent.getStringExtra(EXTRA_CRASH_LOG_SUBJECT);
handleShareCrashLog(crashLogFilePath, subject); final String emailTo = intent.getStringExtra(EXTRA_CRASH_LOG_EMAIL_TO);
handleShareCrashLog(crashLogFilePath, subject, emailTo);
} }
private void handleShareCrashLog(final String crashLogFilePath, final String subject) { private String getAppInfo() {
StringBuilder sb = new StringBuilder();
sb.append("========== 应用信息 ==========\n");
try {
PackageInfo pkgInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
sb.append("应用包名: ").append(getPackageName()).append("\n");
sb.append("版本名称: ").append(pkgInfo.versionName).append("\n");
sb.append("版本号: ").append(pkgInfo.versionCode).append("\n");
} catch (PackageManager.NameNotFoundException e) {
sb.append("应用包名: ").append(getPackageName()).append("\n");
sb.append("版本信息: 获取失败\n");
}
sb.append("\n");
return sb.toString();
}
private String getDeviceInfo() {
StringBuilder sb = new StringBuilder();
sb.append("========== 设备信息 ==========\n");
sb.append("设备制造商: ").append(Build.MANUFACTURER).append("\n");
sb.append("设备型号: ").append(Build.MODEL).append("\n");
sb.append("设备名称: ").append(Build.DEVICE).append("\n");
sb.append("Android版本: ").append(Build.VERSION.RELEASE).append("\n");
sb.append("Android API: ").append(Build.VERSION.SDK_INT).append("\n");
sb.append("系统指纹: ").append(Build.FINGERPRINT).append("\n");
sb.append("\n");
return sb.toString();
}
private void handleShareCrashLog(final String crashLogFilePath, final String subject, final String emailTo) {
Log.d(TAG, "handleShareCrashLog crashLogFilePath = " + crashLogFilePath); Log.d(TAG, "handleShareCrashLog crashLogFilePath = " + crashLogFilePath);
final File crashLogFile = new File(crashLogFilePath); final File crashLogFile = new File(crashLogFilePath);
@@ -67,16 +101,25 @@ public class ShareLogActivity extends Activity {
} }
final String logContent = sb.toString(); final String logContent = sb.toString();
final Intent shareIntent = new Intent(Intent.ACTION_SEND); final StringBuilder emailContent = new StringBuilder();
shareIntent.setType("text/plain"); emailContent.append(getAppInfo());
shareIntent.putExtra(Intent.EXTRA_TEXT, logContent); emailContent.append(getDeviceInfo());
emailContent.append("========== 崩溃日志 ==========\n");
emailContent.append(logContent);
final Intent shareIntent = new Intent(Intent.ACTION_SENDTO);
shareIntent.setData(android.net.Uri.parse("mailto:"));
shareIntent.putExtra(Intent.EXTRA_TEXT, emailContent.toString());
if (subject != null && !subject.isEmpty()) { if (subject != null && !subject.isEmpty()) {
shareIntent.putExtra(Intent.EXTRA_SUBJECT, subject); shareIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
} else { } else {
shareIntent.putExtra(Intent.EXTRA_SUBJECT, "崩溃日志"); shareIntent.putExtra(Intent.EXTRA_SUBJECT, "崩溃日志");
} }
if (emailTo != null && !emailTo.isEmpty()) {
shareIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{emailTo});
}
startActivity(Intent.createChooser(shareIntent, "分享日志到")); startActivity(Intent.createChooser(shareIntent, "发送日志到"));
Log.d(TAG, "handleShareCrashLog 分享成功"); Log.d(TAG, "handleShareCrashLog 分享成功");
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG, "handleShareCrashLog 异常", e); Log.e(TAG, "handleShareCrashLog 异常", e);