需求拆解
需求分析 沙盒环境 Jetpack Compose
深入分析沙盒环境约束条件,定义最小可行的 lint 工作流
用户目标
用户的核心诉求可归纳为:在沙盒环境中建立一个「零编译产出的 Kotlin 代码质量门禁」,支持 Jetpack Compose 框架的专项检测。
目标工作流
flowchart LR
A[编写代码] --> B{Lint 检查}
B -->|发现错误| C[修复代码]
C --> B
B -->|全部通过| D[提交代码]
style A fill:#e3f2fd
style D fill:#c8e6c9
style B fill:#fff3e0
这个循环需要满足三个硬性指标:
- 即时反馈:从保存文件到获得结果 < 3 秒
- 零编译依赖:不生成 APK/DEX/AAR 等任何构建产物
- Compose 感知:能够检测 Compose 特有的代码模式(如 remember、SideEffect 等)
约束条件量化
| 约束维度 | 沙盒限制 | 传统 Android Studio 环境 | 差距分析 |
|---|---|---|---|
| 内存上限 | 512MB - 2GB | 8GB - 16GB | 需降低 8-30 倍 |
| 磁盘空间 | 1GB - 5GB | 20GB+(含 SDK) | 需精简 80%+ |
| 网络访问 | 受限或离线 | 完整访问 | 无法动态下载依赖 |
| 启动时间 | < 5 秒 | 30-60 秒(Gradle Sync) | 需提速 6-12 倍 |
| 持久化 | 容器重启后重置 | 持久化缓存 | 需预置工具链 |
关键路径识别
要实现目标工作流,必须突破以下技术障碍:
障碍 1:Android Lint 的 Gradle 耦合
问题本质:Android Lint 并非设计为独立工具,其核心依赖 Android Gradle Plugin (AGP) 提供的 LintModel 和项目结构元数据。
证据数据:
- 直接调用
lintCLI 在 Gradle 项目上会报错:"myModule" is a Gradle project. To correctly analyze Gradle projects, you should run "gradlew :lint" instead. - Android Lint 需要解析
build.gradle文件获取依赖树、资源路径等元信息
影响评估:
- 严重阻塞:无法直接在沙盒中使用标准 Android Lint
- 替代需求:寻找不依赖 AGP 的静态分析方案
障碍 2:Jetpack Compose 的语义分析
问题本质:Compose 不是普通 Kotlin 库,其使用模式依赖 Kotlin 编译器插件生成的特殊 IR(Intermediate Representation)。
典型 Compose 模式:
// 需要检测的 Compose 特定模式
@Composable
fun MyScreen() {
// ❌ 错误:在 Composition 中直接调用非 @Composable 函数
val data = fetchData()
// ✅ 正确:使用 remember 缓存计算结果
val cachedData = remember { fetchData() }
// ❌ 错误:MutableState 赋值未使用委托
var count = mutableStateOf(0)
count.value++ // 正确,但 count++ 不会触发重组
}
现有工具支持度分析:
| 检测项 | ktlint | Detekt | Android Lint | 可行性 |
|---|---|---|---|---|
| 代码风格(缩进、命名) | ✅ 完整 | ✅ 完整 | ✅ 完整 | 高 |
| 复杂度(圈复杂度) | ❌ 不支持 | ✅ 内置 | ⚠️ 有限 | 高 |
@Composable 标注检查 | ❌ 不支持 | ⚠️ 需自定义 | ✅ 内置 | 中 |
remember 使用模式 | ❌ 不支持 | ⚠️ 需插件 | ✅ 内置 | 低 |
| State 委托规范 | ❌ 不支持 | ❌ 不支持 | ✅ 内置 | 低 |
障碍 3:类型解析的依赖困境
问题本质:高级静态分析(如空安全检测、API 弃用检查)需要类型解析(Type Resolution),这要求访问项目依赖的类路径(Classpath)。
依赖规模实测:
- 最小 Jetpack Compose 项目(单模块,基础依赖):
- Gradle 下载量:~150MB
- 解析后的 Classpath:~80MB
- 依赖项数量:~200 个
沙盒困境:
- 无法预先下载所有可能的依赖组合
- 离线环境下无法解析 Maven/Gradle 依赖
最小可行方案定义
基于上述障碍分析,定义沙盒环境的最小可行产品(MVP):
必须满足(Must Have)
- 纯源码级检查:不依赖编译产物或完整 Classpath
- 亚秒级响应:单文件分析时间 < 1 秒
- Compose 基础规则:覆盖最常见的 10 种 Compose 反模式
- 自动修复能力:80% 以上的风格问题可一键修复
应该支持(Should Have)
- 增量分析:仅检查变更文件,全项目扫描可在 5 秒内完成
- CI/CD 集成:支持 SARIF 标准输出格式
- 自定义规则:团队可扩展私有检查规则
可以延后(Could Have)
- 完整类型解析:需要依赖预下载或网络代理
- Android Lint 全规则:仅在资源允许时启用
- 实时 IDE 集成:通过 LSP 协议提供即时反馈
成功指标
定量指标
| 指标 | 目标值 | 测量方法 |
|---|---|---|
| 分析延迟(冷启动) | < 3 秒 | 从 CLI 调用到结果输出的时间 |
| 分析延迟(热启动) | < 0.5 秒 | 重复分析同一代码的耗时 |
| 内存占用峰值 | < 512MB | docker stats 监控 |
| 规则覆盖率 | > 70% | 与 Android Studio 默认规则的对比 |
| 误报率 | < 5% | 人工抽样检查结果 |
定性指标
- 开发者体验:lint 反馈的准确性、可读性、可操作性
- 集成复杂度:从现有 Android Studio 工作流迁移的难度
- 维护成本:规则更新、工具升级的投入工作量
技术选型约束
硬性排除项
以下方案因不满足沙盒约束而被排除:
- 完整 Gradle 构建:内存占用过高(>2GB),启动时间过长(>15s)
- Android Studio 远程模式:依赖 GUI 组件,无法在 headless 沙盒运行
- Kotlin Compiler Daemon:虽可复用进程,但仍需完整 Classpath
候选方案初筛
| 方案 | 原理 | 优势 | 劣势 | 沙盒适配性 |
|---|---|---|---|---|
| ktlint CLI | Kotlin AST 解析 | 单二进制、零依赖、极速 | 无类型解析、规则有限 | ⭐⭐⭐⭐⭐ |
| Detekt CLI | Kotlin PSI + 规则引擎 | 规则丰富、可扩展 | 需 JVM、内存占用中等 | ⭐⭐⭐⭐ |
| Qodana | JetBrains 代码分析云 | 规则全面 | 需网络、付费、非沙盒 | ⭐ |
| SonarQube | 多语言分析平台 | 生态成熟 | 需服务端、资源占用高 | ⭐⭐ |
本章节定义了沙盒 lint 方案的需求基线,后续章节将基于这些约束进行工具能力验证和方案设计。