关于 argent-device-interact
面向编码 Agent 的设备交互技能,为 iOS、Android 和 Chromium 目标提供统一工具流程,涵盖启动应用、界面发现、手势、键盘输入和等待操作,适用于测试与检查。
主要功能
- 01跨支持目标的统一交互
- 02启动应用并打开 URL
- 03检查可访问的界面元素
- 04手势、键盘输入和硬件按钮
- 05等待界面元素或屏幕空闲
适用场景
- 01在模拟器或仿真器上运行应用流程
- 02交互前检查屏幕元素
- 03测试 URL scheme 和键盘操作
- 04自动执行可重复的界面交互序列
MCP 相关
该技能介绍用于设备和 Chromium 目标的统一交互工具界面,包括界面发现与输入操作。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ software-mansion/ argent --skill argent-device-interact安装后在 Claude Code 中输入/argent-device-interact确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/chromium.mdgesture-examples.mdharmonyos.mdsecrets.md详细介绍
统一工具界面
以下所有交互工具都接受 udid 参数,并根据其格式自动分派到 iOS 或 Android(UUID → iOS 模拟器,chromium-cdp-<port> → Chromium(CDP)应用,其他值 → Android adb 序列号)。在所有平台上使用相同的工具名称。
Chromium(CDP)应用 = 暴露 Chrome DevTools Protocol 端点的 Electron 应用或 Chromium 系浏览器(Chrome/Brave/Edge)。相同的描述/点击/键盘/截图界面可驱动这些应用,但滚动、标签页、Cookie 和存储方式有所不同:在驱动 chromium 目标前,请先阅读 references/chromium.md。
1. 开始之前
如果将模拟器任务委派给子 Agent,请确保它们拥有 MCP 权限。
使用 list-devices 获取目标 ID。结果会标注 platform(ios、android 或 chromium);已启动/就绪的设备会排在前面。对于 harmony 目标,在驱动前请阅读 references/harmonyos.md。选择第一个符合所需平台的条目;如果没有就绪设备,则使用 udid(iOS)、avdName(Android)或 electronAppPath(将 Electron 应用作为 chromium 设备启动)调用 boot-device。已通过 CDP 端口运行的 Chromium 浏览器会直接显示,无需调用 boot-device。完整设置流程请参阅 argent-ios-simulator-setup / argent-android-emulator-setup。
首次使用前加载工具架构。 手势工具(gesture-tap、gesture-swipe、gesture-pinch、gesture-rotate、gesture-custom)可能会延迟加载:只有获取后才会加载其参数架构。在调用任何手势工具之前,请务必使用 ToolSearch 加载所有计划使用的手势工具架构。如果跳过此步骤,参数可能会被强制转换为字符串而非数字,从而导致验证错误。
2. 最佳实践
- 点击前务必参阅 argent.md 规则中的 tapping_rule。
- 执行交互前,请考虑是否可以按顺序分派——更多信息请参阅
run-sequence。 - 对列表/滚动使用
gesture-swipe,除非需要非线性移动,否则不要使用gesture-custom。在 Chromium 上改用gesture-scroll;gesture-swipe仅适用于触控。考虑是否需要多次滑动;如果需要,请使用run-sequence。如果滑动应在结束前减速以实现精确移动,请传入momentum: false。 - 输入文字前先点击文本字段,然后使用
keyboard输入文字。 - 坐标已归一化:始终使用 0.0–1.0,而非像素。
- 进行应用内导航时,使用每次操作后返回的元素树(
--- Elements after action (describe) ---);只有当前屏幕没有最新元素树时才调用describe。它无需重启应用即可在任意屏幕上运行。除非元素树未能提供可靠的目标,否则不要在普通应用内屏幕上根据截图像素导航。仅在需要应用范围的 UIKit 属性时才使用native-describe-screen。
3. 打开应用
切勿通过点击主屏幕图标导航到应用。 使用 launch-app 或 open-url:它们即时且可靠。
launch-app:通过 bundle ID
{ "udid": "<UDID>", "bundleId": "com.apple.MobileSMS" }
常见 ID:com.apple.MobileSMS(信息)、com.apple.mobilesafari(Safari)、com.apple.Preferences(设置)、com.apple.Maps、com.apple.mobileslideshow(照片)、com.apple.MobileAddressBook(通讯录)
open-url:通过 URL scheme
{ "udid": "<UDID>", "url": "messages://" }
常见 scheme:messages://、settings://、maps://?q=<query>、tel://<number>、mailto:<address>、https://...(Safari)
4. 选择合适的工具
| 操作 | 工具 | 说明 |
|---|---|---|
| 多个操作 | run-sequence | 在一次调用中批量执行步骤(没有中间截图) |
| 打开应用 | launch-app | 始终遵守:切勿点击主屏幕图标 |
| 重启应用 | restart-app | 按 bundle ID 终止并重新启动 |
| 打开 URL/方案 | open-url | 网页、深层链接、URL 方案 |
| 单次点击 | gesture-tap | 按钮、链接、复选框 |
| 滚动/滑动 | gesture-swipe | 直线滚动或滑动 |
| 滚动(Chromium) | gesture-scroll | 基于滚轮;delta 以窗口尺寸的比例表示,正值 deltaY = 向下 |
| 拖动(Chromium) | gesture-drag | 滑块、拖放、文本选择 |
| 长按 | gesture-custom | 上下文菜单、开始拖动 |
| 拖放 | gesture-custom | 复杂的拖动交互 |
| 捏合/缩放 | gesture-pinch | 双指捏合,自动插值 |
| 旋转 | gesture-rotate | 双指旋转,自动插值 |
| 自定义手势 | gesture-custom | 任意触摸序列,可选插值 |
| 硬件按键 | button | Home、返回、电源、音量、应用切换、操作按钮 |
| 输入文本 | keyboard | 所有平台。每次调用输入文本或一个命名按键,不可同时使用 |
| 粘贴文本 | paste | 仅用于用户通常会粘贴内容的场景(OTP 验证码、长链接)。仅限模拟器 |
| 旋转设备 | rotate | 更改方向 |
| 折叠设备 | fold | 可折叠模拟器:折叠/半展开/展开,或指定角度 |
| 摇晃设备 | shake | 摇晃处理程序(仅限模拟器)、撤销输入提示、RN 开发菜单 |
| 等待 UI | await-ui-element | 阻塞,直到元素可见/隐藏/存在/包含文本 |
| 等待空闲 | await-screen-idle | 阻塞,直到非空屏幕树停止变化 |
5. 查找可点击目标
重要:执行操作后切换到其他屏幕,或不知道组件的坐标时,务必先进行适当的发现。
| 应用类型 | 发现工具 | 返回内容 |
|---|---|---|
| 目标应用发现 | describe | 当前设备屏幕的无障碍元素树(iOS AX-service、Android uiautomator 或 Chromium DOM walker),包含经过归一化的框架坐标。适用于任何应用、系统对话框和主屏幕;无需重启应用或提供 bundleId |
| React Native | debugger-component-tree | React 组件树,包含名称、文本、testID 和(点击:x,y) |
| 应用范围的原生检查 | native-describe-screen | 应用范围内的底层无障碍元素,包含归一化坐标和原始坐标;需要 bundleId |
| 权限 / 系统模态覆盖层 | describe | describe 会自动检测系统对话框,并返回带有点击坐标的对话框按钮。只有当 describe 未显示控件时,才回退到 screenshot |
| 最终视觉回退方案 | screenshot | 仅当发现工具无法可靠地检查当前 UI 时使用。不要根据截图确定常规应用内导航目标 |
在已有候选点后,可使用以下原生诊断工具进行进一步检查:
native-user-interactable-view-at-point:在已知的原始 iOS 坐标处,最深层的可接收触摸的原生视图;需要bundleIdnative-view-at-point:在已知的原始 iOS 坐标处,最深层的可见原生视图;需要bundleId
如果 describe 工具失败
读取确切的错误信息,并选择与之匹配的操作:
- 错误提到
ax-service不可用或守护进程启动失败: ax-service 守护进程无法启动。请检查模拟器是否已启动。可暂时回退到screenshot,或者在应用已注入原生开发工具的情况下,使用带有显式bundleId的native-describe-screen。 describe返回空元素列表: 屏幕可能是空白的、正在加载,或显示了没有无障碍标签的内容。使用screenshot查看当前可见内容,然后在内容加载完成后重试。describe成功,但对 React Native 应用而言细节不足: 接下来使用debugger-component-tree。- 需要使用完整的 UIKit 属性(
accessibilityIdentifier、viewClassName)进行应用范围的检查: 使用带有显式bundleId的native-describe-screen。这需要注入原生开发工具(dylib)。 - 已有候选点,并想确认实际会接收触摸的对象:
使用
native-user-interactable-view-at-point。如果想查看视觉上最深层的视图,而非命中测试目标,则使用native-view-at-point。
6. 工具使用
gesture-tap:在某个点单击
{ "udid": "<UDID>", "x": 0.5, "y": 0.5 }
坐标:0.0 = 左侧/顶部,1.0 = 右侧/底部。
在 React Native 应用中单击屏幕底部附近之前,请确认没有显示“Open Debugger to View Warnings”横幅:单击横幅会导致调试器连接中断。如果有,请点击 X 图标将其关闭。
gesture-swipe:直线手势
{ "udid": "<UDID>", "fromX": 0.5, "fromY": 0.7, "toX": 0.5, "toY": 0.3 }
向上滑动(fromY > toY)= 向下滚动内容。默认时长:300ms。可选:"durationMs": 500,减慢滑动速度。
"momentum" 默认值为 true(自然甩动滑动)。传入 "momentum": false 可禁用惯性:手指减速至终点,几乎不会产生甩动效果。此时 durationMs 必须至少为 150,低于此值会被拒绝。
gesture-pinch:双指捏合
{ "udid": "<UDID>", "centerX": 0.5, "centerY": 0.5, "startDistance": 0.2, "endDistance": 0.6 }
所有值都标准化为 0.0–1.0(屏幕比例,而非像素),与其他手势工具相同。startDistance: 0.2 表示两指起始间距为屏幕宽度的 20%;endDistance: 0.6 表示结束间距为 60%。startDistance < endDistance = 捏合张开(放大)。startDistance > endDistance = 捏合收拢(缩小)。默认值:angle: 0(水平),durationMs: 300。可选:"angle": 90 表示垂直方向,"durationMs": 500 可减慢捏合速度;还可以用 "endCenterX"/"endCenterY" 让质心在手势过程中移动到新的中心点(省略时中心点固定)。
gesture-rotate:双指旋转
{
"udid": "<UDID>",
"centerX": 0.5,
"centerY": 0.5,
"radius": 0.15,
"startAngle": 0,
"endAngle": 90
}
所有位置和半径都标准化为 0.0–1.0(屏幕比例,而非像素)。radius: 0.15 表示每根手指距离中心 15% 的屏幕宽度。endAngle > startAngle = 顺时针。默认时长:300ms。可选:"durationMs": 500 可减慢旋转速度;还可以使用 "radiusX"/"radiusY"(分别为屏幕宽度/高度的比例;两者必须同时提供,并会覆盖 radius),其中 radiusX·width = radiusY·height 可实现实际圆形轨迹;在非正方形屏幕上,单独使用 radius 会描出实际椭圆轨迹,并在旋转过程中带入轻微的捏合动作。
gesture-custom:自定义触摸序列
长按、拖放和其他复杂序列,请参阅 references/gesture-examples.md。设置 "interpolate": 10 可在关键帧之间自动生成平滑的中间 Move 事件。
button:按下硬件按钮
{ "udid": "<UDID>", "button": "home" }
取值:home、back、power、volumeUp、volumeDown、appSwitch、actionButton
keyboard:输入文本或按下特殊按键
{ "udid": "<UDID>", "text": "search query" }
一次调用只执行一个操作。text 和 key 不能同时使用;同时包含两者的调用会被拒绝,且不会输入任何内容。要先输入再提交,请在一个 run-sequence(§ 8)中发送两个 keyboard 步骤:{ "text": "search query" },然后 { "key": "enter" }。分两次调用执行相同操作,但会多一次往返。
React Native:输入后第一次单击可能只会关闭键盘。 在默认 keyboardShouldPersistTaps="never" 的滚动视图中,React Native 会将对焦字段之外的单击用于关闭键盘,而不会继续传递该单击(设置为 "handled" 或 "always" 时,单击会传递到按钮),因此输入后立即单击的按钮可能需要再点一次;请检查返回的树结构。如果字段会在按下回车键时提交,则 { "key": "enter" } 可避免多点一次。
特殊按键:enter、escape、backspace、tab、space、arrow-up、arrow-down、arrow-left、arrow-right、f1–f12。可选:设置 "delayMs": 100,以控制按键间隔(默认 50ms);适用于 iOS 模拟器和 Chromium;在 Android 手机/平板(通过 adb input text 输入,不支持逐键间隔)、Vega 和电视目标上会被忽略。
输入机密信息。 若要输入凭据,且不让明文进入上下文、记录内容或日志,请在 text 中使用机密占位符(适用于 keyboard、paste、run-sequence 中的键盘步骤,以及 e2e type 步骤):
{ "udid": "<UDID>", "text": "{{secret:APP_PASSWORD}}" }
有关值的读取来源和占位符使用规则(包括之后不得对该字段截图),请参阅 references/secrets.md。输入任何凭据前,请先阅读该文档。
paste:将文本粘贴到当前聚焦的字段
{ "udid": "<UDID>", "text": "482913" }
将 text 放入设备剪贴板,并触发平台的粘贴快捷键。仅支持 iOS 模拟器和 Android 模拟器;电视目标、实体设备、Chromium 和 Vega 均不支持。
paste 不是更快的 keyboard。keyboard 会像用户打字一样输入,并且仍是所有文本输入的默认方式:搜索查询、登录信息、表单字段。只有在真实用户会粘贴的场景下才使用 paste:从其他应用复制的 2FA / OTP 代码、较长的链接或令牌,或者测试应用如何处理粘贴的输入。它还支持输入特定平台上 keyboard 无法输入的内容(Android 上的多行文本、非 ASCII 字符),但这本身并不是粘贴的理由;要考虑用户是否会这样做。
先点击字段使其获得焦点;没有聚焦字段时粘贴会静默无效,这与 keyboard 一样。text 接受与 keyboard 相同的 {{secret:<NAME>}} 占位符,也会以相同方式跳过自动截图。
rotate:更改方向
{ "udid": "<UDID>", "orientation": "LandscapeLeft" }
可用值:Portrait、LandscapeLeft、LandscapeRight、PortraitUpsideDown
在展开状态的折叠屏模拟器上,该值设置的是设备方向,而不是 UI 方向。Portrait 会显示横向 UI。LandscapeLeft 会显示纵向 UI。
fold:折叠或展开折叠屏设备
{ "udid": "<UDID>", "posture": "open" }
指定 posture(closed、half-open 或 open)或 angle(0–180)。两者不可同时指定。
仅在折叠屏 iOS 模拟器(iPhone Duo)或 Android 模拟器(Pixel Fold 或通用折叠屏 AVD)上使用 fold。list-devices 会将这些设备标记为 foldable: true。其他设备会拒绝此调用。
折叠时,外屏显示 UI。半展开和展开时,内屏显示 UI。所有工具都会使用当前活动屏幕(显示 UI 的屏幕),即使折叠是在 argent 之外进行的也是如此。设备重新接受输入后,fold 才会返回,因此下一次点击能够落在正确位置。run-sequence 中的下一步也同样如此。
规则:
- 坐标会随屏幕变化。点击前,请读取
fold结果中的元素树,或再次运行describe。不要使用折叠前的坐标框。 - 截图尺寸会随屏幕变化。每种折叠状态都应保留一个截图差异基线。
- iOS:展开时,UI 为横向。截图中的 UI 会旋转 90 度,
describe坐标框使用相同坐标轴,与旋转后的 iPhone 一样。 - iOS:在两个既非 0 度也非 180 度的角度之间折叠,可能会保持当前屏幕不变。结果会指出当前活动屏幕。若要切换屏幕,请折叠至
closed或open。 - 请在手势之间折叠,不要在手势过程中折叠。手势会始终作用于其开始时所在的屏幕。
- Android:结果会提供
deviceState(CLOSED、HALF_OPENED、OPENED)。折叠至关闭状态时出现的锁屏会被关闭;如果无法关闭,或折叠后仍显示锁屏,warning会说明情况。执行下一步操作前,请先解锁设备。 - Android:只有 Pixel Fold AVD 有外屏。通用折叠屏 AVD 关闭时,模拟器只显示屏幕左侧部分。
describe的坐标框与点击坐标不匹配。Argent 只能可靠地点击覆盖可见区域的元素,例如全宽行。请使用 Pixel Fold AVD 测试外屏。 - iOS:如果 argent 无法找到活动屏幕,就会使用外屏。此时工具结果中会包含
warning,截图差异摘要中会有一行panel:。请截屏查看设备显示内容,然后按照警告中的提示进行检查。
await-ui-element:阻塞,直到 UI 元素达到某种状态
切勿通过循环轮询 screenshot/describe 来等待。 使用 await-ui-element:它会在服务端阻塞,并读取与 describe 相同的树。它按设计不提供单纯的定时器模式;如需纯粹暂停,请使用你自己的测试框架中的休眠功能。
{ "udid": "<UDID>", "condition": "visible", "selector": { "text": "Continue" } }
该工具自身的描述会说明条件、选择器匹配方式、默认值和返回结构。以下信息则未包含在其中:
- 如果
hidden检查立即成功,可能是假通过:此时note会指出选择器根本没有匹配到任何内容。请将其视为检查失败并修正选择器;不要将其理解为“元素消失了”。 describe输出的合成ROOT容器永远不会被匹配,因此像AXGroup/html这样的role不会轻易“匹配整个屏幕”。- 若要明确宽泛的选择器,可将
role指定为StaticText这样的文本角色;这样就会跳过同名按钮。 text超时时,note会引用检查实际读取到的元素文本,因此你可以看出它匹配到了哪个元素。
await-screen-idle:阻塞,直到屏幕停止变化
在启动/导航后、执行原始点击前使用,以防刚绘制出来的元素仍在移动:
{ "udid": "<UDID>", "timeoutMs": 3000, "minStableMs": 250 }
在本地 iOS、Android 和 Chromium 上,该工具会等待非空的 describe 树停止变化。仅当 settled: true 时才继续。请将其与针对目标页面的 await-ui-element 搭配使用;画面静止并不能确定当前页面。
仅将其用于实时诊断。不要记录它,也不要将其放入 run-sequence。E2E 测试使用 await: { idle: true },该模式还会比较像素。此实时工具可能会在呈现层动画期间返回。
7. 屏幕截图
仅在以下情况使用显式的 screenshot 工具:
- 需要在执行任何操作前确认初始屏幕状态。
- 即将编辑可见界面,需要在更改前先截取基线。
- 自动附加的屏幕截图显示的是过渡或加载画面。
- 需要更多上下文。
- 想在延迟后检查状态(例如等待网络响应)。
- 屏幕上显示权限对话框、系统警告或原生模态叠层,且
describe未能提供可靠的目标。
使用 screenshot 进行权限或原生模态界面导航时:
- 不要仅仅因为出现模态界面就改用基于屏幕截图的导航。在普通应用屏幕和应用内模态界面中,继续使用
describe。 - 优先选择明显且居中的警告按钮,例如
Allow、OK、Don't Allow、Not Now或Continue。 - 一次点击一个控件,并在执行其他操作前检查返回的自动屏幕截图。
- 关闭模态界面后,使用
describe、native-describe-screen或debugger-component-tree恢复常规界面发现流程。
优先使用对话框,而非 Settings 工具。 应用触发自身的权限提示时,在此处作出选择才是用户的实际操作路径;请直接处理。只有在无法通过应用完成更改时,才使用
settings-permissions工具:在应用询问前预先允许或拒绝权限、重新启用用户已拒绝的权限(iOS 不会再次询问),或重置权限以重新显示提示。请参阅argent-settings-permissions技能。
可选旋转参数:{ "udid": "<UDID>", "rotation": "LandscapeLeft" }:旋转捕获图像,但不更改模拟器方向。
默认情况下,屏幕截图会缩小为原始分辨率的 30%,以减少上下文占用。使用常规缩小后的屏幕截图查看界面上下文和检查状态。scale 接受 0.01 到 1.0 之间的值,但不要将 scale: 1.0 用作常规的可读性或点击辅助。
仅在保存用于比较的基线/当前 PNG 文件时使用全分辨率屏幕截图。在这种情况下,请抑制图像块,避免将全尺寸 PNG 加载到 Agent 上下文中:
{ "udid": "<UDID>", "scale": 1.0, "includeImageInContext": false }
有关视觉回归检查、前后屏幕截图比较,以及 screenshot-diff 参数的详细说明,请使用 argent-screenshot-diff 技能。此技能应专注于设备交互机制和屏幕截图捕获。
故障排查
| 问题 | 解决方案 |
|---|---|
| 屏幕截图超时 | 使用 stop-simulator-server 工具重启 simulator-server |
| 没有已启动的 iOS 模拟器 | 使用 iOS udid 调用 boot-device |
| 没有就绪的 Android 设备 | 使用 avdName 调用 boot-device |
8. 使用 run-sequence 编排操作
使用 run-sequence 将多个交互步骤批量合并为一次工具调用。所有步骤完成后才会返回一张屏幕截图。
如果某个步骤需要根据上一步的结果进行操作,请勿使用 run-sequence。
使用场景
- “滚动到底部”、“滚动到顶部”、“滚动直到出现 X” → 连续滚动 3-5 次
- 表单交互、“清空并重新输入字段” → 三击以全选,然后输入新值
- “提交表单” → 按顺序填写所有字段,然后点击提交
- “返回 X” → 按照定义好的点击顺序导航
run-sequence 中允许使用的工具
gesture-tap、gesture-swipe、gesture-scroll、gesture-drag、gesture-custom、gesture-pinch、gesture-rotate、button、keyboard、paste、rotate、shake、fold、tv-remote、await-ui-element
所有步骤共享 udid;不要在每个步骤的 args 中包含它。每个步骤可以设置可选的 delayMs(默认值为 100ms)。
添加一个 await-ui-element 步骤,让后续点击等待屏幕转换完成(例如:点击 → 等待下一屏上的按钮出现 → 点击该按钮)。如果在超时前未满足条件,序列会在该步骤停止,后续步骤不会运行,因此点击不会因时机不对而触发在尚未稳定的屏幕上。
示例
向下滚动三次:
{
"udid": "<UDID>",
"steps": [
{ "tool": "gesture-swipe", "args": { "fromX": 0.5, "fromY": 0.7, "toX": 0.5, "toY": 0.3 } },
{ "tool": "gesture-swipe", "args": { "fromX": 0.5, "fromY": 0.7, "toX": 0.5, "toY": 0.3 } },
{ "tool": "gesture-swipe", "args": { "fromX": 0.5, "fromY": 0.7, "toX": 0.5, "toY": 0.3 } }
]
}
在已聚焦的字段中输入文字并提交。这是混合输入文字和按键的唯一方式,因为一次 keyboard 调用无法同时传入两者:
{
"udid": "<UDID>",
"steps": [
{ "tool": "keyboard", "args": { "text": "hello world" } },
{ "tool": "keyboard", "args": { "key": "enter" } }
]
}
点击一个已知按钮,然后向下滚动:
{
"udid": "<UDID>",
"steps": [
{ "tool": "gesture-tap", "args": { "x": 0.5, "y": 0.15 } },
{
"tool": "gesture-swipe",
"args": { "fromX": 0.5, "fromY": 0.7, "toX": 0.5, "toY": 0.3 },
"delayMs": 300
}
]
}
点击、等待下一屏出现,然后在该屏上执行操作:await-ui-element 步骤会控制其后的点击是否执行:
{
"udid": "<UDID>",
"steps": [
{ "tool": "gesture-tap", "args": { "x": 0.5, "y": 0.9 } },
{
"tool": "await-ui-element",
"args": { "condition": "visible", "selector": { "text": "Continue" } }
},
{ "tool": "gesture-tap", "args": { "x": 0.5, "y": 0.5 } }
]
}
如果某个步骤依赖屏幕转换,优先使用此方式,而不是固定的 delayMs:它会适应实际加载时间;如果在超时前未满足条件,序列会立即在此处停止,避免后续点击触发在尚未稳定的屏幕上。
遇到第一个错误(或 await-ui-element 条件未满足)时停止,并返回部分结果。
9. 平台特定说明
Android
- Metro 连通性:在 RN 应用启动前,在设备上运行
adb reverse tcp:8081 tcp:8081,否则设备将无法访问 Metro。完整工作流请参阅argent-metro-debugger。如果设备重启,请重新运行。 - 首次启动时的权限提示:在 Android 上,
reinstall-app始终使用-g安装,因此首次启动时已预先授予运行时权限;无需传入标志。 - 锁屏/安全界面:如果无法捕获(例如 keyguard、DRM、Play Integrity),
describe会抛出明确的错误。请解锁设备或改用screenshot。 reinstall-app中的 APK 与 .app:在 Android 上传入.apk的绝对路径;在 iOS 上传入.app目录。
Chromium
请参阅 references/chromium.md(标签页、Cookie/存储)。
iOS
(目前还没有收集到仅适用于 iOS 的注意事项;遇到时请添加)