移动端自动化:Appium 在 Android 自动化中的落地经验

前面几篇我一直在强调,移动端自动化不要一上来就把全部希望压在 UI 框架上,而应该先把 ADB、设备控制、日志采集、证据留存、并发治理这些基础能力打好。

但这并不意味着 Appium 不重要。

相反,在 Android 自动化里,只要你的目标是验证:

  • 页面元素是否出现
  • 用户真实操作路径是否可走通
  • 核心业务流程的 UI 回归是否稳定
  • 跨页面、跨控件交互是否符合预期

Appium 依然是一条非常现实、非常常用的方案。

问题在于,对 Appium 的理解停在两个极端:

  • 一种是把它当万能框架,什么都想让它测
  • 另一种是跑了几次不稳定后,就直接得出“Appium 不适合落地”

这两个结论都不够准确。

所以这篇文章我想讲的是:

Appium 在 Android 自动化里到底该怎么落地,才能真正服务项目,而不是沦为一套 demo 级脚本。

一、Appium 适合什么,不适合什么,必须先说清楚

的 Appium 项目之所以后面越来越痛苦,第一步就错了:适用边界没定义。

如果边界不清楚,最后就会出现两类问题:

  • 简单问题被过度框架化
  • 不适合 UI 自动化的问题也被硬塞给 Appium

更倾向把 Appium 的适用场景限定在下面几类。

1. 核心业务主链路回归

比如:

  • 登录
  • 下单
  • 支付确认
  • 提交工单
  • 关键审批流

这类流程的特点是:

  • 真实用户会反复走
  • 一旦出问题,业务影响大
  • 单纯接口自动化无法覆盖完整交互链路

2. 关键页面 UI 冒烟

比如:

  • 首页是否能正常加载
  • 核心入口是否可点击
  • 重要页面是否出现空白或闪退

这类场景不需要覆盖得很深,但适合用 Appium 做“页面还活着”的快速校验。

3. 需要真实交互驱动的问题

比如:

  • 输入框、下拉框、弹窗交互
  • 页面跳转和返回链路
  • WebView 与 Native 混合页面切换
  • 手势触发的关键交互

这类问题如果只靠 ADB 或接口自动化,覆盖不到真正的用户行为。

但 Appium 也有明确不适合的地方。

4. 不适合全量铺开的业务回归

如果一个业务流程包含大量动态内容、频繁改版、控件不稳定,而你又希望把它全量自动化,Appium 的维护成本会迅速失控。

5. 不适合替代接口验证和底层状态验证

比如:

  • 接口字段断言
  • 数据落库校验
  • 服务端业务规则验证

这类事情应该交给接口自动化或后端验证层,不应该让 UI 自动化硬扛。

6. 不适合承载所有环境异常排查

一看到 Appium 失败,就先从 locator 或控件问题猜起。
实际上相当一部分失败来自:

  • 设备不稳
  • 页面加载慢
  • 权限弹窗挡住
  • 网络环境问题
  • 测试账号状态脏

这些问题本质上不属于 Appium 框架本身,但会直接表现成“元素找不到”。

二、Appium 项目最怕的,不是起不来,而是“起得来但越跑越脆”

第一次接触 Appium 时,几天内就能把 demo 跑通:

  • 安装 Appium Server
  • 连设备
  • 启应用
  • 定位元素
  • 点几下按钮

但真正的难点从来不在这里。
真正难的是:为什么三周以后,这套脚本开始越来越慢、越来越脆、越来越难维护。

我见过最常见的几个原因。

1. 用例粒度太细,维护量爆炸

如果完全照着手工用例去拆,就很容易把每个页面、每个按钮、每个文案都写成独立 UI case。
这样短期看覆盖率很高,长期看则几乎不可维护。

因为 Appium 的稳定性成本天然高于接口自动化,你不应该用它去堆数量,而应该用它去守住关键链路。

2. 页面对象抽象做得太机械

一上来就套标准 Page Object,但最后演化成:

  • 页面对象很厚
  • 业务逻辑和页面定位混在一起
  • 等待逻辑散落到各个方法里

结果是改一个页面,不只要改 locator,还要顺着页面类一路修逻辑。

3. 把等待问题理解成“多加几个 sleep”

这是 Appium 项目失控最快的路径之一。
一开始脚本不稳,就有人加 sleep(2);再不稳,再加 sleep(5);最后所有 case 都在等。

结果通常是:

  • 执行越来越慢
  • 依然不稳
  • 真正的性能问题被 sleep 掩盖掉

4. 设备和环境问题没有被隔离出框架层

如果脚本层直接面对:

  • 权限弹窗
  • 设备解锁
  • 应用重装
  • 崩溃留证
  • 设备回收

那用例层会非常脏。
以为自己是在写 UI 自动化,其实是在用 test case 充当设备治理脚本。

三、更推荐的 Appium 落地方式:让它只负责 UI 交互,不负责一切

如果要从头搭一套 Android Appium 自动化,不适合让 Appium 承担全部职责。

更倾向把整套能力拆成三层。

1. 设备与环境层

职责:

  • 设备连通性检查
  • 安装、卸载、清数据
  • 权限处理
  • 截图、录屏、日志采集
  • 失败恢复

这一层更适合由 ADB 能力和设备管理层负责。

2. 驱动与页面交互层

职责:

  • 创建和销毁 Appium session
  • 元素定位
  • 页面动作封装
  • 基础等待机制

这一层才是 Appium 最擅长的部分。

3. 业务场景编排层

职责:

  • 组织业务流程
  • 调用页面动作
  • 做断言
  • 与接口、数据库或 mock 能力联动

这样做的最大好处是:

  • Appium 只做自己擅长的 UI 驱动
  • 设备治理不会污染用例
  • 场景逻辑不会直接绑死在页面对象上

如果三层不拆,后面任何一个问题都会让代码越来越缠。

四、元素定位策略决定了 Appium 项目 60% 以上的稳定性

很多 Appium 项目后期维护成本高,本质上不是框架选型问题,而是定位策略从一开始就不稳。

定位优先级通常可以先定成下面这样:

1. 优先使用稳定业务标识

如果应用支持明确的资源 ID、测试专用标识或稳定 accessibility 标识,这是最优解。

原因很简单:

  • 可读性好
  • 变化可控
  • 不容易被布局调整误伤

2. 谨慎使用文本定位

文本定位不是不能用,但非常容易受这些因素影响:

  • 文案调整
  • 多语言
  • A/B 实验
  • 动态文案拼接

它适合做辅助,不适合做大规模主定位方式。

3. 尽量少用长链路 XPath

这是最典型的“能跑,但后面会持续还债”的定位方式。
页面结构稍微一改,整条 XPath 就可能失效。

XPath 不是完全禁用,但应该只在确实没有更好锚点时谨慎使用。

4. 定位失败信息要足够可诊断

如果元素找不到时,框架只抛一句 NoSuchElementException,排查价值很低。
更有价值的做法是同时输出:

  • 当前页面标识
  • 定位器信息
  • 当前截图
  • 失败前等待时长
  • 必要时输出页面层级快照

这样才能快速判断到底是页面没到、定位不稳,还是环境问题。

五、等待机制需要单独设计,不能把稳定性押给 sleep

Appium 在真实业务里的很多脆弱性,表面上看是“定位不到”,本质上其实是等待机制设计不合理。

更倾向把等待分成三类。

1. 页面级等待

比如:

  • 页面主元素出现
  • 页面 loading 消失
  • 关键区域可交互

这类等待用来确认“页面已经可测”。

2. 动作后等待

比如:

  • 点击提交后等待结果页出现
  • 切换 tab 后等待内容区域刷新
  • 提交表单后等待 toast 或提示框出现

这类等待要和具体动作绑定,而不是散落在 case 里。

3. 条件失败后的补充诊断

如果等待超时,不应该只返回失败,而应该补充:

  • 截图
  • 当前 Activity
  • 页面层级
  • 关键日志窗口

这样等待机制本身也能成为排障入口。

六、Appium 落地时,最该控制的是 case 数量,不是驱动能力

这是 容易反直觉的一点。
他们往往会先追求“支持更多动作、更复杂手势、更全的页面能力”,但真正更关键的是:不要让 Appium case 膨胀失控。

更倾向的策略是:

  • 用 Appium 守核心链路
  • 用接口自动化守业务规则
  • 用 ADB 和日志能力守环境和证据
  • 用人工探索补复杂体验问题

这样 Appium 的价值会更清晰。

如果把所有验证都压到 Appium 上,短期像是在提高自动化覆盖,长期其实是在堆维护债。

七、我在 Android Appium 落地里踩过的几个典型坑

坑 1:脚本失败看起来像元素问题,实际是设备问题

现象:

  • 元素找不到
  • 点击无响应
  • session 偶发中断

最后查下来往往是:

  • 设备锁屏了
  • 权限弹窗挡住了页面
  • 应用实际已经闪退
  • 设备连接状态不稳

如果没有把设备健康检查和失败留证做好,这类问题很容易被误判成 locator 不稳定。

坑 2:页面对象越来越厚,最后没人敢改

现象:

  • 一个页面类几百行甚至上千行
  • 定位、动作、断言、业务流程全写在一起
  • 改一个控件可能影响多条链路

这类问题本质上是抽象层次没控住。
页面层应该主要关注“页面如何交互”,不应该背太多业务编排逻辑。

坑 3:为了稳,疯狂加 sleep,最后把问题藏起来

这类问题非常普遍。
表面上看用例通过率提高了,实际发生的是:

  • 脚本变慢
  • 随机问题还在
  • 真正的加载瓶颈被掩盖

最后你得到的是一套“看起来稳定、实际信息量很低”的自动化。

坑 4:把 Appium 当成跨端统一答案

Appium 的优势之一确实是跨端思路相对统一,但这不等于 Android 和 iOS 可以用完全一样的落地策略。

例如:

  • 控件树差异
  • 权限模型差异
  • WebView 行为差异
  • 系统弹窗处理差异

如果一开始就强行要求“一套脚本思路覆盖两端”,往往会把 Android 端本可以做得很稳的能力也拖复杂。

八、如果要把 Appium 接进团队体系,更看重哪些能力

如果一个团队准备长期维护 Android Appium 自动化,更看重的不是“有没有写出几十个 case”,而是下面几件事有没有补齐。

1. 失败时有没有高质量证据

至少包括:

  • 截图
  • 日志
  • 当前 Activity
  • 设备信息
  • 失败步骤上下文

2. 有没有把设备治理从 case 里抽出去

如果每个 case 都在自己处理:

  • 解锁
  • 权限弹窗
  • 安装应用
  • 清理环境

那这套自动化很快就会失控。

3. 有没有稳定的定位规范和等待规范

没有这两套规范,脚本数量一多就会出现明显风格漂移,不同人写出来的 case 稳定性差异会非常大。

4. 有没有明确的用例选择标准

Appium 最怕的不是数量少,而是数量太多却没有重点。
如果团队不能说明“为什么这条链路值得 UI 自动化”,那很可能不该写。

九、排查 Appium 问题时,可以按什么顺序看

一看到 Appium 报错就先去看 locator,是很常见的反应。
但更倾向按下面顺序排查。

1. 先看设备和应用是不是还活着

确认:

  • 设备是否在线
  • 应用是否在前台
  • 是否有 crash 或权限弹窗

2. 再看页面是不是到了预期状态

确认:

  • 页面主元素是否出现
  • loading 是否结束
  • 页面切换是否真的完成

3. 再看定位策略本身是否稳定

确认:

  • 是否用了脆弱 XPath
  • 文本是否动态变化
  • 定位器是否过于依赖布局层级

4. 最后才看 case 逻辑

因为很多所谓“case 逻辑错”,前面三步已经能发现其实是环境问题、页面状态问题,或者等待机制问题。

结语

Appium 在 Android 自动化里并不是没用,也不是万能。
它真正有价值的前提是:你把它放在合适的位置上。

更关键的是一套真正能落地的 Android Appium 自动化,至少要做到:

  • 只覆盖值得做 UI 自动化的关键链路
  • 让 Appium 专注于页面交互,不背设备治理的锅
  • 有稳定的定位和等待策略
  • 失败时有足够强的证据链支撑排障
  • 和 ADB、日志、设备管理能力形成协同,而不是互相替代

如果这些基础都没打好,Appium 很容易从“提高回归效率的工具”变成“持续制造维护成本的系统”;
但如果边界清楚、分层清楚、治理到位,它依然是 Android 自动化里非常实用的一环。