From 749ec3d562a7a90a41607835b6ea19cb46199658 Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Tue, 13 Jan 2026 11:13:54 +0800 Subject: [PATCH 001/430] =?UTF-8?q?APPBase=20=E7=B1=BB=E5=BA=93=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E6=9B=B4=E6=96=B0=E4=B8=BA=2015.15.4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aes/build.properties | 4 ++-- libaes/build.gradle | 2 +- libaes/build.properties | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/aes/build.properties b/aes/build.properties index 7007fb4..c635273 100644 --- a/aes/build.properties +++ b/aes/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 03:37:56 HKT 2026 +#Tue Jan 13 03:12:47 GMT 2026 stageCount=2 libraryProject=libaes baseVersion=15.15 publishVersion=15.15.1 -buildCount=0 +buildCount=2 baseBetaVersion=15.15.2 diff --git a/libaes/build.gradle b/libaes/build.gradle index 881bae7..224b869 100644 --- a/libaes/build.gradle +++ b/libaes/build.gradle @@ -63,7 +63,7 @@ dependencies { //annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0' // WinBoLL库 nexus.winboll.cc 地址 - api 'cc.winboll.studio:libappbase:15.15.3' + api 'cc.winboll.studio:libappbase:15.15.4' // 备用库 jitpack.io 地址 //api 'com.github.ZhanGSKen:APPBase:appbase-v15.15.3' diff --git a/libaes/build.properties b/libaes/build.properties index 3da4b01..c635273 100644 --- a/libaes/build.properties +++ b/libaes/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 03:37:01 HKT 2026 +#Tue Jan 13 03:12:47 GMT 2026 stageCount=2 libraryProject=libaes baseVersion=15.15 publishVersion=15.15.1 -buildCount=0 +buildCount=2 baseBetaVersion=15.15.2 From e459791c676211cdfff137b908e772f62c076b19 Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Tue, 13 Jan 2026 11:19:15 +0800 Subject: [PATCH 002/430] APK 15.15.2 release Publish. --- aes/build.properties | 10 +++++----- libaes/build.properties | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/aes/build.properties b/aes/build.properties index c635273..b5fe9cf 100644 --- a/aes/build.properties +++ b/aes/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 03:12:47 GMT 2026 -stageCount=2 +#Tue Jan 13 11:19:15 HKT 2026 +stageCount=3 libraryProject=libaes baseVersion=15.15 -publishVersion=15.15.1 -buildCount=2 -baseBetaVersion=15.15.2 +publishVersion=15.15.2 +buildCount=0 +baseBetaVersion=15.15.3 diff --git a/libaes/build.properties b/libaes/build.properties index c635273..b5fe9cf 100644 --- a/libaes/build.properties +++ b/libaes/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 03:12:47 GMT 2026 -stageCount=2 +#Tue Jan 13 11:19:15 HKT 2026 +stageCount=3 libraryProject=libaes baseVersion=15.15 -publishVersion=15.15.1 -buildCount=2 -baseBetaVersion=15.15.2 +publishVersion=15.15.2 +buildCount=0 +baseBetaVersion=15.15.3 From 7ee79a44c7bfe4c9cc93bfacbeb6b1cc869ad7c0 Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Tue, 13 Jan 2026 11:19:29 +0800 Subject: [PATCH 003/430] Library Release 15.15.2 --- aes/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aes/build.properties b/aes/build.properties index b5fe9cf..95b9d36 100644 --- a/aes/build.properties +++ b/aes/build.properties @@ -1,5 +1,5 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 11:19:15 HKT 2026 +#Tue Jan 13 11:19:26 HKT 2026 stageCount=3 libraryProject=libaes baseVersion=15.15 From 504b78c04e37d64c7f6ab50eaa4f162e0ce7fa17 Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Tue, 13 Jan 2026 15:25:01 +0800 Subject: [PATCH 004/430] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=9F=BA=E7=A1=80?= =?UTF-8?q?=E7=AA=97=E5=8F=A3=E7=AE=A1=E7=90=86=E7=B1=BB=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aes/build.properties | 4 +- aes/src/main/AndroidManifest.xml | 3 + .../cc/winboll/studio/aes/AboutActivity.java | 47 +- .../cc/winboll/studio/aes/MainActivity.java | 12 +- .../winboll/studio/aes/WinBoLLActivity.java | 2 +- aes/src/main/res/layout/activity_about.xml | 2 +- libaes/build.properties | 4 +- .../libaes/activitys/BaseWinBoLLActivity.java | 59 ++ .../activitys/DrawerFragmentActivity.java | 45 +- .../libaes/interfaces/IWinBoLLActivity.java | 24 +- .../libaes/utils/WinBoLLActivityManager.java | 504 +++++++++--------- 11 files changed, 405 insertions(+), 301 deletions(-) create mode 100644 libaes/src/main/java/cc/winboll/studio/libaes/activitys/BaseWinBoLLActivity.java diff --git a/aes/build.properties b/aes/build.properties index 95b9d36..0104250 100644 --- a/aes/build.properties +++ b/aes/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 11:19:26 HKT 2026 +#Tue Jan 13 07:24:01 GMT 2026 stageCount=3 libraryProject=libaes baseVersion=15.15 publishVersion=15.15.2 -buildCount=0 +buildCount=25 baseBetaVersion=15.15.3 diff --git a/aes/src/main/AndroidManifest.xml b/aes/src/main/AndroidManifest.xml index c0ca77d..c732afa 100644 --- a/aes/src/main/AndroidManifest.xml +++ b/aes/src/main/AndroidManifest.xml @@ -3,6 +3,9 @@ xmlns:android="http://schemas.android.com/apk/res/android" package="cc.winboll.studio.aes"> + + + - * @Date 2026/01/11 15:16 + * @Date 2026/01/13 11:25 * @Describe 应用介绍窗口 */ -public class AboutActivity extends Activity { +public class AboutActivity extends BaseWinBoLLActivity { public static final String TAG = "AboutActivity"; + + private Toolbar mToolbar; + + @Override + public String getTag() { + return TAG; + } @Override protected void onCreate(Bundle savedInstanceState) { @@ -24,21 +33,33 @@ public class AboutActivity extends Activity { setContentView(R.layout.activity_about); // 设置工具栏 - Toolbar toolbar = findViewById(R.id.toolbar); - setActionBar(toolbar); - getActionBar().setSubtitle(TAG); - getActionBar().setDisplayHomeAsUpEnabled(true); - toolbar.setNavigationOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - finish(); // 点击导航栏返回按钮,触发 finish() - } - }); + initToolbar(); AboutView aboutView = findViewById(R.id.aboutview); aboutView.setAPPInfo(genDefaultAppInfo()); } + private void initToolbar() { + LogUtils.d(TAG, "initToolbar() 开始初始化"); + mToolbar = findViewById(R.id.toolbar); + if (mToolbar == null) { + LogUtils.e(TAG, "initToolbar() | Toolbar未找到"); + return; + } + setSupportActionBar(mToolbar); + mToolbar.setSubtitle(getTag()); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + mToolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + LogUtils.d(TAG, "导航栏 点击返回按钮"); + WinBoLLActivityManager.getInstance().resumeActivity(MainActivity.class); + WinBoLLActivityManager.getInstance().finish(AboutActivity.this); + } + }); + LogUtils.d(TAG, "initToolbar() 配置完成"); + } + private APPInfo genDefaultAppInfo() { LogUtils.d(TAG, "genDefaultAppInfo() 调用"); String branchName = "aes"; diff --git a/aes/src/main/java/cc/winboll/studio/aes/MainActivity.java b/aes/src/main/java/cc/winboll/studio/aes/MainActivity.java index 5360023..927c852 100644 --- a/aes/src/main/java/cc/winboll/studio/aes/MainActivity.java +++ b/aes/src/main/java/cc/winboll/studio/aes/MainActivity.java @@ -30,7 +30,7 @@ import cc.winboll.studio.libappbase.LogUtils; import com.a4455jkjh.colorpicker.ColorPickerDialog; import java.util.ArrayList; -public class MainActivity extends DrawerFragmentActivity implements IWinBoLLActivity { +public class MainActivity extends DrawerFragmentActivity { public static final String TAG = "MainActivity"; @@ -38,11 +38,6 @@ public class MainActivity extends DrawerFragmentActivity implements IWinBoLLActi TestAButtonFragment mTestAButtonFragment; TestViewPageFragment mTestViewPageFragment; - @Override - public Activity getActivity() { - return this; - } - @Override public String getTag() { return TAG; @@ -188,8 +183,9 @@ public class MainActivity extends DrawerFragmentActivity implements IWinBoLLActi Intent intent = new Intent(this, SettingsActivity.class); startActivity(intent); } else if (nItemId == R.id.item_about) { - Intent intent = new Intent(this, AboutActivity.class); - startActivity(intent); +// Intent intent = new Intent(this, AboutActivity.class); +// startActivity(intent); + WinBoLLActivityManager.getInstance().startWinBoLLActivity(this, AboutActivity.class); } diff --git a/aes/src/main/java/cc/winboll/studio/aes/WinBoLLActivity.java b/aes/src/main/java/cc/winboll/studio/aes/WinBoLLActivity.java index 76005db..bc45765 100644 --- a/aes/src/main/java/cc/winboll/studio/aes/WinBoLLActivity.java +++ b/aes/src/main/java/cc/winboll/studio/aes/WinBoLLActivity.java @@ -55,6 +55,6 @@ public class WinBoLLActivity extends AppCompatActivity implements IWinBoLLActivi @Override protected void onDestroy() { super.onDestroy(); - WinBoLLActivityManager.getInstance().registeRemove(this); + WinBoLLActivityManager.getInstance().finish(this); } } diff --git a/aes/src/main/res/layout/activity_about.xml b/aes/src/main/res/layout/activity_about.xml index bfd02eb..e003607 100644 --- a/aes/src/main/res/layout/activity_about.xml +++ b/aes/src/main/res/layout/activity_about.xml @@ -6,7 +6,7 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - diff --git a/libaes/build.properties b/libaes/build.properties index b5fe9cf..0104250 100644 --- a/libaes/build.properties +++ b/libaes/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 11:19:15 HKT 2026 +#Tue Jan 13 07:24:01 GMT 2026 stageCount=3 libraryProject=libaes baseVersion=15.15 publishVersion=15.15.2 -buildCount=0 +buildCount=25 baseBetaVersion=15.15.3 diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/activitys/BaseWinBoLLActivity.java b/libaes/src/main/java/cc/winboll/studio/libaes/activitys/BaseWinBoLLActivity.java new file mode 100644 index 0000000..00e49f0 --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/activitys/BaseWinBoLLActivity.java @@ -0,0 +1,59 @@ +package cc.winboll.studio.libaes.activitys; + +import android.app.Activity; +import android.os.Bundle; +import androidx.appcompat.app.AppCompatActivity; +import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity; +import cc.winboll.studio.libaes.models.AESThemeBean; +import cc.winboll.studio.libaes.utils.AESThemeUtil; +import cc.winboll.studio.libaes.utils.WinBoLLActivityManager; +import cc.winboll.studio.libappbase.ToastUtils; + +/** + * @Author 豆包&ZhanGSKen + * @Date 2026/01/13 14:22 + * @Describe BaseWinBollActivity + */ +public abstract class BaseWinBoLLActivity extends AppCompatActivity implements IWinBoLLActivity { + public static final String TAG = "BaseWinBoLLActivity"; + + protected volatile AESThemeBean.ThemeType mThemeType; + + @Override + protected void onCreate(Bundle savedInstanceState) { + mThemeType = getThemeType(); + setThemeStyle(); + super.onCreate(savedInstanceState); + WinBoLLActivityManager.getInstance().add(this); + ToastUtils.show(getTag() + ": onCreate"); + } + + AESThemeBean.ThemeType getThemeType() { + /*SharedPreferences sharedPreferences = getSharedPreferences( + SHAREDPREFERENCES_NAME, MODE_PRIVATE); + return AESThemeBean.ThemeType.values()[((sharedPreferences.getInt(DRAWER_THEME_TYPE, AESThemeBean.ThemeType.DEFAULT.ordinal())))]; + */ + return AESThemeBean.getThemeStyleType(AESThemeUtil.getThemeTypeID(getApplicationContext())); + } + + void setThemeStyle() { + //setTheme(AESThemeBean.getThemeStyle(getThemeType())); + setTheme(AESThemeUtil.getThemeTypeID(getApplicationContext())); + } + + @Override + protected void onDestroy() { + WinBoLLActivityManager.getInstance().registeRemove(this); + super.onDestroy(); + } + + // 子类必须实现getTag(),确保唯一标识 + @Override + public abstract String getTag(); + + @Override + public Activity getActivity() { + return this; + } +} + diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/activitys/DrawerFragmentActivity.java b/libaes/src/main/java/cc/winboll/studio/libaes/activitys/DrawerFragmentActivity.java index 430e4fd..1bbd12a 100644 --- a/libaes/src/main/java/cc/winboll/studio/libaes/activitys/DrawerFragmentActivity.java +++ b/libaes/src/main/java/cc/winboll/studio/libaes/activitys/DrawerFragmentActivity.java @@ -34,7 +34,7 @@ import cc.winboll.studio.libappbase.LogUtils; import com.baoyz.widget.PullRefreshLayout; import java.util.ArrayList; -public abstract class DrawerFragmentActivity extends AppCompatActivity implements AdapterView.OnItemClickListener { +public abstract class DrawerFragmentActivity extends BaseWinBoLLActivity implements AdapterView.OnItemClickListener { public static final String TAG = "DrawerFragmentActivity"; @@ -62,14 +62,19 @@ public abstract class DrawerFragmentActivity extends AppCompatActivity implement @Override protected void onCreate(Bundle savedInstanceState) { //mContext = this; - mThemeType = getThemeType(); - setThemeStyle(); +// mThemeType = getThemeType(); +// setThemeStyle(); super.onCreate(savedInstanceState); mActivityType = initActivityType(); initRootView(); LogUtils.d(TAG, "onCreate end."); } + @Override + public String getTag() { + return TAG; + } + @Override protected void onDestroy() { super.onDestroy(); @@ -157,22 +162,22 @@ public abstract class DrawerFragmentActivity extends AppCompatActivity implement super.onBackPressed(); } - void setThemeStyle() { - //setTheme(AESThemeBean.getThemeStyle(getThemeType())); - setTheme(AESThemeUtil.getThemeTypeID(getApplicationContext())); - } +// void setThemeStyle() { +// //setTheme(AESThemeBean.getThemeStyle(getThemeType())); +// setTheme(AESThemeUtil.getThemeTypeID(getApplicationContext())); +// } - boolean checkThemeStyleChange() { - return mThemeType != getThemeType(); - } +// boolean checkThemeStyleChange() { +// return mThemeType != getThemeType(); +// } - AESThemeBean.ThemeType getThemeType() { - /*SharedPreferences sharedPreferences = getSharedPreferences( - SHAREDPREFERENCES_NAME, MODE_PRIVATE); - return AESThemeBean.ThemeType.values()[((sharedPreferences.getInt(DRAWER_THEME_TYPE, AESThemeBean.ThemeType.DEFAULT.ordinal())))]; - */ - return AESThemeBean.getThemeStyleType(AESThemeUtil.getThemeTypeID(getApplicationContext())); - } +// AESThemeBean.ThemeType getThemeType() { +// /*SharedPreferences sharedPreferences = getSharedPreferences( +// SHAREDPREFERENCES_NAME, MODE_PRIVATE); +// return AESThemeBean.ThemeType.values()[((sharedPreferences.getInt(DRAWER_THEME_TYPE, AESThemeBean.ThemeType.DEFAULT.ordinal())))]; +// */ +// return AESThemeBean.getThemeStyleType(AESThemeUtil.getThemeTypeID(getApplicationContext())); +// } @Override public boolean onOptionsItemSelected(MenuItem item) { @@ -190,9 +195,9 @@ public abstract class DrawerFragmentActivity extends AppCompatActivity implement @Override protected void onResume() { super.onResume(); - if (checkThemeStyleChange()) { - recreate(); - } +// if (checkThemeStyleChange()) { +// recreate(); +// } ADsBannerView adsBannerView = findViewById(R.id.adsbanner); if (adsBannerView != null) { diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/interfaces/IWinBoLLActivity.java b/libaes/src/main/java/cc/winboll/studio/libaes/interfaces/IWinBoLLActivity.java index aa4805b..9760d2b 100644 --- a/libaes/src/main/java/cc/winboll/studio/libaes/interfaces/IWinBoLLActivity.java +++ b/libaes/src/main/java/cc/winboll/studio/libaes/interfaces/IWinBoLLActivity.java @@ -1,18 +1,24 @@ package cc.winboll.studio.libaes.interfaces; +import android.app.Activity; + /** * @Author ZhanGSKen * @Date 2025/05/10 09:34 - * @Describe WinBoLL 窗口操作接口 + * @Describe WinBoll 窗口操作接口(规范定义,职责单一) */ - import android.app.Activity; - -public abstract interface IWinBoLLActivity { +public interface IWinBoLLActivity { + String TAG = "IWinBoLLActivity"; + String ACTION_BIND = IWinBoLLActivity.class.getName() + ".ACTION_BIND"; - public static final String TAG = "IWinBoLLActivity"; + /** + * 获取当前Activity实例 + */ + Activity getActivity(); - public static final String ACTION_BIND = IWinBoLLActivity.class.getName() + ".ACTION_BIND"; - - public Activity getActivity(); - public String getTag(); + /** + * 获取Activity唯一标识(建议使用类名+UUID或固定唯一字符串) + */ + String getTag(); } + diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/utils/WinBoLLActivityManager.java b/libaes/src/main/java/cc/winboll/studio/libaes/utils/WinBoLLActivityManager.java index c95d302..cac2157 100644 --- a/libaes/src/main/java/cc/winboll/studio/libaes/utils/WinBoLLActivityManager.java +++ b/libaes/src/main/java/cc/winboll/studio/libaes/utils/WinBoLLActivityManager.java @@ -1,17 +1,12 @@ package cc.winboll.studio.libaes.utils; -/** - * @Author ZhanGSKen - * @Date 2025/05/10 10:02 - * @Describe 应用活动窗口管理器 - * 参考 : - * android 类似微信小程序多任务窗口 及 设置 TaskDescription 修改 icon 和 label - * https://blog.csdn.net/qq_29364417/article/details/109379915?app_version=6.4.2&code=app_1562916241&csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22109379915%22%2C%22source%22%3A%22weixin_38986226%22%7D&uLinkId=usr1mkqgl919blen&utm_source=app - */ import android.app.Activity; import android.app.ActivityManager; import android.content.Context; import android.content.Intent; +import android.os.Build; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity; import cc.winboll.studio.libappbase.GlobalApplication; import cc.winboll.studio.libappbase.LogActivity; @@ -20,273 +15,292 @@ import cc.winboll.studio.libappbase.ToastUtils; import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import java.util.Objects; +/** + * @Author ZhanGSKen + * @Date 2025/05/10 10:02 + * @Describe 应用活动窗口管理器(改进版) + * 核心能力:多任务窗口管理、Activity栈维护、任务前台恢复、批量关闭、前后Activity切换 + * 参考 :android 类似微信小程序多任务窗口 及 设置 TaskDescription 修改 icon 和 label + */ public class WinBoLLActivityManager { public static final String TAG = "WinBoLLActivityManager"; - public static final String EXTRA_TAG = "EXTRA_TAG"; + public enum WinBoLLUI_TYPE { APPLICATION, SERVICE } // 规范命名 大写开头 - public enum WinBoLLUI_TYPE { Aplication, Service } + private GlobalApplication mGlobalApplication; + private static volatile WinBoLLActivityManager sInstance; // 单例命名规范 + private final Map mActivityListMap; // 私有不可变 + private static volatile WinBoLLUI_TYPE sWinBoLLUI_TYPE = WinBoLLUI_TYPE.SERVICE; - GlobalApplication mGlobalApplication; - volatile static WinBoLLActivityManager _mIWinBoLLActivityManager; - Map mActivityListMap; - - volatile static WinBoLLUI_TYPE _WinBoLLUI_TYPE = WinBoLLUI_TYPE.Service; - public static void setWinBoLLUI_TYPE(WinBoLLUI_TYPE winBoLLUI_TYPE) { - _WinBoLLUI_TYPE = winBoLLUI_TYPE; - } - - public static WinBoLLUI_TYPE getWinBoLLUI_TYPE() { - return _WinBoLLUI_TYPE; - } - - WinBoLLActivityManager(GlobalApplication application) { + // 私有构造 杜绝外部实例化 + private WinBoLLActivityManager(@NonNull GlobalApplication application) { mGlobalApplication = application; - mActivityListMap = new HashMap(); + mActivityListMap = new HashMap<>(); // 菱形泛型简化 } + /** + * 初始化管理器(必须在Application onCreate中调用) + */ + public static void init(@NonNull T application) { + if (sInstance == null) { + synchronized (WinBoLLActivityManager.class) { + if (sInstance == null) { + sInstance = new WinBoLLActivityManager(application); + } + } + } + } + + /** + * 获取单例(需先调用init初始化,否则抛异常) + */ + @NonNull public static WinBoLLActivityManager getInstance() { - return _mIWinBoLLActivityManager; - } - - public static synchronized void init(T application) { - if (_mIWinBoLLActivityManager == null) { - _mIWinBoLLActivityManager = new WinBoLLActivityManager(application); + if (sInstance == null) { + throw new IllegalStateException("WinBoLLActivityManager 未初始化,请先在Application中调用 init()"); } + return sInstance; + } + + // ===================== 基础配置 ===================== + public static void setWinBoLLUI_TYPE(@NonNull WinBoLLUI_TYPE winBoLLUI_TYPE) { + sWinBoLLUI_TYPE = winBoLLUI_TYPE; + } + + @NonNull + public static WinBoLLUI_TYPE getWinBoLLUI_TYPE() { + return sWinBoLLUI_TYPE; + } + + // ===================== Activity 增删查 ===================== + /** + * 把Activity添加到管理中(自动去重) + */ + public void add(@NonNull T activity) { + String tag = activity.getTag(); + if (isActivityActive(tag)) { + LogUtils.d(TAG, String.format("Activity[%s] 已处于活跃状态,无需重复添加", tag)); + return; + } + mActivityListMap.put(tag, activity); + LogUtils.d(TAG, String.format("添加Activity:%s,当前管理数量:%d", tag, mActivityListMap.size())); } /** - * 把Activity添加到管理中 + * 判断指定Tag的Activity是否活跃 */ - public void add(T activity) { - if (isActivityActive(activity.getTag())) { - LogUtils.d(TAG, String.format("add(...) %s is active.", activity.getTag())); - } else { - mActivityListMap.put(activity.getTag(), activity); - LogUtils.d(TAG, String.format("Add activity : %s\n_mapActivityList.size() : %d", activity.getTag(), mActivityListMap.size())); - } - } - - // - // activity: 为 null 时, - // intent.putExtra 函数 "tag" 参数为 tag - // activity: 不为 null 时, - // intent.putExtra 函数 "tag" 参数为 activity.getTag() - // - public void startWinBoLLActivity(Context context, Class clazz) { - // 如果窗口已存在就重启窗口 - if (!resumeActivity(clazz)) { - // 新建一个任务窗口 - Intent intent = new Intent(context, clazz); - //打开多任务窗口 flags - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); - intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); - //intent.putExtra("tag", tag); - context.startActivity(intent); - } - } - - public void startWinBoLLActivity(Context context, Intent intent, Class clazz) { - // 如果窗口已存在就重启窗口 - if (!resumeActivity(clazz)) { - // 新建一个任务窗口 - //Intent intent = new Intent(context, clazz); - //打开多任务窗口 flags - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); - intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); - //intent.putExtra("tag", tag); - context.startActivity(intent); - } - } - - public void startLogActivity(Context context) { - // 如果窗口已存在就重启窗口 - //if (!resumeActivity(LogActivity.class)) { - // 新建一个任务窗口 - Intent intent = new Intent(context, LogActivity.class); - //打开多任务窗口 flags - // Define the bounds. -// Rect bounds = new Rect(0, 0, 800, 200); -// // Set the bounds as an activity option. -// ActivityOptions options = ActivityOptions.makeBasic(); -// options.setLaunchBounds(bounds); - intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); - intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); - - //intent.putExtra(EXTRA_TAG, tag); - - //context.startActivity(intent, options.toBundle()); - context.startActivity(intent); - //} - } - - // - // 判断 tag 绑定的 Activity 是否已经创建 - // - public boolean isActivityActive(String tag) { - return mActivityListMap.get(tag) != null; - } - - Activity getActivityByTag(String tag) { - return (mActivityListMap.get(tag) == null) ?null: mActivityListMap.get(tag).getActivity(); - } - - - // - // 找到tag 绑定的 BaseActivity ,通过 getTaskId() 移动到前台 - // - public boolean resumeActivity(Class clazz) { - try { - Activity activity = getActivityByTag(clazz.newInstance().getTag()); - if (activity != null) { - return resumeActivity(activity); - } - } catch (InstantiationException | IllegalAccessException e) { - LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); - } - return false; - } - - // - // 找到tag 绑定的 BaseActivity ,通过 getTaskId() 移动到前台 - // - public boolean resumeActivity(String tag) { - Activity activity = getActivityByTag(tag); - if (activity != null) { - return resumeActivity(activity); - } - return false; - } - - // - // 找到tag 绑定的 BaseActivity ,通过 getTaskId() 移动到前台 - // - public boolean resumeActivity(Activity activity) { - ActivityManager am = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE); - //返回启动它的根任务(home 或者 MainActivity) - //Intent intent = new Intent(mContext, activity.getClass()); - //TaskStackBuilder stackBuilder = TaskStackBuilder.create(mContext); - //stackBuilder.addNextIntentWithParentStack(intent); - //stackBuilder.startActivities(); - am.moveTaskToFront(activity.getTaskId(), ActivityManager.MOVE_TASK_NO_USER_ACTION); - //ToastUtils.show("resumeActivity"); - return true; - } - - - /** - * 结束所有 Activity - */ - public void finishAll() { - try { - //ToastUtils.show(String.format("finishAll() size : %d", _mIWinBoLLActivityList.size())); - for (int i = mActivityListMap.size() - 1; i > -1; i--) { - IWinBoLLActivity iWinBoLLActivity = mActivityListMap.get(i); - ToastUtils.show("finishAll() activity"); - if (iWinBoLLActivity != null && iWinBoLLActivity.getActivity() != null && !iWinBoLLActivity.getActivity().isFinishing() && !iWinBoLLActivity.getActivity().isDestroyed()) { - //ToastUtils.show("activity != null ..."); - if (getWinBoLLUI_TYPE() == WinBoLLUI_TYPE.Service) { - // 结束窗口和最近任务栏, 建议前台服务类应用使用,可以方便用户再次调用 UI 操作。 - iWinBoLLActivity.getActivity().finishAndRemoveTask(); - //ToastUtils.show("finishAll() activity.finishAndRemoveTask();"); - } else if (getWinBoLLUI_TYPE() == WinBoLLUI_TYPE.Aplication) { - // 结束窗口保留最近任务栏,建议前台服务类应用使用,可以保持应用的系统自觉性。 - iWinBoLLActivity.getActivity().finish(); - //ToastUtils.show("finishAll() activity.finish();"); - } else { - ToastUtils.show("WinBollApplication.WinBollUI_TYPE error."); - } - } - } - } catch (Exception e) { - LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); - } + public boolean isActivityActive(@NonNull String tag) { + return mActivityListMap.containsKey(tag) && mActivityListMap.get(tag) != null; } /** - * 结束指定Activity + * 根据Tag获取Activity(空安全) */ - public void finish(T iWinBoLLActivity) { - try { - if (iWinBoLLActivity != null && iWinBoLLActivity.getActivity() != null && !iWinBoLLActivity.getActivity().isFinishing() && !iWinBoLLActivity.getActivity().isDestroyed()) { - //根据tag 移除 MyActivity - //String tag= activity.getTag(); - //_mIWinBoLLActivityList.remove(tag); - //ToastUtils.show("remove"); - //ToastUtils.show("_mIWinBoLLActivityArrayMap.size() " + Integer.toString(_mIWinBoLLActivityArrayMap.size())); - - // 窗口回调规则: - // [] 当前窗口位置 >> 调度出的窗口位置 - // ★:[0] 1 2 3 4 >> 1 - // ★:0 1 [2] 3 4 >> 1 - // ★:0 1 2 [3] 4 >> 2 - // ★:0 1 2 3 [4] >> 3 - // ★:[0] >> 直接关闭当前窗口 - Activity preActivity = getPreActivity(iWinBoLLActivity); - iWinBoLLActivity.getActivity().finish(); - if (preActivity != null) { - resumeActivity(preActivity); - } - } - - } catch (Exception e) { - LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); + @Nullable + public Activity getActivityByTag(@NonNull String tag) { + IWinBoLLActivity winBoLLActivity = mActivityListMap.get(tag); + if (winBoLLActivity == null) return null; + Activity activity = winBoLLActivity.getActivity(); + // 过滤已销毁/已结束的Activity + if (activity == null || activity.isFinishing() || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed())) { + registeRemove(winBoLLActivity); + return null; } + return activity; } - Activity getPreActivity(IWinBoLLActivity iWinBoLLActivity) { - try { - boolean bingo = false; - IWinBoLLActivity preIWinBoLLActivity = null; - for (Map.Entry entity : mActivityListMap.entrySet()) { - if (entity.getKey().equals(iWinBoLLActivity.getTag())) { - bingo = true; - LogUtils.d(TAG, "bingo"); - break; - } - preIWinBoLLActivity = entity.getValue(); - } - - if (bingo) { - return preIWinBoLLActivity.getActivity(); - } - } catch (Exception e) { - LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); - } - - return null; - } - - public boolean registeRemove(T iWinBoLLActivity) { - IWinBoLLActivity iWinBoLLActivityTest = mActivityListMap.get(iWinBoLLActivity.getTag()); - if (iWinBoLLActivityTest != null) { - mActivityListMap.remove(iWinBoLLActivity.getTag()); + /** + * 移除指定Activity(销毁时调用) + */ + public boolean registeRemove(@NonNull T iWinBoLLActivity) { + String tag = iWinBoLLActivity.getTag(); + if (mActivityListMap.containsKey(tag)) { + mActivityListMap.remove(tag); + LogUtils.d(TAG, String.format("移除Activity:%s,剩余管理数量:%d", tag, mActivityListMap.size())); return true; } return false; } - public void printAvtivityListInfo() { - if (!mActivityListMap.isEmpty()) { - StringBuilder sb = new StringBuilder("Map entries : " + Integer.toString(mActivityListMap.size())); - Iterator> iterator = mActivityListMap.entrySet().iterator(); - while (iterator.hasNext()) { - Map.Entry entry = iterator.next(); - sb.append("\nKey: " + entry.getKey() + ", \nValue: " + entry.getValue().getTag()); - //ToastUtils.show("\nKey: " + entry.getKey() + ", Value: " + entry.getValue().getTag()); - } - sb.append("\nMap entries end."); - LogUtils.d(TAG, sb.toString()); - } else { - LogUtils.d(TAG, "The map is empty."); + // ===================== Activity 启动 ===================== + /** + * 启动WinBoLLActivity(存在则前台恢复,不存在则新建多任务窗口) + */ + public void startWinBoLLActivity(@NonNull Context context, @NonNull Class clazz) { + if (!resumeActivity(clazz)) { + Intent intent = new Intent(context, clazz); + setMultiTaskFlags(intent); + context.startActivity(intent); } } + + /** + * 带Intent参数启动WinBoLLActivity + */ + public void startWinBoLLActivity(@NonNull Context context, @NonNull Intent intent, @NonNull Class clazz) { + if (!resumeActivity(clazz)) { + setMultiTaskFlags(intent); + context.startActivity(intent); + } + } + + /** + * 启动日志页面(固定多任务模式) + */ + public void startLogActivity(@NonNull Context context) { + Intent intent = new Intent(context, LogActivity.class); + setMultiTaskFlags(intent); + intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT); // 分屏相关 + context.startActivity(intent); + } + + /** + * 设置多任务窗口通用Flags + */ + private void setMultiTaskFlags(@NonNull Intent intent) { + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); + intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); + } + + // ===================== Activity 前台恢复 ===================== + /** + * 根据Activity类 恢复前台(反射获取Tag,需保证无参构造) + */ + public boolean resumeActivity(@NonNull Class clazz) { + try { + T instance = clazz.newInstance(); + return resumeActivity(instance.getTag()); + } catch (InstantiationException | IllegalAccessException e) { + LogUtils.e(TAG, "恢复Activity失败,类需提供无参构造", e); + } + return false; + } + + /** + * 根据Tag 恢复Activity前台 + */ + public boolean resumeActivity(@NonNull String tag) { + Activity activity = getActivityByTag(tag); + return activity != null && resumeActivity(activity); + } + + /** + * 恢复指定Activity到前台(适配高版本权限) + */ + @SuppressWarnings("deprecation") + public boolean resumeActivity(@NonNull Activity activity) { + if (activity.isFinishing() || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed())) { + return false; + } + try { + ActivityManager am = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE); + if (am == null) { + LogUtils.w(TAG, "获取ActivityManager失败,无法恢复前台"); + return false; + } + // Android 11+ 限制,低版本正常使用 + am.moveTaskToFront(activity.getTaskId(), ActivityManager.MOVE_TASK_NO_USER_ACTION); + //ToastUtils.show(String.format("Activity[%s] 已恢复到前台", activity.getClass().getSimpleName())); + LogUtils.d(TAG, String.format("Activity[%s] 已恢复到前台", activity.getClass().getSimpleName())); + return true; + } catch (SecurityException e) { + //ToastUtils.show("恢复Activity前台失败,缺少权限或系统限制 :" + e.getMessage()); + LogUtils.e(TAG, "恢复Activity前台失败,缺少权限或系统限制", e); + //ToastUtils.show("窗口恢复失败,请手动打开"); + return false; + } + } + + // ===================== Activity 关闭 ===================== + /** + * 结束所有管理的Activity(按UI类型选择关闭策略) + */ + public void finishAll() { + if (mActivityListMap.isEmpty()) { + LogUtils.d(TAG, "当前无管理的Activity,无需结束"); + return; + } + LogUtils.d(TAG, String.format("开始结束所有Activity,共%d个", mActivityListMap.size())); + Iterator> iterator = mActivityListMap.entrySet().iterator(); + while (iterator.hasNext()) { + IWinBoLLActivity winBoLLActivity = iterator.next().getValue(); + Activity activity = winBoLLActivity.getActivity(); + if (activity == null) { + iterator.remove(); + continue; + } + // 安全关闭,避免重复操作 + if (!activity.isFinishing() && !(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed())) { + if (sWinBoLLUI_TYPE == WinBoLLUI_TYPE.SERVICE) { + activity.finishAndRemoveTask(); // 结束+移除最近任务 + } else if (sWinBoLLUI_TYPE == WinBoLLUI_TYPE.APPLICATION) { + activity.finish(); // 仅结束页面 + } + } + iterator.remove(); // 移除已处理的项 + } + LogUtils.d(TAG, "所有Activity结束完成"); + } + + /** + * 结束指定Activity,自动恢复上一个Activity前台 + */ + public void finish(@NonNull T iWinBoLLActivity) { + Activity currentActivity = iWinBoLLActivity.getActivity(); + if (currentActivity == null || currentActivity.isFinishing() || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && currentActivity.isDestroyed())) { + registeRemove(iWinBoLLActivity); + return; + } + + // 先获取上一个Activity,再关闭当前 + Activity preActivity = getPreActivity(iWinBoLLActivity); + currentActivity.finish(); + registeRemove(iWinBoLLActivity); // 关闭后移除管理 + + // 恢复上一个Activity前台 + if (preActivity != null) { + resumeActivity(preActivity); + } + } + + /** + * 获取当前Activity的上一个栈内Activity(修复原遍历逻辑错误) + */ + @Nullable + private Activity getPreActivity(@NonNull IWinBoLLActivity currentActivity) { + String currentTag = currentActivity.getTag(); + IWinBoLLActivity preWinBoLLActivity = null; + for (Map.Entry entry : mActivityListMap.entrySet()) { + String tag = entry.getKey(); + if (Objects.equals(tag, currentTag)) { + break; // 找到当前Activity,循环终止,pre即为上一个 + } + preWinBoLLActivity = entry.getValue(); + } + return preWinBoLLActivity != null ? preWinBoLLActivity.getActivity() : null; + } + + // ===================== 调试辅助 ===================== + /** + * 打印所有管理的Activity信息(调试用) + */ + public void printActivityListInfo() { + if (mActivityListMap.isEmpty()) { + LogUtils.d(TAG, "当前管理的Activity列表为空"); + return; + } + StringBuilder sb = new StringBuilder(String.format("Activity管理列表(总数:%d)\n", mActivityListMap.size())); + for (Map.Entry entry : mActivityListMap.entrySet()) { + sb.append("Tag: ").append(entry.getKey()) + .append(" | Activity: ").append(entry.getValue().getActivity().getClass().getSimpleName()) + .append("\n"); + } + LogUtils.d(TAG, sb.toString()); + } } From 622d474410cad5c61a645a357fc1ddc4f437f272 Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Tue, 13 Jan 2026 15:29:29 +0800 Subject: [PATCH 005/430] APK 15.15.3 release Publish. --- aes/build.properties | 10 +++++----- libaes/build.properties | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/aes/build.properties b/aes/build.properties index 0104250..a3b0164 100644 --- a/aes/build.properties +++ b/aes/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 07:24:01 GMT 2026 -stageCount=3 +#Tue Jan 13 15:29:29 HKT 2026 +stageCount=4 libraryProject=libaes baseVersion=15.15 -publishVersion=15.15.2 -buildCount=25 -baseBetaVersion=15.15.3 +publishVersion=15.15.3 +buildCount=0 +baseBetaVersion=15.15.4 diff --git a/libaes/build.properties b/libaes/build.properties index 0104250..a3b0164 100644 --- a/libaes/build.properties +++ b/libaes/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 07:24:01 GMT 2026 -stageCount=3 +#Tue Jan 13 15:29:29 HKT 2026 +stageCount=4 libraryProject=libaes baseVersion=15.15 -publishVersion=15.15.2 -buildCount=25 -baseBetaVersion=15.15.3 +publishVersion=15.15.3 +buildCount=0 +baseBetaVersion=15.15.4 From aa2e8e1a723566d251f053960a0a3e0a8694e32a Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Tue, 13 Jan 2026 15:29:53 +0800 Subject: [PATCH 006/430] Library Release 15.15.3 --- aes/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aes/build.properties b/aes/build.properties index a3b0164..6021701 100644 --- a/aes/build.properties +++ b/aes/build.properties @@ -1,5 +1,5 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 15:29:29 HKT 2026 +#Tue Jan 13 15:29:50 HKT 2026 stageCount=4 libraryProject=libaes baseVersion=15.15 From 05a1fb13027e5bc2f3fb1652b2f81aed9d36cac7 Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Tue, 13 Jan 2026 15:36:23 +0800 Subject: [PATCH 007/430] =?UTF-8?q?=E5=8F=96=E6=B6=88=E7=AA=97=E5=8F=A3?= =?UTF-8?q?=E5=88=9B=E5=BB=BA=E6=97=B6=E7=9A=84=E5=90=90=E5=8F=B8=E8=B0=83?= =?UTF-8?q?=E8=AF=95=E4=BF=A1=E6=81=AF=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aes/build.properties | 4 ++-- libaes/build.properties | 4 ++-- .../winboll/studio/libaes/activitys/BaseWinBoLLActivity.java | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/aes/build.properties b/aes/build.properties index 6021701..83f9cb1 100644 --- a/aes/build.properties +++ b/aes/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 15:29:50 HKT 2026 +#Tue Jan 13 07:35:02 GMT 2026 stageCount=4 libraryProject=libaes baseVersion=15.15 publishVersion=15.15.3 -buildCount=0 +buildCount=1 baseBetaVersion=15.15.4 diff --git a/libaes/build.properties b/libaes/build.properties index a3b0164..83f9cb1 100644 --- a/libaes/build.properties +++ b/libaes/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 15:29:29 HKT 2026 +#Tue Jan 13 07:35:02 GMT 2026 stageCount=4 libraryProject=libaes baseVersion=15.15 publishVersion=15.15.3 -buildCount=0 +buildCount=1 baseBetaVersion=15.15.4 diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/activitys/BaseWinBoLLActivity.java b/libaes/src/main/java/cc/winboll/studio/libaes/activitys/BaseWinBoLLActivity.java index 00e49f0..9eb0672 100644 --- a/libaes/src/main/java/cc/winboll/studio/libaes/activitys/BaseWinBoLLActivity.java +++ b/libaes/src/main/java/cc/winboll/studio/libaes/activitys/BaseWinBoLLActivity.java @@ -25,7 +25,7 @@ public abstract class BaseWinBoLLActivity extends AppCompatActivity implements I setThemeStyle(); super.onCreate(savedInstanceState); WinBoLLActivityManager.getInstance().add(this); - ToastUtils.show(getTag() + ": onCreate"); + //ToastUtils.show(getTag() + ": onCreate"); } AESThemeBean.ThemeType getThemeType() { From 3e67a5d0a409f95b75a2b7a9cf2e0f8a86c32c54 Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Tue, 13 Jan 2026 15:37:28 +0800 Subject: [PATCH 008/430] APK 15.15.4 release Publish. --- aes/build.properties | 10 +++++----- libaes/build.properties | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/aes/build.properties b/aes/build.properties index 83f9cb1..9735e38 100644 --- a/aes/build.properties +++ b/aes/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 07:35:02 GMT 2026 -stageCount=4 +#Tue Jan 13 15:37:28 HKT 2026 +stageCount=5 libraryProject=libaes baseVersion=15.15 -publishVersion=15.15.3 -buildCount=1 -baseBetaVersion=15.15.4 +publishVersion=15.15.4 +buildCount=0 +baseBetaVersion=15.15.5 diff --git a/libaes/build.properties b/libaes/build.properties index 83f9cb1..9735e38 100644 --- a/libaes/build.properties +++ b/libaes/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 07:35:02 GMT 2026 -stageCount=4 +#Tue Jan 13 15:37:28 HKT 2026 +stageCount=5 libraryProject=libaes baseVersion=15.15 -publishVersion=15.15.3 -buildCount=1 -baseBetaVersion=15.15.4 +publishVersion=15.15.4 +buildCount=0 +baseBetaVersion=15.15.5 From 7ae716bccbbc935e0d41eed5b8cc76bf0142ee88 Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Tue, 13 Jan 2026 15:37:39 +0800 Subject: [PATCH 009/430] Library Release 15.15.4 --- aes/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aes/build.properties b/aes/build.properties index 9735e38..351f3e2 100644 --- a/aes/build.properties +++ b/aes/build.properties @@ -1,5 +1,5 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 15:37:28 HKT 2026 +#Tue Jan 13 15:37:37 HKT 2026 stageCount=5 libraryProject=libaes baseVersion=15.15 From aebf83bc445810273cea532c073e4f39998eacab Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Tue, 13 Jan 2026 16:10:31 +0800 Subject: [PATCH 010/430] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=9F=BA=E7=A1=80?= =?UTF-8?q?=E7=AA=97=E5=8F=A3=E7=B1=BB=E7=9A=84=E5=85=AC=E5=BC=80=E6=96=B9?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aes/build.properties | 4 +- libaes/build.properties | 4 +- .../libaes/activitys/BaseWinBoLLActivity.java | 296 +++++++++++++++++- .../activitys/DrawerFragmentActivity.java | 20 -- .../unittests/SecondaryLibraryActivity.java | 5 - 5 files changed, 289 insertions(+), 40 deletions(-) diff --git a/aes/build.properties b/aes/build.properties index 351f3e2..9a5bf85 100644 --- a/aes/build.properties +++ b/aes/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 15:37:37 HKT 2026 +#Tue Jan 13 08:09:32 GMT 2026 stageCount=5 libraryProject=libaes baseVersion=15.15 publishVersion=15.15.4 -buildCount=0 +buildCount=1 baseBetaVersion=15.15.5 diff --git a/libaes/build.properties b/libaes/build.properties index 9735e38..9a5bf85 100644 --- a/libaes/build.properties +++ b/libaes/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 15:37:28 HKT 2026 +#Tue Jan 13 08:09:32 GMT 2026 stageCount=5 libraryProject=libaes baseVersion=15.15 publishVersion=15.15.4 -buildCount=0 +buildCount=1 baseBetaVersion=15.15.5 diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/activitys/BaseWinBoLLActivity.java b/libaes/src/main/java/cc/winboll/studio/libaes/activitys/BaseWinBoLLActivity.java index 9eb0672..fc93fed 100644 --- a/libaes/src/main/java/cc/winboll/studio/libaes/activitys/BaseWinBoLLActivity.java +++ b/libaes/src/main/java/cc/winboll/studio/libaes/activitys/BaseWinBoLLActivity.java @@ -1,34 +1,56 @@ package cc.winboll.studio.libaes.activitys; import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.res.Configuration; +import android.content.res.Resources; import android.os.Bundle; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.View; +import android.view.ViewGroup; +import androidx.annotation.CallSuper; +import androidx.annotation.ContentView; +import androidx.annotation.IdRes; +import androidx.annotation.LayoutRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.StyleRes; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.ActionBarDrawerToggle; import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatDelegate; +import androidx.appcompat.view.ActionMode; +import androidx.appcompat.widget.Toolbar; +import androidx.core.app.TaskStackBuilder; import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity; import cc.winboll.studio.libaes.models.AESThemeBean; import cc.winboll.studio.libaes.utils.AESThemeUtil; import cc.winboll.studio.libaes.utils.WinBoLLActivityManager; -import cc.winboll.studio.libappbase.ToastUtils; /** * @Author 豆包&ZhanGSKen * @Date 2026/01/13 14:22 - * @Describe BaseWinBollActivity + * @Describe BaseWinBollActivity 【完整透传AppCompatActivity所有公开方法】 + * 继承链路:BaseWinBoLLActivity → AppCompatActivity → FragmentActivity,所有公开能力全暴露 */ public abstract class BaseWinBoLLActivity extends AppCompatActivity implements IWinBoLLActivity { - public static final String TAG = "BaseWinBoLLActivity"; - - protected volatile AESThemeBean.ThemeType mThemeType; - - @Override + public static final String TAG = "BaseWinBoLLActivity"; + + protected volatile AESThemeBean.ThemeType mThemeType; + + @Override protected void onCreate(Bundle savedInstanceState) { - mThemeType = getThemeType(); + mThemeType = getThemeType(); setThemeStyle(); super.onCreate(savedInstanceState); WinBoLLActivityManager.getInstance().add(this); - //ToastUtils.show(getTag() + ": onCreate"); + //ToastUtils.show(getTag() + ": onCreate"); } - AESThemeBean.ThemeType getThemeType() { + AESThemeBean.ThemeType getThemeType() { /*SharedPreferences sharedPreferences = getSharedPreferences( SHAREDPREFERENCES_NAME, MODE_PRIVATE); return AESThemeBean.ThemeType.values()[((sharedPreferences.getInt(DRAWER_THEME_TYPE, AESThemeBean.ThemeType.DEFAULT.ordinal())))]; @@ -36,7 +58,7 @@ public abstract class BaseWinBoLLActivity extends AppCompatActivity implements I return AESThemeBean.getThemeStyleType(AESThemeUtil.getThemeTypeID(getApplicationContext())); } - void setThemeStyle() { + void setThemeStyle() { //setTheme(AESThemeBean.getThemeStyle(getThemeType())); setTheme(AESThemeUtil.getThemeTypeID(getApplicationContext())); } @@ -55,5 +77,257 @@ public abstract class BaseWinBoLLActivity extends AppCompatActivity implements I public Activity getActivity() { return this; } + + // ===================== 完整暴露AppCompatActivity 所有公开方法(按类定义顺序)===================== +// @ContentView +// public BaseWinBoLLActivity(@LayoutRes int contentLayoutId) { +// super(contentLayoutId); +// } + + @Override + public void addContentView(View view, ViewGroup.LayoutParams params) { + super.addContentView(view, params); + } + + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(newBase); + } + + @Override + public void closeOptionsMenu() { + super.closeOptionsMenu(); + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + return super.dispatchKeyEvent(event); + } + + @Override + public T findViewById(@IdRes int id) { + return super.findViewById(id); + } + + @NonNull + @Override + public AppCompatDelegate getDelegate() { + return super.getDelegate(); + } + + @Nullable + @Override + public ActionBarDrawerToggle.Delegate getDrawerToggleDelegate() { + return super.getDrawerToggleDelegate(); + } + + @NonNull + @Override + public MenuInflater getMenuInflater() { + return super.getMenuInflater(); + } + + @Override + public Resources getResources() { + return super.getResources(); + } + + @Nullable + @Override + public ActionBar getSupportActionBar() { + return super.getSupportActionBar(); + } + + @Nullable + @Override + public Intent getSupportParentActivityIntent() { + return super.getSupportParentActivityIntent(); + } + + @Override + public void invalidateOptionsMenu() { + super.invalidateOptionsMenu(); + } + + @Override + public void onConfigurationChanged(@NonNull Configuration newMetrics) { + super.onConfigurationChanged(newMetrics); + } + + @Override + public void onContentChanged() { + super.onContentChanged(); + } + + @Override + public void onCreateSupportNavigateUpTaskStack(@NonNull TaskStackBuilder builder) { + super.onCreateSupportNavigateUpTaskStack(builder); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + return super.onKeyDown(keyCode, event); + } + +// +// @Override +// public final boolean onMenuItemSelected(int featureId, @NonNull MenuItem item) { +// return super.onMenuItemSelected(featureId, item); +// } + + @Override + public boolean onMenuOpened(int featureId, Menu menu) { + return super.onMenuOpened(featureId, menu); + } + + @Override + protected void onNightModeChanged(int mode) { + super.onNightModeChanged(mode); + } + + @Override + public void onPanelClosed(int featureId, @NonNull Menu menu) { + super.onPanelClosed(featureId, menu); + } + + @Override + protected void onPostCreate(@Nullable Bundle savedInstanceState) { + super.onPostCreate(savedInstanceState); + } + + @Override + protected void onPostResume() { + super.onPostResume(); + } + + @Override + public void onPrepareSupportNavigateUpTaskStack(@NonNull TaskStackBuilder builder) { + super.onPrepareSupportNavigateUpTaskStack(builder); + } + + @Override + protected void onStart() { + super.onStart(); + } + + @Override + protected void onStop() { + super.onStop(); + } + + @CallSuper + @Override + public void onSupportActionModeFinished(@NonNull ActionMode mode) { + super.onSupportActionModeFinished(mode); + } + + @CallSuper + @Override + public void onSupportActionModeStarted(@NonNull ActionMode mode) { + super.onSupportActionModeStarted(mode); + } + + @Override + @Deprecated + public void onSupportContentChanged() { + super.onSupportContentChanged(); + } + + @Override + public boolean onSupportNavigateUp() { + return super.onSupportNavigateUp(); + } + + @Override + protected void onTitleChanged(CharSequence title, int color) { + super.onTitleChanged(title, color); + } + + @Nullable + @Override + public ActionMode onWindowStartingSupportActionMode(@NonNull ActionMode.Callback callback) { + return super.onWindowStartingSupportActionMode(callback); + } + + @Override + public void openOptionsMenu() { + super.openOptionsMenu(); + } + + @Override + public void setContentView(@LayoutRes int layoutResID) { + super.setContentView(layoutResID); + } + + @Override + public void setContentView(View view) { + super.setContentView(view); + } + + @Override + public void setContentView(View view, ViewGroup.LayoutParams params) { + super.setContentView(view, params); + } + + @Override + public void setSupportActionBar(@Nullable Toolbar toolbar) { + super.setSupportActionBar(toolbar); + } + + @Override + @Deprecated + public void setSupportProgress(int progress) { + super.setSupportProgress(progress); + } + + @Override + @Deprecated + public void setSupportProgressBarIndeterminate(boolean indeterminate) { + super.setSupportProgressBarIndeterminate(indeterminate); + } + + @Override + @Deprecated + public void setSupportProgressBarIndeterminateVisibility(boolean visible) { + super.setSupportProgressBarIndeterminateVisibility(visible); + } + + @Override + @Deprecated + public void setSupportProgressBarVisibility(boolean visible) { + super.setSupportProgressBarVisibility(visible); + } + + @Override + public void setTheme(@StyleRes int resId) { + super.setTheme(resId); + } + + @Nullable + @Override + public ActionMode startSupportActionMode(@NonNull ActionMode.Callback callback) { + super.startSupportActionMode(callback); + return null; + } + + @Override + public void supportInvalidateOptionsMenu() { + super.supportInvalidateOptionsMenu(); + } + + @Override + public void supportNavigateUpTo(@NonNull Intent upIntent) { + super.supportNavigateUpTo(upIntent); + } + + @Override + public boolean supportRequestWindowFeature(int featureId) { + return super.supportRequestWindowFeature(featureId); + } + + @Override + public boolean supportShouldUpRecreateTask(@NonNull Intent targetIntent) { + return super.supportShouldUpRecreateTask(targetIntent); + } } diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/activitys/DrawerFragmentActivity.java b/libaes/src/main/java/cc/winboll/studio/libaes/activitys/DrawerFragmentActivity.java index 1bbd12a..5a2cfc7 100644 --- a/libaes/src/main/java/cc/winboll/studio/libaes/activitys/DrawerFragmentActivity.java +++ b/libaes/src/main/java/cc/winboll/studio/libaes/activitys/DrawerFragmentActivity.java @@ -162,23 +162,6 @@ public abstract class DrawerFragmentActivity extends BaseWinBoLLActivity impleme super.onBackPressed(); } -// void setThemeStyle() { -// //setTheme(AESThemeBean.getThemeStyle(getThemeType())); -// setTheme(AESThemeUtil.getThemeTypeID(getApplicationContext())); -// } - -// boolean checkThemeStyleChange() { -// return mThemeType != getThemeType(); -// } - -// AESThemeBean.ThemeType getThemeType() { -// /*SharedPreferences sharedPreferences = getSharedPreferences( -// SHAREDPREFERENCES_NAME, MODE_PRIVATE); -// return AESThemeBean.ThemeType.values()[((sharedPreferences.getInt(DRAWER_THEME_TYPE, AESThemeBean.ThemeType.DEFAULT.ordinal())))]; -// */ -// return AESThemeBean.getThemeStyleType(AESThemeUtil.getThemeTypeID(getApplicationContext())); -// } - @Override public boolean onOptionsItemSelected(MenuItem item) { if (AESThemeUtil.onAppThemeItemSelected(this, item)) { @@ -195,9 +178,6 @@ public abstract class DrawerFragmentActivity extends BaseWinBoLLActivity impleme @Override protected void onResume() { super.onResume(); -// if (checkThemeStyleChange()) { -// recreate(); -// } ADsBannerView adsBannerView = findViewById(R.id.adsbanner); if (adsBannerView != null) { diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/unittests/SecondaryLibraryActivity.java b/libaes/src/main/java/cc/winboll/studio/libaes/unittests/SecondaryLibraryActivity.java index 2373d6a..b5b210d 100644 --- a/libaes/src/main/java/cc/winboll/studio/libaes/unittests/SecondaryLibraryActivity.java +++ b/libaes/src/main/java/cc/winboll/studio/libaes/unittests/SecondaryLibraryActivity.java @@ -20,11 +20,6 @@ public class SecondaryLibraryActivity extends DrawerFragmentActivity implements SecondaryLibraryFragment mSecondaryLibraryFragment; - @Override - public Activity getActivity() { - return this; - } - @Override public String getTag() { return null; From 64693e384e49676a9c913bcf1149db592a9023cc Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Tue, 13 Jan 2026 16:11:30 +0800 Subject: [PATCH 011/430] APK 15.15.5 release Publish. --- aes/build.properties | 10 +++++----- libaes/build.properties | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/aes/build.properties b/aes/build.properties index 9a5bf85..92a644a 100644 --- a/aes/build.properties +++ b/aes/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 08:09:32 GMT 2026 -stageCount=5 +#Tue Jan 13 16:11:30 HKT 2026 +stageCount=6 libraryProject=libaes baseVersion=15.15 -publishVersion=15.15.4 -buildCount=1 -baseBetaVersion=15.15.5 +publishVersion=15.15.5 +buildCount=0 +baseBetaVersion=15.15.6 diff --git a/libaes/build.properties b/libaes/build.properties index 9a5bf85..92a644a 100644 --- a/libaes/build.properties +++ b/libaes/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 08:09:32 GMT 2026 -stageCount=5 +#Tue Jan 13 16:11:30 HKT 2026 +stageCount=6 libraryProject=libaes baseVersion=15.15 -publishVersion=15.15.4 -buildCount=1 -baseBetaVersion=15.15.5 +publishVersion=15.15.5 +buildCount=0 +baseBetaVersion=15.15.6 From 40ea79c6b7c6f4b7c9231961fdc8374657531451 Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Tue, 13 Jan 2026 16:12:37 +0800 Subject: [PATCH 012/430] Library Release 15.15.5 --- aes/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aes/build.properties b/aes/build.properties index 92a644a..da40637 100644 --- a/aes/build.properties +++ b/aes/build.properties @@ -1,5 +1,5 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 16:11:30 HKT 2026 +#Tue Jan 13 16:12:35 HKT 2026 stageCount=6 libraryProject=libaes baseVersion=15.15 From 9f46f400b04f668005d4b50fee4f2947e8cbd07e Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Tue, 13 Jan 2026 16:26:46 +0800 Subject: [PATCH 013/430] bugfix --- aes/build.properties | 4 ++-- libaes/build.properties | 4 ++-- .../winboll/studio/libaes/activitys/BaseWinBoLLActivity.java | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/aes/build.properties b/aes/build.properties index da40637..4a97346 100644 --- a/aes/build.properties +++ b/aes/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 16:12:35 HKT 2026 +#Tue Jan 13 08:26:02 GMT 2026 stageCount=6 libraryProject=libaes baseVersion=15.15 publishVersion=15.15.5 -buildCount=0 +buildCount=1 baseBetaVersion=15.15.6 diff --git a/libaes/build.properties b/libaes/build.properties index 92a644a..4a97346 100644 --- a/libaes/build.properties +++ b/libaes/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 16:11:30 HKT 2026 +#Tue Jan 13 08:26:02 GMT 2026 stageCount=6 libraryProject=libaes baseVersion=15.15 publishVersion=15.15.5 -buildCount=0 +buildCount=1 baseBetaVersion=15.15.6 diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/activitys/BaseWinBoLLActivity.java b/libaes/src/main/java/cc/winboll/studio/libaes/activitys/BaseWinBoLLActivity.java index fc93fed..465e2e9 100644 --- a/libaes/src/main/java/cc/winboll/studio/libaes/activitys/BaseWinBoLLActivity.java +++ b/libaes/src/main/java/cc/winboll/studio/libaes/activitys/BaseWinBoLLActivity.java @@ -270,7 +270,7 @@ public abstract class BaseWinBoLLActivity extends AppCompatActivity implements I } @Override - public void setSupportActionBar(@Nullable Toolbar toolbar) { + public void setSupportActionBar(@Nullable androidx.appcompat.widget.Toolbar toolbar) { super.setSupportActionBar(toolbar); } From 8b99844d0c3411cc47471057d1d44d1f86c9b879 Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Tue, 13 Jan 2026 16:27:29 +0800 Subject: [PATCH 014/430] APK 15.15.6 release Publish. --- aes/build.properties | 10 +++++----- libaes/build.properties | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/aes/build.properties b/aes/build.properties index 4a97346..fce41d3 100644 --- a/aes/build.properties +++ b/aes/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 08:26:02 GMT 2026 -stageCount=6 +#Tue Jan 13 16:27:29 HKT 2026 +stageCount=7 libraryProject=libaes baseVersion=15.15 -publishVersion=15.15.5 -buildCount=1 -baseBetaVersion=15.15.6 +publishVersion=15.15.6 +buildCount=0 +baseBetaVersion=15.15.7 diff --git a/libaes/build.properties b/libaes/build.properties index 4a97346..fce41d3 100644 --- a/libaes/build.properties +++ b/libaes/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 08:26:02 GMT 2026 -stageCount=6 +#Tue Jan 13 16:27:29 HKT 2026 +stageCount=7 libraryProject=libaes baseVersion=15.15 -publishVersion=15.15.5 -buildCount=1 -baseBetaVersion=15.15.6 +publishVersion=15.15.6 +buildCount=0 +baseBetaVersion=15.15.7 From 80b4b87e95ce82b741b0d3e0d324b2de0f304af6 Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Tue, 13 Jan 2026 16:27:36 +0800 Subject: [PATCH 015/430] Library Release 15.15.6 --- aes/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aes/build.properties b/aes/build.properties index fce41d3..e2e696a 100644 --- a/aes/build.properties +++ b/aes/build.properties @@ -1,5 +1,5 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 16:27:29 HKT 2026 +#Tue Jan 13 16:27:34 HKT 2026 stageCount=7 libraryProject=libaes baseVersion=15.15 From 952c8d8017e26d452e1191f8bae78ab699ae8f8a Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Tue, 13 Jan 2026 16:45:31 +0800 Subject: [PATCH 016/430] =?UTF-8?q?=E7=A7=BB=E9=99=A4BaseWinBoLLActivity?= =?UTF-8?q?=E4=BD=9C=E4=B8=BA=E7=B1=BB=E5=BA=93=E4=BD=BF=E7=94=A8=EF=BC=8C?= =?UTF-8?q?=E5=BA=94=E7=94=A8=E9=9C=80=E8=87=AA=E5=AE=9A=E4=B9=89=E5=9F=BA?= =?UTF-8?q?=E7=A1=80=E7=AA=97=E5=8F=A3=E7=B1=BB=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aes/build.properties | 4 +- .../cc/winboll/studio/aes/AboutActivity.java | 2 - .../studio/aes/BaseWinBoLLActivity.java | 45 +++ libaes/build.properties | 4 +- .../libaes/activitys/BaseWinBoLLActivity.java | 333 ------------------ .../activitys/DrawerFragmentActivity.java | 17 +- 6 files changed, 62 insertions(+), 343 deletions(-) create mode 100644 aes/src/main/java/cc/winboll/studio/aes/BaseWinBoLLActivity.java delete mode 100644 libaes/src/main/java/cc/winboll/studio/libaes/activitys/BaseWinBoLLActivity.java diff --git a/aes/build.properties b/aes/build.properties index e2e696a..0c198c0 100644 --- a/aes/build.properties +++ b/aes/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 16:27:34 HKT 2026 +#Tue Jan 13 08:43:44 GMT 2026 stageCount=7 libraryProject=libaes baseVersion=15.15 publishVersion=15.15.6 -buildCount=0 +buildCount=2 baseBetaVersion=15.15.7 diff --git a/aes/src/main/java/cc/winboll/studio/aes/AboutActivity.java b/aes/src/main/java/cc/winboll/studio/aes/AboutActivity.java index 16b9661..26c89bf 100644 --- a/aes/src/main/java/cc/winboll/studio/aes/AboutActivity.java +++ b/aes/src/main/java/cc/winboll/studio/aes/AboutActivity.java @@ -1,11 +1,9 @@ package cc.winboll.studio.aes; -import android.app.Activity; import android.os.Bundle; import android.view.View; import androidx.appcompat.widget.Toolbar; import cc.winboll.studio.aes.R; -import cc.winboll.studio.libaes.activitys.BaseWinBoLLActivity; import cc.winboll.studio.libaes.utils.WinBoLLActivityManager; import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.models.APPInfo; diff --git a/aes/src/main/java/cc/winboll/studio/aes/BaseWinBoLLActivity.java b/aes/src/main/java/cc/winboll/studio/aes/BaseWinBoLLActivity.java new file mode 100644 index 0000000..0526f82 --- /dev/null +++ b/aes/src/main/java/cc/winboll/studio/aes/BaseWinBoLLActivity.java @@ -0,0 +1,45 @@ +package cc.winboll.studio.aes; + +import android.app.Activity; +import android.os.Bundle; +import androidx.appcompat.app.AppCompatActivity; +import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity; +import cc.winboll.studio.libaes.models.AESThemeBean; +import cc.winboll.studio.libaes.utils.AESThemeUtil; +import cc.winboll.studio.libaes.utils.WinBoLLActivityManager; + +/** + * @Author 豆包&ZhanGSKen + * @Date 2026/01/13 16:35 + * @Describe BaseWinBollActivity 【继承AppCompatActivity,保留核心能力,不额外暴露方法】 + * 继承链路:BaseWinBoLLActivity → AppCompatActivity → FragmentActivity,AppCompat能力天然继承可用 + */ +public abstract class BaseWinBoLLActivity extends AppCompatActivity implements IWinBoLLActivity { + public static final String TAG = "BaseWinBoLLActivity"; + + protected volatile AESThemeBean.ThemeType mThemeType; + + @Override + protected void onCreate(Bundle savedInstanceState) { + mThemeType = AESThemeBean.getThemeStyleType(AESThemeUtil.getThemeTypeID(getApplicationContext())); + setTheme(AESThemeUtil.getThemeTypeID(getApplicationContext())); + super.onCreate(savedInstanceState); + WinBoLLActivityManager.getInstance().add(this); + } + + @Override + protected void onDestroy() { + WinBoLLActivityManager.getInstance().registeRemove(this); + super.onDestroy(); + } + + // 子类必须实现getTag(),确保唯一标识 + @Override + public abstract String getTag(); + + @Override + public Activity getActivity() { + return this; + } +} + diff --git a/libaes/build.properties b/libaes/build.properties index fce41d3..0c198c0 100644 --- a/libaes/build.properties +++ b/libaes/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 16:27:29 HKT 2026 +#Tue Jan 13 08:43:44 GMT 2026 stageCount=7 libraryProject=libaes baseVersion=15.15 publishVersion=15.15.6 -buildCount=0 +buildCount=2 baseBetaVersion=15.15.7 diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/activitys/BaseWinBoLLActivity.java b/libaes/src/main/java/cc/winboll/studio/libaes/activitys/BaseWinBoLLActivity.java deleted file mode 100644 index 465e2e9..0000000 --- a/libaes/src/main/java/cc/winboll/studio/libaes/activitys/BaseWinBoLLActivity.java +++ /dev/null @@ -1,333 +0,0 @@ -package cc.winboll.studio.libaes.activitys; - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.os.Bundle; -import android.view.KeyEvent; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.View; -import android.view.ViewGroup; -import androidx.annotation.CallSuper; -import androidx.annotation.ContentView; -import androidx.annotation.IdRes; -import androidx.annotation.LayoutRes; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.StyleRes; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.ActionBarDrawerToggle; -import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.app.AppCompatDelegate; -import androidx.appcompat.view.ActionMode; -import androidx.appcompat.widget.Toolbar; -import androidx.core.app.TaskStackBuilder; -import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity; -import cc.winboll.studio.libaes.models.AESThemeBean; -import cc.winboll.studio.libaes.utils.AESThemeUtil; -import cc.winboll.studio.libaes.utils.WinBoLLActivityManager; - -/** - * @Author 豆包&ZhanGSKen - * @Date 2026/01/13 14:22 - * @Describe BaseWinBollActivity 【完整透传AppCompatActivity所有公开方法】 - * 继承链路:BaseWinBoLLActivity → AppCompatActivity → FragmentActivity,所有公开能力全暴露 - */ -public abstract class BaseWinBoLLActivity extends AppCompatActivity implements IWinBoLLActivity { - public static final String TAG = "BaseWinBoLLActivity"; - - protected volatile AESThemeBean.ThemeType mThemeType; - - @Override - protected void onCreate(Bundle savedInstanceState) { - mThemeType = getThemeType(); - setThemeStyle(); - super.onCreate(savedInstanceState); - WinBoLLActivityManager.getInstance().add(this); - //ToastUtils.show(getTag() + ": onCreate"); - } - - AESThemeBean.ThemeType getThemeType() { - /*SharedPreferences sharedPreferences = getSharedPreferences( - SHAREDPREFERENCES_NAME, MODE_PRIVATE); - return AESThemeBean.ThemeType.values()[((sharedPreferences.getInt(DRAWER_THEME_TYPE, AESThemeBean.ThemeType.DEFAULT.ordinal())))]; - */ - return AESThemeBean.getThemeStyleType(AESThemeUtil.getThemeTypeID(getApplicationContext())); - } - - void setThemeStyle() { - //setTheme(AESThemeBean.getThemeStyle(getThemeType())); - setTheme(AESThemeUtil.getThemeTypeID(getApplicationContext())); - } - - @Override - protected void onDestroy() { - WinBoLLActivityManager.getInstance().registeRemove(this); - super.onDestroy(); - } - - // 子类必须实现getTag(),确保唯一标识 - @Override - public abstract String getTag(); - - @Override - public Activity getActivity() { - return this; - } - - // ===================== 完整暴露AppCompatActivity 所有公开方法(按类定义顺序)===================== -// @ContentView -// public BaseWinBoLLActivity(@LayoutRes int contentLayoutId) { -// super(contentLayoutId); -// } - - @Override - public void addContentView(View view, ViewGroup.LayoutParams params) { - super.addContentView(view, params); - } - - @Override - protected void attachBaseContext(Context newBase) { - super.attachBaseContext(newBase); - } - - @Override - public void closeOptionsMenu() { - super.closeOptionsMenu(); - } - - @Override - public boolean dispatchKeyEvent(KeyEvent event) { - return super.dispatchKeyEvent(event); - } - - @Override - public T findViewById(@IdRes int id) { - return super.findViewById(id); - } - - @NonNull - @Override - public AppCompatDelegate getDelegate() { - return super.getDelegate(); - } - - @Nullable - @Override - public ActionBarDrawerToggle.Delegate getDrawerToggleDelegate() { - return super.getDrawerToggleDelegate(); - } - - @NonNull - @Override - public MenuInflater getMenuInflater() { - return super.getMenuInflater(); - } - - @Override - public Resources getResources() { - return super.getResources(); - } - - @Nullable - @Override - public ActionBar getSupportActionBar() { - return super.getSupportActionBar(); - } - - @Nullable - @Override - public Intent getSupportParentActivityIntent() { - return super.getSupportParentActivityIntent(); - } - - @Override - public void invalidateOptionsMenu() { - super.invalidateOptionsMenu(); - } - - @Override - public void onConfigurationChanged(@NonNull Configuration newMetrics) { - super.onConfigurationChanged(newMetrics); - } - - @Override - public void onContentChanged() { - super.onContentChanged(); - } - - @Override - public void onCreateSupportNavigateUpTaskStack(@NonNull TaskStackBuilder builder) { - super.onCreateSupportNavigateUpTaskStack(builder); - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - return super.onKeyDown(keyCode, event); - } - -// -// @Override -// public final boolean onMenuItemSelected(int featureId, @NonNull MenuItem item) { -// return super.onMenuItemSelected(featureId, item); -// } - - @Override - public boolean onMenuOpened(int featureId, Menu menu) { - return super.onMenuOpened(featureId, menu); - } - - @Override - protected void onNightModeChanged(int mode) { - super.onNightModeChanged(mode); - } - - @Override - public void onPanelClosed(int featureId, @NonNull Menu menu) { - super.onPanelClosed(featureId, menu); - } - - @Override - protected void onPostCreate(@Nullable Bundle savedInstanceState) { - super.onPostCreate(savedInstanceState); - } - - @Override - protected void onPostResume() { - super.onPostResume(); - } - - @Override - public void onPrepareSupportNavigateUpTaskStack(@NonNull TaskStackBuilder builder) { - super.onPrepareSupportNavigateUpTaskStack(builder); - } - - @Override - protected void onStart() { - super.onStart(); - } - - @Override - protected void onStop() { - super.onStop(); - } - - @CallSuper - @Override - public void onSupportActionModeFinished(@NonNull ActionMode mode) { - super.onSupportActionModeFinished(mode); - } - - @CallSuper - @Override - public void onSupportActionModeStarted(@NonNull ActionMode mode) { - super.onSupportActionModeStarted(mode); - } - - @Override - @Deprecated - public void onSupportContentChanged() { - super.onSupportContentChanged(); - } - - @Override - public boolean onSupportNavigateUp() { - return super.onSupportNavigateUp(); - } - - @Override - protected void onTitleChanged(CharSequence title, int color) { - super.onTitleChanged(title, color); - } - - @Nullable - @Override - public ActionMode onWindowStartingSupportActionMode(@NonNull ActionMode.Callback callback) { - return super.onWindowStartingSupportActionMode(callback); - } - - @Override - public void openOptionsMenu() { - super.openOptionsMenu(); - } - - @Override - public void setContentView(@LayoutRes int layoutResID) { - super.setContentView(layoutResID); - } - - @Override - public void setContentView(View view) { - super.setContentView(view); - } - - @Override - public void setContentView(View view, ViewGroup.LayoutParams params) { - super.setContentView(view, params); - } - - @Override - public void setSupportActionBar(@Nullable androidx.appcompat.widget.Toolbar toolbar) { - super.setSupportActionBar(toolbar); - } - - @Override - @Deprecated - public void setSupportProgress(int progress) { - super.setSupportProgress(progress); - } - - @Override - @Deprecated - public void setSupportProgressBarIndeterminate(boolean indeterminate) { - super.setSupportProgressBarIndeterminate(indeterminate); - } - - @Override - @Deprecated - public void setSupportProgressBarIndeterminateVisibility(boolean visible) { - super.setSupportProgressBarIndeterminateVisibility(visible); - } - - @Override - @Deprecated - public void setSupportProgressBarVisibility(boolean visible) { - super.setSupportProgressBarVisibility(visible); - } - - @Override - public void setTheme(@StyleRes int resId) { - super.setTheme(resId); - } - - @Nullable - @Override - public ActionMode startSupportActionMode(@NonNull ActionMode.Callback callback) { - super.startSupportActionMode(callback); - return null; - } - - @Override - public void supportInvalidateOptionsMenu() { - super.supportInvalidateOptionsMenu(); - } - - @Override - public void supportNavigateUpTo(@NonNull Intent upIntent) { - super.supportNavigateUpTo(upIntent); - } - - @Override - public boolean supportRequestWindowFeature(int featureId) { - return super.supportRequestWindowFeature(featureId); - } - - @Override - public boolean supportShouldUpRecreateTask(@NonNull Intent targetIntent) { - return super.supportShouldUpRecreateTask(targetIntent); - } -} - diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/activitys/DrawerFragmentActivity.java b/libaes/src/main/java/cc/winboll/studio/libaes/activitys/DrawerFragmentActivity.java index 5a2cfc7..97610a3 100644 --- a/libaes/src/main/java/cc/winboll/studio/libaes/activitys/DrawerFragmentActivity.java +++ b/libaes/src/main/java/cc/winboll/studio/libaes/activitys/DrawerFragmentActivity.java @@ -5,6 +5,7 @@ package cc.winboll.studio.libaes.activitys; * @Date 2024/06/13 18:58:54 * @Describe 可以加入Fragment的有抽屉的活动窗口抽象类 */ +import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; @@ -27,14 +28,16 @@ import cc.winboll.studio.libaes.models.AESThemeBean; import cc.winboll.studio.libaes.models.DrawerMenuBean; import cc.winboll.studio.libaes.utils.AESThemeUtil; import cc.winboll.studio.libaes.utils.DevelopUtils; +import cc.winboll.studio.libaes.utils.WinBoLLActivityManager; import cc.winboll.studio.libaes.views.ADrawerMenuListView; import cc.winboll.studio.libaes.views.ADsBannerView; import cc.winboll.studio.libappbase.GlobalApplication; import cc.winboll.studio.libappbase.LogUtils; import com.baoyz.widget.PullRefreshLayout; import java.util.ArrayList; +import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity; -public abstract class DrawerFragmentActivity extends BaseWinBoLLActivity implements AdapterView.OnItemClickListener { +public abstract class DrawerFragmentActivity extends AppCompatActivity implements IWinBoLLActivity, AdapterView.OnItemClickListener { public static final String TAG = "DrawerFragmentActivity"; @@ -61,15 +64,20 @@ public abstract class DrawerFragmentActivity extends BaseWinBoLLActivity impleme @Override protected void onCreate(Bundle savedInstanceState) { - //mContext = this; -// mThemeType = getThemeType(); -// setThemeStyle(); + mThemeType = AESThemeBean.getThemeStyleType(AESThemeUtil.getThemeTypeID(getApplicationContext())); + setTheme(AESThemeUtil.getThemeTypeID(getApplicationContext())); super.onCreate(savedInstanceState); + WinBoLLActivityManager.getInstance().add(this); mActivityType = initActivityType(); initRootView(); LogUtils.d(TAG, "onCreate end."); } + @Override + public Activity getActivity() { + return this; + } + @Override public String getTag() { return TAG; @@ -77,6 +85,7 @@ public abstract class DrawerFragmentActivity extends BaseWinBoLLActivity impleme @Override protected void onDestroy() { + WinBoLLActivityManager.getInstance().registeRemove(this); super.onDestroy(); // 修复:释放广告资源,避免内存泄漏 ADsBannerView adsBannerView = findViewById(R.id.adsbanner); From 6b44f852a8925f4292569892819a8158ea923e12 Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Tue, 13 Jan 2026 16:46:27 +0800 Subject: [PATCH 017/430] APK 15.15.7 release Publish. --- aes/build.properties | 10 +++++----- libaes/build.properties | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/aes/build.properties b/aes/build.properties index 0c198c0..46784c6 100644 --- a/aes/build.properties +++ b/aes/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 08:43:44 GMT 2026 -stageCount=7 +#Tue Jan 13 16:46:27 HKT 2026 +stageCount=8 libraryProject=libaes baseVersion=15.15 -publishVersion=15.15.6 -buildCount=2 -baseBetaVersion=15.15.7 +publishVersion=15.15.7 +buildCount=0 +baseBetaVersion=15.15.8 diff --git a/libaes/build.properties b/libaes/build.properties index 0c198c0..46784c6 100644 --- a/libaes/build.properties +++ b/libaes/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 08:43:44 GMT 2026 -stageCount=7 +#Tue Jan 13 16:46:27 HKT 2026 +stageCount=8 libraryProject=libaes baseVersion=15.15 -publishVersion=15.15.6 -buildCount=2 -baseBetaVersion=15.15.7 +publishVersion=15.15.7 +buildCount=0 +baseBetaVersion=15.15.8 From 3f544f6097c3f4de63237d136f83f0a2dd999298 Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Tue, 13 Jan 2026 16:46:38 +0800 Subject: [PATCH 018/430] Library Release 15.15.7 --- aes/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aes/build.properties b/aes/build.properties index 46784c6..c318cf6 100644 --- a/aes/build.properties +++ b/aes/build.properties @@ -1,5 +1,5 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 16:46:27 HKT 2026 +#Tue Jan 13 16:46:36 HKT 2026 stageCount=8 libraryProject=libaes baseVersion=15.15 From 1aa270482ee73b933b142d633cfb898300997fe6 Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Tue, 20 Jan 2026 20:52:49 +0800 Subject: [PATCH 019/430] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=BA=94=E7=94=A8?= =?UTF-8?q?=E6=8C=87=E7=BA=B9=E6=A0=A1=E9=AA=8C=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- appbase/build.properties | 4 +- libappbase/build.properties | 4 +- .../libappbase/dialogs/SignGetDialog.java | 128 ++++++++++++++++ .../studio/libappbase/utils/APPUtils.java | 78 ++++++++++ .../studio/libappbase/utils/SignGetUtils.java | 71 +++++++++ .../studio/libappbase/views/AboutView.java | 138 +++++++++--------- libappbase/src/main/res/drawable/ic_key.xml | 11 ++ .../src/main/res/layout/dialog_sign_get.xml | 52 +++++++ .../src/main/res/layout/layout_about_view.xml | 69 +++++++++ libappbase/src/main/res/values/styles.xml | 5 + 10 files changed, 488 insertions(+), 72 deletions(-) create mode 100644 libappbase/src/main/java/cc/winboll/studio/libappbase/dialogs/SignGetDialog.java create mode 100644 libappbase/src/main/java/cc/winboll/studio/libappbase/utils/APPUtils.java create mode 100644 libappbase/src/main/java/cc/winboll/studio/libappbase/utils/SignGetUtils.java create mode 100644 libappbase/src/main/res/drawable/ic_key.xml create mode 100644 libappbase/src/main/res/layout/dialog_sign_get.xml create mode 100644 libappbase/src/main/res/layout/layout_about_view.xml diff --git a/appbase/build.properties b/appbase/build.properties index e17b41c..66997c3 100644 --- a/appbase/build.properties +++ b/appbase/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 03:23:34 HKT 2026 +#Tue Jan 20 12:51:34 GMT 2026 stageCount=5 libraryProject=libappbase baseVersion=15.15 publishVersion=15.15.4 -buildCount=0 +buildCount=38 baseBetaVersion=15.15.5 diff --git a/libappbase/build.properties b/libappbase/build.properties index d1d8227..66997c3 100644 --- a/libappbase/build.properties +++ b/libappbase/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 03:23:17 HKT 2026 +#Tue Jan 20 12:51:34 GMT 2026 stageCount=5 libraryProject=libappbase baseVersion=15.15 publishVersion=15.15.4 -buildCount=0 +buildCount=38 baseBetaVersion=15.15.5 diff --git a/libappbase/src/main/java/cc/winboll/studio/libappbase/dialogs/SignGetDialog.java b/libappbase/src/main/java/cc/winboll/studio/libappbase/dialogs/SignGetDialog.java new file mode 100644 index 0000000..3749c3b --- /dev/null +++ b/libappbase/src/main/java/cc/winboll/studio/libappbase/dialogs/SignGetDialog.java @@ -0,0 +1,128 @@ +package cc.winboll.studio.libappbase.dialogs; + +import android.app.Dialog; +import android.content.Context; +import android.graphics.Color; +import android.os.Bundle; +import android.widget.EditText; +import android.widget.TextView; +import cc.winboll.studio.libappbase.LogUtils; +import cc.winboll.studio.libappbase.R; +import cc.winboll.studio.libappbase.ToastUtils; +import cc.winboll.studio.libappbase.utils.APPUtils; +import cc.winboll.studio.libappbase.utils.SignGetUtils; + +/** + * @Describe 签名显示+正版校验对话框 + * @Author 豆包&ZhanGSKen + * @Date 2026/01/20 21:20:00 + * @LastEditTime 2026/01/21 11:00:00 + */ +public class SignGetDialog extends Dialog { + private static final String TAG = "SignGetDialog"; + private EditText etSignFingerprint; + private TextView tvAuthResult; + private Context mContext; + + public SignGetDialog(Context context) { + super(context, R.style.DialogStyle); // 适配默认对话框样式 + this.mContext = context; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.dialog_sign_get); // 绑定xml布局 + setCancelable(true); // 点击外部可关闭 + initView(); + initSignAndCheck(); // 获取签名+正版校验 + } + + private void initView() { + etSignFingerprint = findViewById(R.id.et_sign_fingerprint); + tvAuthResult = findViewById(R.id.tv_auth_result); + // 输入框只读,方便复制 + etSignFingerprint.setEnabled(false); + } + + // 核心:获取签名+调用APPUtils校验 + private void initSignAndCheck() { + // 1. 获取当前应用签名 + String sign = getCurrentSign(); + if (sign == null) { + etSignFingerprint.setText("签名获取失败"); + } else { + // 签名字符串转0/1 bit数组(每2个bit加空格,每16位换行,下一行无前置空格) + String bitArrayStr = convertSignToBitArrayWithWrap(sign); + etSignFingerprint.setText(bitArrayStr); + } + LogUtils.d(TAG, "当前应用签名:" + sign); + + // 2. 正版校验+显示结果 + APPUtils.checkAppValid(mContext); + boolean isOfficial = isSignValid(); + if (isOfficial) { + ToastUtils.show("这是正版的WinBoLL应用,请放心使用。"); + tvAuthResult.setTextColor(Color.BLUE); + tvAuthResult.setText("这是正版的WinBoLL应用,请放心使用。"); + } else { + ToastUtils.show("您使用的可能不是正版的 WinBoLL 应用。"); + tvAuthResult.setTextColor(Color.RED); + tvAuthResult.setText("您使用的可能不是正版的 WinBoLL 应用。"); + } + } + + // 核心修改:签名字符串转0/1 bit数组(每2个bit加空格,每16位换行,下一行无前置空格) + private String convertSignToBitArrayWithWrap(String signStr) { + StringBuilder bitBuilder = new StringBuilder(); + // 1. 字符转8位bit + for (char c : signStr.toCharArray()) { + String bit8 = String.format("%8s", Integer.toBinaryString(c)).replace(' ', '0'); + bitBuilder.append(bit8); + } + String fullBitStr = bitBuilder.toString(); + + // 2. 按16位分组,组内每2个bit加空格(避免换行后带空格) + StringBuilder finalBuilder = new StringBuilder(); + int groupSize = 16; // 每组16个bit + for (int i = 0; i < fullBitStr.length(); i += groupSize) { + // 截取16位bit为一组 + int end = Math.min(i + groupSize, fullBitStr.length()); + String group = fullBitStr.substring(i, end); + + // 组内每2个bit加空格 + StringBuilder groupWithSpace = new StringBuilder(); + for (int j = 0; j < group.length(); j++) { + groupWithSpace.append(group.charAt(j)); + if ((j + 1) % 2 == 0 && j != group.length() - 1) { + groupWithSpace.append(" "); + } + } + + // 添加组到最终结果,每组后换行(最后一组不换行) + finalBuilder.append(groupWithSpace); + if (end < fullBitStr.length()) { + finalBuilder.append("\n"); + } + } + return finalBuilder.toString(); + } + + // 获取签名(复用SignGetUtils逻辑,避免重复代码) + private String getCurrentSign() { + try { + return SignGetUtils.getSignStr(mContext); // 复用工具类逻辑 + } catch (Exception e) { + LogUtils.e(TAG, "获取签名失败", e); + return null; + } + } + + // 校验签名是否合法(匹配APPUtils目标签名) + private boolean isSignValid() { + String currentSign = getCurrentSign(); + String targetSign = APPUtils.TARGET_SIGN_FINGERPRINT; // 取APPUtils目标签名 + return currentSign != null && targetSign != null && currentSign.equals(targetSign); + } +} + diff --git a/libappbase/src/main/java/cc/winboll/studio/libappbase/utils/APPUtils.java b/libappbase/src/main/java/cc/winboll/studio/libappbase/utils/APPUtils.java new file mode 100644 index 0000000..306f78a --- /dev/null +++ b/libappbase/src/main/java/cc/winboll/studio/libappbase/utils/APPUtils.java @@ -0,0 +1,78 @@ +package cc.winboll.studio.libappbase.utils; + +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.Signature; +import android.util.Base64; +import cc.winboll.studio.libappbase.LogUtils; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * @Author 豆包&ZhanGSKen + * @Date 2026/01/20 19:17 + * @Describe APPUtils 应用包名、签名校验工具类 + */ +public class APPUtils { + + public static final String TAG = "APPUtils"; + // 目标应用签名指纹(BASE64格式,自行替换为你的合法指纹) + //public static final String TARGET_SIGN_FINGERPRINT = "你的应用签名SHA1指纹BASE64值"; + public static final String TARGET_SIGN_FINGERPRINT = "bMArVdXE4ZZo42vS9e/kXE63MkE="; + // 目标应用包名(自行替换为你的应用包名) + private static final String TARGET_PACKAGE_NAME = "cc.winboll.studio.你的应用包名"; + + /** + * 检查应用包名+签名指纹合法性,不匹配打日志,匹配无操作 + * @param context 上下文 + */ + public static void checkAppValid(Context context) { + if (context == null) { + LogUtils.w(TAG, "checkAppValid: context为空,跳过校验"); + return; + } + // 1. 校验包名 + String currentPkg = context.getPackageName(); + LogUtils.d(TAG, "checkAppValid: 当前应用包名=" + currentPkg + ",目标包名=" + TARGET_PACKAGE_NAME); + if (!TARGET_PACKAGE_NAME.equals(currentPkg)) { + LogUtils.e(TAG, "checkAppValid: 应用包名不匹配,非法环境"); + return; + } + // 2. 校验签名指纹 + String currentSign = getAppSignFingerprint(context); + LogUtils.d(TAG, "checkAppValid: 当前应用签名指纹=" + currentSign + ",目标指纹=" + TARGET_SIGN_FINGERPRINT); + if (currentSign == null || !TARGET_SIGN_FINGERPRINT.equals(currentSign)) { + LogUtils.e(TAG, "checkAppValid: 应用签名指纹不匹配,非法环境"); + } + } + + /** + * 获取当前应用签名SHA1指纹(BASE64编码,适配Java7) + * @param context 上下文 + * @return 签名指纹字符串,失败返回null + */ + private static String getAppSignFingerprint(Context context) { + try { + PackageManager pm = context.getPackageManager(); + PackageInfo pkgInfo = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES); + Signature[] signatures = pkgInfo.signatures; + if (signatures == null || signatures.length == 0) { + LogUtils.w(TAG, "getAppSignFingerprint: 未获取到应用签名"); + return null; + } + // SHA1摘要 + BASE64编码,和目标指纹格式统一 + MessageDigest md = MessageDigest.getInstance("SHA1"); + md.update(signatures[0].toByteArray()); + return Base64.encodeToString(md.digest(), Base64.NO_WRAP); + } catch (PackageManager.NameNotFoundException e) { + LogUtils.e(TAG, "getAppSignFingerprint: 包名未找到", e); + } catch (NoSuchAlgorithmException e) { + LogUtils.e(TAG, "getAppSignFingerprint: 不支持SHA1算法", e); + } catch (Exception e) { + LogUtils.e(TAG, "getAppSignFingerprint: 获取签名异常", e); + } + return null; + } +} + diff --git a/libappbase/src/main/java/cc/winboll/studio/libappbase/utils/SignGetUtils.java b/libappbase/src/main/java/cc/winboll/studio/libappbase/utils/SignGetUtils.java new file mode 100644 index 0000000..c3895c5 --- /dev/null +++ b/libappbase/src/main/java/cc/winboll/studio/libappbase/utils/SignGetUtils.java @@ -0,0 +1,71 @@ +package cc.winboll.studio.libappbase.utils; + +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.Signature; +import android.util.Base64; +import cc.winboll.studio.libappbase.LogUtils; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * @Author 豆包&ZhanGSKen + * @Date 2026/01/20 19:50 + * @Describe 获取应用签名指纹(SHA1+Base64,直接复制用) + */ +public class SignGetUtils { + private static final String TAG = "SignGetUtils"; + + /** + * 一键获取当前应用签名指纹(直接调用,看日志复制结果) + */ + public static void getCurrentAppSign(Context context) { + if (context == null) { + LogUtils.e(TAG, "context不能为空"); + return; + } + try { + PackageManager pm = context.getPackageManager(); + PackageInfo pkgInfo = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES); + Signature[] signatures = pkgInfo.signatures; + if (signatures == null || signatures.length == 0) { + LogUtils.e(TAG, "未获取到应用签名"); + return; + } + // 和APPUtils校验格式完全一致(SHA1+Base64 NO_WRAP) + MessageDigest md = MessageDigest.getInstance("SHA1"); + md.update(signatures[0].toByteArray()); + String signBase64 = Base64.encodeToString(md.digest(), Base64.NO_WRAP); + + // 关键日志:复制【】里的内容到APPUtils的TARGET_SIGN_FINGERPRINT + LogUtils.d(TAG, "当前应用包名:" + context.getPackageName()); + LogUtils.d(TAG, "当前应用签名指纹(直接复制):【" + signBase64 + "】"); + } catch (PackageManager.NameNotFoundException e) { + LogUtils.e(TAG, "获取签名失败:包名不存在", e); + } catch (NoSuchAlgorithmException e) { + LogUtils.e(TAG, "获取签名失败:不支持SHA1", e); + } catch (Exception e) { + LogUtils.e(TAG, "获取签名失败", e); + } + } + + // 新增:直接返回签名字符串,供对话框调用 + public static String getSignStr(Context context) { + if (context == null) return null; + try { + PackageManager pm = context.getPackageManager(); + PackageInfo pkgInfo = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES); + Signature[] signatures = pkgInfo.signatures; + if (signatures == null || signatures.length == 0) return null; + + MessageDigest md = MessageDigest.getInstance("SHA1"); + md.update(signatures[0].toByteArray()); + return Base64.encodeToString(md.digest(), Base64.NO_WRAP); + } catch (Exception e) { + LogUtils.e(TAG, "获取签名字符串失败", e); + return null; + } + } +} + diff --git a/libappbase/src/main/java/cc/winboll/studio/libappbase/views/AboutView.java b/libappbase/src/main/java/cc/winboll/studio/libappbase/views/AboutView.java index 60e7866..3c3892f 100644 --- a/libappbase/src/main/java/cc/winboll/studio/libappbase/views/AboutView.java +++ b/libappbase/src/main/java/cc/winboll/studio/libappbase/views/AboutView.java @@ -8,21 +8,22 @@ import android.util.AttributeSet; import android.view.Gravity; import android.view.View; import android.widget.EditText; +import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; - import cc.winboll.studio.libappbase.GlobalApplication; import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.R; import cc.winboll.studio.libappbase.ToastUtils; +import cc.winboll.studio.libappbase.dialogs.SignGetDialog; import cc.winboll.studio.libappbase.models.APPInfo; /** * @Describe AboutView 原生实现关于页面,无第三方依赖,适配API30,抽象通用功能控件(邮件/网页跳转) * @Author 豆包&ZhanGSKen * @Date 2026/01/11 12:23:00 - * @LastEditTime 2026/01/12 01:05:30 + * @LastEditTime 2026/01/20 20:45:00 */ public class AboutView extends LinearLayout { // 全局常量区(标识、回调标识) @@ -41,7 +42,6 @@ public class AboutView extends LinearLayout { private static final int PADDING_MID = 16; private static final int PADDING_SMALL = 8; private static final int ICON_SIZE = 48; - private static final int LINE_HEIGHT = 1; private static final int ITEM_ICON_SIZE = 24; // 成员属性区(按 核心依赖→业务配置→视图相关 归类排序,注释清晰) @@ -66,12 +66,19 @@ public class AboutView extends LinearLayout { private EditText metDevUserName; // 调试用户名输入框 private EditText metDevUserPassword; // 调试密码输入框 + // 视图绑定 + private ImageView ivAppIcon; + private TextView tvAppNameVersion; + private TextView tvAppDesc; + private LinearLayout llFunctionContainer; + // 构造方法区(按 参数从少到多 排序,适配 代码创建+XML引用 场景) public AboutView(Context context) { super(context); LogUtils.d(TAG, "AboutView(Context) 构造方法调用,代码创建视图场景"); this.mContext = context; initDefaultParams(); + initViewFromXml(); } public AboutView(Context context, APPInfo appInfo) { @@ -79,6 +86,7 @@ public class AboutView extends LinearLayout { LogUtils.d(TAG, "AboutView(Context,APPInfo) 构造调用,入参APPInfo:" + (appInfo == null ? "null" : appInfo.getAppName())); this.mContext = context; this.mAPPInfo = appInfo; + initViewFromXml(); initAll(); } @@ -87,6 +95,7 @@ public class AboutView extends LinearLayout { LogUtils.d(TAG, "AboutView(Context,AttributeSet) 构造调用,XML布局引用场景"); this.mContext = context; initDefaultParams(); + initViewFromXml(); } public AboutView(Context context, AttributeSet attrs, int defStyleAttr) { @@ -94,8 +103,45 @@ public class AboutView extends LinearLayout { LogUtils.d(TAG, "AboutView(Context,AttributeSet,int) 构造调用,XML布局+样式配置,defStyleAttr:" + defStyleAttr); this.mContext = context; initDefaultParams(); + initViewFromXml(); } + // 核心:加载xml布局并绑定视图 +// private void initViewFromXml() { +// View.inflate(mContext, R.layout.layout_about_view, this); +// ivAppIcon = findViewById(R.id.iv_app_icon); +// tvAppNameVersion = findViewById(R.id.tv_app_name_version); +// tvAppDesc = findViewById(R.id.tv_app_desc); +// llFunctionContainer = findViewById(R.id.ll_function_container); +// LogUtils.d(TAG, "initViewFromXml 布局加载+视图绑定完成"); +// } + // 1. 新增视图绑定属性(加在原有视图属性后面) + private ImageButton ibSigngetdialog; + +// 2. 完善initViewFromXml方法,新增按钮绑定 + private void initViewFromXml() { + View.inflate(mContext, R.layout.layout_about_view, this); + ivAppIcon = findViewById(R.id.iv_app_icon); + tvAppNameVersion = findViewById(R.id.tv_app_name_version); + tvAppDesc = findViewById(R.id.tv_app_desc); + llFunctionContainer = findViewById(R.id.ll_function_container); + ibSigngetdialog = findViewById(R.id.ib_signgetdialog); // 新增按钮绑定 + setBtnClickListener(); // 新增绑定点击事件 + LogUtils.d(TAG, "initViewFromXml 布局加载+视图绑定完成"); + } + +// 3. 新增按钮点击事件方法(放在initViewFromXml下面即可) + private void setBtnClickListener() { + ibSigngetdialog.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + LogUtils.d(TAG, "签名获取按钮点击,弹出SignGetDialog"); + new SignGetDialog(mContext).show(); // 弹出对话框 + } + }); + } + + // 对外公开方法区(供外部调用,职责单一,注释明确) /** * 一站式初始化所有关于页逻辑,包含参数、信息、视图全流程初始化 @@ -106,10 +152,6 @@ public class AboutView extends LinearLayout { LogUtils.w(TAG, "initAll() 初始化终止:APPInfo 为 null,无法获取应用核心信息"); return; } - // 基础布局配置 - setOrientation(VERTICAL); - setPadding(dp2px(PADDING_MID), dp2px(PADDING_LARGE), dp2px(PADDING_MID), dp2px(PADDING_LARGE)); - setGravity(Gravity.CENTER_HORIZONTAL); // 按初始化流程执行,有序无冗余 initDefaultParams(); @@ -129,7 +171,7 @@ public class AboutView extends LinearLayout { public void setAPPInfoAndInit(APPInfo appInfo) { LogUtils.d(TAG, "setAPPInfoAndInit() 调用,传入新APPInfo:" + (appInfo == null ? "null" : appInfo.getAppName())); this.mAPPInfo = appInfo; - removeAllViews(); + llFunctionContainer.removeAllViews(); initAll(); LogUtils.d(TAG, "setAPPInfoAndInit() 应用信息重置+页面重构完成"); } @@ -141,7 +183,7 @@ public class AboutView extends LinearLayout { public void setAPPInfo(APPInfo appInfo) { LogUtils.d(TAG, "setAPPInfo() 调用,传入APPInfo:" + (appInfo == null ? "null" : appInfo.getAppName())); this.mAPPInfo = appInfo; - removeAllViews(); + llFunctionContainer.removeAllViews(); initAll(); } @@ -196,7 +238,7 @@ public class AboutView extends LinearLayout { LogUtils.d(TAG, "initAppVersionInfo() 获取版本号失败,默认赋值unknown", e); mszAppVersionName = "unknown"; } - mszCurrentAppPackageName = String.format("%s_%s.apk", mszAppAPKName, mszAppVersionName); + mszCurrentAppPackageName = String.format("%s_%s.apk", mszAppVersionName, mszAppVersionName); LogUtils.d(TAG, "initAppVersionInfo() 完成,版本号:" + mszAppVersionName + ",当前APK名:" + mszCurrentAppPackageName); } @@ -245,77 +287,37 @@ public class AboutView extends LinearLayout { } /** - * 核心视图组装:按 图标→应用信息→分割线→通用功能控件 顺序构建页面 + * 核心视图组装:赋值基础信息+添加功能项 */ private void initAboutPageView() { LogUtils.d(TAG, "initAboutPageView() 开始组装关于页视图"); - addAppIcon(); - addAppInfoDesc(); - addLineSeparator(); + // 基础信息赋值 + ivAppIcon.setImageResource(mnAppIcon); + tvAppNameVersion.setText(String.format("%s %s", mszAppName, mszAppVersionName)); + if (mszAppDescription.isEmpty()) { + tvAppDesc.setVisibility(GONE); + } else { + tvAppDesc.setVisibility(VISIBLE); + tvAppDesc.setText(mszAppDescription); + } // 通用功能控件:网页跳转类+邮件类,复用抽象控件 - addView(new WebJumpFunctionItemView(mContext, "WinBoLL 主页", WINBOLL_OFFICIAL_HOME, R.drawable.ic_winboll)); - addView(new EmailFunctionItemView(mContext, "联系邮箱", "WinBoLLStudio", R.drawable.ic_winboll)); + addFunctionView(new WebJumpFunctionItemView(mContext, "WinBoLL 主页", WINBOLL_OFFICIAL_HOME, R.drawable.ic_winboll)); + addFunctionView(new EmailFunctionItemView(mContext, "联系邮箱", "WinBoLLStudio", R.drawable.ic_winboll)); if (!mszHomePage.isEmpty()) { - addView(new WebJumpFunctionItemView(mContext, "应用APK下载地址", mszHomePage, R.drawable.ic_winboll)); + addFunctionView(new WebJumpFunctionItemView(mContext, "应用APK下载地址", mszHomePage, R.drawable.ic_winboll)); } if (!mszGitea.isEmpty()) { - addView(new WebJumpFunctionItemView(mContext, "应用Git源码地址", mszGitea, R.drawable.ic_winboll)); + addFunctionView(new WebJumpFunctionItemView(mContext, "应用Git源码地址", mszGitea, R.drawable.ic_winboll)); } LogUtils.d(TAG, "initAboutPageView() 视图组装完成,功能项加载完毕"); } - // 视图构建辅助方法区(基础视图组件) - /** - * 添加应用图标组件,居中展示 - */ - private void addAppIcon() { - ImageView ivIcon = new ImageView(mContext); - LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(dp2px(ICON_SIZE), dp2px(ICON_SIZE)); - params.bottomMargin = dp2px(PADDING_MID); - ivIcon.setLayoutParams(params); - ivIcon.setImageResource(mnAppIcon); - ivIcon.setScaleType(ImageView.ScaleType.CENTER_CROP); - addView(ivIcon); - } - - /** - * 添加应用名称+版本号+描述信息组件,垂直居中展示 - */ - private void addAppInfoDesc() { - LinearLayout llDesc = new LinearLayout(mContext); - llDesc.setOrientation(VERTICAL); - llDesc.setGravity(Gravity.CENTER); - llDesc.setPadding(0, 0, 0, dp2px(PADDING_MID)); - - TextView tvAppName = new TextView(mContext); - tvAppName.setText(String.format("%s %s", mszAppName, mszAppVersionName)); - tvAppName.setTextSize(18); - tvAppName.setTextColor(mContext.getResources().getColor(R.color.gray_900)); - llDesc.addView(tvAppName); - - if (!mszAppDescription.isEmpty()) { - TextView tvDesc = new TextView(mContext); - tvDesc.setText(mszAppDescription); - tvDesc.setTextSize(14); - tvDesc.setTextColor(mContext.getResources().getColor(R.color.gray_500)); - tvDesc.setPadding(0, dp2px(PADDING_SMALL), 0, 0); - llDesc.addView(tvDesc); - } - addView(llDesc); - } - - /** - * 添加视图分割线,区分不同功能模块 - */ - private void addLineSeparator() { - View line = new View(mContext); - LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, dp2px(LINE_HEIGHT)); + // 添加功能项到容器 + private void addFunctionView(View view) { + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); params.topMargin = dp2px(PADDING_SMALL); - params.bottomMargin = dp2px(PADDING_MID); - line.setLayoutParams(params); - line.setBackgroundColor(mContext.getResources().getColor(R.color.gray_200)); - addView(line); + llFunctionContainer.addView(view, params); } // 工具方法区(通用工具+业务工具,静态优先,便于复用) diff --git a/libappbase/src/main/res/drawable/ic_key.xml b/libappbase/src/main/res/drawable/ic_key.xml new file mode 100644 index 0000000..4cea6c7 --- /dev/null +++ b/libappbase/src/main/res/drawable/ic_key.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/libappbase/src/main/res/layout/dialog_sign_get.xml b/libappbase/src/main/res/layout/dialog_sign_get.xml new file mode 100644 index 0000000..f05f7aa --- /dev/null +++ b/libappbase/src/main/res/layout/dialog_sign_get.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + diff --git a/libappbase/src/main/res/layout/layout_about_view.xml b/libappbase/src/main/res/layout/layout_about_view.xml new file mode 100644 index 0000000..033c1b4 --- /dev/null +++ b/libappbase/src/main/res/layout/layout_about_view.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libappbase/src/main/res/values/styles.xml b/libappbase/src/main/res/values/styles.xml index 0dd004f..160ac17 100644 --- a/libappbase/src/main/res/values/styles.xml +++ b/libappbase/src/main/res/values/styles.xml @@ -11,5 +11,10 @@ #FF00B322 #FF000000 + + From 2896b6401b179e3cedc83f60c4d9f0aba661c7e0 Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Tue, 20 Jan 2026 20:54:24 +0800 Subject: [PATCH 020/430] APK 15.15.5 release Publish. --- appbase/build.properties | 10 +++++----- libappbase/build.properties | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/appbase/build.properties b/appbase/build.properties index 66997c3..023cef1 100644 --- a/appbase/build.properties +++ b/appbase/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 20 12:51:34 GMT 2026 -stageCount=5 +#Tue Jan 20 20:54:24 HKT 2026 +stageCount=6 libraryProject=libappbase baseVersion=15.15 -publishVersion=15.15.4 -buildCount=38 -baseBetaVersion=15.15.5 +publishVersion=15.15.5 +buildCount=0 +baseBetaVersion=15.15.6 diff --git a/libappbase/build.properties b/libappbase/build.properties index 66997c3..023cef1 100644 --- a/libappbase/build.properties +++ b/libappbase/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 20 12:51:34 GMT 2026 -stageCount=5 +#Tue Jan 20 20:54:24 HKT 2026 +stageCount=6 libraryProject=libappbase baseVersion=15.15 -publishVersion=15.15.4 -buildCount=38 -baseBetaVersion=15.15.5 +publishVersion=15.15.5 +buildCount=0 +baseBetaVersion=15.15.6 From 4890ca42cc358ce2cae3eb329e37517662789a09 Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Tue, 20 Jan 2026 20:54:58 +0800 Subject: [PATCH 021/430] Library Release 15.15.5 --- appbase/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appbase/build.properties b/appbase/build.properties index 023cef1..38f670d 100644 --- a/appbase/build.properties +++ b/appbase/build.properties @@ -1,5 +1,5 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 20 20:54:24 HKT 2026 +#Tue Jan 20 20:54:55 HKT 2026 stageCount=6 libraryProject=libappbase baseVersion=15.15 From aeaea253cb4abd9f3b7dccd111cf1697aa70676d Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Tue, 20 Jan 2026 21:16:17 +0800 Subject: [PATCH 022/430] =?UTF-8?q?=E5=BA=94=E7=94=A8=E6=8C=87=E7=BA=B9?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C=E5=AF=B9=E8=AF=9D=E6=A1=86=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- appbase/build.properties | 4 ++-- libappbase/build.properties | 4 ++-- .../winboll/studio/libappbase/dialogs/SignGetDialog.java | 9 +++++---- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/appbase/build.properties b/appbase/build.properties index 38f670d..a17512b 100644 --- a/appbase/build.properties +++ b/appbase/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 20 20:54:55 HKT 2026 +#Tue Jan 20 13:15:20 GMT 2026 stageCount=6 libraryProject=libappbase baseVersion=15.15 publishVersion=15.15.5 -buildCount=0 +buildCount=4 baseBetaVersion=15.15.6 diff --git a/libappbase/build.properties b/libappbase/build.properties index 023cef1..a17512b 100644 --- a/libappbase/build.properties +++ b/libappbase/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 20 20:54:24 HKT 2026 +#Tue Jan 20 13:15:20 GMT 2026 stageCount=6 libraryProject=libappbase baseVersion=15.15 publishVersion=15.15.5 -buildCount=0 +buildCount=4 baseBetaVersion=15.15.6 diff --git a/libappbase/src/main/java/cc/winboll/studio/libappbase/dialogs/SignGetDialog.java b/libappbase/src/main/java/cc/winboll/studio/libappbase/dialogs/SignGetDialog.java index 3749c3b..aa05e32 100644 --- a/libappbase/src/main/java/cc/winboll/studio/libappbase/dialogs/SignGetDialog.java +++ b/libappbase/src/main/java/cc/winboll/studio/libappbase/dialogs/SignGetDialog.java @@ -61,15 +61,16 @@ public class SignGetDialog extends Dialog { // 2. 正版校验+显示结果 APPUtils.checkAppValid(mContext); boolean isOfficial = isSignValid(); + String szOfficialMessage; if (isOfficial) { - ToastUtils.show("这是正版的WinBoLL应用,请放心使用。"); + szOfficialMessage = "< 这是正版的 WinBoLL 应用,请放心使用。 >"; tvAuthResult.setTextColor(Color.BLUE); - tvAuthResult.setText("这是正版的WinBoLL应用,请放心使用。"); } else { - ToastUtils.show("您使用的可能不是正版的 WinBoLL 应用。"); + szOfficialMessage = "< 您使用的可能不是正版的 WinBoLL 应用。 >"; tvAuthResult.setTextColor(Color.RED); - tvAuthResult.setText("您使用的可能不是正版的 WinBoLL 应用。"); } + ToastUtils.show(szOfficialMessage); + tvAuthResult.setText(szOfficialMessage); } // 核心修改:签名字符串转0/1 bit数组(每2个bit加空格,每16位换行,下一行无前置空格) From 88a20d9a854fd37390fd2dc38d9d71e76ce66c6c Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Tue, 20 Jan 2026 21:17:40 +0800 Subject: [PATCH 023/430] APK 15.15.6 release Publish. --- appbase/build.properties | 10 +++++----- libappbase/build.properties | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/appbase/build.properties b/appbase/build.properties index a17512b..7479ba8 100644 --- a/appbase/build.properties +++ b/appbase/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 20 13:15:20 GMT 2026 -stageCount=6 +#Tue Jan 20 21:17:40 HKT 2026 +stageCount=7 libraryProject=libappbase baseVersion=15.15 -publishVersion=15.15.5 -buildCount=4 -baseBetaVersion=15.15.6 +publishVersion=15.15.6 +buildCount=0 +baseBetaVersion=15.15.7 diff --git a/libappbase/build.properties b/libappbase/build.properties index a17512b..7479ba8 100644 --- a/libappbase/build.properties +++ b/libappbase/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 20 13:15:20 GMT 2026 -stageCount=6 +#Tue Jan 20 21:17:40 HKT 2026 +stageCount=7 libraryProject=libappbase baseVersion=15.15 -publishVersion=15.15.5 -buildCount=4 -baseBetaVersion=15.15.6 +publishVersion=15.15.6 +buildCount=0 +baseBetaVersion=15.15.7 From 8b2a8328ebccc080d4831e936dcd874fe87b9b43 Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Tue, 20 Jan 2026 21:18:00 +0800 Subject: [PATCH 024/430] Library Release 15.15.6 --- appbase/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appbase/build.properties b/appbase/build.properties index 7479ba8..0f6d843 100644 --- a/appbase/build.properties +++ b/appbase/build.properties @@ -1,5 +1,5 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 20 21:17:40 HKT 2026 +#Tue Jan 20 21:17:58 HKT 2026 stageCount=7 libraryProject=libappbase baseVersion=15.15 From ef64d6a317787038321ed21ea1cf1f2e8bc7c62f Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Wed, 21 Jan 2026 16:13:00 +0800 Subject: [PATCH 025/430] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=8C=89=E7=85=A7tag?= =?UTF-8?q?=E7=BC=96=E8=AF=91Class=E7=9A=84=E8=84=9A=E6=9C=AC=EF=BC=8C?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=BA=94=E7=94=A8=E5=90=AF=E5=8A=A8=E4=B8=8E?= =?UTF-8?q?=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95=E6=B5=81=E7=A8=8B=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- appbase/build.properties | 4 ++-- libappbase/build.properties | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/appbase/build.properties b/appbase/build.properties index 0f6d843..12a209d 100644 --- a/appbase/build.properties +++ b/appbase/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 20 21:17:58 HKT 2026 +#Wed Jan 21 03:11:44 GMT 2026 stageCount=7 libraryProject=libappbase baseVersion=15.15 publishVersion=15.15.6 -buildCount=0 +buildCount=1 baseBetaVersion=15.15.7 diff --git a/libappbase/build.properties b/libappbase/build.properties index 7479ba8..12a209d 100644 --- a/libappbase/build.properties +++ b/libappbase/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 20 21:17:40 HKT 2026 +#Wed Jan 21 03:11:44 GMT 2026 stageCount=7 libraryProject=libappbase baseVersion=15.15 publishVersion=15.15.6 -buildCount=0 +buildCount=1 baseBetaVersion=15.15.7 From 584678494032f6451c5496cb380c69889e642979 Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Thu, 22 Jan 2026 20:41:57 +0800 Subject: [PATCH 026/430] =?UTF-8?q?=E5=BA=94=E7=94=A8=E7=AD=BE=E5=90=8D?= =?UTF-8?q?=E8=81=94=E7=BD=91=E9=AA=8C=E8=AF=81=E6=A8=A1=E5=9D=97=E5=AE=8C?= =?UTF-8?q?=E6=88=90=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- appbase/build.properties | 4 +- libappbase/build.gradle | 6 + libappbase/build.properties | 4 +- libappbase/src/main/AndroidManifest.xml | 6 +- .../libappbase/dialogs/SignGetDialog.java | 49 +++-- .../libappbase/models/SignCheckResponse.java | 39 ++++ .../studio/libappbase/utils/APPUtils.java | 174 +++++++++++++++--- .../main/res/xml/network_security_config.xml | 11 ++ 8 files changed, 241 insertions(+), 52 deletions(-) create mode 100644 libappbase/src/main/java/cc/winboll/studio/libappbase/models/SignCheckResponse.java create mode 100644 libappbase/src/main/res/xml/network_security_config.xml diff --git a/appbase/build.properties b/appbase/build.properties index 12a209d..2e5a1a5 100644 --- a/appbase/build.properties +++ b/appbase/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Wed Jan 21 03:11:44 GMT 2026 +#Thu Jan 22 12:38:42 GMT 2026 stageCount=7 libraryProject=libappbase baseVersion=15.15 publishVersion=15.15.6 -buildCount=1 +buildCount=11 baseBetaVersion=15.15.7 diff --git a/libappbase/build.gradle b/libappbase/build.gradle index b11c04e..f5f89d2 100644 --- a/libappbase/build.gradle +++ b/libappbase/build.gradle @@ -21,5 +21,11 @@ android { } dependencies { + // 网络连接类库 + api 'com.squareup.okhttp3:okhttp:4.4.1' + // Gson + api 'com.google.code.gson:gson:2.8.9' + // Html 解析 + api 'org.jsoup:jsoup:1.13.1' api fileTree(dir: 'libs', include: ['*.jar']) } diff --git a/libappbase/build.properties b/libappbase/build.properties index 12a209d..2e5a1a5 100644 --- a/libappbase/build.properties +++ b/libappbase/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Wed Jan 21 03:11:44 GMT 2026 +#Thu Jan 22 12:38:42 GMT 2026 stageCount=7 libraryProject=libappbase baseVersion=15.15 publishVersion=15.15.6 -buildCount=1 +buildCount=11 baseBetaVersion=15.15.7 diff --git a/libappbase/src/main/AndroidManifest.xml b/libappbase/src/main/AndroidManifest.xml index 434c960..3ad3f91 100644 --- a/libappbase/src/main/AndroidManifest.xml +++ b/libappbase/src/main/AndroidManifest.xml @@ -3,7 +3,11 @@ xmlns:android="http://schemas.android.com/apk/res/android" package="cc.winboll.studio.libappbase"> - + + + + + * @Date 2026/01/22 20:37 + */ +// ==================== JSON响应模型(与后端返回字段完全匹配)==================== +public class SignCheckResponse { + private int code; // 根节点code(后端返回) + private String msg; // 根节点提示信息(后端返回,替换原message) + private DataBean data; // 根节点data对象(后端返回) + + // 内部DataBean:对应后端返回的data字段内容 + public static class DataBean { + private boolean valid; // 实际是否合法的标识(后端data.valid) + private String signature; // 加密后的签名 + private String decryptedSign;// 解密后的原始签名 + private long validTime; // 时间戳 + } + + // Getter/Setter(关键:获取data中的valid字段) + public boolean isValid() { + return data != null && data.valid; // 从data中获取valid值 + } + + public String getMessage() { + return msg; // 对应后端根节点的msg字段 + } + + // 其他必要的Getter/Setter(用于后续扩展) + public int getCode() { + return code; + } + + public DataBean getData() { + return data; + } +} + diff --git a/libappbase/src/main/java/cc/winboll/studio/libappbase/utils/APPUtils.java b/libappbase/src/main/java/cc/winboll/studio/libappbase/utils/APPUtils.java index 306f78a..b4f3320 100644 --- a/libappbase/src/main/java/cc/winboll/studio/libappbase/utils/APPUtils.java +++ b/libappbase/src/main/java/cc/winboll/studio/libappbase/utils/APPUtils.java @@ -5,52 +5,137 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.Signature; import android.util.Base64; +import cc.winboll.studio.libappbase.GlobalApplication; import cc.winboll.studio.libappbase.LogUtils; +import cc.winboll.studio.libappbase.models.SignCheckResponse; +import com.google.gson.Gson; +import java.io.IOException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.util.Date; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; /** * @Author 豆包&ZhanGSKen * @Date 2026/01/20 19:17 - * @Describe APPUtils 应用包名、签名校验工具类 + * @Describe APPUtils 应用包名、签名校验工具类(OKHTTP网络校验版) */ public class APPUtils { - public static final String TAG = "APPUtils"; - // 目标应用签名指纹(BASE64格式,自行替换为你的合法指纹) - //public static final String TARGET_SIGN_FINGERPRINT = "你的应用签名SHA1指纹BASE64值"; - public static final String TARGET_SIGN_FINGERPRINT = "bMArVdXE4ZZo42vS9e/kXE63MkE="; - // 目标应用包名(自行替换为你的应用包名) - private static final String TARGET_PACKAGE_NAME = "cc.winboll.studio.你的应用包名"; + // 网络校验接口地址 + private static final String CHECK_API_URL = "https://console.winboll.cc/api/app-signatures-check"; + private static final String CHECK_API_URL_DEGUG = "http://localhost:8080/api/app-signatures-check"; + // OKHTTP客户端(单例复用) + private static OkHttpClient sOkHttpClient = new OkHttpClient(); + // Gson解析实例 + private static Gson sGson = new Gson(); /** - * 检查应用包名+签名指纹合法性,不匹配打日志,匹配无操作 + * 检查应用合法性(包名校验+OKHTTP网络校验签名) * @param context 上下文 + * @param callback 校验结果回调(主线程回调) */ - public static void checkAppValid(Context context) { + public static void checkAppValid(Context context, final CheckResultCallback callback) { if (context == null) { LogUtils.w(TAG, "checkAppValid: context为空,跳过校验"); + if (callback != null) callback.onResult(false, "context为空"); return; } - // 1. 校验包名 - String currentPkg = context.getPackageName(); - LogUtils.d(TAG, "checkAppValid: 当前应用包名=" + currentPkg + ",目标包名=" + TARGET_PACKAGE_NAME); - if (!TARGET_PACKAGE_NAME.equals(currentPkg)) { - LogUtils.e(TAG, "checkAppValid: 应用包名不匹配,非法环境"); - return; - } - // 2. 校验签名指纹 + + // 2. 获取当前应用签名(SHA1+Base64)和证书生效时间 String currentSign = getAppSignFingerprint(context); - LogUtils.d(TAG, "checkAppValid: 当前应用签名指纹=" + currentSign + ",目标指纹=" + TARGET_SIGN_FINGERPRINT); - if (currentSign == null || !TARGET_SIGN_FINGERPRINT.equals(currentSign)) { - LogUtils.e(TAG, "checkAppValid: 应用签名指纹不匹配,非法环境"); + long certValidTime = getCertValidTime(context); // 证书生效时间(毫秒时间戳) + if (currentSign == null) { + String errorMsg = "获取应用签名失败"; + LogUtils.e(TAG, "checkAppValid: " + errorMsg); + if (callback != null) callback.onResult(false, errorMsg); + return; + } + + // 新增:对currentSign进行Base64二次加密(URL安全编码,避免特殊字符) + String encryptedSign = base64Encode(currentSign); + LogUtils.d(TAG, "checkAppValid: 原始签名=" + currentSign + ",Base64二次加密后=" + encryptedSign); + + // 3. 构建请求URL(拼接加密后的签名参数) + String requestUrl = String.format("%s?signature=%s&validTime=%d", + GlobalApplication.isDebugging()?CHECK_API_URL_DEGUG:CHECK_API_URL, + encryptedSign, // 替换为加密后的签名 + certValidTime); + LogUtils.d(TAG, "checkAppValid: 发起网络校验请求,URL=" + requestUrl); + + // 4. OKHTTP发起异步GET请求 + Request request = new Request.Builder().url(requestUrl).build(); + sOkHttpClient.newCall(request).enqueue(new Callback() { + @Override + public void onFailure(Call call, IOException e) { + final String errorMsg = "网络校验请求失败:" + e.getMessage(); + LogUtils.e(TAG, "checkAppValid: " + errorMsg, e); + if (callback != null) { + // 切换到主线程回调 + new android.os.Handler(android.os.Looper.getMainLooper()).post(new Runnable() { + @Override + public void run() { + callback.onResult(false, errorMsg); + } + }); + } + } + + @Override + public void onResponse(Call call, Response response) throws IOException { + if (response.isSuccessful() && response.body() != null) { + String responseJson = response.body().string(); + LogUtils.d(TAG, "checkAppValid: 网络校验响应JSON=" + responseJson); + // 解析JSON响应 + SignCheckResponse checkResponse = sGson.fromJson(responseJson, SignCheckResponse.class); + final boolean isValid = checkResponse != null && checkResponse.isValid(); + final String msg = checkResponse != null ? checkResponse.getMessage() : "响应解析失败"; + if (callback != null) { + new android.os.Handler(android.os.Looper.getMainLooper()).post(new Runnable() { + @Override + public void run() { + callback.onResult(isValid, msg); + } + }); + } + } else { + final String errorMsg = "网络校验响应失败,code=" + response.code(); + LogUtils.e(TAG, "checkAppValid: " + errorMsg); + if (callback != null) { + new android.os.Handler(android.os.Looper.getMainLooper()).post(new Runnable() { + @Override + public void run() { + callback.onResult(false, errorMsg); + } + }); + } + } + } + }); + } + + /** + * 新增:Base64加密工具(URL安全编码,避免特殊字符影响URL拼接) + * @param content 待加密内容 + * @return 加密后的Base64字符串 + */ + private static String base64Encode(String content) { + try { + // 使用URL安全的Base64编码(替换+为-,/为_,去除=) + byte[] contentBytes = content.getBytes("UTF-8"); + return Base64.encodeToString(contentBytes, Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP); + } catch (Exception e) { + LogUtils.e(TAG, "base64Encode: 加密失败", e); + return content; // 加密失败则返回原始内容,避免请求异常 } } /** - * 获取当前应用签名SHA1指纹(BASE64编码,适配Java7) - * @param context 上下文 - * @return 签名指纹字符串,失败返回null + * 获取当前应用签名SHA1指纹(BASE64编码) */ private static String getAppSignFingerprint(Context context) { try { @@ -61,18 +146,49 @@ public class APPUtils { LogUtils.w(TAG, "getAppSignFingerprint: 未获取到应用签名"); return null; } - // SHA1摘要 + BASE64编码,和目标指纹格式统一 MessageDigest md = MessageDigest.getInstance("SHA1"); md.update(signatures[0].toByteArray()); return Base64.encodeToString(md.digest(), Base64.NO_WRAP); - } catch (PackageManager.NameNotFoundException e) { - LogUtils.e(TAG, "getAppSignFingerprint: 包名未找到", e); - } catch (NoSuchAlgorithmException e) { - LogUtils.e(TAG, "getAppSignFingerprint: 不支持SHA1算法", e); - } catch (Exception e) { + } catch (PackageManager.NameNotFoundException | NoSuchAlgorithmException e) { LogUtils.e(TAG, "getAppSignFingerprint: 获取签名异常", e); + } catch (Exception e) { + LogUtils.e(TAG, "getAppSignFingerprint: 未知异常", e); } return null; } + + /** + * 获取应用证书生效时间(毫秒时间戳) + */ + private static long getCertValidTime(Context context) { + try { + PackageManager pm = context.getPackageManager(); + PackageInfo pkgInfo = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES); + Signature[] signatures = pkgInfo.signatures; + if (signatures == null || signatures.length == 0) { + LogUtils.w(TAG, "getCertValidTime: 未获取到应用签名"); + return new Date().getTime(); // 默认当前时间 + } + // 解析签名证书,获取生效时间(简化实现,实际需解析X.509证书) + // 注意:若需精准获取证书生效时间,需解析Signature的toByteArray()为X509Certificate + // 此处为简化版,若需精准实现可告知,将补充完整证书解析逻辑 + return new Date().getTime(); + } catch (PackageManager.NameNotFoundException e) { + LogUtils.e(TAG, "getCertValidTime: 获取包信息异常", e); + } catch (Exception e) { + LogUtils.e(TAG, "getCertValidTime: 未知异常", e); + } + return new Date().getTime(); + } + + // ==================== 校验结果回调接口 ==================== + public interface CheckResultCallback { + /** + * 校验结果回调(主线程调用) + * @param isValid 是否合法 + * @param message 校验信息 + */ + void onResult(boolean isValid, String message); + } } diff --git a/libappbase/src/main/res/xml/network_security_config.xml b/libappbase/src/main/res/xml/network_security_config.xml new file mode 100644 index 0000000..89ad175 --- /dev/null +++ b/libappbase/src/main/res/xml/network_security_config.xml @@ -0,0 +1,11 @@ + + + + + winboll.cc + + localhost + 127.0.0.1 + + + From d20192cb3658636febfb53ef214d3dde639fe348 Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Thu, 22 Jan 2026 21:19:39 +0800 Subject: [PATCH 027/430] =?UTF-8?q?=E6=AD=A3=E5=9C=A8=E6=94=B9=E9=80=A0Win?= =?UTF-8?q?BoLL=E4=B8=BB=E6=9C=BA=E5=88=87=E6=8D=A2=E5=AF=B9=E8=AF=9D?= =?UTF-8?q?=E6=A1=86=E4=B8=8E=E6=8C=89=E9=92=AE=E3=80=82=E3=80=82=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- appbase/build.properties | 4 +- libappbase/build.properties | 4 +- .../studio/libappbase/GlobalApplication.java | 53 +++++++++- .../libappbase/dialogs/DebugHostDialog.java | 99 +++++++++++++++++++ .../studio/libappbase/views/AboutView.java | 8 +- libappbase/src/main/res/drawable/ic_bug.xml | 11 +++ .../src/main/res/layout/dialog_debug_host.xml | 60 +++++++++++ .../src/main/res/layout/layout_about_view.xml | 10 +- 8 files changed, 235 insertions(+), 14 deletions(-) create mode 100644 libappbase/src/main/java/cc/winboll/studio/libappbase/dialogs/DebugHostDialog.java create mode 100644 libappbase/src/main/res/drawable/ic_bug.xml create mode 100644 libappbase/src/main/res/layout/dialog_debug_host.xml diff --git a/appbase/build.properties b/appbase/build.properties index 2e5a1a5..4be9f3e 100644 --- a/appbase/build.properties +++ b/appbase/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Thu Jan 22 12:38:42 GMT 2026 +#Thu Jan 22 13:18:42 GMT 2026 stageCount=7 libraryProject=libappbase baseVersion=15.15 publishVersion=15.15.6 -buildCount=11 +buildCount=15 baseBetaVersion=15.15.7 diff --git a/libappbase/build.properties b/libappbase/build.properties index 2e5a1a5..b03a2a5 100644 --- a/libappbase/build.properties +++ b/libappbase/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Thu Jan 22 12:38:42 GMT 2026 +#Thu Jan 22 13:18:03 GMT 2026 stageCount=7 libraryProject=libappbase baseVersion=15.15 publishVersion=15.15.6 -buildCount=11 +buildCount=15 baseBetaVersion=15.15.7 diff --git a/libappbase/src/main/java/cc/winboll/studio/libappbase/GlobalApplication.java b/libappbase/src/main/java/cc/winboll/studio/libappbase/GlobalApplication.java index 9fb8035..4e51b99 100644 --- a/libappbase/src/main/java/cc/winboll/studio/libappbase/GlobalApplication.java +++ b/libappbase/src/main/java/cc/winboll/studio/libappbase/GlobalApplication.java @@ -2,6 +2,7 @@ package cc.winboll.studio.libappbase; import android.app.Application; import android.content.Context; +import android.content.SharedPreferences; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; @@ -26,6 +27,12 @@ public class GlobalApplication extends Application { */ private static volatile boolean isDebugging = false; + // 新增:WinBoLL 服务器主机地址(volatile 保证多线程可见性) + private static volatile String winbollHost = null; + // 新增:SP 存储相关常量(私有存储,仅当前应用可访问) + private static final String SP_NAME = "WinBoLL_SP_CONFIG"; + private static final String SP_KEY_WINBOLL_HOST = "winboll_host"; + /** * 获取全局 Application 单例实例(外部可通过此方法获取上下文) * @return GlobalApplication 单例(未初始化时返回 null,需确保配置 AndroidManifest) @@ -53,7 +60,7 @@ public class GlobalApplication extends Application { } // 将调试状态封装为 APPModel 并保存到文件 APPModel.saveBeanToFile( - getAppModelFilePath(application), + getAppModelFilePath(application), new APPModel(isDebugging) ); } @@ -76,6 +83,37 @@ public class GlobalApplication extends Application { return isDebugging; } + // 新增:设置 WinBoLL 服务器主机地址(同时保存到 SP 持久化) + public static void setWinbollHost(String host) { + if (sInstance == null) { + LogUtils.e(TAG, "setWinbollHost: 应用未初始化,设置失败"); + return; + } + // 更新内存中的字段 + winbollHost = host; + // 保存到 SP 持久化(私有模式,安全) + SharedPreferences sp = sInstance.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); + sp.edit().putString(SP_KEY_WINBOLL_HOST, host).apply(); + LogUtils.d(TAG, "setWinbollHost: 服务器地址已设置并持久化,host=" + host); + } + + // 新增:获取 WinBoLL 服务器主机地址(优先内存,内存为空则从 SP 读取) + public static String getWinbollHost() { + if (winbollHost != null) { + // 内存中存在,直接返回(提高效率) + return winbollHost; + } + if (sInstance == null) { + LogUtils.e(TAG, "getWinbollHost: 应用未初始化,获取失败"); + return null; + } + // 内存中不存在,从 SP 读取并更新到内存 + SharedPreferences sp = sInstance.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); + winbollHost = sp.getString(SP_KEY_WINBOLL_HOST, null); + LogUtils.d(TAG, "getWinbollHost: 从 SP 读取服务器地址,host=" + winbollHost); + return winbollHost; + } + /** * 应用启动时初始化(仅执行一次) * 初始化核心框架、恢复调试状态、配置全局异常处理等 @@ -85,12 +123,13 @@ public class GlobalApplication extends Application { super.onCreate(); // 初始化单例实例(确保在所有初始化操作前完成) sInstance = this; - // 初始化基础组件(日志、崩溃处理、Toast) initCoreComponents(); // 恢复/初始化调试模式状态(从本地文件读取,无文件则默认关闭调试) restoreDebugStatus(); + // 新增:初始化服务器地址(从 SP 读取到内存,提高后续访问效率) + initWinbollHost(); LogUtils.d(TAG, "GlobalApplication 初始化完成,单例实例已创建"); } @@ -115,7 +154,7 @@ public class GlobalApplication extends Application { private void restoreDebugStatus() { // 从文件加载 APPModel 实例(存储调试状态的模型类) APPModel appModel = APPModel.loadBeanFromFile( - getAppModelFilePath(this), + getAppModelFilePath(this), APPModel.class ); @@ -131,6 +170,11 @@ public class GlobalApplication extends Application { } } + // 新增:初始化服务器地址(应用启动时从 SP 读取到内存) + private void initWinbollHost() { + getWinbollHost(); // 触发从 SP 读取并更新内存 + } + /** * 获取应用名称(从 AndroidManifest.xml 的 android:label 读取) * @param context 上下文(建议传入 Application 上下文,避免内存泄漏) @@ -154,7 +198,7 @@ public class GlobalApplication extends Application { return appName; } catch (NameNotFoundException e) { // 包名不存在(理论上不会发生,捕获异常避免崩溃) - LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); + LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); //LogUtils.e(TAG, "获取应用名称失败:包名不存在", e); e.printStackTrace(); } @@ -170,7 +214,6 @@ public class GlobalApplication extends Application { // 释放单例引用(可选,避免内存泄漏风险) sInstance = null; LogUtils.d(TAG, "GlobalApplication 终止,单例实例已释放"); - } } diff --git a/libappbase/src/main/java/cc/winboll/studio/libappbase/dialogs/DebugHostDialog.java b/libappbase/src/main/java/cc/winboll/studio/libappbase/dialogs/DebugHostDialog.java new file mode 100644 index 0000000..79a9bb6 --- /dev/null +++ b/libappbase/src/main/java/cc/winboll/studio/libappbase/dialogs/DebugHostDialog.java @@ -0,0 +1,99 @@ +package cc.winboll.studio.libappbase.dialogs; + +import android.app.Dialog; +import android.content.Context; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.Toast; +import cc.winboll.studio.libappbase.GlobalApplication; +import cc.winboll.studio.libappbase.LogUtils; +import cc.winboll.studio.libappbase.R; +import cc.winboll.studio.libappbase.ToastUtils; + +/** + * @Author 豆包&ZhanGSKen + * @Date 2026/01/22 20:59 + * @Describe WinBoLL服务器地址设置对话框(调试模式专用) + */ +public class DebugHostDialog extends Dialog implements View.OnClickListener { + public static final String TAG = "DebugHostDialog"; + + private Context mContext; + private EditText etHostInput; + private Button btnConfirm; + private Button btnCancel; + + // 构造方法(适配默认样式) + public DebugHostDialog(Context context) { + super(context, R.style.DialogStyle); + this.mContext = context; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.dialog_debug_host); // 绑定XML布局 + setCancelable(true); // 点击外部可关闭 + initView(); + initData(); + LogUtils.d(TAG, "DebugHostDialog 初始化完成"); + } + + // 初始化视图 + private void initView() { + etHostInput = findViewById(R.id.et_host_input); + btnConfirm = findViewById(R.id.btn_confirm); + btnCancel = findViewById(R.id.btn_cancel); + + // 绑定点击事件 + btnConfirm.setOnClickListener(this); + btnCancel.setOnClickListener(this); + } + + // 初始化数据(显示当前已保存的地址) + private void initData() { + String currentHost = GlobalApplication.getWinbollHost(); + if (!TextUtils.isEmpty(currentHost)) { + etHostInput.setText(currentHost); + etHostInput.setSelection(currentHost.length()); // 光标定位到末尾 + LogUtils.d(TAG, "当前已保存的服务器地址:" + currentHost); + } + } + + @Override + public void onClick(View v) { + int id = v.getId(); + if (id == R.id.btn_confirm) { + handleConfirm(); // 确认设置 + } else if (id == R.id.btn_cancel) { + dismiss(); // 取消对话框 + } + } + + // 处理确认设置逻辑 + private void handleConfirm() { + String inputHost = etHostInput.getText().toString().trim(); + if (TextUtils.isEmpty(inputHost)) { + ToastUtils.show("服务器地址不能为空"); + LogUtils.w(TAG, "设置失败:地址为空"); + return; + } + + // 简单校验URL格式(避免明显错误) + if (!inputHost.startsWith("http://") && !inputHost.startsWith("https://")) { + ToastUtils.show("地址需以http://或https://开头"); + LogUtils.w(TAG, "设置失败:地址格式错误,input=" + inputHost); + return; + } + + // 保存地址到SP+内存 + GlobalApplication.setWinbollHost(inputHost); + ToastUtils.show("服务器地址设置成功"); + LogUtils.d(TAG, "服务器地址设置成功:" + inputHost); + dismiss(); // 关闭对话框 + } +} + diff --git a/libappbase/src/main/java/cc/winboll/studio/libappbase/views/AboutView.java b/libappbase/src/main/java/cc/winboll/studio/libappbase/views/AboutView.java index 3c3892f..ddc294b 100644 --- a/libappbase/src/main/java/cc/winboll/studio/libappbase/views/AboutView.java +++ b/libappbase/src/main/java/cc/winboll/studio/libappbase/views/AboutView.java @@ -116,7 +116,8 @@ public class AboutView extends LinearLayout { // LogUtils.d(TAG, "initViewFromXml 布局加载+视图绑定完成"); // } // 1. 新增视图绑定属性(加在原有视图属性后面) - private ImageButton ibSigngetdialog; + private ImageButton ibSigngetDialog; + private ImageButton ibWinBoLLHostDialog; // 2. 完善initViewFromXml方法,新增按钮绑定 private void initViewFromXml() { @@ -125,14 +126,15 @@ public class AboutView extends LinearLayout { tvAppNameVersion = findViewById(R.id.tv_app_name_version); tvAppDesc = findViewById(R.id.tv_app_desc); llFunctionContainer = findViewById(R.id.ll_function_container); - ibSigngetdialog = findViewById(R.id.ib_signgetdialog); // 新增按钮绑定 + ibSigngetDialog = findViewById(R.id.ib_signgetdialog); // 新增按钮绑定 + ibWinBoLLHostDialog = findViewById(R.id.ib_winbollhostdialog); // 新增按钮绑定 setBtnClickListener(); // 新增绑定点击事件 LogUtils.d(TAG, "initViewFromXml 布局加载+视图绑定完成"); } // 3. 新增按钮点击事件方法(放在initViewFromXml下面即可) private void setBtnClickListener() { - ibSigngetdialog.setOnClickListener(new OnClickListener() { + ibSigngetDialog.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { LogUtils.d(TAG, "签名获取按钮点击,弹出SignGetDialog"); diff --git a/libappbase/src/main/res/drawable/ic_bug.xml b/libappbase/src/main/res/drawable/ic_bug.xml new file mode 100644 index 0000000..41a7159 --- /dev/null +++ b/libappbase/src/main/res/drawable/ic_bug.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/libappbase/src/main/res/layout/dialog_debug_host.xml b/libappbase/src/main/res/layout/dialog_debug_host.xml new file mode 100644 index 0000000..df7fe80 --- /dev/null +++ b/libappbase/src/main/res/layout/dialog_debug_host.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + +