应用签名校验模块测试完成。

This commit is contained in:
2026-01-23 03:09:19 +08:00
parent 7eed7357f0
commit 6e34ee73e9
8 changed files with 65 additions and 28 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Thu Jan 22 16:27:07 GMT 2026 #Thu Jan 22 19:08:20 GMT 2026
stageCount=7 stageCount=7
libraryProject=libappbase libraryProject=libappbase
baseVersion=15.15 baseVersion=15.15
publishVersion=15.15.6 publishVersion=15.15.6
buildCount=18 buildCount=36
baseBetaVersion=15.15.7 baseBetaVersion=15.15.7

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Thu Jan 22 16:27:07 GMT 2026 #Thu Jan 22 19:08:20 GMT 2026
stageCount=7 stageCount=7
libraryProject=libappbase libraryProject=libappbase
baseVersion=15.15 baseVersion=15.15
publishVersion=15.15.6 publishVersion=15.15.6
buildCount=18 buildCount=36
baseBetaVersion=15.15.7 baseBetaVersion=15.15.7

View File

@@ -82,20 +82,25 @@ public class GlobalApplication extends Application {
public static boolean isDebugging() { public static boolean isDebugging() {
return isDebugging; return isDebugging;
} }
// 新增:设置 WinBoLL 服务器主机地址(同时保存到 SP 持久化) // 新增:设置 WinBoLL 服务器主机地址(同时保存到 SP 持久化)
public static void setWinbollHost(String host) { public static void setWinbollHost(String host) {
if (sInstance == null) { if (sInstance == null) {
LogUtils.e(TAG, "setWinbollHost: 应用未初始化,设置失败"); LogUtils.e(TAG, "setWinbollHost: 应用未初始化,设置失败");
return; return;
} }
// 更新内存中的字段 // 检查并补全末尾 / 核心改动
winbollHost = host; if (host != null && !host.isEmpty() && !host.endsWith("/")) {
// 保存到 SP 持久化(私有模式,安全) host += "/";
SharedPreferences sp = sInstance.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); }
sp.edit().putString(SP_KEY_WINBOLL_HOST, host).apply(); // 更新内存中的字段
LogUtils.d(TAG, "setWinbollHost: 服务器地址已设置并持久化host=" + host); 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 读取) // 新增:获取 WinBoLL 服务器主机地址(优先内存,内存为空则从 SP 读取)
public static String getWinbollHost() { public static String getWinbollHost() {
@@ -109,7 +114,7 @@ public class GlobalApplication extends Application {
} }
// 内存中不存在,从 SP 读取并更新到内存 // 内存中不存在,从 SP 读取并更新到内存
SharedPreferences sp = sInstance.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); SharedPreferences sp = sInstance.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
winbollHost = sp.getString(SP_KEY_WINBOLL_HOST, null); winbollHost = sp.getString(SP_KEY_WINBOLL_HOST, "https://console.winboll.cc/");
LogUtils.d(TAG, "getWinbollHost: 从 SP 读取服务器地址host=" + winbollHost); LogUtils.d(TAG, "getWinbollHost: 从 SP 读取服务器地址host=" + winbollHost);
return winbollHost; return winbollHost;
} }

View File

@@ -35,7 +35,7 @@ public class DebugHostDialog extends Dialog implements View.OnClickListener {
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.dialog_debug_host); // 绑定XML布局 setContentView(R.layout.dialog_winboll_host); // 绑定XML布局
setCancelable(true); // 点击外部可关闭 setCancelable(true); // 点击外部可关闭
initView(); initView();
initData(); initData();

View File

@@ -27,8 +27,7 @@ import okhttp3.Response;
public class APPUtils { public class APPUtils {
public static final String TAG = "APPUtils"; public static final String TAG = "APPUtils";
// 网络校验接口地址 // 网络校验接口地址
private static final String CHECK_API_URL = "https://console.winboll.cc/api/app-signatures-check"; private static final String CHECK_API_URI = "api/app-signatures-check";
private static final String CHECK_API_URL_DEGUG = "http://localhost:8080/api/app-signatures-check";
// OKHTTP客户端单例复用 // OKHTTP客户端单例复用
private static OkHttpClient sOkHttpClient = new OkHttpClient(); private static OkHttpClient sOkHttpClient = new OkHttpClient();
// Gson解析实例 // Gson解析实例
@@ -62,7 +61,7 @@ public class APPUtils {
// 3. 构建请求URL拼接加密后的签名参数 // 3. 构建请求URL拼接加密后的签名参数
String requestUrl = String.format("%s?signature=%s&validTime=%d", String requestUrl = String.format("%s?signature=%s&validTime=%d",
GlobalApplication.isDebugging()?CHECK_API_URL_DEGUG:CHECK_API_URL, GlobalApplication.getWinbollHost() + CHECK_API_URI,
encryptedSign, // 替换为加密后的签名 encryptedSign, // 替换为加密后的签名
certValidTime); certValidTime);
LogUtils.d(TAG, "checkAppValid: 发起网络校验请求URL=" + requestUrl); LogUtils.d(TAG, "checkAppValid: 发起网络校验请求URL=" + requestUrl);

View File

@@ -16,6 +16,7 @@ import cc.winboll.studio.libappbase.GlobalApplication;
import cc.winboll.studio.libappbase.LogUtils; 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.SignGetDialog; import cc.winboll.studio.libappbase.dialogs.SignGetDialog;
import cc.winboll.studio.libappbase.models.APPInfo; import cc.winboll.studio.libappbase.models.APPInfo;
@@ -128,6 +129,7 @@ public class AboutView extends LinearLayout {
llFunctionContainer = findViewById(R.id.ll_function_container); 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); // 新增按钮绑定 ibWinBoLLHostDialog = findViewById(R.id.ib_winbollhostdialog); // 新增按钮绑定
ibWinBoLLHostDialog.setVisibility(GlobalApplication.isDebugging()?View.VISIBLE:View.GONE);
setBtnClickListener(); // 新增绑定点击事件 setBtnClickListener(); // 新增绑定点击事件
LogUtils.d(TAG, "initViewFromXml 布局加载+视图绑定完成"); LogUtils.d(TAG, "initViewFromXml 布局加载+视图绑定完成");
} }
@@ -141,6 +143,13 @@ public class AboutView extends LinearLayout {
new SignGetDialog(mContext).show(); // 弹出对话框 new SignGetDialog(mContext).show(); // 弹出对话框
} }
}); });
ibWinBoLLHostDialog.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
LogUtils.d(TAG, "签名获取按钮点击弹出SignGetDialog");
new DebugHostDialog(mContext).show(); // 弹出对话框
}
});
} }

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical"
android:padding="16dp" android:padding="16dp"
@@ -19,7 +19,7 @@
<!-- 地址输入框 --> <!-- 地址输入框 -->
<EditText <EditText
android:id="@+id/et_host_input" android:id="@+id/et_host_input"
android:layout_width="match_parent" android:layout_width="300dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:hint="请输入服务器地址如http://localhost:8080" android:hint="请输入服务器地址如http://localhost:8080"
android:textSize="14sp" android:textSize="14sp"

View File

@@ -1,11 +1,35 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<network-security-config> <network-security-config>
<domain-config cleartextTrafficPermitted="true"> <domain-config cleartextTrafficPermitted="true">
<!-- 原有配置:允许 winboll.cc 及其子域名的明文流量 --> <!-- 原有配置 保留 -->
<domain includeSubdomains="true">winboll.cc</domain> <domain includeSubdomains="true">winboll.cc</domain>
<!-- 新增:允许 localhost 所有端口(* 匹配任意端口) -->
<domain includeSubdomains="true">localhost</domain> <domain includeSubdomains="true">localhost</domain>
<domain includeSubdomains="true">127.0.0.1</domain> <!-- 兼容IP形式的本地地址 --> <domain includeSubdomains="true">127.0.0.1</domain>
<!-- 精准配置10.8.0.0/24 前20个IP10.8.0.0~10.8.0.19-->
<domain includeSubdomains="false">10.8.0.0</domain>
<domain includeSubdomains="false">10.8.0.1</domain>
<domain includeSubdomains="false">10.8.0.2</domain>
<domain includeSubdomains="false">10.8.0.3</domain>
<domain includeSubdomains="false">10.8.0.4</domain>
<domain includeSubdomains="false">10.8.0.5</domain>
<domain includeSubdomains="false">10.8.0.6</domain>
<domain includeSubdomains="false">10.8.0.7</domain>
<domain includeSubdomains="false">10.8.0.8</domain>
<domain includeSubdomains="false">10.8.0.9</domain>
<domain includeSubdomains="false">10.8.0.10</domain>
<domain includeSubdomains="false">10.8.0.11</domain>
<domain includeSubdomains="false">10.8.0.12</domain>
<domain includeSubdomains="false">10.8.0.13</domain>
<domain includeSubdomains="false">10.8.0.14</domain>
<domain includeSubdomains="false">10.8.0.15</domain>
<domain includeSubdomains="false">10.8.0.16</domain>
<domain includeSubdomains="false">10.8.0.17</domain>
<domain includeSubdomains="false">10.8.0.18</domain>
<domain includeSubdomains="false">10.8.0.19</domain>
</domain-config> </domain-config>
</network-security-config> </network-security-config>