Appium自动化测试跑了半年,我几乎天天跟开发者强调一个事:脚本能不能稳定跑,八成取决于设备上那个默默无闻的Appium Settings应用。它不像测试用例那样显眼,也不像driver那样天天被提起,但一旦它出问题,你看到的不是splash页加载慢,而是session创建失败、动画关不掉、输入法切不过来、权限弹窗点不完。这篇文章就把Android环境里Appium Settings的部署、配置、授权、验证、排错讲透,给你一份能直接落地的操作手册。适合刚从Appium 1.x升级到2.x的测试开发,也适合在真机群控上反复踩坑的团队。
1. 环境准备:装对基础,才有后面的省心
1.1 基础依赖清单
在碰Appium Settings之前,先把底层环境梳理利索。这里说的底层环境,不是让你把整个CI系统都重新搭一遍,而是确认几件关键组件的版本和状态是匹配的。
- JDK:建议8或11,Appium 2.x加上UiAutomator2驱动对JDK版本的要求比较温和,但别用太新的JDK版本,某些发行版在Android工具链上会有兼容性隐患。
- Node.js:Appium 2.x以npm包形式分发,你通过npx appium启动服务,所以Node版本建议保持在18以上的LTS版本,老版本Node在依赖解析上容易出问题。
- Android SDK:platform-tools(里面是adb)、build-tools(里面有aapt等),这两个是Appium和Android设备通信的基础,缺一不可。
很多新手最容易忽略的就是platform-tools的版本。如果你的adb太老,而设备系统是较新的Android版本,一些高级命令执行会直接报错。反正我是吃过这个亏的,最开始用旧版platform-tools去操作一台高版本系统的设备,Appium Settings的授权命令怎么执行都是无响应,后来升级了platform-tools就好了。
另外提一个容易忽视的地方:Appium 2.x的驱动安装。即使你全局装了Appium,如果没装UiAutomator2驱动,会话依然是建不起来的。执行:
appium driver install uiautomator2装完之后,driver包里面会自带Appium Settings的APK文件。这一点很重要,后面手动安装时会用到。
1.2 Android SDK与设备连接
环境变量的配置听起来很基础,但确实有同事在这里栽过跟头。Appium服务端需要找到adb可执行文件,如果你在终端里配好了环境变量,但启动服务用的那个进程没有继承这些变量(比如通过脚本后台启动),就会出现“找不到adb”之类的问题。
配置建议:
export ANDROID_HOME=$HOME/Library/Android/sdk # macOS路径示例 export ANDROID_SDK_ROOT=$ANDROID_HOME export PATH=$PATH:$ANDROID_HOME/platform-tools:$ANDROID_HOME/tools注意,Windows上就是对应的setx或者在系统环境变量里加。配置完别急着跑脚本,先用一行命令验证设备是否在线:
adb devices -l正常情况下列表里会显示你的设备序列号,状态是device。如果你的设备是unauthorized状态,去设备上点一下允许USB调试的弹窗。事情虽然小,但你如果哪天发现Appium Settings无法安装,先回头看看这一步,大概率能省掉半小时的排查时间。
1.3 版本匹配的坑
版本匹配是整个环境准备里最隐蔽的坑。Appium 2.x之后,UiAutomator2驱动是独立打包的,每个驱动版本里携带的Appium Settings版本也不一样。你如果强行用一个旧版本的settings APK去适配新版驱动,在Android 13以上的设备上可能连启动都启动不了。
我一般在搭建新环境时,会检查一下驱动和Appium的版本对应关系:
appium driver list appium --version确保没有明显冲突。同时确认node_modules里确实存在settings APK文件(下面会讲路径)。版本不对,优先做法是更新驱动或Appium本体,而不是单独替换settings APK,因为你不知道新版本依赖了settings的哪个新接口。
2. Appium Settings是什么,为什么自动化离不开它
2.1 它在整个测试链路中的定位
Appium Settings不是被测应用,也不是测试框架本身,它是Appium在Android设备上安装的一个辅助性质的系统级应用,包名就叫io.appium.settings。
你可以把它理解成工地上的后勤保障组。真正干活的是UiAutomator2驱动和你的测试代码,但如果没有Settings在后台处理一批“需要系统权限才能完成”的杂活,整个工地的进度就卡住了。
具体到分工来看,UiAutomator2驱动负责与设备上的UiAutomator2服务通信,执行点击、滑动、获取控件树等操作。而Appium Settings负责的是另一类任务:修改系统动画缩放、切换输入法、管理权限、获取设备状态信息等。这些操作往往需要调用系统API,普通应用没有权限,Settings作为一个系统级辅助应用,才能拿到这类操作的入口。
所以,在整个测试链路里,它更像是一个“特权执行器”,帮你把测试环境和被测应用之间的状态调整到最干净。
2.2 核心功能的实际价值
我把Appium Settings提供的功能拆成几块,讲讲它都干了什么活:
动画设置。这是做自动化测试时必不可少的一环。系统动画不关闭,很多操作会因为等待动画完成而变得不稳定,查找元素的时候尤甚。Settings可以一键关闭窗口动画、过渡动画、Activity动画,让整个UI响应变成即时模式。
输入法切换。测试中要输入中文时,光有adb发送文本是不够的,需要切换到一个支持文本输入的输入法。Appium Settings可以配合Appium特有的输入法完成这项操作,避免在中文输入法上碰到键盘弹起遮挡、联想词干扰的问题。
权限管理。新安装的应用总会弹出各种权限请求,通知权限、定位权限、存储权限。自动化过程中遇到这类弹窗,脚本不一定能稳定处理。Settings可以在应用安装后自动授予或撤销权限,绕开弹窗。
网络状态控制。在飞行模式测试、弱网模拟等场景下,需要切换Wi-Fi、蓝牙、GPS、飞行模式的开关状态。Settings暴露的这些接口让脚本可以直接控制。
设备信息获取。比如当前设备是否处于低内存状态、是否有ANR或崩溃日志,Settings提供了一些获取这类信息的通道。
你在配置Appium会话时,可能注意到有些参数,比如skipUnlock、disableWindowAnimation,这些配置项的底层执行者就是Appium Settings。它不直接出现在你的测试代码里,但你配置的每一个这类参数,最终都是通过它来落地的。
2.3 新版Appium下的角色变化
Appium 2.x和1.x的最大区别在于驱动机制和模块化设计。Appium Settings依然存在,但不再由Appium主服务直接管理,而是跟随UiAutomator2驱动一起被分发到设备上。
这意味着什么?意味着你升级Appium或者升级驱动时,settings的版本也在变化。老旧的手动安装习惯在新版驱动下要特别注意。你手动装了一个旧版本的settings,新版驱动启动时会做一次版本检查,如果版本不对,可能直接重新安装,也可能直接报错。
我自己在维护测试池时,会对每台设备做一次核对,确保设备上settings的版本与CI上Appium的driver版本一一对应。不要在这个环节偷懒,因为版本不一致时出的问题非常诡异,有时候是某些功能失效,有时候是启动时卡在“安装Appium Settings”阶段。
3. 安装与部署:自动与手动两条路
3.1 自动安装机制与条件
大多数情况下,你不需要手动安装Appium Settings,因为Appium在创建会话时会自动检查设备上是否安装了它,以及版本是否正确。如果缺失或版本不匹配,它会自动安装。
这个自动安装的过程通常在session创建后的几个动作之间发生。不同版本的driver处理方式略有差异,但大致都是在启动UiAutomator2服务之前完成。你要留意的是,自动安装并不是永远可靠的。
实际运行中,自动安装失败常见于三种情况:
- 设备存储空间不足,APK无法写入。
- 设备锁屏状态下,安装流程被拦截。
- 某些厂商ROM对后台安装有严格限制,自动安装被系统拦截。
所以自动安装更像是一个便捷的默认行为,而不是保底方案,这一点要在团队里说清楚。
3.2 手动安装步骤
手动安装其实并不复杂,步骤完全可以标准化,我现在就用的这套。如果你不是通过npm全局安装的Appium,而是项目里的node_modules方式,找到APK文件的路径可能略有差异,但思路一致。
先定位APK文件。如果是npm安装的Appium 2.x版本,路径大概如下:
# UiAutomator2驱动目录下的settings APK node_modules/appium-uiautomator2-driver/node_modules/io.appium.settings/apks/settings_apk-debug.apk或者直接从Appium的GitHub仓库的release页面下载对应版本的Settings APK。
然后开始安装和授权:
adb install -r settings_apk-debug.apk adb shell pm grant io.appium.settings android.permission.WRITE_SECURE_SETTINGS adb shell pm grant io.appium.settings android.permission.CHANGE_WIFI_STATE adb shell pm grant io.appium.settings android.permission.CHANGE_NETWORK_STATE adb shell pm grant io.appium.settings android.permission.ACCESS_FINE_LOCATION adb shell pm grant io.appium.settings android.permission.ACCESS_COARSE_LOCATION有的版本还需要grant其他权限,比如CHANGE_WIFI_STATE、ACCESS_WIFI_STATE等。授权清单不必死记,后面用命令查一下当前应用运行时权限,缺哪个补哪个。
最后启动一下,确认服务能起来:
adb shell am start-foreground-service io.appium.settings/.Settings如果没有任何报错,说明服务正常启动了。如果出现Permission Denied,多半是上面的grant命令没有全部执行。
3.3 授权与初始化检查
授权处理完之后,不要急着跑自动化用例,先做一些基础检查。
第一,确认settings包被系统识别为已安装应用:
adb shell pm list packages | grep appium能搜到io.appium.settings包名,说明安装成功。
第二,用dumpsys看service状态:
adb shell dumpsys activity services io.appium.settings如果输出中包含ServiceRecord相关信息,说明服务正在运行。
第三,直接验证核心能力。通过系统设置命令检查动画状态:
adb shell settings get global window_animation_scale如果返回0.0,说明动画已经被禁用了。这一条是验证Settings是否真正“有权限干活”的黄金标准。
按理说,初始化检查做到这一步,settings部署就算真正完成了。但很多人会忽略一个问题:真机上每次系统更新、应用清理,都可能清掉settings的授权状态。所以即使部署完成后,也建议定期执行授权步骤。
4. 配置参数与功能验证
4.1 Desired Capabilities关键参数
Appium Settings能不能稳定工作,很大程度上取决于你在创建会话时配置的那一堆capabilities。这些参数直接影响自动化过程中的稳定性和行为表现。
常用参数我做了一个速查表:
| Capability | 取值 | 作用 |
|---|---|---|
| appium:skipUnlock | true/false | 跳过解锁流程,适合不需要锁屏处理的场景 |
| appium:disableWindowAnimation | true/false | 禁用窗口动画,减少元素查找时的等待时间 |
| appium:autoGrantPermissions | true/false | 自动授予应用权限,避免安装应用后的权限弹窗 |
| appium:noReset | true/false | 不重置应用数据,常用于保留登录态 |
| appium:fullReset | true/false | 完全重置应用数据并重新安装 |
| appium:unicodeKeyboard | true/false | 启用Unicode输入法,配合sendKeys输入中文 |
| appium:resetKeyboard | true/false | 测试结束后恢复系统默认输入法 |
配置示例:
{ "platformName": "Android", "appium:automationName": "UiAutomator2", "appium:deviceName": "emulator-5554", "appium:platformVersion": "13.0", "appium:skipUnlock": true, "appium:disableWindowAnimation": true, "appium:autoGrantPermissions": true, "appium:noReset": false }这里有个经验:skipUnlock和disableWindowAnimation这两个参数建议保持开启。skipUnlock能避免锁屏状态下UI交互失败,disableWindowAnimation则能让整个操作节奏加快不少。还有其他一些参数,比如ignoreUnimportantViews、enableMultiWindows,也需要根据业务场景来调整。
4.2 动画、通知权限等验证方法
参数配置好,session能创建成功,不代表settings整个链路就是正常的。一定要做验证。
验证分三层:
第一层,验证session创建时settings自动部署正常。创建session后,马上在命令行里执行:
adb shell pm list packages | grep io.appium.settings如果包存在,说明自动部署环节没掉链子。
第二层,验证动画关闭效果。设置disableWindowAnimation为true后,跑一个简单的打开应用动作,同时另一终端执行:
adb shell settings get global window_animation_scale adb shell settings get global transition_animation_scale adb shell settings get global animator_duration_scale三个值都应该是0.0。如果不是,说明settings的动画控制没生效,通常是权限问题。
第三层,验证通知权限控制。在某个应用刚安装完、还没弹出通知权限请求时,检查应用的通知权限状态:
adb shell appops get <被测应用包名> android:post_notification如果返回值是allow,说明autoGrantPermissions生效了。如果返回ignore,说明权限授予流程有异常,需要在代码里处理弹窗。
4.3 多设备与并发场景配置
多台设备同时跑自动化时,Appium Settings的管理会变得复杂。因为不同设备的状态、系统版本、ROM都不一样,自动部署结果不一定是同步的。
我建议在多设备场景下做两件事:
第一,保留一份统一的settings APK版本在CI服务器上,各设备统一使用手动安装进行一次初始化,避免每台设备自动下载不同版本的APK。混合安卓版本的测试池,尽量让settings选一个兼容性较广的版本。
第二,给每台设备设置独立的初始化脚本,在跑任务前先执行一轮授权检查和动画状态检查。防止上一轮任务留下的状态污染这一轮的执行。
并发时另外一个值得注意的点是设备磁盘空间。settings APK虽然不大,但如果设备的/system分区被塞满,自动安装失败的概率会大增。定期清理测试设备上残留的安装包和日志,看起来不起眼,但确实能减少很多奇怪的失败。
5. 常见问题排查与避坑实录
5.1 高频问题速查表
把我在实际维护中遇到的高频问题整理成表格,方便你按图索骥:
| 问题现象 | 可能原因 | 排查与解决 |
|---|---|---|
| Session创建失败,卡在安装Appium Settings | 设备存储空间不足或自动安装被ROM拦截 | 清理设备空间,或改用手动安装 |
| Settings服务起不来,报Permission Denied | 授权命令未执行完整或授权被还原 | 重新执行pm grant命令序列 |
| 动画一直关不掉 | WRITE_SECURE_SETTINGS授权失败 | 单独grant该权限后重启Settings服务 |
| 中文输入无效 | unicodeKeyboard参数未启用 | 添加unicodeKeyboard和resetKeyboard参数 |
| 通知权限弹窗处理不掉 | autoGrantPermissions参数设为false | 改为true,或在脚本中处理弹窗 |
| 某些方法执行时找不到Service | 多设备并发时端口或设备指向错乱 | 核对udid参数是否指向正确的设备 |
| 重启设备后Settings失效 | 服务未设置开机自启 | 重新执行一次安装和授权脚本 |
5.2 真机厂商ROM适配
真机相比模拟器要复杂得多,根源在于各个厂商ROM对后台服务和应用权限的态度不一样。有些ROM会把不活跃的后台服务杀掉,有些会拦截未经用户手动允许的通知权限,有些在安装应用时会强制弹出风险提示。
处理这类问题,核心原则只有一个:给Appium Settings它需要的改动尽量低,给测试应用设置足够的底栏权限。
- 在开发者选项里关闭“不保留活动”,防止后台服务被清理。
- 如果ROM自带电池优化白名单,把Appium相关包名加进去,包含io.appium.settings和被测应用。
- 部分ROM需要手动开启“后台弹出界面”之类的开关,这类开关通常依赖应用自身权限,不能通过adb直接设置。
另外,如果你的真机是某国际品牌的旗舰机型,测试时用的是企业定制系统,情况会更不可控。有条件的话,建议在项目初期就固定一台“统一型号的测试真机”,尽量用同一批设备跑,降低ROM差异带来的不确定性。
5.3 调试技巧
排障时最怕的是两眼一抹黑找不着方向。我习惯的调试流程是这样:
抓取logcat日志,看settings相关异常:
adb logcat -s AppiumSettings:V如果你执行的步骤涉及通知权限、输入法切换等动作,日志里会出现相应的处理记录,比如“setAnimationScale”一类的行。这些记录会告诉你,问题到底出在settings进程本身,还是出在命令传输层面。
第二个实用技巧是重置settings应用数据。如果settings状态越来越乱,授权命令全部重跑仍然无效,可以考虑:
adb shell pm clear io.appium.settings但注意,clear之后应用的数据、权限会被清掉,等同于重装前的状态。执行完要重新授权、重新启动服务。
第三个技巧是使用Appium自带的环境检查命令:
appium driver doctor这个命令会检查UiAutomator2驱动所需的环境条件,包括Java、Android SDK、adb等。如果你在settings的部署上反复出错,先跑一遍这个命令,能排除掉环境层面的干扰因素。
6. 部署后的稳定运行建议
6.1 日常巡检与日志管理
settings部署完成后不是一劳永逸的。自动化测试跑得越频繁,设备状态变化越剧烈,越需要做日常巡检。
我建议在每轮测试任务启动前,增加一个预检脚本,检查项包括:
- 设备是否在线:adb devices -l
- settings包是否安装:pm list packages | grep io.appium.settings
- 必要权限是否有效:pm dump io.appium.settings(看granted状态)
- 动画缩放值是否为0:settings get global window_animation_scale
- 当前输入法是否正常:settings get secure default_input_method
这套预检脚本放在CI里,五分钟之内就能完成,能把大部分隐患扼杀在任务开始之前。
日志管理方面,注意轮转。Appium日志本身会增长,设置轮换策略避免磁盘被日志占满。一个简单的策略是按天切分日志文件,保留最近七天的即可。
6.2 与输入法、解锁模块的协作
settings在自动化执行中有一个很关键的协作对象:输入法。Appium的unicodeKeyboard参数会让设备默认切换到Appium的UnicodeIME。测试结束时,resetKeyboard参数会恢复默认输入法。
实际操作中,我遇到过一种情况:即使resetKeyboard设成true,某些ROM上输入法切换并不生效,导致手动操作设备时,键盘还是Appium的UnicodeIME,中文输入变得不正常。
解决办法是,在测试收尾阶段显式执行:
adb shell ime reset或者干脆在脚本里调用resetKeyboard并等待几秒,再确认当前输入法已经切换回去。这个细节在长时间无人值守的任务运行中尤其重要,因为它不会让某一条用例崩掉,但会让下一轮用例的输入行为变得诡异。
与解锁模块的协作同理。skipUnlock参数会在某些场景下跳过解锁流程,但如果设备在会话中途熄屏了,后续操作可能直接失败。建议在测试代码的每个关键操作节点前,加一个屏幕状态检查,必要时唤醒屏幕并解锁。settings虽然能协助设置动画和权限,但屏幕状态的兜底还是得靠自己。
6.3 脚本层面的稳定性设计
部署层面的问题,也可以在脚本设计上做一层兜底。
我习惯在每个session创建成功后,加一个“环境确认”的步骤,验证关键参数是否真正生效。比如检查动画缩放值,正确的话继续,不对就重启settings服务再创建session。
另外,测试任务的重试逻辑很重要。Appium Settings的自动安装不是次次都能成功的,但重试时如果忽略“settings未装好”这个前提,很容易反复失败在同一个点。建议重试逻辑里加入“重试前先执行初始化脚本”的设计:
- 失败任务捕获
- 对设备执行安装检查与授权
- 重跑失败用例
- 连续失败超过三次才标记为可疑
这样既能避免环境因素导致的任务中断,也不会过度掩盖代码本身的问题。我在日常项目中,单台设备连续跑一周以上,稳定性明显提升,很大程度上就是靠这一层兜底逻辑。
最后再分享一个实操心得:无论你的自动化跑得多熟练,都不要小看Appium Settings这一步。它就像你家里的水管,平时不会去注意,一旦堵了,整个用水都会受牵连。把Settings部署当作一个可重复、可验证、有日志的流程来对待,你省下的时间远比你投入的多。