自定义编译器
自定义编译器用于把业务专用的生成、转换或校验逻辑插入 Jugg 增量编译链路。它适合团队内部已有特殊编译步骤,但又不希望每次都回退完整 Gradle 的场景。
使用前提
自定义编译器适合补充 Jugg 增量编译链路中的工程专用前后处理,例如:
- 编译前消费特定文件,并阻止后续内置编译器重复处理。
- 资源、源码或 dex 阶段前后执行业务生成逻辑。
- 把已有自研转换工具接入 Jugg 增量链路。
- 对编译产物执行校验或补充产物输出。
它有明确边界:
- 替代 Gradle plugin 的完整生命周期。
- 接管安装、启动、热重载或部署状态提交。
- 执行需要长时间阻塞 IDE 的任务。
- 依赖人工 UI 交互才能完成的编译逻辑。
接入方式
自定义编译器以 jar 形式提供,并通过 SPI 暴露入口:
text
自定义 jar
-> META-INF/services/com.sickworm.intellij.jugg.compiler.custom.ICompilerCreator
-> ICompilerCreator.create(...)
-> 返回 ICompiler
-> 根据 CompileOrder 插入 Jugg 编译阶段jar 可以来自:
- 本地绝对路径。
- 相对工程目录的路径。
- HTTP / HTTPS 远端地址。
配置中需要包含 jar 文件名、路径和 md5。Jugg 会校验 md5;本地已有 jar 或远端下载 jar 不匹配时,不会作为有效自定义编译器使用。
本地项目配置
不通过后台下发时,可以在项目中维护以下文件:
text
build/jugg/config/
custom_config.json
custom_compilers/
example.jar将自定义编译器声明合并到 build/jugg/config/custom_config.json 的现有配置中:
json
{
"customCompilers": [
{
"jarFileName": "example.jar",
"path": "build/jugg/config/custom_compilers/example.jar",
"md5": "<example.jar 的 md5>"
}
]
}path 相对于项目根目录,也可以填写本地绝对路径。只把 jar 放入 custom_compilers 目录不会自动加载,仍需在 custom_config.json 中声明。保存配置后,下一次通过 Jugg Run 编译时会重新读取配置。
执行顺序
自定义编译器通过 CompileOrder 选择插入点:
| 插入点 | 常见用途 |
|---|---|
atFirst / atLast | 整轮编译前后 |
beforeAsset / afterAsset | assets 或 native lib 处理前后 |
beforeRes / afterRes | 资源、Manifest、R 相关处理前后 |
beforeSource / afterSource | Java/Kotlin/DataBinding mapper 处理前后 |
beforeMinify / afterMinify | release 混淆阶段前后 |
beforeDex / afterDex | DEX 生成前后 |
before hook 可以通过消费输入文件影响后续内置编译;after hook 主要处理内置编译产物。
使用建议
- 让自定义编译器只处理明确文件类型或明确模块,避免每轮扫描全工程。
- 失败时给出用户可读错误,避免只抛异常。
- 选择最窄的
CompileOrder区间,减少对其它阶段的影响。 - 不要打包与 Jugg API 冲突的依赖版本。
- 远端 jar 更新后,下一轮编译才一定会重新加载新实例。
常见问题
| 现象 | 处理方式 |
|---|---|
| jar 配置后不生效 | 检查路径、md5,以及本地 custom_config.json 或后台配置是否已生效 |
| 远端 jar 下载成功但本轮没执行 | 再触发一轮编译,确认懒加载缓存已刷新 |
ServiceLoader 找不到实现 | 检查 META-INF/services/...ICompilerCreator |
| 执行阶段不对 | 检查 ICompiler.order 是否落在目标阶段区间内 |
| 自定义编译器失败导致整轮失败 | 查看 compile_latest.log 中的 warn 和异常摘要 |