Compare commits

..

37 Commits

Author SHA1 Message Date
c2cff1a2bb <aes>APK 15.20.8 release Publish. 2026-05-20 20:04:49 +08:00
98dd2a60b8 添加网站https://jitpack.io接口编译配置 2026-05-20 20:02:37 +08:00
25e966099f Merge remote-tracking branch 'origin/projects_keeper_tag' into aes 2026-05-20 19:56:45 +08:00
8876896cbc 合并模块APPBase 同步最新时间标签appbase-v15.20.20 2026-05-20 17:00:01 +08:00
28e6a8ee78 合并模块APPBase 同步最新时间标签appbase-v15.20.19 2026-05-20 15:00:01 +08:00
0a69b54dd0 Merge branch 'aes' into merge 2026-05-20 12:09:20 +08:00
e87513b179 Merge branch 'projects_keeper_tag' into merge 2026-05-20 12:08:49 +08:00
186b1656a7 更新联系邮箱 2026-05-20 11:19:18 +08:00
7d872fd14c 合并模块APPBase 同步最新时间标签appbase-v15.20.18 2026-05-20 04:00:01 +08:00
4ce22e8750 更换APPBase类库 2026-05-20 03:19:52 +08:00
d6fab2133f 合并模块AES 同步最新时间标签aes-v15.20.7 2026-05-19 21:00:01 +08:00
45821b8daa 合并模块APPBase 同步最新时间标签appbase-v15.20.17 2026-05-19 21:00:01 +08:00
5c8505dcbd <libaes>Library Release 15.20.7 2026-05-19 20:39:08 +08:00
9c3963822e <aes>APK 15.20.7 release Publish. 2026-05-19 20:38:13 +08:00
30532f8e8d 版本号对齐APPBase。 2026-05-19 20:26:18 +08:00
2b98149e0f Merge branch 'aes' into merge 2026-05-19 19:45:12 +08:00
80d9b764ee Merge branch 'projects_keeper_tag' into merge 2026-05-19 19:44:19 +08:00
d4f24a9b0c Merge branch 'aes' into merge 2026-05-19 19:30:17 +08:00
f357e353ee Merge branch 'projects_keeper_tag' into merge 2026-05-19 19:30:12 +08:00
edd312a525 合并模块APPBase 同步最新时间标签appbase-v15.20.16 2026-05-19 19:00:01 +08:00
aec680e36e 合并模块AES 同步最新时间标签aes-v15.20.6 2026-05-19 01:53:02 +08:00
937f90aa07 <libaes>Library Release 15.20.6 2026-05-19 01:52:54 +08:00
643e91bd71 <aes>APK 15.20.6 release Publish. 2026-05-19 01:52:47 +08:00
1c6f7783e5 合并模块AES 同步最新时间标签aes-v15.20.5 2026-05-19 01:49:06 +08:00
f4c6cea623 <libaes>Library Release 15.20.5 2026-05-19 01:48:56 +08:00
a0309ce98a <aes>APK 15.20.5 release Publish. 2026-05-19 01:48:43 +08:00
931671d85a <libaes>Library Release 15.20.4 2026-05-17 20:53:51 +08:00
580fa87773 <aes>APK 15.20.4 release Publish. 2026-05-17 20:53:39 +08:00
LaizyBoy
a26276e169 fix: 将libaes模块debugTextColor从红色改为灰色
- libaes普通模式debugTextColor改为#FF808080(灰色)
- libaes深色模式debugTextColor改为#FFAAAAAA(浅灰)
2026-05-17 20:49:19 +08:00
LaizyBoy
a3bf1087aa fix: 修复libaes模块Java 7兼容性问题及XML注释语法错误
- 为libaes添加compileOptions,指定Java 7源码与目标兼容级别
- 修复view_adscontrol.xml中XML注释包含非法"--"及缺少关闭符的问题
- 更新aes与libaes的build.properties编译计数
2026-05-17 20:30:41 +08:00
1e5295df95 Merge keeper tag branch sources. 2026-05-17 20:15:50 +08:00
8cb9ea5cae 清理源码冗余模块 2026-05-17 20:07:28 +08:00
8006a05749 恢复winboll/winboll分支的基础类库资料,以便项目初始化时的基础控件使用的分析辅助。 2026-05-13 20:52:54 +08:00
3c9a6ec884 修改示例模板的编译配置文件,设置版本号模板。 2026-05-13 20:21:55 +08:00
8b47043053 更新 LICENSE-Private-Demo
字符更新
2026-05-13 19:51:47 +08:00
202eeed72b 更新 LICENSE-Private-Demo_docs/LICENSE-Private-Demo
字符更新
2026-05-13 19:48:38 +08:00
4511bf8730 添加WinBoLL-Demo使用的WinBoLL基础类库的基线型号配置文件。整理创建winboll衍生分支所要具备的基础文件。 2026-05-13 19:25:51 +08:00
64 changed files with 586 additions and 1008 deletions

5
.gitignore vendored
View File

@@ -97,6 +97,5 @@ lint-results.html
## WinBoLL 基础应用(避免上传敏感配置) ## WinBoLL 基础应用(避免上传敏感配置)
/winboll.properties /winboll.properties
/local.properties /local.properties
/settings.gradle #/settings.gradle
/gradle.properties #/gradle.properties

1
BaseVersion.flag Normal file
View File

@@ -0,0 +1 @@
15.20

View File

@@ -6,11 +6,11 @@
## 核心声明 ## 核心声明
本文档**唯一核心设计目的**通过文件标识、分支隔离、操作规范、责任界定四重约束,**从根源规避私有开发分支代码被人为合并、推送、提交至公共开源主流分支的风险**,明确人为操作失误、违规合并的全部责任归属,同时保证私有分支可正常同步、拉取公共主流分支的上游更新。 本文档**唯一核心设计目的**: 通过文件标识、分支隔离、操作规范、责任界定四重约束,**从根源规避私有开发分支代码被人为合并、推送、提交至公共开源主流分支的风险**,明确人为操作失误、违规合并的全部责任归属,同时保证私有分支可正常同步、拉取公共主流分支的上游更新。
## 一、文件宗旨与风险防控说明 ## 一、文件宗旨与风险防控说明
本文件为 WinBoLL 项目公共开源分支转为私有独立分支开发的**强制标准化操作手册与责任界定文件**,核心风控目标 本文件为 WinBoLL 项目公共开源分支转为私有独立分支开发的**强制标准化操作手册与责任界定文件**,核心风控目标:
1. 严格隔离公共开源分支与私有开发分支,通过授权文件标记实现分支属性一眼可辨,杜绝人为操作混淆 1. 严格隔离公共开源分支与私有开发分支,通过授权文件标记实现分支属性一眼可辨,杜绝人为操作混淆
@@ -24,7 +24,7 @@
### 1. 公共开源分支唯一标识 ### 1. 公共开源分支唯一标识
**文件名LICENSE** **文件名: LICENSE**
- 仅允许存在于公共主流分支 `winboll` 及官方公共衍生分支 - 仅允许存在于公共主流分支 `winboll` 及官方公共衍生分支
@@ -34,7 +34,7 @@
### 2. 私有开发分支唯一标识 ### 2. 私有开发分支唯一标识
**文件名LICENSE-Private** **文件名: LICENSE-Private**
- 仅允许存在于私有开发分支,**绝对禁止出现在公共 ****`winboll`**** 分支** - 仅允许存在于私有开发分支,**绝对禁止出现在公共 ****`winboll`**** 分支**
@@ -44,15 +44,15 @@
## 三、分支管理与合并风控规则(强制遵守) ## 三、分支管理与合并风控规则(强制遵守)
1. **公共主流分支**固定为 `winboll`,为项目唯一开源主线,仅保留 `LICENSE` 文件,**禁止接收任何私有分支的合并、提交、推送请求**。 1. **公共主流分支**: 固定为 `winboll`,为项目唯一开源主线,仅保留 `LICENSE` 文件,**禁止接收任何私有分支的合并、提交、推送请求**。
2. **私有开发分支**统一从 `winboll` 分支检出,命名固定格式为 `private-demo-*`,与公共分支物理隔离。 2. **私有开发分支**: 统一从 `winboll` 分支检出,命名固定格式为 `private-demo-*`,与公共分支物理隔离。
3. **核心合并风控铁则** 3. **核心合并风控铁则**
- 私有分支 → 公共分支**永久禁止任何形式的合并、推送、PR 提交、代码回合,人为操作也绝不允许** - 私有分支 → 公共分支: **永久禁止任何形式的合并、推送、PR 提交、代码回合,人为操作也绝不允许**
- 公共分支 → 私有分支允许正常拉取、同步上游更新,不影响私有开发迭代 - 公共分支 → 私有分支: 允许正常拉取、同步上游更新,不影响私有开发迭代
4. 所有仓库提交者、合并操作者,均视为已阅读并完全认可本规则,**人为执行私有分支向公共分支的合并操作,由操作人承担全部代码泄露、合规违约、项目安全风险**。 4. 所有仓库提交者、合并操作者,均视为已阅读并完全认可本规则,**人为执行私有分支向公共分支的合并操作,由操作人承担全部代码泄露、合规违约、项目安全风险**。
@@ -68,7 +68,7 @@
4. 将本规范文件 `LICENSE-Private-Demo` 复制并重命名为 `LICENSE-Private`,作为私有分支生效授权文件。 4. 将本规范文件 `LICENSE-Private-Demo` 复制并重命名为 `LICENSE-Private`,作为私有分支生效授权文件。
5. 将以上所有变更执行一次性 Git 提交,**提交信息必须固定使用以下内容,不可修改** 5. 将以上所有变更执行一次性 Git 提交,**提交信息必须固定使用以下内容,不可修改**:
> 初始化私有开发分支,已切换私有授权文件,本分支禁止任何人为合并、推送至 winboll 公共分支 > 初始化私有开发分支,已切换私有授权文件,本分支禁止任何人为合并、推送至 winboll 公共分支
> >
@@ -84,14 +84,14 @@
3. 仓库管理员需严格校验合并请求的分支标识与授权文件,发现带有 `LICENSE-Private` 标记的分支申请合并至公共分支,一律直接拒绝,并记录操作人信息。 3. 仓库管理员需严格校验合并请求的分支标识与授权文件,发现带有 `LICENSE-Private` 标记的分支申请合并至公共分支,一律直接拒绝,并记录操作人信息。
4. 分支属性校验以根目录授权文件为唯一标准只要分支内存在 `LICENSE-Private` 文件,就绝对禁止向公共分支发起任何合并操作。 4. 分支属性校验以根目录授权文件为唯一标准: 只要分支内存在 `LICENSE-Private` 文件,就绝对禁止向公共分支发起任何合并操作。
## 六、分支状态校验与异常处理 ## 六、分支状态校验与异常处理
- 合规公共分支仅存在 `LICENSE`,无 `LICENSE-Private` - 合规公共分支: 仅存在 `LICENSE`,无 `LICENSE-Private`
- 合规私有分支仅存在 `LICENSE-Private`,无 `LICENSE` - 合规私有分支: 仅存在 `LICENSE-Private`,无 `LICENSE`
- 异常状态两个文件同时存在 / 均不存在 → 立即停止开发与提交,按本规范重置分支状态,严禁执行任何合并操作 - 异常状态: 两个文件同时存在 / 均不存在 → 立即停止开发与提交,按本规范重置分支状态,严禁执行任何合并操作
> (注文档部分内容可能由 AI 生成) > (注: 文档部分内容可能由 AI 生成)

View File

@@ -6,11 +6,11 @@
## 核心声明 ## 核心声明
本文档**唯一核心设计目的**通过文件标识、分支隔离、操作规范、责任界定四重约束,**从根源规避私有开发分支代码被人为合并、推送、提交至公共开源主流分支的风险**,明确人为操作失误、违规合并的全部责任归属,同时保证私有分支可正常同步、拉取公共主流分支的上游更新。 本文档**唯一核心设计目的**: 通过文件标识、分支隔离、操作规范、责任界定四重约束,**从根源规避私有开发分支代码被人为合并、推送、提交至公共开源主流分支的风险**,明确人为操作失误、违规合并的全部责任归属,同时保证私有分支可正常同步、拉取公共主流分支的上游更新。
## 一、文件宗旨与风险防控说明 ## 一、文件宗旨与风险防控说明
本文件为 WinBoLL 项目公共开源分支转为私有独立分支开发的**强制标准化操作手册与责任界定文件**,核心风控目标 本文件为 WinBoLL 项目公共开源分支转为私有独立分支开发的**强制标准化操作手册与责任界定文件**,核心风控目标:
1. 严格隔离公共开源分支与私有开发分支,通过授权文件标记实现分支属性一眼可辨,杜绝人为操作混淆 1. 严格隔离公共开源分支与私有开发分支,通过授权文件标记实现分支属性一眼可辨,杜绝人为操作混淆
@@ -24,7 +24,7 @@
### 1. 公共开源分支唯一标识 ### 1. 公共开源分支唯一标识
**文件名LICENSE** **文件名: LICENSE**
- 仅允许存在于公共主流分支 `winboll` 及官方公共衍生分支 - 仅允许存在于公共主流分支 `winboll` 及官方公共衍生分支
@@ -34,7 +34,7 @@
### 2. 私有开发分支唯一标识 ### 2. 私有开发分支唯一标识
**文件名LICENSE-Private** **文件名: LICENSE-Private**
- 仅允许存在于私有开发分支,**绝对禁止出现在公共 ****`winboll`**** 分支** - 仅允许存在于私有开发分支,**绝对禁止出现在公共 ****`winboll`**** 分支**
@@ -44,15 +44,15 @@
## 三、分支管理与合并风控规则(强制遵守) ## 三、分支管理与合并风控规则(强制遵守)
1. **公共主流分支**固定为 `winboll`,为项目唯一开源主线,仅保留 `LICENSE` 文件,**禁止接收任何私有分支的合并、提交、推送请求**。 1. **公共主流分支**: 固定为 `winboll`,为项目唯一开源主线,仅保留 `LICENSE` 文件,**禁止接收任何私有分支的合并、提交、推送请求**。
2. **私有开发分支**统一从 `winboll` 分支检出,命名固定格式为 `private-demo-*`,与公共分支物理隔离。 2. **私有开发分支**: 统一从 `winboll` 分支检出,命名固定格式为 `private-demo-*`,与公共分支物理隔离。
3. **核心合并风控铁则** 3. **核心合并风控铁则**
- 私有分支 → 公共分支**永久禁止任何形式的合并、推送、PR 提交、代码回合,人为操作也绝不允许** - 私有分支 → 公共分支: **永久禁止任何形式的合并、推送、PR 提交、代码回合,人为操作也绝不允许**
- 公共分支 → 私有分支允许正常拉取、同步上游更新,不影响私有开发迭代 - 公共分支 → 私有分支: 允许正常拉取、同步上游更新,不影响私有开发迭代
4. 所有仓库提交者、合并操作者,均视为已阅读并完全认可本规则,**人为执行私有分支向公共分支的合并操作,由操作人承担全部代码泄露、合规违约、项目安全风险**。 4. 所有仓库提交者、合并操作者,均视为已阅读并完全认可本规则,**人为执行私有分支向公共分支的合并操作,由操作人承担全部代码泄露、合规违约、项目安全风险**。
@@ -68,7 +68,7 @@
4. 将本规范文件 `LICENSE-Private-Demo` 复制并重命名为 `LICENSE-Private`,作为私有分支生效授权文件。 4. 将本规范文件 `LICENSE-Private-Demo` 复制并重命名为 `LICENSE-Private`,作为私有分支生效授权文件。
5. 将以上所有变更执行一次性 Git 提交,**提交信息必须固定使用以下内容,不可修改** 5. 将以上所有变更执行一次性 Git 提交,**提交信息必须固定使用以下内容,不可修改**:
> 初始化私有开发分支,已切换私有授权文件,本分支禁止任何人为合并、推送至 winboll 公共分支 > 初始化私有开发分支,已切换私有授权文件,本分支禁止任何人为合并、推送至 winboll 公共分支
> >
@@ -84,14 +84,14 @@
3. 仓库管理员需严格校验合并请求的分支标识与授权文件,发现带有 `LICENSE-Private` 标记的分支申请合并至公共分支,一律直接拒绝,并记录操作人信息。 3. 仓库管理员需严格校验合并请求的分支标识与授权文件,发现带有 `LICENSE-Private` 标记的分支申请合并至公共分支,一律直接拒绝,并记录操作人信息。
4. 分支属性校验以根目录授权文件为唯一标准只要分支内存在 `LICENSE-Private` 文件,就绝对禁止向公共分支发起任何合并操作。 4. 分支属性校验以根目录授权文件为唯一标准: 只要分支内存在 `LICENSE-Private` 文件,就绝对禁止向公共分支发起任何合并操作。
## 六、分支状态校验与异常处理 ## 六、分支状态校验与异常处理
- 合规公共分支仅存在 `LICENSE`,无 `LICENSE-Private` - 合规公共分支: 仅存在 `LICENSE`,无 `LICENSE-Private`
- 合规私有分支仅存在 `LICENSE-Private`,无 `LICENSE` - 合规私有分支: 仅存在 `LICENSE-Private`,无 `LICENSE`
- 异常状态两个文件同时存在 / 均不存在 → 立即停止开发与提交,按本规范重置分支状态,严禁执行任何合并操作 - 异常状态: 两个文件同时存在 / 均不存在 → 立即停止开发与提交,按本规范重置分支状态,严禁执行任何合并操作
> (注文档部分内容可能由 AI 生成) > (注: 文档部分内容可能由 AI 生成)

View File

@@ -9,15 +9,15 @@ WinBoLL 手机源码计划,旨在通过核心项目 WinBoLL 构建手机端与
#### **仓库类型:功能说明** #### **仓库类型:功能说明**
☆ 基础项目分支 WinBoLL手机端安卓应用开发基础模板。 ☆ 基础项目分支 WinBoLL手机端安卓应用开发基础模板。
☆ 应用项目分支 APPBase、AES、PowerBell、Positions**:安卓应用单一管理系列项目。 ☆ 应用项目分支 APPBase、AES、PowerBell、Positions**:安卓应用单一管理系列项目。
☆ 源码汇总管理 Projects_Keeper**:各类分支源码合并存档,不适宜作为开发库使用。 ☆ 源码汇总管理 OriginMaster**:各类分支源码合并存档,不适宜作为开发库使用。
### 3. 源码合并管理推送路线图 ### 3. 源码合并管理推送路线图
⚠️ **注意**:仅仅展示不同应用模块源码的综合管理路线。分支合并操作时,必须具备 Git 管理经验。 ⚠️ **注意**:仅仅展示不同应用模块源码的综合管理路线。分支合并操作时,必须具备 Git 管理经验。
★ WinBoLL → APPBase → Projects_Keeper ★ WinBoLL → APPBase → OriginMaster
★ WinBoLL → AES → Projects_Keeper ★ WinBoLL → AES → OriginMaster
★ WinBoLL → PowerBell → Projects_Keeper ★ WinBoLL → PowerBell → OriginMaster
★ WinBoLL → Positions → Projects_Keeper ★ WinBoLL → Positions → OriginMaster
## 二、WinBoLL 项目核心信息 ## 二、WinBoLL 项目核心信息

View File

@@ -20,7 +20,7 @@ WinBoLL AndroidX 可视化元素类库。
1. Fork 本仓库 1. Fork 本仓库
2. 新建 Feat_xxx 分支 2. 新建 Feat_xxx 分支
3. 提交代码 : ZhanGSKen(ZhanGSKen<zhangsken@188.com>) 3. 提交代码 : ZhanGSKen(ZhanGSKen<ZhanGSKen@QQ.COM>)
4. 新建 Pull Request 4. 新建 Pull Request

View File

@@ -26,7 +26,10 @@ android {
applicationId "cc.winboll.studio.aes" applicationId "cc.winboll.studio.aes"
minSdkVersion 26 minSdkVersion 26
targetSdkVersion 30 targetSdkVersion 30
versionCode 1 //1. Android 官方规则
//-  versionCode  类型int 整型
//- Java int 最大值2147483647
versionCode 1520000
// versionName 更新后需要手动设置 // versionName 更新后需要手动设置
// 项目模块目录的 build.gradle 文件的 stageCount=0 // 项目模块目录的 build.gradle 文件的 stageCount=0
// Gradle编译环境下合起来的 versionName 就是 "${versionName}.0" // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0"

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Sun May 17 20:53:39 HKT 2026 #Wed May 20 20:04:49 HKT 2026
stageCount=5 stageCount=9
libraryProject=libaes libraryProject=libaes
baseVersion=15.20 baseVersion=15.20
publishVersion=15.20.4 publishVersion=15.20.8
buildCount=0 buildCount=0
baseBetaVersion=15.20.5 baseBetaVersion=15.20.9

View File

@@ -18,8 +18,6 @@ public class App extends GlobalApplication {
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
setIsDebugging(BuildConfig.DEBUG);
//setIsDebugging(false);
WinBoLLActivityManager.init(this); WinBoLLActivityManager.init(this);
// 初始化 Toast 框架 // 初始化 Toast 框架

View File

@@ -20,7 +20,7 @@ WinBoLL 安卓手机端安卓应用开发基础类库。
1. Fork 本仓库 1. Fork 本仓库
2. 新建 Feat_xxx 分支 2. 新建 Feat_xxx 分支
3. 提交代码 : ZhanGSKen(ZhanGSKen<zhangsken@188.com>) 3. 提交代码 : ZhanGSKen(ZhanGSKen<ZhanGSKen@QQ.COM>)
4. 新建 Pull Request 4. 新建 Pull Request

View File

@@ -26,7 +26,10 @@ android {
applicationId "cc.winboll.studio.appbase" applicationId "cc.winboll.studio.appbase"
minSdkVersion 26 minSdkVersion 26
targetSdkVersion 30 targetSdkVersion 30
versionCode 1 //1. Android 官方规则
//-  versionCode  类型int 整型
//- Java int 最大值2147483647
versionCode 1520000
// versionName 更新后需要手动设置 // versionName 更新后需要手动设置
// .winboll/winbollBuildProps.properties 文件的 stageCount=0 // .winboll/winbollBuildProps.properties 文件的 stageCount=0
// Gradle编译环境下合起来的 versionName 就是 "${versionName}.0" // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0"

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Sun May 17 16:16:36 HKT 2026 #Wed May 20 16:12:13 HKT 2026
stageCount=16 stageCount=21
libraryProject=libappbase libraryProject=libappbase
baseVersion=15.20 baseVersion=15.20
publishVersion=15.20.15 publishVersion=15.20.20
buildCount=0 buildCount=0
baseBetaVersion=15.20.16 baseBetaVersion=15.20.21

View File

@@ -37,7 +37,7 @@ public class AboutActivity extends Activity {
appInfo.setAppName("APPBase"); 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("APPBase");
appInfo.setAppGitOwner("Studio"); appInfo.setAppGitOwner("Studio");
appInfo.setAppGitAPPBranch(branchName); appInfo.setAppGitAPPBranch(branchName);
appInfo.setAppGitAPPSubProjectFolder(branchName); appInfo.setAppGitAPPSubProjectFolder(branchName);

View File

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

View File

@@ -2,8 +2,8 @@ package cc.winboll.studio.appbase.model;
import android.util.JsonReader; import android.util.JsonReader;
import android.util.JsonWriter; import android.util.JsonWriter;
import cc.winboll.studio.libappbase.BaseBean;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.models.libs1520000.BaseBean;
import java.io.IOException; import java.io.IOException;
/** /**

View File

@@ -1 +0,0 @@
/build

View File

@@ -1 +0,0 @@

View File

@@ -1,80 +0,0 @@
apply plugin: 'com.android.application'
apply from: '../.winboll/winboll_app_build.gradle'
apply from: '../.winboll/winboll_lint_build.gradle'
def genVersionName(def versionName){
// 检查编译标志位配置
assert (winbollBuildProps['stageCount'] != null)
assert (winbollBuildProps['baseVersion'] != null)
// 保存基础版本号
winbollBuildProps.setProperty("baseVersion", "${versionName}");
//保存编译标志配置
FileOutputStream fos = new FileOutputStream(winbollBuildPropsFile)
winbollBuildProps.store(fos, "${winbollBuildPropsDesc}");
fos.close();
// 返回编译版本号
return "${versionName}." + winbollBuildProps['stageCount']
}
android {
compileSdkVersion 30
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
defaultConfig {
applicationId "cc.winboll.studio.dailystamp"
minSdkVersion 26
targetSdkVersion 30
versionCode 1
// versionName 更新后需要手动设置
// .winboll/winbollBuildProps.properties 文件的 stageCount=0
// Gradle编译环境下合起来的 versionName 就是 "${versionName}.0"
versionName "15.20"
if(true) {
versionName = genVersionName("${versionName}")
}
}
}
dependencies {
// 下拉控件
api 'com.baoyz.pullrefreshlayout:library:1.2.0'
// 拼音搜索
// https://mvnrepository.com/artifact/com.github.open-android/pinyin4j
api 'com.github.open-android:pinyin4j:2.5.0'
// SSH
api 'com.jcraft:jsch:0.1.55'
// Html 解析
api 'org.jsoup:jsoup:1.13.1'
// 二维码类库
api 'com.google.zxing:core:3.4.1'
api 'com.journeyapps:zxing-android-embedded:3.6.0'
// 应用介绍页类库
api 'io.github.medyo:android-about-page:2.0.0'
// 网络连接类库
api 'com.squareup.okhttp3:okhttp:4.4.1'
// AndroidX 类库
api 'androidx.appcompat:appcompat:1.1.0'
api 'androidx.cardview:cardview:1.0.0'
api 'com.google.android.material:material:1.4.0'
//api 'androidx.viewpager:viewpager:1.0.0'
//api 'androidx.vectordrawable:vectordrawable:1.1.0'
//api 'androidx.vectordrawable:vectordrawable-animated:1.1.0'
//api 'androidx.fragment:fragment:1.1.0'
//注意以下5个库必须要引入
//implementation 'androidx.appcompat:appcompat:1.4.1'
api 'androidx.recyclerview:recyclerview:1.0.0'
api 'com.google.code.gson:gson:2.8.5'
api 'com.github.bumptech.glide:glide:4.9.0'
//annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0'
// WinBoLL库 nexus.winboll.cc 地址
api 'cc.winboll.studio:libaes:15.20.4'
api 'cc.winboll.studio:libappbase:15.20.15'
api fileTree(dir: 'libs', include: ['*.jar'])
}

View File

@@ -1,8 +0,0 @@
#Created by .winboll/winboll_app_build.gradle
#Mon May 18 14:32:43 GMT 2026
stageCount=0
libraryProject=
baseVersion=15.20
publishVersion=15.20.0
buildCount=1
baseBetaVersion=15.20.1

View File

@@ -1,21 +0,0 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" >
<application>
<!-- Put flavor specific code here -->
</application>
</manifest>

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">印记标签 ☼</string>
</resources>

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Daily Stamp ☼</string>
</resources>

View File

@@ -1,37 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="cc.winboll.studio.dailystamp">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:label="@string/app_name"
android:theme="@style/MyAppTheme"
android:resizeableActivity="true"
android:name=".App">
<activity
android:name=".MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<meta-data
android:name="android.max_aspect"
android:value="4.0"/>
<activity android:name=".GlobalApplication$CrashActivity"/>
</application>
</manifest>

View File

@@ -1,344 +0,0 @@
package cc.winboll.studio.dailystamp;
import android.app.Activity;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.res.Resources;
import android.graphics.Typeface;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.ViewGroup;
import android.widget.HorizontalScrollView;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import cc.winboll.studio.libappbase.GlobalApplication;
import cc.winboll.studio.libappbase.ToastUtils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.Thread.UncaughtExceptionHandler;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
public class App extends GlobalApplication {
private static Handler MAIN_HANDLER = new Handler(Looper.getMainLooper());
@Override
public void onCreate() {
super.onCreate();
// 初始化 Toast 框架
ToastUtils.init(this);
// 设置 Toast 布局样式
//ToastUtils.setView(R.layout.view_toast);
// ToastUtils.setStyle(new WhiteToastStyle());
// ToastUtils.setGravity(Gravity.BOTTOM, 0, 200);
//
//CrashHandler.getInstance().registerGlobal(this);
//CrashHandler.getInstance().registerPart(this);
}
public static void write(InputStream input, OutputStream output) throws IOException {
byte[] buf = new byte[1024 * 8];
int len;
while ((len = input.read(buf)) != -1) {
output.write(buf, 0, len);
}
}
public static void write(File file, byte[] data) throws IOException {
File parent = file.getParentFile();
if (parent != null && !parent.exists()) parent.mkdirs();
ByteArrayInputStream input = new ByteArrayInputStream(data);
FileOutputStream output = new FileOutputStream(file);
try {
write(input, output);
} finally {
closeIO(input, output);
}
}
public static String toString(InputStream input) throws IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream();
write(input, output);
try {
return output.toString("UTF-8");
} finally {
closeIO(input, output);
}
}
public static void closeIO(Closeable... closeables) {
for (Closeable closeable : closeables) {
try {
if (closeable != null) closeable.close();
} catch (IOException ignored) {}
}
}
public static class CrashHandler {
public static final UncaughtExceptionHandler DEFAULT_UNCAUGHT_EXCEPTION_HANDLER = Thread.getDefaultUncaughtExceptionHandler();
private static CrashHandler sInstance;
private PartCrashHandler mPartCrashHandler;
public static CrashHandler getInstance() {
if (sInstance == null) {
sInstance = new CrashHandler();
}
return sInstance;
}
public void registerGlobal(Context context) {
registerGlobal(context, null);
}
public void registerGlobal(Context context, String crashDir) {
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandlerImpl(context.getApplicationContext(), crashDir));
}
public void unregister() {
Thread.setDefaultUncaughtExceptionHandler(DEFAULT_UNCAUGHT_EXCEPTION_HANDLER);
}
public void registerPart(Context context) {
unregisterPart(context);
mPartCrashHandler = new PartCrashHandler(context.getApplicationContext());
MAIN_HANDLER.postAtFrontOfQueue(mPartCrashHandler);
}
public void unregisterPart(Context context) {
if (mPartCrashHandler != null) {
mPartCrashHandler.isRunning.set(false);
mPartCrashHandler = null;
}
}
private static class PartCrashHandler implements Runnable {
private final Context mContext;
public AtomicBoolean isRunning = new AtomicBoolean(true);
public PartCrashHandler(Context context) {
this.mContext = context;
}
@Override
public void run() {
while (isRunning.get()) {
try {
Looper.loop();
} catch (final Throwable e) {
e.printStackTrace();
if (isRunning.get()) {
MAIN_HANDLER.post(new Runnable(){
@Override
public void run() {
Toast.makeText(mContext, e.toString(), Toast.LENGTH_LONG).show();
}
});
} else {
if (e instanceof RuntimeException) {
throw (RuntimeException)e;
} else {
throw new RuntimeException(e);
}
}
}
}
}
}
private static class UncaughtExceptionHandlerImpl implements UncaughtExceptionHandler {
private static DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy_MM_dd-HH_mm_ss");
private final Context mContext;
private final File mCrashDir;
public UncaughtExceptionHandlerImpl(Context context, String crashDir) {
this.mContext = context;
this.mCrashDir = TextUtils.isEmpty(crashDir) ? new File(mContext.getExternalCacheDir(), "crash") : new File(crashDir);
}
@Override
public void uncaughtException(Thread thread, Throwable throwable) {
try {
String log = buildLog(throwable);
writeLog(log);
try {
Intent intent = new Intent(mContext, CrashActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(Intent.EXTRA_TEXT, log);
mContext.startActivity(intent);
} catch (Throwable e) {
e.printStackTrace();
writeLog(e.toString());
}
throwable.printStackTrace();
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
} catch (Throwable e) {
if (DEFAULT_UNCAUGHT_EXCEPTION_HANDLER != null) DEFAULT_UNCAUGHT_EXCEPTION_HANDLER.uncaughtException(thread, throwable);
}
}
private String buildLog(Throwable throwable) {
String time = DATE_FORMAT.format(new Date());
String versionName = "unknown";
long versionCode = 0;
try {
PackageInfo packageInfo = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0);
versionName = packageInfo.versionName;
versionCode = Build.VERSION.SDK_INT >= 28 ? packageInfo.getLongVersionCode() : packageInfo.versionCode;
} catch (Throwable ignored) {}
LinkedHashMap<String, String> head = new LinkedHashMap<String, String>();
head.put("Time Of Crash", time);
head.put("Device", String.format("%s, %s", Build.MANUFACTURER, Build.MODEL));
head.put("Android Version", String.format("%s (%d)", Build.VERSION.RELEASE, Build.VERSION.SDK_INT));
head.put("App Version", String.format("%s (%d)", versionName, versionCode));
head.put("Kernel", getKernel());
head.put("Support Abis", Build.VERSION.SDK_INT >= 21 && Build.SUPPORTED_ABIS != null ? Arrays.toString(Build.SUPPORTED_ABIS): "unknown");
head.put("Fingerprint", Build.FINGERPRINT);
StringBuilder builder = new StringBuilder();
for (String key : head.keySet()) {
if (builder.length() != 0) builder.append("\n");
builder.append(key);
builder.append(" : ");
builder.append(head.get(key));
}
builder.append("\n\n");
builder.append(Log.getStackTraceString(throwable));
return builder.toString();
}
private void writeLog(String log) {
String time = DATE_FORMAT.format(new Date());
File file = new File(mCrashDir, "crash_" + time + ".txt");
try {
write(file, log.getBytes("UTF-8"));
} catch (Throwable e) {
e.printStackTrace();
}
}
private static String getKernel() {
try {
return App.toString(new FileInputStream("/proc/version")).trim();
} catch (Throwable e) {
return e.getMessage();
}
}
}
}
public static final class CrashActivity extends Activity {
private String mLog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTheme(android.R.style.Theme_DeviceDefault);
setTitle("App Crash");
mLog = getIntent().getStringExtra(Intent.EXTRA_TEXT);
ScrollView contentView = new ScrollView(this);
contentView.setFillViewport(true);
HorizontalScrollView horizontalScrollView = new HorizontalScrollView(this);
TextView textView = new TextView(this);
int padding = dp2px(16);
textView.setPadding(padding, padding, padding, padding);
textView.setText(mLog);
textView.setTextIsSelectable(true);
textView.setTypeface(Typeface.DEFAULT);
textView.setLinksClickable(true);
horizontalScrollView.addView(textView);
contentView.addView(horizontalScrollView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
setContentView(contentView);
}
private void restart() {
Intent intent = getPackageManager().getLaunchIntentForPackage(getPackageName());
if (intent != null) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
finish();
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
}
private static int dp2px(float dpValue) {
final float scale = Resources.getSystem().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, android.R.id.copy, 0, android.R.string.copy)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.copy:
ClipboardManager cm = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
cm.setPrimaryClip(ClipData.newPlainText(getPackageName(), mLog));
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onBackPressed() {
restart();
}
}
}

View File

@@ -1,31 +0,0 @@
package cc.winboll.studio.dailystamp;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import cc.winboll.studio.libappbase.LogView;
import cc.winboll.studio.libappbase.ToastUtils;
public class MainActivity extends AppCompatActivity {
LogView mLogView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar=(Toolbar)findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mLogView = findViewById(R.id.logview);
ToastUtils.show("onCreate");
}
@Override
protected void onResume() {
super.onResume();
mLogView.start();
}
}

View File

@@ -1,34 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillType="evenOdd"
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
android:strokeColor="#00000000"
android:strokeWidth="1">
<aapt:attr name="android:fillColor">
<gradient
android:endX="78.5885"
android:endY="90.9159"
android:startX="48.7653"
android:startY="61.0927"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
android:strokeColor="#00000000"
android:strokeWidth="1" />
</vector>

View File

@@ -1,170 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillColor="#26A69A"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
</vector>

View File

@@ -1,49 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
</com.google.android.material.appbar.AppBarLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.0"
android:gravity="center_vertical|center_horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/app_name"
android:textAppearance="?android:attr/textAppearanceLarge"/>
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.0">
<cc.winboll.studio.libappbase.LogView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/logview"/>
</LinearLayout>
</LinearLayout>

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">印记标签 ☼</string>
</resources>

View File

@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#009688</color>
<color name="colorPrimaryDark">#00796B</color>
<color name="colorAccent">#FF9800</color>
<color name="mainWindowBackgroundColor">#FFF5F5F5</color>
<color name="mainWindowTextColor">#FF000000</color>
<color name="toolbarBackgroundColor">#FF009688</color>
<color name="toolbarTextColor">#FFFFFFFF</color>
<color name="debugTextColor">#FF808080</color>
</resources>

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Daily Stamp</string>
</resources>

View File

@@ -1,34 +0,0 @@
<resources>
<style name="MyAppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="themeDebug">@style/MyDebugActivityTheme</item>
<item name="toolbarBackgroundColor">@color/toolbarBackgroundColor</item>
<item name="toolbarTextColor">@color/toolbarTextColor</item>
<item name="textViewBackgroundColor">?attr/mainWindowBackgroundColor</item>
<item name="textViewTextColor">?attr/mainWindowTextColor</item>
<item name="editTextBackgroundColor">?attr/mainWindowBackgroundColor</item>
<item name="editTextTextColor">?attr/mainWindowTextColor</item>
<item name="scrollViewBackgroundColor">?attr/mainWindowBackgroundColor</item>
<item name="activityBackgroundColor">?attr/mainWindowBackgroundColor</item>
<item name="activityTextColor">?attr/mainWindowTextColor</item>
<item name="mainWindowBackgroundColor">@color/mainWindowBackgroundColor</item>
<item name="mainWindowTextColor">@color/mainWindowTextColor</item>
<item name="mainWindowDarkBackgroundColor">@color/mainWindowBackgroundColor</item>
<item name="mainWindowDarkTextColor">@color/mainWindowTextColor</item>
</style>
<style name="MyDebugActivityTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:statusBarColor">@color/colorPrimaryDark</item>
<item name="colorTittle">?attr/mainWindowTextColor</item>
<item name="colorTittleBackgound">?attr/toolbarBackgroundColor</item>
<item name="colorText">?attr/debugTextColor</item>
<item name="colorTextBackgound">?attr/mainWindowBackgroundColor</item>
<item name="debugTextColor">@color/debugTextColor</item>
<item name="toolbarTextColor">@color/toolbarTextColor</item>
</style>
</resources>

View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" >
<application>
<!-- Put flavor specific code here -->
</application>
</manifest>

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Put flavor specific strings here -->
</resources>

21
gradle.properties Normal file
View File

@@ -0,0 +1,21 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app"s APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
# 保持与旧版Gradle插件的兼容
android.disableAutomaticComponentCreation=true

View File

@@ -66,7 +66,7 @@ dependencies {
//annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0' //annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0'
// WinBoLL库 nexus.winboll.cc 地址 // WinBoLL库 nexus.winboll.cc 地址
api 'cc.winboll.studio:libappbase:15.20.9' api 'cc.winboll.studio:libappbase:15.20.18'
// 备用库 jitpack.io 地址 // 备用库 jitpack.io 地址
//api 'com.github.ZhanGSKen:APPBase:appbase-v15.15.3' //api 'com.github.ZhanGSKen:APPBase:appbase-v15.15.3'

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Sun May 17 20:53:39 HKT 2026 #Wed May 20 20:04:49 HKT 2026
stageCount=5 stageCount=9
libraryProject=libaes libraryProject=libaes
baseVersion=15.20 baseVersion=15.20
publishVersion=15.20.4 publishVersion=15.20.8
buildCount=0 buildCount=0
baseBetaVersion=15.20.5 baseBetaVersion=15.20.9

View File

@@ -8,7 +8,7 @@ package cc.winboll.studio.libaes.models;
import android.util.JsonReader; import android.util.JsonReader;
import android.util.JsonWriter; import android.util.JsonWriter;
import cc.winboll.studio.libaes.R; import cc.winboll.studio.libaes.R;
import cc.winboll.studio.libappbase.BaseBean; import cc.winboll.studio.libappbase.models.libs1520000.BaseBean;
import java.io.IOException; import java.io.IOException;
public class AESThemeBean extends BaseBean { public class AESThemeBean extends BaseBean {

View File

@@ -7,7 +7,7 @@ package cc.winboll.studio.libaes.models;
import android.content.Context; import android.content.Context;
import android.util.JsonReader; import android.util.JsonReader;
import android.util.JsonWriter; import android.util.JsonWriter;
import cc.winboll.studio.libappbase.BaseBean; import cc.winboll.studio.libappbase.models.libs1520000.BaseBean;
import java.io.IOException; import java.io.IOException;
public class WinBoLLClientServiceBean extends BaseBean { public class WinBoLLClientServiceBean extends BaseBean {

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Sun May 17 16:16:36 HKT 2026 #Wed May 20 16:12:13 HKT 2026
stageCount=16 stageCount=21
libraryProject=libappbase libraryProject=libappbase
baseVersion=15.20 baseVersion=15.20
publishVersion=15.20.15 publishVersion=15.20.20
buildCount=0 buildCount=0
baseBetaVersion=15.20.16 baseBetaVersion=15.20.21

View File

@@ -2,6 +2,7 @@ package cc.winboll.studio.libappbase;
import android.util.JsonReader; import android.util.JsonReader;
import android.util.JsonWriter; import android.util.JsonWriter;
import cc.winboll.studio.libappbase.models.libs1520000.BaseBean;
import java.io.IOException; import java.io.IOException;
/** /**

View File

@@ -129,11 +129,10 @@ public class GlobalApplication extends Application {
// 初始化单例实例(确保在所有初始化操作前完成) // 初始化单例实例(确保在所有初始化操作前完成)
sInstance = this; sInstance = this;
restoreDebugStatus();
// 初始化基础组件日志、崩溃处理、Toast // 初始化基础组件日志、崩溃处理、Toast
initCoreComponents(); initCoreComponents();
// 恢复/初始化调试模式状态(从本地文件读取,无文件则默认关闭调试 // 初始化服务器地址(从 SP 读取到内存,提高后续访问效率
restoreDebugStatus();
// 新增:初始化服务器地址(从 SP 读取到内存,提高后续访问效率)
initWinbollHost(); initWinbollHost();
LogUtils.d(TAG, "GlobalApplication 初始化完成,单例实例已创建"); LogUtils.d(TAG, "GlobalApplication 初始化完成,单例实例已创建");
@@ -144,7 +143,11 @@ public class GlobalApplication extends Application {
*/ */
private void initCoreComponents() { private void initCoreComponents() {
// 初始化日志工具(传入 Application 上下文) // 初始化日志工具(传入 Application 上下文)
LogUtils.init(this);
// 调试状态下初始化日志工具
if (GlobalApplication.isDebugging()) {
LogUtils.init(this);
}
// 初始化全局异常处理器(捕获应用崩溃信息,用于调试或上报) // 初始化全局异常处理器(捕获应用崩溃信息,用于调试或上报)
CrashHandler.init(this); CrashHandler.init(this);
// 初始化 Toast 工具(统一 Toast 样式、避免内存泄漏等) // 初始化 Toast 工具(统一 Toast 样式、避免内存泄漏等)

View File

@@ -27,6 +27,11 @@ public class LogActivity extends Activity {
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
if(!GlobalApplication.isDebugging()) {
ToastUtils.show("非调试状态日志功能不可用");
finish();
}
// 设置布局文件(包含 LogView 控件) // 设置布局文件(包含 LogView 控件)
setContentView(R.layout.activity_log); setContentView(R.layout.activity_log);

View File

@@ -67,45 +67,29 @@ public class LogUtils {
// ====================== 初始化入口 ====================== // ====================== 初始化入口 ======================
public static void init(final Context context) { public static void init(final Context context) {
init(context, LOG_LEVEL.Off); init(context, LOG_LEVEL.Off);
} }
public static void init(final Context context, final LOG_LEVEL logLevel) { public static void init(final Context context, final LOG_LEVEL logLevel) {
Log.d(TAG, "init 执行日志工具初始化"); if (!GlobalApplication.isDebugging()) {
_mContext = context; return;
}
Log.d(TAG, "init 执行日志工具初始化");
_mContext = context;
if (GlobalApplication.isDebugging()) { initLogUtilsDir();
initDebugDir();
} else {
initReleaseDir();
}
initLogConfigBean(); initLogConfigBean();
addClassTAGList(); addClassTAGList();
loadTAGBeanSettings(); loadTAGBeanSettings();
checkAndTrimLogFileSize(); checkAndTrimLogFileSize();
_IsInited = true; _IsInited = true;
Log.d(TAG, "init 日志工具初始化完成"); Log.d(TAG, "init 执行日志工具初始化完成");
} }
// ====================== 目录初始化 ====================== // ====================== 目录初始化 ======================
private static void initDebugDir() { private static void initLogUtilsDir() {
final Context appContext = _mContext.getApplicationContext();
_mfLogCacheDir = new File(appContext.getExternalCacheDir(), TAG);
if (!_mfLogCacheDir.exists()) {
_mfLogCacheDir.mkdirs();
}
_mfLogCatchFile = new File(_mfLogCacheDir, "log.txt");
_mfLogDataDir = appContext.getExternalFilesDir(TAG);
if (!_mfLogDataDir.exists()) {
_mfLogDataDir.mkdirs();
}
_mfLogUtilsBeanFile = new File(_mfLogDataDir, TAG + ".json");
}
private static void initReleaseDir() {
final Context appContext = _mContext.getApplicationContext(); final Context appContext = _mContext.getApplicationContext();
_mfLogCacheDir = new File(appContext.getCacheDir(), TAG); _mfLogCacheDir = new File(appContext.getCacheDir(), TAG);
if (!_mfLogCacheDir.exists()) { if (!_mfLogCacheDir.exists()) {
@@ -113,7 +97,7 @@ public class LogUtils {
} }
_mfLogCatchFile = new File(_mfLogCacheDir, "log.txt"); _mfLogCatchFile = new File(_mfLogCacheDir, "log.txt");
_mfLogDataDir = new File(appContext.getFilesDir(), TAG); _mfLogDataDir = appContext.getExternalFilesDir(TAG);
if (!_mfLogDataDir.exists()) { if (!_mfLogDataDir.exists()) {
_mfLogDataDir.mkdirs(); _mfLogDataDir.mkdirs();
} }
@@ -136,7 +120,7 @@ public class LogUtils {
} }
final long KEEP_FILE_SIZE = 25000L; // ~25KB 确保剪贴板可完整复制 final long KEEP_FILE_SIZE = 25000L; // ~25KB 确保剪贴板可完整复制
final long MAX_FILE_SIZE = 2*KEEP_FILE_SIZE; final long MAX_FILE_SIZE = 2 * KEEP_FILE_SIZE;
final long fileSize = _mfLogCatchFile.length(); final long fileSize = _mfLogCatchFile.length();
if (fileSize <= MAX_FILE_SIZE) { if (fileSize <= MAX_FILE_SIZE) {
@@ -266,6 +250,9 @@ public class LogUtils {
} }
public static void setTAGListEnable(final String tag, final boolean isEnable) { public static void setTAGListEnable(final String tag, final boolean isEnable) {
if (!_IsInited) {
return;
}
final Iterator<Map.Entry<String, Boolean>> iterator = mapTAGList.entrySet().iterator(); final Iterator<Map.Entry<String, Boolean>> iterator = mapTAGList.entrySet().iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
final Map.Entry<String, Boolean> entry = iterator.next(); final Map.Entry<String, Boolean> entry = iterator.next();
@@ -279,6 +266,9 @@ public class LogUtils {
} }
public static void setALlTAGListEnable(final boolean isEnable) { public static void setALlTAGListEnable(final boolean isEnable) {
if (!_IsInited) {
return;
}
for (final Map.Entry<String, Boolean> entry : mapTAGList.entrySet()) { for (final Map.Entry<String, Boolean> entry : mapTAGList.entrySet()) {
entry.setValue(isEnable); entry.setValue(isEnable);
} }
@@ -288,15 +278,22 @@ public class LogUtils {
// ====================== 日志级别控制 ====================== // ====================== 日志级别控制 ======================
public static void setLogLevel(final LOG_LEVEL logLevel) { public static void setLogLevel(final LOG_LEVEL logLevel) {
if (_mLogUtilsBean == null) {
Log.d(TAG, "setLogLevel LogUtils未初始化忽略设置日志级别");
return;
}
_mLogUtilsBean.setLogLevel(logLevel); _mLogUtilsBean.setLogLevel(logLevel);
_mLogUtilsBean.saveBeanToFile(_mfLogUtilsBeanFile.getPath(), _mLogUtilsBean); _mLogUtilsBean.saveBeanToFile(_mfLogUtilsBeanFile.getPath(), _mLogUtilsBean);
} }
public static LOG_LEVEL getLogLevel() { public static LOG_LEVEL getLogLevel() {
return _mLogUtilsBean.getLogLevel(); return _mLogUtilsBean == null ?LOG_LEVEL.Off: _mLogUtilsBean.getLogLevel();
} }
private static boolean isLoggable(final String tag, final LOG_LEVEL logLevel) { private static boolean isLoggable(final String tag, final LOG_LEVEL logLevel) {
if (!GlobalApplication.isDebugging()) {
return false;
}
if (!_IsInited) { if (!_IsInited) {
return false; return false;
} }

View File

@@ -2,6 +2,7 @@ package cc.winboll.studio.libappbase;
import android.util.JsonReader; import android.util.JsonReader;
import android.util.JsonWriter; import android.util.JsonWriter;
import cc.winboll.studio.libappbase.models.libs1520000.BaseBean;
import java.io.IOException; import java.io.IOException;
/** /**

View File

@@ -2,6 +2,7 @@ package cc.winboll.studio.libappbase;
import android.util.JsonReader; import android.util.JsonReader;
import android.util.JsonWriter; import android.util.JsonWriter;
import cc.winboll.studio.libappbase.models.libs1520000.BaseBean;
import java.io.IOException; import java.io.IOException;
/** /**

View File

@@ -1,6 +1,7 @@
package cc.winboll.studio.libappbase; package cc.winboll.studio.libappbase;
import android.os.FileObserver; import android.os.FileObserver;
import java.io.File;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
/** /**
@@ -51,30 +52,38 @@ public class LogViewThread extends Thread {
*/ */
@Override @Override
public void run() { public void run() {
// 获取日志缓存目录路径(从 LogUtils 统一获取,确保路径一致性) // 调试状态进行日志输出任务
String logDirPath = LogUtils.getLogCacheDir().getPath(); if (GlobalApplication.isDebugging()) {
LogUtils.d(TAG, "启动日志文件监听,监听目录:" + logDirPath); // 获取日志缓存目录路径(从 LogUtils 统一获取,确保路径一致性)
File logDir = LogUtils.getLogCacheDir();
if (logDir == null) {
LogUtils.d(TAG, "日志缓存目录未初始化,线程退出");
return;
}
String logDirPath = logDir.getPath();
LogUtils.d(TAG, "启动日志文件监听,监听目录:" + logDirPath);
// 初始化日志文件监听器(监听目标目录的文件事件) // 初始化日志文件监听器(监听目标目录的文件事件)
mLogListener = new LogListener(logDirPath); mLogListener = new LogListener(logDirPath);
// 开始监听文件事件(非阻塞,内部通过 Native 层实现) // 开始监听文件事件(非阻塞,内部通过 Native 层实现)
mLogListener.startWatching(); mLogListener.startWatching();
// 循环等待退出标志(每 1 秒检查一次,降低 CPU 占用) // 循环等待退出标志(每 1 秒检查一次,降低 CPU 占用)
while (!isExit()) { while (!isExit()) {
try { try {
Thread.sleep(1000); // 休眠 1 秒,避免忙等 Thread.sleep(1000); // 休眠 1 秒,避免忙等
} catch (InterruptedException e) { } catch (InterruptedException e) {
// 线程被中断时,恢复中断标志并退出循环(避免无限阻塞) // 线程被中断时,恢复中断标志并退出循环(避免无限阻塞)
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
LogUtils.d(TAG, "日志监听线程被中断,准备退出。" + e); LogUtils.d(TAG, "日志监听线程被中断,准备退出。" + e);
break; break;
} }
} }
// 收到退出标志,停止监听并释放资源 // 收到退出标志,停止监听并释放资源
mLogListener.stopWatching(); mLogListener.stopWatching();
LogUtils.d(TAG, "日志文件监听已停止,线程退出"); LogUtils.d(TAG, "日志文件监听已停止,线程退出");
}
} }
/** /**

View File

@@ -0,0 +1,415 @@
package cc.winboll.studio.libappbase.models.libs1520000;
import android.content.Context;
import android.util.JsonReader;
import android.util.JsonWriter;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.UTF8FileUtils;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
/**
* WinBoLL JSON 数据模型基类(抽象类)
* 定义 Json Bean 的核心规范:序列化/反序列化、文件持久化、列表处理等通用逻辑,
* 子类需实现抽象方法完成自身字段JSON读写业务逻辑
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
* @CreateTime 2026/05/19 22:33:00
* @EditTime 2026/05/19 23:15:48
* @param <T> 泛型约束限定子类必须继承自BaseBean
*/
public abstract class BaseBean<T extends BaseBean> {
// ====================== 静态常量 ======================
/** 日志输出标识TAG */
public static final String TAG = "BaseBean";
/** JSON存储Bean类名字段Key用于类型校验 */
static final String BEAN_NAME = "BeanName";
// ====================== 构造方法 ======================
/**
* 无参空构造,满足反射实例化要求
*/
public BaseBean() {
}
// ====================== 抽象方法 ======================
/**
* 获取当前实体类全类名
* @return 全限定类名字符串
*/
public abstract String getName();
/**
* 从JSON读取器解析构建实体对象
* @param jsonReader JSON读取流
* @return 解析完成实体对象
* @throws IOException IO读写异常
*/
public abstract T readBeanFromJsonReader(final JsonReader jsonReader) throws IOException;
// ====================== 路径获取相关 ======================
/**
* 获取单个实体默认存储JSON文件路径
* @param context 应用上下文
* @return 文件绝对路径
*/
public String getBeanJsonFilePath(final Context context) {
return context.getExternalFilesDir(TAG) + "/" + getName() + ".json";
}
/**
* 获取实体列表默认存储JSON文件路径
* @param context 应用上下文
* @return 文件绝对路径
*/
public String getBeanListJsonFilePath(final Context context) {
return context.getExternalFilesDir(TAG) + "/" + getName() + "_List.json";
}
// ====================== JSON序列化基础方法 ======================
/**
* 写入基础Bean标识字段至JSON
* @param jsonWriter JSON写入流
* @throws IOException 写入异常
*/
public void writeThisToJsonWriter(final JsonWriter jsonWriter) throws IOException {
jsonWriter.name(BEAN_NAME).value(getName());
}
/**
* 基类通用字段解析回调
* @param jsonReader JSON读取流
* @param name 字段名
* @return 是否完成当前字段解析
* @throws IOException 读取异常
*/
public boolean initObjectsFromJsonReader(final JsonReader jsonReader, final String name) throws IOException {
return false;
}
// ====================== 实体字符串序列化 ======================
@Override
public String toString() {
LogUtils.d(TAG, "执行BaseBean实体转JSON字符串");
final StringWriter stringWriter = new StringWriter();
final JsonWriter jsonWriter = new JsonWriter(stringWriter);
jsonWriter.setIndent(" ");
try {
jsonWriter.beginObject();
writeThisToJsonWriter(jsonWriter);
jsonWriter.endObject();
return stringWriter.toString();
} catch (final IOException e) {
LogUtils.d(TAG, "实体转JSON字符串异常", Thread.currentThread().getStackTrace());
}
return "";
}
// ====================== 列表序列化工具 ======================
/**
* Bean列表转为格式化JSON数组字符串
* @param beanList 实体集合
* @param <T> 实体泛型
* @return JSON字符串
*/
public static <T extends BaseBean> String toStringByBeanList(final ArrayList<T> beanList) {
LogUtils.d(TAG, "执行Bean列表序列化JSON操作");
try {
final StringWriter stringWriter = new StringWriter();
final JsonWriter jsonWriter = new JsonWriter(stringWriter);
jsonWriter.setIndent(" ");
jsonWriter.beginArray();
for (int i = 0; i < beanList.size(); i++) {
jsonWriter.beginObject();
beanList.get(i).writeThisToJsonWriter(jsonWriter);
jsonWriter.endObject();
}
jsonWriter.endArray();
jsonWriter.close();
return stringWriter.toString();
} catch (final IOException e) {
LogUtils.d(TAG, "列表序列化JSON异常", Thread.currentThread().getStackTrace());
}
return "";
}
// ====================== JSON字符串解析实体 ======================
/**
* JSON文本解析为单个实体对象
* @param szBean JSON文本
* @param clazz 实体Class字节码
* @param <T> 实体泛型
* @return 解析完成实体
* @throws IOException 解析IO异常
*/
public static <T extends BaseBean> T parseStringToBean(final String szBean, final Class<T> clazz) throws IOException {
LogUtils.d(TAG, "进入字符串解析实体方法目标Class" + clazz.getSimpleName());
final StringReader stringReader = new StringReader(szBean);
final JsonReader jsonReader = new JsonReader(stringReader);
try {
final T beanTemp = clazz.newInstance();
return (T) beanTemp.readBeanFromJsonReader(jsonReader);
} catch (final InstantiationException e) {
LogUtils.d(TAG, "实体反射实例化失败(InstantiationException)", Thread.currentThread().getStackTrace());
} catch (final IllegalAccessException e) {
LogUtils.d(TAG, "实体反射权限访问失败(IllegalAccessException)", Thread.currentThread().getStackTrace());
}
return null;
}
/**
* JSON数组文本解析填充实体列表
* @param szBeanList JSON数组文本
* @param beanList 目标存储集合
* @param clazz 实体字节码
* @param <T> 实体泛型
* @return 解析结果
*/
public static <T extends BaseBean> boolean parseStringToBeanList(final String szBeanList, ArrayList<T> beanList, final Class<T> clazz) {
LogUtils.d(TAG, "进入列表字符串解析方法");
try {
if (beanList == null) {
beanList = new ArrayList<T>();
} else {
beanList.clear();
}
final StringReader stringReader = new StringReader(szBeanList);
final JsonReader jsonReader = new JsonReader(stringReader);
jsonReader.beginArray();
while (jsonReader.hasNext()) {
final T beanTemp = clazz.newInstance();
final T bean = (T) beanTemp.readBeanFromJsonReader(jsonReader);
if (bean != null) {
beanList.add(bean);
}
}
jsonReader.endArray();
return true;
} catch (final InstantiationException e) {
LogUtils.d(TAG, "列表解析反射实例化异常", Thread.currentThread().getStackTrace());
} catch (final IllegalAccessException e) {
LogUtils.d(TAG, "列表解析反射权限异常", Thread.currentThread().getStackTrace());
} catch (final IOException e) {
LogUtils.d(TAG, "列表解析JSON读写异常", Thread.currentThread().getStackTrace());
}
return false;
}
// ====================== 文件加载实体 ======================
/**
* 从默认路径加载单个实体
* @param context 上下文
* @param clazz 实体字节码
* @param <T> 实体泛型
* @return 加载实体
*/
public static <T extends BaseBean> T loadBean(final Context context, final Class<T> clazz) {
LogUtils.d(TAG, "执行默认路径加载实体数据");
try {
final T beanTemp = clazz.newInstance();
return loadBeanFromFile(beanTemp.getBeanJsonFilePath(context), clazz);
} catch (final InstantiationException e) {
LogUtils.d(TAG, "加载实体反射实例化失败", Thread.currentThread().getStackTrace());
} catch (final IllegalAccessException e) {
LogUtils.d(TAG, "加载实体反射权限失败", Thread.currentThread().getStackTrace());
}
return null;
}
/**
* 自定义文件路径加载单个实体
* @param szFilePath 文件路径
* @param clazz 实体字节码
* @param <T> 实体泛型
* @return 实体对象
*/
public static <T extends BaseBean> T loadBeanFromFile(final String szFilePath, final Class<T> clazz) {
LogUtils.d(TAG, "指定路径加载实体,路径:" + szFilePath);
try {
final File file = new File(szFilePath);
if (file.exists()) {
final T beanTemp = clazz.newInstance();
final String json = UTF8FileUtils.readStringFromFile(szFilePath);
return beanTemp.parseStringToBean(json, clazz);
}
} catch (final InstantiationException e) {
LogUtils.d(TAG, "文件加载实体反射实例化异常", Thread.currentThread().getStackTrace());
} catch (final IllegalAccessException e) {
LogUtils.d(TAG, "文件加载实体反射权限异常", Thread.currentThread().getStackTrace());
} catch (final IOException e) {
LogUtils.d(TAG, "文件读取JSON数据异常", Thread.currentThread().getStackTrace());
}
return null;
}
/**
* 默认路径加载实体列表
* @param context 上下文
* @param beanListDst 目标集合
* @param clazz 实体字节码
* @param <T> 实体泛型
* @return 加载结果
*/
public static <T extends BaseBean> boolean loadBeanList(final Context context, final ArrayList<T> beanListDst, final Class<T> clazz) {
LogUtils.d(TAG, "默认路径加载实体列表数据");
try {
final T beanTemp = clazz.newInstance();
return loadBeanListFromFile(beanTemp.getBeanListJsonFilePath(context), beanListDst, clazz);
} catch (final InstantiationException e) {
LogUtils.d(TAG, "列表加载反射实例化异常", Thread.currentThread().getStackTrace());
} catch (final IllegalAccessException e) {
LogUtils.d(TAG, "列表加载反射权限异常", Thread.currentThread().getStackTrace());
}
return false;
}
/**
* 自定义路径加载实体列表
* @param szFilePath 文件路径
* @param beanList 目标集合
* @param clazz 实体字节码
* @param <T> 实体泛型
* @return 加载结果
*/
public static <T extends BaseBean> boolean loadBeanListFromFile(final String szFilePath, final ArrayList<T> beanList, final Class<T> clazz) {
LogUtils.d(TAG, "指定路径加载实体列表,路径:" + szFilePath);
try {
final File file = new File(szFilePath);
if (file.exists()) {
final String listJson = UTF8FileUtils.readStringFromFile(szFilePath);
return parseStringToBeanList(listJson, beanList, clazz);
}
} catch (final IOException e) {
LogUtils.d(TAG, "列表文件读取异常", Thread.currentThread().getStackTrace());
}
return false;
}
// ====================== 实体数据保存文件 ======================
/**
* 默认路径保存单个实体
* @param context 上下文
* @param bean 待保存实体
* @param <T> 实体泛型
* @return 保存结果
*/
public static <T extends BaseBean> boolean saveBean(final Context context, final T bean) {
return saveBeanToFile(bean.getBeanJsonFilePath(context), bean);
}
/**
* 自定义路径保存单个实体
* @param szFilePath 保存路径
* @param bean 待保存实体
* @param <T> 实体泛型
* @return 保存结果
*/
public static <T extends BaseBean> boolean saveBeanToFile(final String szFilePath, final T bean) {
LogUtils.d(TAG, "执行实体数据写入文件操作");
try {
final String json = bean.toString();
UTF8FileUtils.writeStringToFile(szFilePath, json);
return true;
} catch (final IOException e) {
LogUtils.d(TAG, "实体写入文件异常", Thread.currentThread().getStackTrace());
}
return false;
}
/**
* 默认路径保存实体列表
* @param context 上下文
* @param beanList 实体集合
* @param clazz 实体字节码
* @param <T> 实体泛型
* @return 保存结果
*/
public static <T extends BaseBean> boolean saveBeanList(final Context context, final ArrayList<T> beanList, final Class<T> clazz) {
LogUtils.d(TAG, "默认路径保存实体列表数据");
try {
final T beanTemp = clazz.newInstance();
return saveBeanListToFile(beanTemp.getBeanListJsonFilePath(context), beanList);
} catch (final InstantiationException e) {
LogUtils.d(TAG, "列表保存反射实例化异常", Thread.currentThread().getStackTrace());
} catch (final IllegalAccessException e) {
LogUtils.d(TAG, "列表保存反射权限异常", Thread.currentThread().getStackTrace());
}
return false;
}
/**
* 自定义路径保存实体列表
* @param szFilePath 保存路径
* @param beanList 实体集合
* @param <T> 实体泛型
* @return 保存结果
*/
public static <T extends BaseBean> boolean saveBeanListToFile(final String szFilePath, final ArrayList<T> beanList) {
LogUtils.d(TAG, "指定路径保存实体列表数据");
try {
final String json = toStringByBeanList(beanList);
UTF8FileUtils.writeStringToFile(szFilePath, json);
return true;
} catch (final IOException e) {
LogUtils.d(TAG, "列表数据写入文件异常", Thread.currentThread().getStackTrace());
}
return false;
}
// ====================== Bean类型一致性校验 ======================
/**
* 校验本地JSON列表内实体类型是否统一
* @param szFilePath 列表文件路径
* @param clazz 目标校验实体Class
* @param <T> 实体泛型
* @return 校验结果信息
*/
public static <T extends BaseBean> String checkIsTheSameBeanListAndFile(final String szFilePath, final Class<T> clazz) {
final StringBuilder sbResult = new StringBuilder();
final String szErrorInfo = "Check Is The Same Bean List And File Error : ";
try {
int sameCount = 0;
int totalCount = 0;
final T beanTemp = clazz.newInstance();
final String targetBeanName = beanTemp.getName();
final String listJson = UTF8FileUtils.readStringFromFile(szFilePath);
final StringReader stringReader = new StringReader(listJson);
final JsonReader jsonReader = new JsonReader(stringReader);
jsonReader.beginArray();
while (jsonReader.hasNext()) {
totalCount++;
jsonReader.beginObject();
while (jsonReader.hasNext()) {
final String name = jsonReader.nextName();
if (BEAN_NAME.equals(name)) {
if (targetBeanName.equals(jsonReader.nextString())) {
sameCount++;
}
} else {
jsonReader.skipValue();
}
}
jsonReader.endObject();
}
jsonReader.endArray();
if (sameCount != totalCount) {
sbResult.append("Total : ").append(totalCount).append(" Diff : ").append(totalCount - sameCount);
}
} catch (final InstantiationException e) {
sbResult.append(szErrorInfo).append(e);
LogUtils.d(TAG, "类型校验反射实例化异常", Thread.currentThread().getStackTrace());
} catch (final IllegalAccessException e) {
sbResult.append(szErrorInfo).append(e);
LogUtils.d(TAG, "类型校验反射权限异常", Thread.currentThread().getStackTrace());
} catch (final IOException e) {
sbResult.append(szErrorInfo).append(e);
LogUtils.d(TAG, "类型校验文件读取解析异常", Thread.currentThread().getStackTrace());
}
return sbResult.toString();
}
}

View File

@@ -60,4 +60,7 @@
<!-- DebugLogStyle 应用调试日志样式属性 --> <!-- DebugLogStyle 应用调试日志样式属性 -->
<attr name="debugTextColor" format="color"/> <attr name="debugTextColor" format="color"/>
<!-- 边框圆角属性 -->
<attr name="borderCornerRadius" format="dimension"/>
</resources> </resources>

5
settings.gradle Normal file
View File

@@ -0,0 +1,5 @@
// AES 项目编译设置
include ':aes'
include ':libaes'
rootProject.name = "aes"

View File

@@ -96,7 +96,3 @@
// AutoNFC 项目编译设置 // AutoNFC 项目编译设置
//include ':autonfc' //include ':autonfc'
//rootProject.name = "autonfc" //rootProject.name = "autonfc"
// DailyStamp 项目编译设置
//include ':dailystamp'
//rootProject.name = "dailystamp"