- 安装
官网:appium.io/docs/zh/lat…
# 1.安装库
npm install -g appium
# 2.安装驱动
appium driver install uiautomator2
- 配置adb环境变量
D:\Users\wnan\AppData\Local\Android\Sdk\platform-tools - 启动
appium -v
appium
- 测试 Python版
# 搭建虚拟环境
python -m venv .venv
# 安装依赖
pip install Appium-Python-Client
import unittest
import time
from appium import webdriver
from appium.options.android import UiAutomator2Options
from appium.webdriver.common.appiumby import AppiumBy
capabilities = dict(
platformName='Android',
automationName='uiautomator2',
deviceName='Android',
appPackage='com.android.settings',
appActivity='.Settings',
language='en',
locale='US'
)
appium_server_url = 'http://localhost:4723'
class TestAppium(unittest.TestCase):
def setUp(self) -> None:
self.driver = webdriver.Remote(appium_server_url, options=UiAutomator2Options().load_capabilities(capabilities))
def tearDown(self) -> None:
if self.driver:
self.driver.quit()
def test_find_apps(self) -> None:
el = self.driver.find_element(by=AppiumBy.XPATH, value='//*[@text="Apps"]')
time.sleep(10)
el.click()
if __name__ == '__main__':
unittest.main()
Appium Inspector
- 安装
官网:github.com/appium/appi… - 使用流程
1. 查看那IP 填入"appium:udid": "emulator-5554",
adb device
2. 打开app,定位到目标页面
3. 查看软件包和Activity 填入:"appium:appPackage": "com.android.settings","appium:appActivity": "com.android.settings.Settings"
adb shell dumpsys window | findstr mCurrentFocus
compose app
解决compose动态生成的元素id解决方法:Google 官方提供了标准的解决方案:testTag。
- 代码编写时解决
🚀 核心方案:使用 Modifier.testTag()。在 Compose 组件的modifier链中加入.testTag("唯一标识符")。
// ✅ 正确做法:添加固定的 testTag
Button(
onClick = { /*...*/ },
modifier = Modifier
.testTag("login_button") // <--- 关键!这是给自动化测试用的“ID”
.padding(16.dp)
) {
Text("登录")
}
// 列表项也可以加
LazyColumn {
items(users) { user ->
Row(
modifier = Modifier
.testTag("user_item_${user.id}") // 甚至可以带动态参数,只要规则固定
.fillMaxWidth()
) {
Text(user.name)
}
}
}
一旦加了 testTag,它在 UiAutomator2 的语义树中会映射为 resource-id 或者 accessibility-id (通常两者皆可,推荐优先试 accessibility-id)。
from appium import webdriver
from appium.options.android import UiAutomator2Options
from selenium.webdriver.common.by import By
# ... (初始化 driver 代码略)
# 策略 A: 使用 ACCESSIBILITY_ID (推荐,对应 testTag)
# 在 Compose 中,testTag 通常直接映射为 accessibility-id
login_btn = driver.find_element(By.ACCESSIBILITY_ID, "login_button")
login_btn.click()
# 策略 B: 使用 ID (对应 resource-id)
# 如果 A 不行,尝试这个,有时 testTag 也会出现在 resource-id 中
# login_btn = driver.find_element(By.ID, "login_button")
# 策略 C: 混合定位 (如果 testTag 带了前缀)
# 假如代码里是 testTag("item_123"),你可以用 XPath 模糊匹配
# item = driver.find_element(By.XPATH, "//*[@content-desc='item_123']")
- 🛡️ 如果开发人员没加
testTag怎么办? (备选方案)
方案 1: 通过文本内容定位 (By.ANDROID_UIAUTOMATOR)
如果按钮上的文字是固定的(如“登录”、“提交”),这是最稳妥的备选。
# 使用 AndroidUiAutomator 语法通过文本查找
# new UiSelector().text("精确文本")
# new UiSelector().textContains("包含文本")
login_btn = driver.find_element(
By.ANDROID_UIAUTOMATOR,
'new UiSelector().text("登录")'
)
缺点:多语言应用(国际化)会失效;动态文本(如“欢迎张三”)难以处理。
方案 2: 通过相对位置定位 (XPath),利用 Compose 的层级结构,通过“父元素”或“兄弟元素”来定位。
# 例如:找到文本为 "用户名" 的输入框旁边的那个输入框 (密码框)
# 这种写法非常脆弱,UI 微调就会挂
password_box = driver.find_element(
By.XPATH,
"//android.widget.EditText[preceding-sibling::android.widget.TextView[@text='用户名']]"
)
方案 3: 索引定位 (最不推荐)
# 找到页面上第 3 个 Button
buttons = driver.find_elements(By.CLASS_NAME, "android.widget.Button")
target_btn = buttons[2]
缺点:只要页面中间插了一个广告或新按钮,脚本必挂。