speed_tools
Introduction: 敏捷开发工具包
Tags:
目标:让你不看 demo 工程也能从 0 到 1 接入并跑通。
说明:本项目当前推荐 源码依赖接入,不再推荐旧坐标implementation 'com.liyihangjson:speed_tools:1.1.1'。
变更说明(2026-05-18):本版 README 已按“可独立使用手册”重新整理,可直接用于接入,不依赖 demo 工程阅读。
目录
- 1. 框架概览
- 2. 能力边界与适用场景
- 3. 模块说明
- 4. 快速开始(10 分钟跑通)
- 5. 插件化接入手册(完整)
- 6. 换肤与字体切换手册(完整)
- 7. 常见问题与排障手册
- 8. 生产落地建议
- 9. API 速查
- 10. 版本与兼容说明
1. 框架概览
Speed Tools 是一套基于代理模式的 Android 本地插件化方案,主要能力:
- 宿主动态加载插件 APK(插件无需安装);
- 宿主代理跳转插件页面;
- 运行时主题切换(换肤);
- 运行时字体大小切换。
核心思路:
- 插件 APK 放在宿主
assets(或你自定义来源); - 运行时拷贝到宿主私有目录;
- 使用 DexClassLoader + 资源桥接完成类与资源加载;
- 通过统一代理接口转发生命周期。
2. 能力边界与适用场景
2.1 适用场景
- 多业务模块独立演进,希望按插件方式解耦;
- 需要“不安装皮肤包”的动态换肤;
- 需要低侵入接入现有宿主工程。
2.2 不适用场景
- 对 Google Play 动态交付有强依赖(建议评估 PAD/Feature Module);
- 对严格安全审计要求极高但没有签名校验链路;
- 需要跨进程插件隔离(当前不是隔离进程架构)。
3. 模块说明
| 模块 | 类型 | 作用 |
|---|---|---|
lib_speed_tools |
Library | 核心能力(插件加载、代理、换肤、字体) |
module_host_main |
App | 宿主示例(加载并启动插件) |
module_client_one |
App | 插件示例 1 |
module_client_two |
App | 插件示例 2 |
theme_dome |
App | 换肤与字体切换示例 |
black_theme |
App | 皮肤包示例 |
lib_img_utils |
Library | 第三方库测试模块 |
4. 快速开始(10 分钟跑通)
你可以先按这个最短路径确认“框架可用”,再看后续完整手册。
步骤 1:引入核心库
在你的工程 settings.gradle:
include ':lib_speed_tools'
在宿主 app/build.gradle:
dependencies {
implementation project(':lib_speed_tools')
}
步骤 2:准备插件 APK
把插件 APK 放到宿主 src/main/assets/,例如:
module_client_one-debug.apkmodule_client_two-debug.apk
步骤 3:宿主启动时加载插件
File apk = SpeedUtils.getNativeApkPath(getApplicationContext(), "module_client_one-debug.apk");
if (apk != null) {
SpeedApkManager.getInstance().loadApk("first_apk", apk.getAbsolutePath(), "dex_output2", this);
}
步骤 4:点击按钮跳转插件
SpeedUtils.goActivity(this, "first_apk", null);
到这里你已完成最小可运行链路。
5. 插件化接入手册(完整)
5.1 总体流程图(文字版)
- 宿主准备插件 APK(assets/下载);
- 宿主将 APK 拷贝到私有目录;
- 宿主调用
SpeedApkManager.loadApk(...); - 代理层创建插件实例并建立资源上下文;
- 宿主通过
SpeedUtils.goActivity(...)进入插件; - 生命周期由代理 Activity 转发给插件实现类。
5.2 宿主工程接入要求
必须项
- 宿主依赖
lib_speed_tools; - 有一个用于承载插件页面的 Activity(建议继承库中的宿主基类);
- 有稳定的插件 key 命名策略(不可重复);
- 插件加载路径可访问且可读。
推荐项
- 插件 key 按业务域命名:
biz_order_v1; - 每个插件独立
dexOutPath; - 对加载失败进行 UI 提示 + 结构化日志记录。
5.3 插件 APK 准备规范
文件名规范
- 允许自定义,但必须与加载代码一致;
- 推荐格式:
{pluginId}-{buildType}.apk。
放置方式
- 开发调试:放
assets/; - 生产建议:下载到私有目录后再加载(并做签名/哈希校验)。
5.4 宿主加载实现(建议模板)
private void loadPlugin(String key, String assetApkName, String dexOutPath) {
File pluginApk = SpeedUtils.getNativeApkPath(getApplicationContext(), assetApkName);
if (pluginApk == null) {
// 1) 用户可见提示
// 2) 技术日志:key、assetApkName、phase=copy
return;
}
SpeedApkManager.getInstance().loadApk(key, pluginApk.getAbsolutePath(), dexOutPath, this);
}
5.5 页面跳转与入口策略
SpeedUtils.goActivity(this, "first_apk", null);
参数说明:
- 参数 1:Context;
- 参数 2:插件 key(加载时同名);
- 参数 3:类标识(可空,空时走默认入口)。
建议:
- 对外统一封装一层 Router,不要在业务层散落 key 字符串;
- key 与版本绑定,避免“同 key 不同包”导致错配。
5.6 插件实现规范(建议)
建议目录结构:
PluginMainActivity:页面壳PluginEntry:插件入口逻辑(供代理调用)res/:插件资源
建议编码规范:
- 不要在入口实现里做重 I/O(避免阻塞首帧);
- 插件内部资源访问统一封装;
- 对可失败流程(网络、文件)给降级方案。
5.7 生命周期与线程建议
- 插件加载在后台线程执行;
- UI 更新必须切回主线程;
- Activity 销毁时及时取消加载任务。
5.8 安全建议(强烈推荐)
- 校验插件 APK 的签名或 SHA-256;
- 校验插件版本与宿主兼容范围;
- 禁止加载未知来源 APK;
- 对加载异常做埋点告警。
6. 换肤与字体切换手册(完整)
本章节可直接用于业务项目接入,不依赖 demo 阅读。
6.1 核心对象
SPThemeManager:主题管理(切换/刷新)SPFontManager:字体大小管理SPUpdateUIListener:刷新回调接口
6.2 初始化(Application)
在自定义 Application 中尽早执行:
@Override
public void onCreate() {
super.onCreate();
SPFontManager.getInstance().init(this);
SPThemeManager.getInstance().init(this);
}
注意:如果未初始化,后续换肤/字体 API 不生效。
6.3 Activity 基类接入
创建业务基类 BaseActivity 并注册监听:
public class BaseActivity extends AppCompatActivity implements SPUpdateUIListener {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
SPThemeManager.getInstance().registerUpdateUI(this);
super.onCreate(savedInstanceState);
}
@Override
protected void onDestroy() {
SPThemeManager.getInstance().unRegisterUpdateUI(this);
super.onDestroy();
}
@Override
public void updateUI(boolean isFistLoading) {
// 在这里处理局部刷新(如自定义控件状态)
}
}
6.4 资源命名规则(必须遵守)
- 颜色/背景/图片等换肤资源前缀:
cxt_ - 字体维度资源前缀:
cxf_
示例:
@color/cxt_test@mipmap/cxt_server@dimen/cxf_normal
规则要点:
- 主工程与皮肤包资源名必须一致;
- 值可以不同(这正是换肤本质)。
6.5 主工程资源准备
确保主工程包含可替换资源:
colors.xml:定义cxt_*dimens.xml:定义cxf_*mipmap/drawable:放置cxt_*对应图片
布局中按普通资源引用:
android:background="@color/cxt_test"
android:textSize="@dimen/cxf_normal"
android:src="@mipmap/cxt_server"
6.6 皮肤包工程准备(black_theme 同理)
皮肤包必须包含同名资源:
cxt_testcxt_servercxf_normal
并打包生成 black_theme-debug.apk(或你自定义命名)。
6.7 放置皮肤 APK
调试方式:把皮肤 APK 放入主题宿主工程 assets/。
生产方式:下载到本地目录并校验后加载。
6.8 触发换肤与恢复默认
SPThemeManager.getInstance().changeTheme("black_theme-debug.apk").sendUpdateUIAction();
SPThemeManager.getInstance().changeTheme(SPThemeManager.DEFAULT_THEMES).sendUpdateUIAction();
- 第一行:切换到皮肤包;
- 第二行:恢复默认主题。
6.9 触发字体大小调整
SPFontManager.getInstance().changeConfig(40).updateUI(); // 放大
SPFontManager.getInstance().changeConfig(0).updateUI(); // 恢复
建议:
- 将字号档位做枚举/配置化(小/中/大),避免魔法值;
- 字号变化后同步持久化用户设置。
6.10 换肤模块排障(逐条检查)
- Application 是否已初始化 Theme/Font Manager;
- Activity 是否 register/unregister 监听;
- 皮肤 APK 文件名是否与
changeTheme(...)一致; - 资源名是否完全一致(包括前缀和大小写);
- 是否调用
sendUpdateUIAction()主动触发刷新。
7. 常见问题与排障手册
7.1 插件加载失败
现象:按钮可见但点击无跳转 / 提示加载失败。
排查:
- assets 文件是否存在;
- 插件 key 是否一致;
- dexOutPath 是否可写;
- 日志里是否有 ClassNotFound。
7.2 页面空白或崩溃
现象:进入插件后白屏/崩溃。
排查:
- 入口类声明是否正确;
- 插件资源是否齐全;
- 插件与宿主接口版本是否一致。
7.3 换肤无效果
现象:点击“切换主题”无变化。
排查:
- 是否正确调用
sendUpdateUIAction(); - 资源名是否满足
cxt_规则; - 皮肤包是否放到了可访问路径。
7.4 字体未变化
现象:调用 changeConfig 后无变化。
排查:
- 布局是否使用了
@dimen/cxf_*; - 页面是否实现并注册了更新监听;
- 是否调用
updateUI()。
8. 生产落地建议
- 增加插件签名校验与白名单;
- 加入插件版本兼容矩阵(hostMin/hostMax);
- 加入加载失败重试与回滚策略;
- 建立 CI:
assembleDebug + lint + unitTest; - 逐步迁移 AndroidX 与新 AGP。
9. API 速查
插件相关
SpeedApkManager.getInstance().loadApk(key, apkPath, dexOutPath, context):加载插件SpeedApkManager.getInstance().getHelper(key):获取已加载插件 helperSpeedUtils.getNativeApkPath(context, assetName):从 assets 拷贝插件到私有目录SpeedUtils.goActivity(activity, key, classTag):跳转插件页面
主题/字体相关
SPThemeManager.getInstance().init(context):初始化主题系统SPThemeManager.getInstance().changeTheme(apkName).sendUpdateUIAction():切换主题并刷新SPFontManager.getInstance().init(context):初始化字体系统SPFontManager.getInstance().changeConfig(size).updateUI():变更字号并刷新
10. 版本与兼容说明
- 当前仓库示例构建基线:Android Support +
compileSdkVersion 28; - 文档以当前仓库代码为准;
- 旧文档
THEME_MANAGER.md作为历史参考,存在冲突时以本 README 为准。
附:相关文档
PROJECT_OPTIMIZATION_REPORT.md:项目早期优化路线THEME_MANAGER.md:历史主题文档
