第4章:动态交付——CI/CD与自动化测试在ANR治理中的应用
说实话,很多人觉得ANR治理就是出了问题时,拿个trace文件分析一下,改改代码。但我在几个大厂项目里待过之后,发现事情没那么简单。
你想想看,一个功能团队几十人,每天提交上百次代码。等用户反馈ANR再处理?黄花菜都凉了。所以我们必须把ANR治理往前移,移到代码还没合并、还没发布的时候就把它拦住。
这就引出了我们今天要聊的核心——动态交付。说白了,就是用持续集成(CI)、持续交付(CD)和自动化测试,打造一条ANR的“检测-预防-快速修复”流水线。
为什么动态交付能治ANR?
传统开发流程里,ANR往往等到提测甚至灰度后才暴露。修复成本高、周期长。而动态交付的核心是:
- 每一次代码提交都做质量门禁
- 每一次构建都自动执行ANR相关检查
- 每一次发布都有自动化测试兜底
我个人习惯把这条流水线叫做“ANR防火墙”。下面我们一个个拆开来看。
持续集成(CI)——把ANR扼杀在萌芽
CI要做的事很简单:代码一提交,服务器立刻拉下来编译、跑检查。在ANR治理方面,我们主要做三件事:
| 检查项 | 工具/方法 | 拦截目标 |
|---|---|---|
| 静态代码分析 | Android Lint + 自定义Detector | 在主线程做IO、网络请求等耗时操作 |
| 线程模型检查 | 自定义Gradle插件 | Handler使用不当、锁持有时间过长 |
| 依赖分析 | Dex分包、ProGuard R8规则 | 方法数超限导致编译卡顿(间接引发ANR) |
CI Pipeline示例(伪代码):
pipeline {
agent any
stages {
stage('Checkout') { /* 拉代码 */ }
stage('Lint') {
steps {
script {
// 如果检测到主线程耗时操作,直接失败
def result = sh(script: './gradlew lint', returnStatus: true)
if (result != 0) {
error("ANR风险代码被拦截,请修复后重新提交")
}
}
}
}
stage('Build') { /* 编译 */ }
stage('UnitTest') { /* 跑单测 */ }
}
}
持续交付(CD)——让ANR修复跑得更快
CD的核心是自动化部署。在ANR治理上,CD主要解决两个问题:
- 快速分发带修复的版本——发现ANR后,从提PR到灰度用户拿到修复包,时间从几天缩短到几小时。
- 自动化灰度监控——每次发版,CD管道自动开启ANR数据采集,对比基线。如果新版本ANR率超过阈值,自动触发回滚。
我见过一个项目,因为CD配上自动化回滚,硬生生把一次线上严重ANR事故从影响10万用户缩小到只有200人。嗯,这就是CD的魅力。
CD Pipeline关键步骤:
- CI通过后,CD自动构建Release包。
- 自动签名、混淆、对齐。
- 上传到内测分发平台(如蒲公英/自家平台)。
- 推送给灰度设备池,自动安装并跑Monkey+ANR监控。
- 如果ANR率 > 0.1%,CD自动打回,不进入全量发布。
自动化测试——用机器代替人肉排查
CI/CD管道里,测试是承上启下的关键。针对ANR,我们至少需要三类自动化测试:
| 测试类型 | 工具 | 检测内容 |
|---|---|---|
| UI自动化 | Espresso / UI Automator | 每步操作后检查UI线程是否响应超时 |
| 压力测试 | Monkey + blockcanary | 长时间随机操作,捕捉主线程卡顿超过5秒 |
| 专项ANR测试 | 自定义脚本 + 系统trace | 模拟低内存、磁盘IO满、网络慢等异常场景 |
说个具体的例子。我在做智能家居App时,发现某个页面在切换网络时ANR频发。普通Monkey很难复现。后来我们在测试脚本里加了模拟网络切换的步骤:
// 伪代码:在Espresso测试中模拟网络切换
@Rule
public ActivityScenarioRule<MainActivity> rule = ...;
@Test
public void testNetworkSwitchANR() {
// 1. 进入联网页面
onView(withId(R.id.btn_load_data)).perform(click());
// 2. 模拟网络断开
toggleWifi(false);
// 3. 等待2秒后恢复网络
SystemClock.sleep(2000);
toggleWifi(true);
// 4. 立即检查ANR
assertThat(device.isInCall(), is(false)); // 实际用更精细的ANR检测
}
把流水线串起来:一张图看清全貌
下面这张图汇总了CI/CD/自动化测试在ANR治理中的协作关系。建议你保存下来,画板子或者做汇报都能用上。
看懂这张图了吗?从左到右是流水线的主流程:代码提交 → CI检查 → 自动化测试 → CD发布 → 灰度监控。如果灰度ANR率超标,自动回滚;如果正常,才全量发布。最下面那条虚线的反馈回路,把线上数据带回到CI规则里,形成闭环。
落地踩过的坑
最后分享一个实际教训吧。我们曾经把CI里的Lint检查设得太严格,任何warnings都直接阻断构建。结果开发同学为了赶快合并代码,直接加 //noinspection 忽略所有警告。ANR检测形同虚设。
正确的做法是:
- 对高风险项(如主线程IO、锁死锁)设为error,不可忽略。
- 对中风险项(如handler泄漏)设为warning,不阻断构建,但记录在CI报告里,最终汇总到每周质量会议。
- 自动化测试的ANR监测结果,直接关联到CD的门禁,只有通过才能上线。