本文是我对 AutoX (AutoJs 的开源分支) 项目的深度技术分析,从架构师的角度全面剖析这个 Android 自动化框架的设计与实现。
一、项目基础信息
1.1 基本信息
| 项目属性 | 值 |
|---|---|
| 项目名称 | AutoX (AutoJs 社区分支) |
| 包名 | org.autojs.autoxjs |
| 版本号 | 6.6.8 (versionCode: 668) |
| 开发语言 | Java + Kotlin 混合 |
| 许可证 | Mozilla Public License |
1.2 SDK 配置
| SDK 配置项 | 版本 |
|---|---|
| minSdk | 21 (Android 5.0) |
| targetSdk | 28 (Android 9.0) |
| compileSdk | 34 (Android 14) |
| buildToolsVersion | 34.0.0 |
1.3 构建工具版本
| 工具 | 版本 |
|---|---|
| Gradle | 8.0 |
| Android Gradle Plugin (AGP) | 8.0.2 |
| Kotlin | 1.6.21 |
| Jetpack Compose | 1.2.0-rc01 |
| JDK | 17 |
| IDE 推荐 | Android Studio 2023.3.1 Patch 2 |
1.4 构建变体配置
项目采用 channel 维度的产品风味(Product Flavors):
flavorDimensions.add("channel")
productFlavors {
create("common") {
applicationId = "org.autojs.autoxjs"
versionCode = 668
versionName = "6.6.8"
}
create("v6") {
applicationIdSuffix = ".v6" // org.autojs.autoxjs.v6
versionCode = 668
versionName = "6.6.8"
}
}同时启用了 ABI 分包:
arm64-v8a(ARMv8 64位)armeabi-v7a(ARM 32位)
二、架构分析
2.1 整体架构模式
经过对源码的深入分析,我发现 AutoX 采用的是混合架构模式,主要以 MVVM 为主,同时保留了大量 MVC 风格的遗留代码:
flowchart TB
subgraph Presentation["表现层 Presentation"]
direction TB
Activity["Activities
(MainActivity, BuildActivity)"] Fragment["Fragments
(ScriptListFragment, TaskManagerFragment)"] Compose["Compose UI
(BuildPage, SearchBox)"] ViewModel["ViewModels
(BuildViewModel, DrawerViewModel)"] end subgraph Domain["领域层 Domain"] direction TB Service["Services
(UserService, VersionService)"] Tool["Tools
(AccessibilityServiceTool)"] AutoJs["AutoJs Core
(ScriptRuntime, ScriptEngine)"] end subgraph Data["数据层 Data"] direction TB API["Network APIs
(Retrofit Interfaces)"] Storage["Local Storage
(SharedPreferences, Database)"] Model["Models
(User, VersionInfo, Script)"] end Activity --> ViewModel Fragment --> ViewModel Compose --> ViewModel ViewModel --> Service ViewModel --> AutoJs Service --> API Service --> Storage AutoJs --> Model API --> Model Storage --> Model
(MainActivity, BuildActivity)"] Fragment["Fragments
(ScriptListFragment, TaskManagerFragment)"] Compose["Compose UI
(BuildPage, SearchBox)"] ViewModel["ViewModels
(BuildViewModel, DrawerViewModel)"] end subgraph Domain["领域层 Domain"] direction TB Service["Services
(UserService, VersionService)"] Tool["Tools
(AccessibilityServiceTool)"] AutoJs["AutoJs Core
(ScriptRuntime, ScriptEngine)"] end subgraph Data["数据层 Data"] direction TB API["Network APIs
(Retrofit Interfaces)"] Storage["Local Storage
(SharedPreferences, Database)"] Model["Models
(User, VersionInfo, Script)"] end Activity --> ViewModel Fragment --> ViewModel Compose --> ViewModel ViewModel --> Service ViewModel --> AutoJs Service --> API Service --> Storage AutoJs --> Model API --> Model Storage --> Model
2.2 模块化结构
项目采用多模块 Gradle 结构,模块划分清晰:
graph TD
subgraph MainModules["主要模块"]
app["📱 app
主应用模块"] autojs["⚙️ autojs
核心引擎库"] automator["🤖 automator
自动化库"] common["📦 common
公共工具库"] inrt["🚀 inrt
运行时模块"] apkbuilder["🔨 apkbuilder
APK构建库"] paddleocr["👁️ paddleocr
OCR识别库"] end subgraph LocalRepo["本地仓库模块"] libtermexec["libtermexec"] emulatorview["emulatorview"] term["term"] p7zip["p7zip"] opencv["OpenCV 4.5.5"] end app --> autojs app --> apkbuilder autojs --> common autojs --> automator autojs --> libtermexec autojs --> emulatorview autojs --> term autojs --> p7zip autojs --> opencv autojs --> paddleocr automator --> common inrt --> autojs inrt --> automator inrt --> common
主应用模块"] autojs["⚙️ autojs
核心引擎库"] automator["🤖 automator
自动化库"] common["📦 common
公共工具库"] inrt["🚀 inrt
运行时模块"] apkbuilder["🔨 apkbuilder
APK构建库"] paddleocr["👁️ paddleocr
OCR识别库"] end subgraph LocalRepo["本地仓库模块"] libtermexec["libtermexec"] emulatorview["emulatorview"] term["term"] p7zip["p7zip"] opencv["OpenCV 4.5.5"] end app --> autojs app --> apkbuilder autojs --> common autojs --> automator autojs --> libtermexec autojs --> emulatorview autojs --> term autojs --> p7zip autojs --> opencv autojs --> paddleocr automator --> common inrt --> autojs inrt --> automator inrt --> common
2.3 依赖注入方案
项目没有使用任何 DI 框架(无 Dagger/Hilt/Koin),而是采用手动依赖注入配合服务定位器模式:
flowchart LR
subgraph Singletons["单例服务"]
AutoJs["AutoJs.getInstance()"]
GlobalAppContext["GlobalAppContext.get()"]
VersionService2["VersionService2
(Kotlin object)"] end subgraph Factories["工厂类"] Factory["BuildViewModelFactory"] end Factory -->|创建| ViewModel["BuildViewModel"] AutoJs -->|依赖| GlobalAppContext ViewModel -->|使用| AutoJs
(Kotlin object)"] end subgraph Factories["工厂类"] Factory["BuildViewModelFactory"] end Factory -->|创建| ViewModel["BuildViewModel"] AutoJs -->|依赖| GlobalAppContext ViewModel -->|使用| AutoJs
服务定位模式示例:
// 单例服务 - Kotlin object
object VersionService2 {
private val retrofit = Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build()
val gitUpdateCheckApi = retrofit.create<GithubUpdateCheckApi>()
}
// 单例获取 - Java static
public static AutoJs getInstance() {
return instance;
}2.4 核心引擎架构
AutoJs 的核心是基于 Mozilla Rhino 的 JavaScript 执行引擎:
flowchart LR
subgraph ScriptExecution["脚本执行流程"]
direction TB
Script["JavaScript 脚本"]
Engine["ScriptEngine
(Rhino 1.7.14)"] Runtime["ScriptRuntime"] API["运行时 API"] end subgraph RuntimeAPIs["运行时 API 模块"] direction TB UI["ui - UI构建"] Auto["auto - 自动化"] Image["images - 图像处理"] OCR["ocr - 文字识别"] Files["files - 文件操作"] Http["http - 网络请求"] Threads["threads - 多线程"] Events["events - 事件系统"] end subgraph NativeSupport["原生支持"] direction TB Accessibility["AccessibilityService
无障碍服务"] OpenCV_Native["OpenCV
图像处理"] Tesseract["Tesseract
OCR引擎"] MLKit["Google MLKit
多语言OCR"] PaddleOCR_Native["PaddleOCR
飞桨OCR"] end Script --> Engine Engine --> Runtime Runtime --> API API --> UI & Auto & Image & OCR & Files & Http & Threads & Events Image --> OpenCV_Native OCR --> Tesseract OCR --> MLKit OCR --> PaddleOCR_Native Auto --> Accessibility
(Rhino 1.7.14)"] Runtime["ScriptRuntime"] API["运行时 API"] end subgraph RuntimeAPIs["运行时 API 模块"] direction TB UI["ui - UI构建"] Auto["auto - 自动化"] Image["images - 图像处理"] OCR["ocr - 文字识别"] Files["files - 文件操作"] Http["http - 网络请求"] Threads["threads - 多线程"] Events["events - 事件系统"] end subgraph NativeSupport["原生支持"] direction TB Accessibility["AccessibilityService
无障碍服务"] OpenCV_Native["OpenCV
图像处理"] Tesseract["Tesseract
OCR引擎"] MLKit["Google MLKit
多语言OCR"] PaddleOCR_Native["PaddleOCR
飞桨OCR"] end Script --> Engine Engine --> Runtime Runtime --> API API --> UI & Auto & Image & OCR & Files & Http & Threads & Events Image --> OpenCV_Native OCR --> Tesseract OCR --> MLKit OCR --> PaddleOCR_Native Auto --> Accessibility
2.5 UI 架构演进
项目正处于从传统 View 体系向 Jetpack Compose 迁移的过渡期:
graph LR
subgraph Legacy["传统架构 (遗留)"]
Activity_Old["Activity"]
Fragment_Old["Fragment"]
XML["XML Layout"]
ButterKnife["ButterKnife
View绑定"] end subgraph Modern["现代架构 (新增)"] Activity_New["Activity"] Compose["Jetpack Compose"] ViewModel_New["ViewModel"] State["Compose State"] end Activity_Old --> XML XML --> ButterKnife Activity_New --> Compose Compose --> ViewModel_New ViewModel_New --> State Legacy -.->|迁移中| Modern
View绑定"] end subgraph Modern["现代架构 (新增)"] Activity_New["Activity"] Compose["Jetpack Compose"] ViewModel_New["ViewModel"] State["Compose State"] end Activity_Old --> XML XML --> ButterKnife Activity_New --> Compose Compose --> ViewModel_New ViewModel_New --> State Legacy -.->|迁移中| Modern
三、代码质量评估
3.1 代码规范遵循情况
| 维度 | 评估 | 说明 |
|---|---|---|
| 命名规范 | ⭐⭐⭐⭐ | 遵循 Android 惯例,成员变量使用 m 前缀 |
| 包结构 | ⭐⭐⭐⭐ | 按功能模块清晰划分 |
| 注释质量 | ⭐⭐⭐ | 类级注释较完整,但存在过时 TODO |
| 代码格式 | ⭐⭐⭐ | Java/Kotlin 混合,风格不够统一 |
3.2 设计模式使用情况
pie title 设计模式分布
"单例模式" : 66
"工厂模式" : 20
"建造者模式" : 15
"观察者模式" : 30
"策略模式" : 5
具体使用:
| 模式 | 实现数量 | 典型示例 |
|---|---|---|
| Singleton | 66+ | AutoJs.getInstance(), DebuggerSingleton |
| Factory | 20+ | ScriptEngineFactory, ViewAttributesFactory |
| Builder | 15+ | JsDialogBuilder, ScriptRuntime.Builder |
| Observer | 30+ | EventDispatcher, ScriptExecutionObserver |
| Delegate | 5+ | ViewAttributeDelegate |
3.3 代码异味(Code Smell)分析
我在源码中发现了以下主要问题:
3.3.1 大型类(God Class)
| 类名 | 行数 | 问题描述 |
|---|---|---|
TokenStream.java | 2,319 | Rhino 词法分析器,职责过重 |
HVScrollView.java | 1,647 | 自定义滚动视图,触摸处理复杂 |
Dim.java | 1,558 | 调试器实现,状态管理混乱 |
BuildPage.kt | 954 | Compose UI,嵌套层级过深 |
JsDialog.java | 810 | 对话框包装,方法委托过多 |
User.java | 755 | 数据实体,185个属性! |
3.3.2 问题代码示例
// HVScrollView.java 中发现的不专业注释
// TODO: FUCK <- 这类注释应该被清理
// 2017-2018年的过时TODO仍未处理
// TODO: 2018/10/24
// TODO: 2018/2/24 优化效率。不绘制透明字体。3.4 单元测试覆盖情况
pie title 测试覆盖率分析
"有测试覆盖" : 0.65
"无测试覆盖" : 99.35
| 指标 | 数值 |
|---|---|
| 总代码行数 | ~100,770 |
| 测试代码行数 | ~656 |
| 实际有效测试 | ~130 行 |
| 测试覆盖率 | 0.65% (极低) |
已有测试:
XmlConverterTest.java- XML布局转换测试 (5个用例)MultiLinePreprocessorTest.java- JS预处理测试 (10个用例)- 其余多为 Example 模板文件
四、依赖管理
4.1 核心依赖库清单
mindmap
root((依赖库))
UI框架
Jetpack Compose 1.2.0-rc01
Material Design 1.9.0
Accompanist 0.24.13-rc
ButterKnife 10.2.1
网络通信
Retrofit 2.9.0
OkHttp 4.10.0
Ktor 2.0.3
异步处理
RxJava2 2.2.21
Kotlin Coroutines 1.6.2
图像处理
OpenCV 4.5.5
Glide 4.8.0
Coil 2.0.0-rc03
OCR识别
Tesseract 4.1.1
Google MLKit 16.0.0-beta5
PaddleOCR
脚本引擎
Rhino 1.7.14
其他
EventBus 3.3.1
LeakCanary 2.13
Bugly 4.0.0
4.2 依赖版本评估
| 库 | 当前版本 | 最新版本 | 状态 |
|---|---|---|---|
| Kotlin | 1.6.21 | 2.0.0+ | ⚠️ 落后2个大版本 |
| Compose | 1.2.0-rc01 | 1.6.0+ | ⚠️ 落后较多 |
| AGP | 8.0.2 | 8.3.0+ | ⚠️ 可升级 |
| OkHttp | 4.10.0 | 4.12.0 | ✅ 较新 |
| Material | 1.9.0 | 1.11.0 | ⚠️ 可升级 |
| Spongy Castle | 1.56.0.0 | - | ❌ 已废弃 |
4.3 废弃/风险库
| 库 | 问题 | 建议 |
|---|---|---|
spongycastle | Android 5.0 后已废弃 | 迁移至 BouncyCastle |
ButterKnife | 已停止维护 | 迁移至 ViewBinding |
AndroidAnnotations | 维护不活跃 | 移除,使用 Kotlin |
tiny-sign | 签名有问题(README提到) | 迁移至 apksigner |
4.4 依赖冲突风险
// build.gradle.kts 中的强制版本控制
configurations.all {
exclude(group = "org.jetbrains", module = "annotations-java5")
exclude(group = "com.github.atlassian.commonmark-java", module = "commonmark")
resolutionStrategy {
force("com.google.code.findbugs:jsr305:3.0.1")
}
}五、性能与安全
5.1 内存泄漏风险
flowchart TD
subgraph MemoryLeaks["内存泄漏风险点"]
L1["🔴 未注销的监听器
Events.java"] L2["🔴 Handler泄漏
无Looper指定"] L3["🟡 Bitmap未回收
Drawables.java"] L4["🟡 静态Context引用
ScriptRuntime.java"] L5["🟡 OrientationEventListener
未disable"] end L1 --> |"addListener()无对应remove"| Leak1["Activity泄漏"] L2 --> |"消息未清理"| Leak2["Handler泄漏"] L3 --> |"大图片堆积"| Leak3["OOM"]
Events.java"] L2["🔴 Handler泄漏
无Looper指定"] L3["🟡 Bitmap未回收
Drawables.java"] L4["🟡 静态Context引用
ScriptRuntime.java"] L5["🟡 OrientationEventListener
未disable"] end L1 --> |"addListener()无对应remove"| Leak1["Activity泄漏"] L2 --> |"消息未清理"| Leak2["Handler泄漏"] L3 --> |"大图片堆积"| Leak3["OOM"]
具体问题代码:
// Events.java - 监听器添加但从未移除
public void observeKey() {
service.getOnKeyObserver().addListener(this); // ❌ 无对应的 removeListener
}
public void observeTouch() {
mTouchObserver.setOnTouchEventListener(this); // ❌ 无清理
mTouchObserver.observe();
}5.2 主线程阻塞风险
| 位置 | 问题 | 严重程度 |
|---|---|---|
HttpUtil.java | 同步HTTP请求 | 🔴 高 |
Drawables.java | 网络图片加载 | 🟡 中 |
FeatureActivity.java | WebView加载HTTP | 🟡 中 |
// HttpUtil.java - 主线程网络请求
public static String doPost(String posturl) {
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setReadTimeout(5000); // 可能阻塞5秒
urlConnection.setConnectTimeout(5000);
urlConnection.connect(); // ❌ 同步阻塞
// ...
}5.3 ProGuard/R8 混淆配置
严重问题:Release 版本未启用混淆!
// app/build.gradle.kts
named("release") {
isShrinkResources = false
isMinifyEnabled = false // ❌ 生产环境未混淆!
}过度宽泛的 keep 规则:
# proguard-rules.pro - 整个包都被保留
-keep class org.mozilla.javascript.** { *; }
-keep class com.stardust.automator.** { *; }
-keep class com.stardust.autojs.** { *; }5.4 网络安全问题
flowchart LR
subgraph SecurityIssues["安全问题"]
S1["❌ 硬编码HTTP URL"]
S2["❌ 无 network_security_config"]
S3["❌ WebView JS桥接漏洞"]
S4["⚠️ SharedPreferences未加密"]
end
S1 --> Risk1["中间人攻击"]
S2 --> Risk2["明文传输"]
S3 --> Risk3["XSS/注入"]
S4 --> Risk4["数据泄露"]
具体问题:
// FeatureActivity.java - 硬编码HTTP
private String url = "http://mk.autoxjs.com/pages/ykapp/choiseFeature"; // ❌ HTTP
// WebView 安全配置不足
settings.setJavaScriptEnabled(true);
settings.setJavaScriptCanOpenWindowsAutomatically(true); // ❌ 风险5.5 安全问题汇总
| 问题类型 | 严重程度 | 位置 | 建议 |
|---|---|---|---|
| HTTP明文传输 | 🔴 高 | FeatureActivity.java | 强制HTTPS |
| 未配置网络安全 | 🔴 高 | 缺少配置文件 | 添加 network_security_config.xml |
| WebView漏洞 | 🟡 中 | FeatureActivity.java | 添加URL白名单验证 |
| 数据未加密 | 🟡 中 | SharedPreferences | 使用 EncryptedSharedPreferences |
| Release未混淆 | 🔴 高 | build.gradle.kts | 启用 R8 混淆 |
六、改进建议
6.1 架构优化建议
flowchart TB
subgraph Current["当前状态"]
C1["混合MVC/MVVM"]
C2["手动DI"]
C3["RxJava + Coroutines混用"]
C4["View + Compose混用"]
end
subgraph Target["目标状态"]
T1["统一MVVM/MVI"]
T2["Hilt依赖注入"]
T3["纯Coroutines + Flow"]
T4["纯Compose UI"]
end
C1 -->|重构| T1
C2 -->|引入| T2
C3 -->|迁移| T3
C4 -->|迁移| T4
6.2 技术债务清单
| 优先级 | 债务项 | 工作量 | 影响范围 |
|---|---|---|---|
| P0 | 启用Release混淆 | 小 | 安全 |
| P0 | 修复内存泄漏 | 中 | 稳定性 |
| P1 | HTTP→HTTPS | 小 | 安全 |
| P1 | 添加网络安全配置 | 小 | 安全 |
| P2 | 提升测试覆盖率 | 大 | 质量 |
| P2 | 清理过时TODO | 小 | 可维护性 |
| P3 | 拆分大型类 | 大 | 可维护性 |
| P3 | 统一异步方案 | 中 | 一致性 |
6.3 迁移建议
Java → Kotlin 迁移路径
gantt
title Java到Kotlin迁移计划
dateFormat X
axisFormat %s
section 第一阶段
工具类迁移 :a1, 0, 1
数据模型迁移 :a2, 1, 2
section 第二阶段
Service层迁移 :b1, 2, 3
Repository层迁移 :b2, 3, 4
section 第三阶段
ViewModel迁移 :c1, 4, 5
UI层迁移 :c2, 5, 6
View → Compose 迁移策略
- 新功能优先使用 Compose
- 逐步迁移简单页面 (Settings, About)
- 复杂页面保持 View (Editor, Explorer)
- 建立 Compose 组件库
6.4 优先级排序的重构计划
timeline
title 重构优先级时间线
section 紧急 (立即)
启用 R8 混淆 : 安全关键
修复监听器泄漏 : 稳定性关键
HTTPS 迁移 : 安全关键
section 高优先级
引入 Hilt DI : 架构改进
统一 Coroutines : 代码一致性
增加单元测试 : 质量保障
section 中优先级
拆分大型类 : 可维护性
移除废弃库 : 技术债务
Kotlin 迁移 : 现代化
section 低优先级
全面 Compose 化 : UI现代化
文档完善 : 可维护性
七、总结
AutoX 是一个功能强大的 Android 自动化框架,其核心 Rhino JavaScript 引擎和丰富的 API 设计体现了较高的工程水平。然而,作为一个社区维护的开源项目,它也面临着一些典型的技术债务问题:
优势:
- 模块化设计清晰,职责分离合理
- 多 OCR 引擎支持(Tesseract、MLKit、PaddleOCR)
- 正在积极向现代架构迁移(Compose、Coroutines)
待改进:
- 测试覆盖率极低(0.65%)
- 安全配置缺失(HTTP、未混淆)
- 存在内存泄漏风险
- Java/Kotlin、RxJava/Coroutines 混用增加维护成本
对于想要基于此项目进行二次开发的开发者,我建议优先解决 P0 级别的安全和稳定性问题,然后逐步进行架构现代化改造。
本文基于 AutoX v6.6.8 版本源码分析