appshots-accessibility-ids

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Accessibility Identifiers for Screenshot Automation

用于截图自动化的可访问性标识符

Before any automation tool (Maestro or AXe) can reliably tap elements in your app, those elements need stable accessibility identifiers. This skill teaches you how to add them across frameworks.
在任何自动化工具(如 Maestro 或 AXe)能够可靠地点击应用中的元素之前,这些元素需要稳定的可访问性标识符。本文将教你如何在不同框架中添加这类标识符。

Why Accessibility Identifiers?

为什么需要可访问性标识符?

Without identifiersWith identifiers
Tap by coordinates → breaks on different screensTap by
id:
→ works everywhere
Tap by text → breaks across localesIdentifiers are locale-independent
Need trial-and-errorPredictable, documented targets
无标识符情况有标识符情况
通过坐标点击 → 在不同屏幕上会失效通过
id:
点击 → 在所有场景下都有效
通过文本点击 → 多语言环境下会失效标识符不受语言环境影响
需要反复试错目标可预测且有文档记录

Framework Reference

框架参考

Flutter (3.19+)

Flutter (3.19+)

dart
Semantics(
  identifier: 'settings_button',       // ← stable, locale-independent
  child: ElevatedButton(
    onPressed: () => openSettings(),
    child: Text(context.l10n.settings), // ← localized, changes per locale
  ),
)
Semantics.identifier
was contributed by the Maestro team in Flutter 3.19.
dart
Semantics(
  identifier: 'settings_button',       // ← 稳定且独立于语言环境
  child: ElevatedButton(
    onPressed: () => openSettings(),
    child: Text(context.l10n.settings), // ← 本地化文本,随语言环境变化
  ),
)
Semantics.identifier
是由 Maestro 团队在 Flutter 3.19 版本中贡献的特性。

SwiftUI

SwiftUI

swift
Button("Settings") {
    openSettings()
}
.accessibilityIdentifier("settings_button")
swift
Button("Settings") {
    openSettings()
}
.accessibilityIdentifier("settings_button")

UIKit

UIKit

swift
button.accessibilityIdentifier = "settings_button"
swift
button.accessibilityIdentifier = "settings_button"

Jetpack Compose

Jetpack Compose

kotlin
Button(
    onClick = { openSettings() },
    modifier = Modifier.semantics { testTag = "settings_button" }
) {
    Text(stringResource(R.string.settings))
}
In Compose, use
testTag
inside
Modifier.semantics { }
— Maestro matches this as
id:
.
kotlin
Button(
    onClick = { openSettings() },
    modifier = Modifier.semantics { testTag = "settings_button" }
) {
    Text(stringResource(R.string.settings))
}
在 Compose 中,需在
Modifier.semantics { }
内使用
testTag
—— Maestro 会将其识别为
id:
选择器。

Android XML Views

Android XML 视图

xml
<Button
    android:id="@+id/settings_button"
    android:contentDescription="@string/settings"
    android:tag="settings_button" />
Maestro uses
android:tag
as the
id:
selector for XML views.
android:id
alone is not enough.
xml
<Button
    android:id="@+id/settings_button"
    android:contentDescription="@string/settings"
    android:tag="settings_button" />
Maestro 会将 XML 视图的
android:tag
作为
id:
选择器。仅使用
android:id
是不够的。

React Native

React Native

jsx
<TouchableOpacity
  testID="settings_button"
  accessibilityLabel="Settings"
  onPress={openSettings}
>
  <Text>{t('settings')}</Text>
</TouchableOpacity>
React Native uses
testID
which maps directly to Maestro's
id:
selector.
jsx
<TouchableOpacity
  testID="settings_button"
  accessibilityLabel="Settings"
  onPress={openSettings}
>
  <Text>{t('settings')}</Text>
</TouchableOpacity>
React Native 使用
testID
,它直接对应 Maestro 的
id:
选择器。

Naming Conventions

命名规范

Use a consistent
context_element
pattern across all frameworks:
undefined
在所有框架中统一使用
context_element
的命名模式:
undefined

Navigation

导航组件

tab_home tab_search tab_profile tab_settings
tab_home tab_search tab_profile tab_settings

Feature cards / buttons

功能卡片/按钮

feature_camera feature_scan feature_create
feature_camera feature_scan feature_create

List items (indexed)

列表项(带索引)

list_item_0 list_item_1 search_result_0
list_item_0 list_item_1 search_result_0

In-screen actions

屏幕内操作按钮

login_submit_button onboarding_next_button dialog_confirm_button
undefined
login_submit_button onboarding_next_button dialog_confirm_button
undefined

Rules

规则

  1. Always lowercase with underscores
    settings_button
    , not
    SettingsButton
  2. Prefix with screen/context — Prevents collisions across screens
  3. Use indices for lists
    list_item_0
    ,
    search_result_0
  4. Avoid localized text — Never use translated strings as identifiers
  5. Keep them short but descriptive
    tab_home
    , not
    bottom_navigation_bar_home_tab_button
  1. 始终使用小写字母加下划线 — 例如
    settings_button
    ,而非
    SettingsButton
  2. 以屏幕/上下文作为前缀 — 避免跨屏幕的标识符冲突
  3. 列表项使用索引 — 如
    list_item_0
    search_result_0
  4. 避免使用本地化文本 — 切勿将翻译后的字符串用作标识符
  5. 保持简短且具有描述性 — 如
    tab_home
    ,而非
    bottom_navigation_bar_home_tab_button

Verification

验证方法

Using Maestro Studio (All Frameworks)

使用 Maestro Studio(所有框架)

bash
maestro studio
Opens a browser UI where you can click elements and see their identifiers.
bash
maestro studio
打开浏览器界面,你可以点击元素并查看其标识符。

Using AXe CLI (iOS Only)

使用 AXe CLI(仅 iOS)

bash
axe describe-ui --udid <SIMULATOR_UDID>
axe describe-ui --udid <SIMULATOR_UDID> | grep "settings_button"
bash
axe describe-ui --udid <SIMULATOR_UDID>
axe describe-ui --udid <SIMULATOR_UDID> | grep "settings_button"

Framework-Specific Debuggers

框架专属调试工具

FrameworkDebug tool
Flutter
showSemanticsDebugger: true
in
MaterialApp
SwiftUI/UIKitXcode Accessibility Inspector
AndroidLayout Inspector → Accessibility pane
React NativeAppium Inspector or
accessibilityLabel
logging
框架调试工具
Flutter
MaterialApp
中设置
showSemanticsDebugger: true
SwiftUI/UIKitXcode 可访问性检查器
Android布局检查器 → 可访问性面板
React NativeAppium Inspector 或
accessibilityLabel
日志

Minimum Identifiers Checklist

最低标识符检查清单

Before running any capture flow, ensure these element types have identifiers:
  • Navigation tabs — every tab bar item
  • Feature cards / CTAs on home screen — primary actions
  • Scrollable content items — cards, list items that need tapping
  • Key action buttons — Play, Start, Submit, Confirm
  • Modal/popup triggers — elements that open detail views
在运行任何截图捕获流程前,确保以下类型的元素已添加标识符:
  • 导航标签 — 每个标签栏项
  • 首页功能卡片/CTA按钮 — 主要操作按钮
  • 可滚动内容项 — 需要点击的卡片、列表项
  • 关键操作按钮 — 播放、开始、提交、确认按钮
  • 弹窗/模态框触发元素 — 打开详情页的元素

Agent Guidelines

Agent 操作指南

Thinking Process

思考流程

When asked to "prepare an app for screenshot automation":
  1. Identify the framework — Flutter, SwiftUI, UIKit, Compose, XML Android, or React Native
  2. Identify screens to capture — List the screenshots needed
  3. Map navigation paths — What taps/swipes reach each screen?
  4. Find missing identifiers — Check which tappable elements lack identifiers
  5. Add identifiers — Use the correct API for the framework (see table above)
  6. Rebuild and verify — Build the app, then run
    maestro studio
    or
    axe describe-ui
当被要求“为截图自动化准备应用”时:
  1. 确定框架类型 — Flutter、SwiftUI、UIKit、Compose、XML Android 或 React Native
  2. 确定需要捕获的屏幕 — 列出需要截图的页面
  3. 梳理导航路径 — 点击/滑动操作如何到达每个屏幕
  4. 找出缺失的标识符 — 检查哪些可点击元素缺少标识符
  5. 添加标识符 — 使用对应框架的正确 API(见上方表格)
  6. 重新构建并验证 — 构建应用,然后运行
    maestro studio
    axe describe-ui
    进行验证

Common Mistakes to Avoid

需避免的常见错误

  • ❌ Adding identifiers to non-interactive widgets (labels, dividers)
  • ❌ Using localized strings as identifiers
  • ❌ Forgetting to rebuild after adding identifiers
  • ❌ Using the same identifier on multiple elements on the same screen
  • ❌ Using
    android:id
    without
    android:tag
    for XML Android views
  • ❌ 为非交互组件(标签、分隔符)添加标识符
  • ❌ 使用本地化字符串作为标识符
  • ❌ 添加标识符后忘记重新构建应用
  • ❌ 在同一屏幕的多个元素上使用相同的标识符
  • ❌ 对于 XML Android 视图,仅使用
    android:id
    而未添加
    android:tag