Compare commits

...

26 Commits

Author SHA1 Message Date
9ae848e4c2 <appbase>APK 15.15.20 release Publish. 2026-04-27 20:18:59 +08:00
9c66f61891 调整MainActivity按钮顺序将关于应用置顶 2026-04-27 20:15:54 +08:00
bfaf3543b9 添加多窗口支持与LogActivity独立任务栈 2026-04-27 20:04:17 +08:00
b44fe3aaf3 添加分屏测试功能支持多窗口MainActivity 2026-04-27 19:27:25 +08:00
d518ac50a9 优化LogActivity分屏模式支持Android 11适配 2026-04-27 18:40:36 +08:00
d532eae971 调整onLogTest调用LogActivity分屏模式 2026-04-27 17:58:53 +08:00
f661acbbbc 添加LogActivity重载函数支持分屏模式切换 2026-04-27 17:33:51 +08:00
ecced75a4d 调整AboutActivity工具栏与MainActivity一致 2026-04-25 12:10:17 +08:00
5e5d34c90c 调整BaseFunctionItemView派生控件高度间隔为无间隔 2026-04-25 10:43:18 +08:00
85a0d39498 添加BaseFunctionItemView类视图1像素美化边框 2026-04-25 10:40:50 +08:00
c542d8dca7 源码整理 2026-04-25 10:25:59 +08:00
ccbdb4010e 调整一下libappbase模块中layout_about_view.xml的布局文件。缩小一下布局中控件的高度间隔。 2026-04-25 10:22:20 +08:00
2e7b9173f2 <libappbase>Library Release 15.15.19 2026-04-25 04:12:02 +08:00
4f12a5de4f <appbase>APK 15.15.19 release Publish. 2026-04-25 04:11:46 +08:00
7ab399e520 编译调试 2026-04-25 04:10:29 +08:00
dd2d9f3e55 Merge branch 'appbase' of https://gitea.winboll.cc/Studio/WinBoLL.git into appbase 2026-04-25 04:07:49 +08:00
098516d4d7 Merge branch 'winboll' into appbase 2026-04-25 04:07:03 +08:00
b1fab5ce46 <libappbase>Library Release 15.15.18 2026-04-25 03:59:02 +08:00
e68098aa10 <appbase>APK 15.15.18 release Publish. 2026-04-10 05:38:18 +08:00
d673ba46a1 更正应用验证时使用的应用包名称配置 2026-04-10 05:36:14 +08:00
6c8867e15c 更正maven库引用顺序 2026-04-09 01:38:28 +08:00
5a1342156f <appbase>APK 15.15.17 release Publish. 2026-04-06 20:39:30 +08:00
4e1784d99f 更换App为APP。以适配应用版本检查时使用的APK应用包名称APPBase。 2026-04-06 20:38:50 +08:00
069e5a66ad <appbase>APK 15.15.16 release Publish. 2026-04-06 20:25:21 +08:00
e9a1dca8ca 应用调试功能切换Logo准备完成。 2026-04-06 20:23:37 +08:00
7e3a3d1446 添加调试状态切换Logo控件 2026-04-06 19:42:34 +08:00
23 changed files with 401 additions and 140 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Wed Mar 25 20:52:43 HKT 2026 #Mon Apr 27 20:18:59 HKT 2026
stageCount=16 stageCount=21
libraryProject=libappbase libraryProject=libappbase
baseVersion=15.15 baseVersion=15.15
publishVersion=15.15.15 publishVersion=15.15.20
buildCount=0 buildCount=0
baseBetaVersion=15.15.16 baseBetaVersion=15.15.21

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="app_name">AppBase+</string> <string name="app_name">APPBase+</string>
</resources> </resources>

View File

@@ -16,6 +16,17 @@
android:label="@string/app_name" android:label="@string/app_name"
android:exported="true" android:exported="true"
android:resizeableActivity="true" android:resizeableActivity="true"
android:launchMode="singleTop"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation">
</activity>
<activity
android:name=".MainActivityAlias"
android:label="@string/app_name"
android:exported="true"
android:resizeableActivity="true"
android:launchMode="singleTop"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"> android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation">
<intent-filter> <intent-filter>
@@ -30,6 +41,17 @@
</activity> </activity>
<activity
android:name=".Main2Activity"
android:label="@string/app_name"
android:exported="true"
android:resizeableActivity="true"
android:launchMode="singleTop"
android:taskAffinity="cc.winboll.studio.appbase.Main2Activity"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation">
</activity>
<activity android:name=".GlobalApplication$CrashActivity"/> <activity android:name=".GlobalApplication$CrashActivity"/>
<meta-data <meta-data

View File

@@ -23,17 +23,8 @@ public class AboutActivity extends Activity {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_about); setContentView(R.layout.activity_about);
// 设置工具栏
Toolbar toolbar = findViewById(R.id.toolbar); Toolbar toolbar = findViewById(R.id.toolbar);
setActionBar(toolbar); setActionBar(toolbar);
getActionBar().setSubtitle(TAG);
getActionBar().setDisplayHomeAsUpEnabled(true);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish(); // 点击导航栏返回按钮,触发 finish()
}
});
AboutView aboutView = findViewById(R.id.aboutview); AboutView aboutView = findViewById(R.id.aboutview);
aboutView.setAPPInfo(genDefaultAppInfo()); aboutView.setAPPInfo(genDefaultAppInfo());
@@ -43,7 +34,7 @@ public class AboutActivity extends Activity {
LogUtils.d(TAG, "genDefaultAppInfo() 调用"); LogUtils.d(TAG, "genDefaultAppInfo() 调用");
String branchName = "appbase"; String branchName = "appbase";
APPInfo appInfo = new APPInfo(); APPInfo appInfo = new APPInfo();
appInfo.setAppName(getString(R.string.app_name)); appInfo.setAppName("APPBase");
appInfo.setAppIcon(R.drawable.ic_winboll); appInfo.setAppIcon(R.drawable.ic_winboll);
appInfo.setAppDescription(getString(R.string.app_description)); appInfo.setAppDescription(getString(R.string.app_description));
appInfo.setAppGitName("WinBoLL"); appInfo.setAppGitName("WinBoLL");

View File

@@ -21,9 +21,12 @@ public class App extends GlobalApplication {
*/ */
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); // 调用父类初始化逻辑(如基础库配置、全局上下文设置) super.onCreate();
//setIsDebugging(false); // 如果应用不在调试状态,就根据编译类型设置调试状态
setIsDebugging(BuildConfig.DEBUG); if (isDebugging() != true) {
setIsDebugging(BuildConfig.DEBUG);
}
// 初始化 Toast 工具类(传入应用全局上下文,确保 Toast 可在任意地方调用) // 初始化 Toast 工具类(传入应用全局上下文,确保 Toast 可在任意地方调用)
ToastUtils.init(getApplicationContext()); ToastUtils.init(getApplicationContext());
} }

View File

@@ -0,0 +1,20 @@
package cc.winboll.studio.appbase;
import android.os.Bundle;
import android.widget.Toolbar;
import cc.winboll.studio.appbase.R;
public class Main2Activity extends MainActivity {
public static final String TAG = "Main2Activity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Toolbar toolbar = findViewById(R.id.toolbar);
if (toolbar != null) {
setActionBar(toolbar);
}
}
}

View File

@@ -103,14 +103,17 @@ public class MainActivity extends Activity {
} }
} }
public void onLogTestNewTask(View view) {
LogActivity.startLogActivity(this, true);
}
/** /**
* 日志测试按钮点击事件(打开日志查看界面) * 日志测试按钮点击事件(打开日志查看界面)
* 启动 LogActivity用于查看应用运行日志 * 启动 LogActivity用于查看应用运行日志
* @param view 触发事件的 View对应布局中的日志测试按钮 * @param view 触发事件的 View对应布局中的日志测试按钮
*/ */
public void onLogTest(View view) { public void onLogTest(View view) {
// 启动日志查看 Activity通过静态方法传入上下文简化跳转逻辑 LogActivity.startLogActivity(this, false);
LogActivity.startLogActivity(this);
} }
/** /**
@@ -158,5 +161,35 @@ public class MainActivity extends Activity {
Intent aboutIntent = new Intent(getApplicationContext(), AboutActivity.class); Intent aboutIntent = new Intent(getApplicationContext(), AboutActivity.class);
startActivity(aboutIntent); startActivity(aboutIntent);
} }
public void onSplitScreenMode(View view) {
LogUtils.d(TAG, "onSplitScreenMode() 分屏测试按钮已点击");
ToastUtils.show("分屏测试:已启动新窗口");
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
android.graphics.Rect bounds = new android.graphics.Rect();
getWindow().getDecorView().getDisplay().getRectSize(bounds);
int height = bounds.height();
int width = bounds.width();
bounds.set(0, 0, width, height / 2);
LogUtils.d(TAG, "onSplitScreenMode() 分屏窗口范围: " + bounds);
android.content.Intent intent = new android.content.Intent(this, MainActivityAlias.class);
intent.setFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK);
LogUtils.d(TAG, "onSplitScreenMode() 准备启动MainActivityAlias");
android.app.ActivityOptions options = android.app.ActivityOptions.makeBasic();
options.setLaunchBounds(bounds);
startActivity(intent, options.toBundle());
LogUtils.d(TAG, "onSplitScreenMode() MainActivityAlias已启动");
}
}
public void onMultiInstance(View view) {
LogUtils.d(TAG, "onMultiInstance() 多开窗口按钮已点击");
ToastUtils.show("多开窗口:已启动新窗口");
android.content.Intent intent = new android.content.Intent(this, Main2Activity.class);
intent.setFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK);
LogUtils.d(TAG, "onMultiInstance() 准备启动Main2Activity");
startActivity(intent);
LogUtils.d(TAG, "onMultiInstance() Main2Activity已启动");
}
} }

View File

@@ -0,0 +1,17 @@
package cc.winboll.studio.appbase;
import android.os.Bundle;
import android.view.View;
import android.widget.Toolbar;
import cc.winboll.studio.appbase.R;
public class MainActivityAlias extends MainActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setActionBar(toolbar);
}
}

View File

@@ -23,6 +23,18 @@
android:gravity="center_vertical" android:gravity="center_vertical"
android:spacing="12dp"> android:spacing="12dp">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="关于应用"
android:textSize="16sp"
android:textColor="@android:color/white"
android:background="#81C7F5"
android:paddingVertical="12dp"
android:layout_marginHorizontal="24dp"
android:onClick="onAboutActivity"
android:layout_margin="10dp"/>
<Button <Button
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -47,6 +59,18 @@
android:onClick="onLogTest" android:onClick="onLogTest"
android:layout_margin="10dp"/> android:layout_margin="10dp"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="应用日志测试(新窗口)"
android:textSize="16sp"
android:textColor="@android:color/white"
android:background="#81C7F5"
android:paddingVertical="12dp"
android:layout_marginHorizontal="24dp"
android:onClick="onLogTestNewTask"
android:layout_margin="10dp"/>
<Button <Button
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -62,13 +86,25 @@
<Button <Button
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="关于应用" android:text="分屏测试"
android:textSize="16sp" android:textSize="16sp"
android:textColor="@android:color/white" android:textColor="@android:color/white"
android:background="#81C7F5" android:background="#81C7F5"
android:paddingVertical="12dp" android:paddingVertical="12dp"
android:layout_marginHorizontal="24dp" android:layout_marginHorizontal="24dp"
android:onClick="onAboutActivity" android:onClick="onSplitScreenMode"
android:layout_margin="10dp"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="多开窗口"
android:textSize="16sp"
android:textColor="@android:color/white"
android:background="#81C7F5"
android:paddingVertical="12dp"
android:layout_marginHorizontal="24dp"
android:onClick="onMultiInstance"
android:layout_margin="10dp"/> android:layout_margin="10dp"/>
</LinearLayout> </LinearLayout>
@@ -76,4 +112,3 @@
</ScrollView> </ScrollView>
</LinearLayout> </LinearLayout>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:background="@android:color/white">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Main2Activity"
android:textSize="24sp"
android:textColor="@color/gray_900"/>
</LinearLayout>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="app_name">AppBase</string> <string name="app_name">APPBase</string>
<string name="app_description">WinBoLL 安卓手机端安卓应用开发基础类库。</string> <string name="app_description">WinBoLL 安卓手机端安卓应用开发基础类库。</string>
<string name="app_normal">Click here is switch to Normal APP</string> <string name="app_normal">Click here is switch to Normal APP</string>
<string name="app_debug">Click here is switch to APP DEBUG</string> <string name="app_debug">Click here is switch to APP DEBUG</string>

View File

@@ -1,6 +1,15 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { buildscript {
repositories { repositories {
maven { url 'https://maven.aliyun.com/repository/public/' }
maven { url 'https://maven.aliyun.com/repository/google/' }
maven { url 'https://maven.aliyun.com/repository/gradle-plugin/' }
maven { url 'https://dl.bintray.com/ppartisan/maven/' }
maven { url "https://clojars.org/repo/" }
maven { url "https://jitpack.io" }
mavenCentral()
google()
mavenLocal { mavenLocal {
// 设置本地Maven仓库路径 // 设置本地Maven仓库路径
url 'file:///sdcard/.m2/repository/' url 'file:///sdcard/.m2/repository/'
@@ -11,19 +20,6 @@ buildscript {
maven { url "https://nexus.winboll.cc/repository/maven-public/" } maven { url "https://nexus.winboll.cc/repository/maven-public/" }
// "WinBoLL Snapshot" // "WinBoLL Snapshot"
maven { url "https://nexus.winboll.cc/repository/maven-snapshots/" } maven { url "https://nexus.winboll.cc/repository/maven-snapshots/" }
maven { url 'https://maven.aliyun.com/repository/public/' }
maven { url 'https://maven.aliyun.com/repository/google/' }
maven { url 'https://maven.aliyun.com/repository/gradle-plugin/' }
maven { url 'https://dl.bintray.com/ppartisan/maven/' }
maven { url "https://clojars.org/repo/" }
maven { url "https://jitpack.io" }
mavenCentral()
google()
//println "mavenLocal : ==========="
//println mavenLocal().url
//println "mavenLocal : ==========="
//mavenLocal()
} }
dependencies { dependencies {
// 适配MIUI12 // 适配MIUI12
@@ -35,6 +31,15 @@ buildscript {
allprojects { allprojects {
repositories { repositories {
maven { url 'https://maven.aliyun.com/repository/public/' }
maven { url 'https://maven.aliyun.com/repository/google/' }
maven { url 'https://maven.aliyun.com/repository/gradle-plugin/' }
maven { url 'https://dl.bintray.com/ppartisan/maven/' }
maven { url "https://clojars.org/repo/" }
maven { url "https://jitpack.io" }
mavenCentral()
google()
mavenLocal { mavenLocal {
// 设置本地Maven仓库路径 // 设置本地Maven仓库路径
url 'file:///sdcard/.m2/repository/' url 'file:///sdcard/.m2/repository/'
@@ -45,19 +50,6 @@ allprojects {
maven { url "https://nexus.winboll.cc/repository/maven-public/" } maven { url "https://nexus.winboll.cc/repository/maven-public/" }
// "WinBoLL Snapshot" // "WinBoLL Snapshot"
maven { url "https://nexus.winboll.cc/repository/maven-snapshots/" } maven { url "https://nexus.winboll.cc/repository/maven-snapshots/" }
maven { url 'https://maven.aliyun.com/repository/public/' }
maven { url 'https://maven.aliyun.com/repository/google/' }
maven { url 'https://maven.aliyun.com/repository/gradle-plugin/' }
maven { url 'https://dl.bintray.com/ppartisan/maven/' }
maven { url "https://clojars.org/repo/" }
maven { url "https://jitpack.io" }
mavenCentral()
google()
//println "mavenLocal : ==========="
//println mavenLocal().url
//println "mavenLocal : ==========="
//mavenLocal()
} }
ext { ext {
// 定义全局变量,常用于版本管理 // 定义全局变量,常用于版本管理

0
gradlew vendored Normal file → Executable file
View File

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Wed Mar 25 20:52:43 HKT 2026 #Mon Apr 27 20:18:59 HKT 2026
stageCount=16 stageCount=21
libraryProject=libappbase libraryProject=libappbase
baseVersion=15.15 baseVersion=15.15
publishVersion=15.15.15 publishVersion=15.15.20
buildCount=0 buildCount=0
baseBetaVersion=15.15.16 baseBetaVersion=15.15.21

View File

@@ -38,6 +38,7 @@
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation" android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
android:exported="true" android:exported="true"
android:launchMode="singleInstance" android:launchMode="singleInstance"
android:taskAffinity="cc.winboll.studio.libappbase.LogActivity"
android:process=":LogActivity"> android:process=":LogActivity">
</activity> </activity>

View File

@@ -1,8 +1,11 @@
package cc.winboll.studio.libappbase; package cc.winboll.studio.libappbase;
import android.app.Activity; import android.app.Activity;
import android.app.ActivityOptions;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import cc.winboll.studio.libappbase.LogView; import cc.winboll.studio.libappbase.LogView;
import cc.winboll.studio.libappbase.R; import cc.winboll.studio.libappbase.R;
@@ -46,20 +49,39 @@ public class LogActivity extends Activity {
* @param context 上下文Activity/Fragment用于启动 Activity * @param context 上下文Activity/Fragment用于启动 Activity
*/ */
public static void startLogActivity(Context context) { public static void startLogActivity(Context context) {
// 创建启动当前 Activity 的 Intent startLogActivity(context, true);
}
/**
* 启动日志 Activity 的静态方法重载(外部调用入口)
* @param context 上下文Activity/Fragment用于启动 Activity
* @param newTask 是否在新窗口中启动
*/
public static void startLogActivity(Context context, boolean newTask) {
Intent intent = new Intent(context, LogActivity.class); Intent intent = new Intent(context, LogActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
// 添加 Intent 标志:支持分屏/多窗口模式API 24+ if (newTask) {
intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
// 添加 Intent 标志:创建新任务栈(避免并入调用者任务栈) intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent);
// 添加 Intent 标志:标记为新文档(多任务窗口中独立显示) } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT);
// 添加 Intent 标志:允许创建多个任务实例(支持多次启动独立窗口) intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
// 启动 Activity Rect bounds = new Rect();
context.startActivity(intent); if (context instanceof Activity) {
Activity activity = (Activity) context;
activity.getWindow().getDecorView().getDisplay().getRectSize(bounds);
bounds.set(0, bounds.height() / 2, bounds.width(), bounds.height());
}
ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchBounds(bounds);
context.startActivity(intent, options.toBundle());
} else {
context.startActivity(intent);
}
} }
} }

View File

@@ -19,7 +19,7 @@ import cc.winboll.studio.libappbase.utils.ApkSignUtils;
* @LastEditTime 2026-01-24 18:45:00 * @LastEditTime 2026-01-24 18:45:00
* @Describe 签名显示+正版校验对话框展示应用签名字节位信息调用网络接口完成正版合法性校验实时返回校验结果 * @Describe 签名显示+正版校验对话框展示应用签名字节位信息调用网络接口完成正版合法性校验实时返回校验结果
*/ */
public class AppValidationDialog extends Dialog { public class APPValidationDialog extends Dialog {
// ===================================== 全局常量 ===================================== // ===================================== 全局常量 =====================================
public static final String TAG = "AppValidationDialog"; public static final String TAG = "AppValidationDialog";
// 签名字节位分组大小 // 签名字节位分组大小
@@ -31,18 +31,18 @@ public class AppValidationDialog extends Dialog {
private TextView tvAuthResult; private TextView tvAuthResult;
// ===================================== 业务入参属性 ===================================== // ===================================== 业务入参属性 =====================================
private String projectName; private String appName;
private String versionName; private String versionName;
private String clientSign; private String clientSign;
private String clientHash; private String clientHash;
// ===================================== 构造方法 ===================================== // ===================================== 构造方法 =====================================
public AppValidationDialog(Context context, String projectName, String versionName) { public APPValidationDialog(Context context, String appName, String versionName) {
super(context, R.style.DialogStyle); super(context, R.style.DialogStyle);
this.mContext = context; this.mContext = context;
this.projectName = projectName; this.appName = appName;
this.versionName = versionName; this.versionName = versionName;
LogUtils.d(TAG, "AppValidationDialog: 构造方法初始化,入参-> projectName=" + projectName + ", versionName=" + versionName); LogUtils.d(TAG, "AppValidationDialog: 构造方法初始化,入参-> projectName=" + appName + ", versionName=" + versionName);
} }
// ===================================== 生命周期方法 ===================================== // ===================================== 生命周期方法 =====================================
@@ -104,7 +104,7 @@ public class AppValidationDialog extends Dialog {
// 调用网络校验接口 // 调用网络校验接口
new APPUtils().checkAPKValidation( new APPUtils().checkAPKValidation(
mContext, mContext,
projectName, appName,
versionName, versionName,
clientSign, clientSign,
clientHash, clientHash,

View File

@@ -49,10 +49,10 @@ public class APPUtils {
* @param clientHash 外部计算的APK SHA256哈希字符串小写16进制 * @param clientHash 外部计算的APK SHA256哈希字符串小写16进制
* @param callback 校验结果回调(主线程调用,返回是否合法+提示信息) * @param callback 校验结果回调(主线程调用,返回是否合法+提示信息)
*/ */
public void checkAPKValidation(Context context, String projectName, String versionName, public void checkAPKValidation(Context context, String appName, String versionName,
String clientSign, String clientHash, final CheckResultCallback callback) { String clientSign, String clientHash, final CheckResultCallback callback) {
// 方法调用+全量入参调试日志 // 方法调用+全量入参调试日志
LogUtils.d(TAG, "checkAPKValidation: 方法调用,入参-> projectName=" + projectName LogUtils.d(TAG, "checkAPKValidation: 方法调用,入参-> appName=" + appName
+ ", versionName=" + versionName + ", clientSign=" + clientSign + ", clientHash=" + clientHash); + ", versionName=" + versionName + ", clientSign=" + clientSign + ", clientHash=" + clientHash);
// 1. 核心入参空值校验(快速失败) // 1. 核心入参空值校验(快速失败)
@@ -61,7 +61,7 @@ public class APPUtils {
callCallbackOnMainThread(callback, false, "上下文对象不能为空"); callCallbackOnMainThread(callback, false, "上下文对象不能为空");
return; return;
} }
if (isStringEmpty(projectName)) { if (isStringEmpty(appName)) {
LogUtils.w(TAG, "checkAPKValidation: 入参projectName为空/空白,直接返回校验失败"); LogUtils.w(TAG, "checkAPKValidation: 入参projectName为空/空白,直接返回校验失败");
callCallbackOnMainThread(callback, false, "项目名称不能为空"); callCallbackOnMainThread(callback, false, "项目名称不能为空");
return; return;
@@ -85,7 +85,7 @@ public class APPUtils {
// 2. 动态参数URL编码避免特殊字符导致请求解析异常 // 2. 动态参数URL编码避免特殊字符导致请求解析异常
LogUtils.d(TAG, "checkAPKValidation: 开始对动态参数进行UTF-8 URL编码"); LogUtils.d(TAG, "checkAPKValidation: 开始对动态参数进行UTF-8 URL编码");
String encodeProjectName = urlEncode(projectName); String encodeProjectName = urlEncode(appName);
String encodeVersionName = urlEncode(versionName); String encodeVersionName = urlEncode(versionName);
String encodeClientSign = urlEncode(clientSign); String encodeClientSign = urlEncode(clientSign);
String encodeClientHash = urlEncode(clientHash); String encodeClientHash = urlEncode(clientHash);

View File

@@ -18,7 +18,7 @@ import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.R; import cc.winboll.studio.libappbase.R;
import cc.winboll.studio.libappbase.ToastUtils; import cc.winboll.studio.libappbase.ToastUtils;
import cc.winboll.studio.libappbase.dialogs.DebugHostDialog; import cc.winboll.studio.libappbase.dialogs.DebugHostDialog;
import cc.winboll.studio.libappbase.dialogs.AppValidationDialog; import cc.winboll.studio.libappbase.dialogs.APPValidationDialog;
import cc.winboll.studio.libappbase.models.APPInfo; import cc.winboll.studio.libappbase.models.APPInfo;
/** /**
@@ -76,10 +76,11 @@ public class AboutView extends LinearLayout {
private EditText metDevUserPassword; private EditText metDevUserPassword;
// ===================================== 页面视图控件 ===================================== // ===================================== 页面视图控件 =====================================
private ImageView ivAppIcon; private DebugSwitchImageView ivAppIcon;
private TextView tvAppNameVersion; private TextView tvAppNameVersion;
private TextView tvAppDesc; private TextView tvAppDesc;
private LinearLayout llFunctionContainer; private LinearLayout llFunctionContainer;
private ImageButton ibSebugStepOver;
private ImageButton ibSigngetDialog; private ImageButton ibSigngetDialog;
private ImageButton ibWinBoLLHostDialog; private ImageButton ibWinBoLLHostDialog;
@@ -92,14 +93,14 @@ public class AboutView extends LinearLayout {
initViewFromXml(); initViewFromXml();
} }
public AboutView(Context context, APPInfo appInfo) { // public AboutView(Context context, APPInfo appInfo) {
super(context); // super(context);
LogUtils.d(TAG, "AboutView(Context,APPInfo)传入应用信息appName=" + (appInfo == null ? "null" : appInfo.getAppName())); // LogUtils.d(TAG, "AboutView(Context,APPInfo)传入应用信息appName=" + (appInfo == null ? "null" : appInfo.getAppName()));
this.mContext = context; // this.mContext = context;
this.mAPPInfo = appInfo; // this.mAPPInfo = appInfo;
initViewFromXml(); // initViewFromXml();
initAll(); // initAll();
} // }
public AboutView(Context context, AttributeSet attrs) { public AboutView(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
@@ -128,10 +129,10 @@ public class AboutView extends LinearLayout {
return; return;
} }
initDefaultParams(); initDefaultParams();
initAppBaseInfo(); initAPPBaseInfo();
initAppVersionInfo(); initAPPVersionInfo();
initServerConfig(); initServerConfig();
initAppLinkInfo(); initAPPLinkInfo();
initReleaseAPKInfo(); initReleaseAPKInfo();
initAboutPageView(); initAboutPageView();
LogUtils.d(TAG, "initAll():所有初始化流程执行完成"); LogUtils.d(TAG, "initAll():所有初始化流程执行完成");
@@ -141,13 +142,13 @@ public class AboutView extends LinearLayout {
* 重置应用信息并重新初始化页面,支持动态更新关于页内容 * 重置应用信息并重新初始化页面,支持动态更新关于页内容
* @param appInfo 新的应用信息实体 * @param appInfo 新的应用信息实体
*/ */
public void setAPPInfoAndInit(APPInfo appInfo) { // public void setAPPInfoAndInit(APPInfo appInfo) {
LogUtils.d(TAG, "setAPPInfoAndInit()重置应用信息appName=" + (appInfo == null ? "null" : appInfo.getAppName())); // LogUtils.d(TAG, "setAPPInfoAndInit()重置应用信息appName=" + (appInfo == null ? "null" : appInfo.getAppName()));
this.mAPPInfo = appInfo; // this.mAPPInfo = appInfo;
if (llFunctionContainer != null) llFunctionContainer.removeAllViews(); // if (llFunctionContainer != null) llFunctionContainer.removeAllViews();
initAll(); // initAll();
LogUtils.d(TAG, "setAPPInfoAndInit():应用信息重置+页面重构完成"); // LogUtils.d(TAG, "setAPPInfoAndInit():应用信息重置+页面重构完成");
} // }
/** /**
* 设置应用信息,兼容旧调用逻辑,设置后自动重构页面 * 设置应用信息,兼容旧调用逻辑,设置后自动重构页面
@@ -185,30 +186,35 @@ public class AboutView extends LinearLayout {
* 加载XML布局并绑定所有视图控件初始化按钮点击事件 * 加载XML布局并绑定所有视图控件初始化按钮点击事件
*/ */
private void initViewFromXml() { private void initViewFromXml() {
LogUtils.d(TAG, "initViewFromXml():开始加载布局并绑定控件"); LogUtils.d(TAG, "initViewFromXml():开始加载布局并绑定控件");
View.inflate(mContext, R.layout.layout_about_view, this); View.inflate(mContext, R.layout.layout_about_view, this);
// 基础控件绑定 // 基础控件绑定
ivAppIcon = findViewById(R.id.iv_app_icon); ivAppIcon = findViewById(R.id.iv_app_icon);
tvAppNameVersion = findViewById(R.id.tv_app_name_version); tvAppNameVersion = findViewById(R.id.tv_app_name_version);
tvAppDesc = findViewById(R.id.tv_app_desc); tvAppDesc = findViewById(R.id.tv_app_desc);
llFunctionContainer = findViewById(R.id.ll_function_container); llFunctionContainer = findViewById(R.id.ll_function_container);
// 功能按钮绑定 // 功能按钮绑定
ibSigngetDialog = findViewById(R.id.ib_signgetdialog); ibSebugStepOver = findViewById(R.id.ib_debug_step_over);
ibWinBoLLHostDialog = findViewById(R.id.ib_winbollhostdialog); ibSigngetDialog = findViewById(R.id.ib_signgetdialog);
// 调试地址按钮动态显隐 ibWinBoLLHostDialog = findViewById(R.id.ib_winbollhostdialog);
ibWinBoLLHostDialog.setVisibility(GlobalApplication.isDebugging() ? View.VISIBLE : View.GONE);
// 绑定按钮点击事件 // 调试按钮统一只在调试模式显示
setBtnClickListener(); ibWinBoLLHostDialog.setVisibility(GlobalApplication.isDebugging() ? View.VISIBLE : View.GONE);
LogUtils.d(TAG, "initViewFromXml():布局加载+控件绑定+事件初始化完成"); //ibSigngetDialog.setVisibility(GlobalApplication.isDebugging() ? View.VISIBLE : View.GONE);
} ibSebugStepOver.setVisibility(GlobalApplication.isDebugging() ? View.VISIBLE : View.GONE);
// 绑定按钮点击事件
setBtnClickListener();
LogUtils.d(TAG, "initViewFromXml():布局加载+控件绑定+事件初始化完成");
}
/** /**
* 从APPInfo实体读取应用基础核心配置赋值到本地属性 * 从APPInfo实体读取应用基础核心配置赋值到本地属性
*/ */
private void initAppBaseInfo() { private void initAPPBaseInfo() {
LogUtils.d(TAG, "initAppBaseInfo()开始读取APPInfo基础配置"); LogUtils.d(TAG, "initAPPBaseInfo()开始读取APPInfo基础配置");
if (mAPPInfo == null) { if (mAPPInfo == null) {
LogUtils.w(TAG, "initAppBaseInfo()跳过执行APPInfo为null"); LogUtils.w(TAG, "initAPPBaseInfo()跳过执行APPInfo为null");
return; return;
} }
mszAppName = mAPPInfo.getAppName() == null ? "" : mAPPInfo.getAppName(); mszAppName = mAPPInfo.getAppName() == null ? "" : mAPPInfo.getAppName();
@@ -218,22 +224,22 @@ public class AboutView extends LinearLayout {
mszAppDescription = mAPPInfo.getAppDescription() == null ? "" : mAPPInfo.getAppDescription(); mszAppDescription = mAPPInfo.getAppDescription() == null ? "" : mAPPInfo.getAppDescription();
mnAppIcon = (mAPPInfo.getAppIcon() != 0) ? mAPPInfo.getAppIcon() : mnAppIcon; mnAppIcon = (mAPPInfo.getAppIcon() != 0) ? mAPPInfo.getAppIcon() : mnAppIcon;
mIsAddDebugTools = mAPPInfo.isAddDebugTools(); mIsAddDebugTools = mAPPInfo.isAddDebugTools();
LogUtils.d(TAG, "initAppBaseInfo():基础配置读取完成,应用名=" + mszAppName + ",调试开关=" + mIsAddDebugTools); LogUtils.d(TAG, "initAPPBaseInfo():基础配置读取完成,应用名=" + mszAppName + ",调试开关=" + mIsAddDebugTools);
} }
/** /**
* 从包管理中获取当前应用版本号,初始化版本相关信息 * 从包管理中获取当前应用版本号,初始化版本相关信息
*/ */
private void initAppVersionInfo() { private void initAPPVersionInfo() {
LogUtils.d(TAG, "initAppVersionInfo():开始初始化应用版本信息"); LogUtils.d(TAG, "initAPPVersionInfo():开始初始化应用版本信息");
try { try {
mszAppVersionName = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0).versionName; mszAppVersionName = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0).versionName;
} catch (PackageManager.NameNotFoundException e) { } catch (PackageManager.NameNotFoundException e) {
LogUtils.e(TAG, "initAppVersionInfo()获取版本号失败默认赋值unknown", e); LogUtils.e(TAG, "initAPPVersionInfo()获取版本号失败默认赋值unknown", e);
mszAppVersionName = "unknown"; mszAppVersionName = "unknown";
} }
mszCurrentAppPackageName = String.format("%s_%s.apk", mszAppVersionName, mszAppVersionName); mszCurrentAppPackageName = String.format("%s_%s.apk", mszAppVersionName, mszAppVersionName);
LogUtils.d(TAG, "initAppVersionInfo():版本信息初始化完成,版本号=" + mszAppVersionName + "当前APK名=" + mszCurrentAppPackageName); LogUtils.d(TAG, "initAPPVersionInfo():版本信息初始化完成,版本号=" + mszAppVersionName + "当前APK名=" + mszCurrentAppPackageName);
} }
/** /**
@@ -246,10 +252,10 @@ public class AboutView extends LinearLayout {
/** /**
* 初始化应用相关链接(主页+Git源码地址根据分支配置动态拼接Git地址 * 初始化应用相关链接(主页+Git源码地址根据分支配置动态拼接Git地址
*/ */
private void initAppLinkInfo() { private void initAPPLinkInfo() {
LogUtils.d(TAG, "initAppLinkInfo():开始初始化应用链接信息"); LogUtils.d(TAG, "initAPPLinkInfo():开始初始化应用链接信息");
if (mAPPInfo == null) { if (mAPPInfo == null) {
LogUtils.w(TAG, "initAppLinkInfo()跳过执行APPInfo为null"); LogUtils.w(TAG, "initAPPLinkInfo()跳过执行APPInfo为null");
return; return;
} }
mszHomePage = mAPPInfo.getAppHomePage() == null ? "" : mAPPInfo.getAppHomePage(); mszHomePage = mAPPInfo.getAppHomePage() == null ? "" : mAPPInfo.getAppHomePage();
@@ -261,7 +267,7 @@ public class AboutView extends LinearLayout {
mAPPInfo.getAppGitOwner(), mszAppGitName, mAPPInfo.getAppGitOwner(), mszAppGitName,
mAPPInfo.getAppGitAPPBranch(), mAPPInfo.getAppGitAPPSubProjectFolder()); mAPPInfo.getAppGitAPPBranch(), mAPPInfo.getAppGitAPPSubProjectFolder());
} }
LogUtils.d(TAG, "initAppLinkInfo():链接信息初始化完成,应用主页=" + mszHomePage + "Git地址=" + mszGitea); LogUtils.d(TAG, "initAPPLinkInfo():链接信息初始化完成,应用主页=" + mszHomePage + "Git地址=" + mszGitea);
} }
/** /**
@@ -312,12 +318,22 @@ public class AboutView extends LinearLayout {
*/ */
private void setBtnClickListener() { private void setBtnClickListener() {
LogUtils.d(TAG, "setBtnClickListener():开始绑定功能按钮点击事件"); LogUtils.d(TAG, "setBtnClickListener():开始绑定功能按钮点击事件");
// 正版校验弹窗 // 取消调试状态按钮
ibSebugStepOver.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
LogUtils.d(TAG, "ibSebugStepOver onClick取消调试状态按钮已点击");
GlobalApplication.setIsDebugging(false);
GlobalApplication.saveDebugStatus(GlobalApplication.getInstance());
ToastUtils.show("已取消调试状态,重启应用可生效。");
}
});
// 正版校验弹窗
ibSigngetDialog.setOnClickListener(new OnClickListener() { ibSigngetDialog.setOnClickListener(new OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
LogUtils.d(TAG, "ibSigngetDialog onClick唤起应用正版校验弹窗"); LogUtils.d(TAG, "ibSigngetDialog onClick唤起应用正版校验弹窗");
new AppValidationDialog(mContext, mszAppGitName, mszAppVersionName).show(); new APPValidationDialog(mContext, mszAppName, mszAppVersionName).show();
} }
}); });
// 调试地址配置弹窗 // 调试地址配置弹窗
@@ -337,7 +353,7 @@ public class AboutView extends LinearLayout {
*/ */
private void addFunctionView(View view) { private void addFunctionView(View view) {
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
params.topMargin = dp2px(PADDING_SMALL); params.topMargin = 0;
llFunctionContainer.addView(view, params); llFunctionContainer.addView(view, params);
} }
@@ -397,7 +413,18 @@ public class AboutView extends LinearLayout {
setPadding(dp2px(PADDING_MID), dp2px(PADDING_SMALL), dp2px(PADDING_MID), dp2px(PADDING_SMALL)); setPadding(dp2px(PADDING_MID), dp2px(PADDING_SMALL), dp2px(PADDING_MID), dp2px(PADDING_SMALL));
setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
setClickable(true); setClickable(true);
setBackgroundResource(android.R.drawable.list_selector_background); setBackground(create_item_background());
}
/**
* 创建带1像素边框的背景drawable
*/
private android.graphics.drawable.Drawable create_item_background() {
android.graphics.drawable.GradientDrawable drawable = new android.graphics.drawable.GradientDrawable();
drawable.setStroke(1, mItemContext.getResources().getColor(R.color.gray_200));
drawable.setCornerRadius(4);
drawable.setColor(mItemContext.getResources().getColor(android.R.color.white));
return drawable;
} }
/** /**

View File

@@ -0,0 +1,61 @@
package cc.winboll.studio.libappbase.views;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;
import cc.winboll.studio.libappbase.GlobalApplication;
/**
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
* @Date 2026/04/06 19:32
* @Describe 具有调试模式切换功能的应用Logo控件连续点击10次弹出提示
*/
public class DebugSwitchImageView extends ImageView {
public static final String TAG = "DebugSwitchImageView";
// 连续点击计数
private int mClickCount = 0;
// 目标点击次数
private static final int TARGET_CLICK_COUNT = 10;
public DebugSwitchImageView(Context context) {
super(context);
init();
}
public DebugSwitchImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public DebugSwitchImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public DebugSwitchImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init() {
setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mClickCount++;
if (mClickCount == TARGET_CLICK_COUNT) {
// 达到10次弹出Toast
Toast.makeText(getContext(), "连续点击已达到10次现在开启应用调试功能。", Toast.LENGTH_SHORT).show();
GlobalApplication.setIsDebugging(true);
GlobalApplication.saveDebugStatus(GlobalApplication.getInstance());
// 重置计数,可再次触发
mClickCount = 0;
}
}
});
}
}

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="#ff000000"
android:pathData="M19,7H16.19C15.74,6.2 15.12,5.5 14.37,5L16,3.41L14.59,2L12.42,4.17C11.96,4.06 11.5,4 11,4S10.05,4.06 9.59,4.17L7.41,2L6,3.41L7.62,5C6.87,5.5 6.26,6.21 5.81,7H3V9H5.09C5.03,9.33 5,9.66 5,10V11H3V13H5V14C5,14.34 5.03,14.67 5.09,15H3V17H5.81C7.26,19.5 10.28,20.61 13,19.65V19C13,18.43 13.09,17.86 13.25,17.31C12.59,17.76 11.8,18 11,18C8.79,18 7,16.21 7,14V10C7,7.79 8.79,6 11,6S15,7.79 15,10V14C15,14.19 15,14.39 14.95,14.58C15.54,14.04 16.24,13.62 17,13.35V13H19V11H17V10C17,9.66 16.97,9.33 16.91,9H19V7M13,9V11H9V9H13M13,13V15H9V13H13M16,16H22V22H16V16Z"/>
</vector>

View File

@@ -10,15 +10,15 @@
android:orientation="vertical" android:orientation="vertical"
android:gravity="center_horizontal" android:gravity="center_horizontal"
android:paddingLeft="16dp" android:paddingLeft="16dp"
android:paddingTop="32dp" android:paddingTop="16dp"
android:paddingRight="16dp" android:paddingRight="16dp"
android:paddingBottom="32dp"> android:paddingBottom="16dp">
<ImageView <cc.winboll.studio.libappbase.views.DebugSwitchImageView
android:id="@+id/iv_app_icon" android:id="@+id/iv_app_icon"
android:layout_width="48dp" android:layout_width="48dp"
android:layout_height="48dp" android:layout_height="48dp"
android:layout_marginBottom="16dp" android:layout_marginBottom="8dp"
android:scaleType="centerCrop"/> android:scaleType="centerCrop"/>
<TextView <TextView
@@ -32,16 +32,16 @@
android:id="@+id/tv_app_desc" android:id="@+id/tv_app_desc"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="4dp"
android:layout_marginBottom="16dp" android:layout_marginBottom="8dp"
android:textSize="14sp" android:textSize="14sp"
android:textColor="@color/gray_500"/> android:textColor="@color/gray_500"/>
<View <View
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="1px" android:layout_height="1px"
android:layout_marginTop="8dp" android:layout_marginTop="4dp"
android:layout_marginBottom="16dp" android:layout_marginBottom="8dp"
android:background="@color/gray_200"/> android:background="@color/gray_200"/>
<LinearLayout <LinearLayout
@@ -55,9 +55,18 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center" android:gravity="center"
android:layout_marginTop="16dp" android:layout_marginTop="8dp"
android:spacing="20dp"> android:spacing="20dp">
<ImageButton
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/ic_debug_step_over"
android:id="@+id/ib_debug_step_over"
android:scaleType="fitCenter"
android:adjustViewBounds="true"
android:background="@null"/>
<ImageButton <ImageButton
android:layout_width="48dp" android:layout_width="48dp"
android:layout_height="48dp" android:layout_height="48dp"

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Mon Mar 16 19:52:21 GMT 2026 #Wed Apr 08 17:37:24 GMT 2026
stageCount=26 stageCount=26
libraryProject= libraryProject=
baseVersion=15.11 baseVersion=15.11
publishVersion=15.11.25 publishVersion=15.11.25
buildCount=29 buildCount=30
baseBetaVersion=15.11.26 baseBetaVersion=15.11.26