除了标准的W3C API
接口,Uiautomator2
还提供了一系列扩展接口来支持Android
平台相关的操作。本文所有测试代码的前提是已经安装Appium
和相关环境(例如JDK
、Android SDK
、AVD
模拟器),可以参考Appium
环境搭建。
应用程序(APP
)管理
1.1 检查被测应用是否已经安装
接口参数说明:
参数名称 | 参数类型 | 参数是否必须提供 | 描述 | 举例说明 |
---|---|---|---|---|
appId |
string |
yes |
appId 是待检测的应用ID ,和package 名称一致,可以通过ADB 或者current_package 属性获取。 |
com.example.android.contactmanager |
接口返回值:True
或False
举例:
# -*- coding: utf-8 -*-
import pytest
from appium import webdriver
from appium.options.android import UiAutomator2Options
from appium.webdriver.appium_service import AppiumService
# 开启服务端
APPIUM_HOST = '127.0.0.1'
APPIUM_PORT = 4723
@pytest.fixture(scope="session")
def start_appium_service():
server = AppiumService()
server.start(args=['--address', APPIUM_HOST, '-p', str(APPIUM_PORT)], timeout_ms=60000)
yield server
server.stop()
# 创建客户端到服务端的会话
def create_appium_session_by_api(custom_opts = None, appium_host = APPIUM_HOST, appium_port = APPIUM_PORT):
options = UiAutomator2Options()
if custom_opts is not None:
options.load_capabilities(custom_opts)
return webdriver.Remote(f'http://{appium_host}:{appium_port}', options=options)
# !检测appu是否已经安装
def test_check_if_app_installed(start_appium_service):
custom_opts = {
"appium:avd": "testPhone",
}
driver = create_appium_session_by_api(custom_opts)
assert driver.is_app_installed(driver.current_package) == True
driver.quit()
1.2 安装/升级APP
接口参数说明:
称 | 参数类型 | 参数是否必须提供 | 描述 | 举例说明 |
---|---|---|---|---|
appPath |
string |
yes |
被测设备本地文件系统上.apk(s) 的路径,或远程url 链接。注意:需要提供全路径(不能是相对路径)!!! |
/tmp/ContactManager.apk |
timeout |
number |
no |
等待app 安装完成的超时时间,单位是毫秒,默认值是6000ms 。 |
60000 |
allowTestPackages |
boolean |
no |
如果需要安装测试包,将该参数设置为true ,默认值是false 。 |
true |
useSdcard |
boolean |
no |
如果需要将app 安装到SD 卡,将该参数设置为true ,默认值是false
|
true |
grantPermissions |
boolean |
no |
设置为true 可以确保app 在完成安装后请求的权限自动满足,需要Android 6+ 。targetSdkVersion 必须大于等于23 ,Android 版本需要6 (API level 23 )及以上。默认值是false 。 |
true |
replace |
boolean |
no |
如果被测设备上应用已经安装,而你又不想升级或者重新安装该应用,将replace 设置为false ,并且此时调用接口会抛出错误。参数默认值是true 。 |
false |
备注:本小结示例中的APP
来源于https://github.com/appium/sample-apps/raw/master/pre-built/ContactManager.apk。并假设下载之后该apk
存放的全路径是/tmp/
举例1:使用本地路径安装,安装后启动APP
可能会需要权限,因此在安装的时候将grantPermissions
设置为true
保证自动授予APP
启动时需要的权限。
# !使用本地路径安装APP
def test_install_app_by_localfile(start_appium_service):
custom_opts = {
"appium:avd": "testPhone",
}
driver = create_appium_session_by_api(custom_opts)
ContactManagerAppId = "com.example.android.contactmanager"
driver.install_app("/tmp/ContactManager.apk", grantPermissions=True)
assert driver.is_app_installed(ContactManagerAppId) == True
driver.start_activity(ContactManagerAppId, ".ContactManager")
assert driver.current_package == ContactManagerAppId
driver.quit()
举例2:使用远程url
路径进行安装。
# !使用远程url路径安装APP
def test_install_app_by_remote_url(start_appium_service):
custom_opts = {
"appium:avd": "testPhone",
}
driver = create_appium_session_by_api(custom_opts)
ContactManagerAppId = "com.example.android.contactmanager"
driver.install_app("https://github.com/appium/sample-apps/raw/master/pre-built/ContactManager.apk", grantPermissions=True)
assert driver.is_app_installed(ContactManagerAppId) == True
driver.start_activity("com.example.android.contactmanager", ".ContactManager")
assert driver.current_package == ContactManagerAppId
driver.quit()
举例3:使用capabilities
初始化APP
路径。同样地,自动授予APP
启动时请求的权限,对应的参数是appium:autoGrantPermissions
。
# !使用Capability参数初始化安装APP
def test_install_app_by_capability(start_appium_service):
custom_opts = {
"appium:avd": "testPhone",
"appium:app": "/tmp/ContactManager.apk",
"appium:autoGrantPermissions": True,
}
driver = create_appium_session_by_api(custom_opts)
ContactManagerAppId = "com.example.android.contactmanager"
assert driver.is_app_installed(ContactManagerAppId) == True
driver.start_activity("com.example.android.contactmanager", ".ContactManager")
assert driver.current_package == ContactManagerAppId
driver.quit()
1.3 激活/启动APP
在必要的时候激活或启动应用,该动作模拟点击应用程序图标操作,APP
启动需要时间,因此后续动作需要等待APP
正常启动,本小结的例子就是延时1S
。
接口参数说明:
参数名称 | 参数类型 | 参数是否必须提供 | 描述 | 举例说明 |
---|---|---|---|---|
appId |
string |
yes |
appId 是待启动的应用ID ,和package 名称一致,可以通过ADB 或者current_package 属性获取。 |
com.example.android.contactmanager |
举例:假设已经安装好APP
。另外一种方式是通过start_activity
指定appId
和activity
来启动应用。
import time
# !启动APP
def test_activate_app(start_appium_service):
custom_opts = {
"appium:avd": "testPhone",
}
driver = create_appium_session_by_api(custom_opts)
# 先安装
driver.install_app("/tmp/ContactManager.apk", grantPermissions=True)
ContactManagerAppId = "com.example.android.contactmanager"
driver.activate_app(ContactManagerAppId)
time.sleep(1) # 延时1S等待应用启动
assert driver.current_package == ContactManagerAppId
driver.quit()
1.4 卸载APP
卸载已经安装的应用,如果待卸载的应用并未安装,则卸载动作会被忽略。
接口参数说明:
参数名称 | 参数类型 | 参数是否必须提供 | 描述 | 举例说明 |
---|---|---|---|---|
appId |
string |
yes |
appId 是待卸载的应用ID ,和package 名称一致,可以通过ADB 或者current_package 属性获取。 |
com.example.android.contactmanager |
keepData |
boolean |
no |
应用被卸载后,是否还保留数据和缓存,默认是False 。 |
True |
timeout |
int |
no |
等待应用卸载的超时时间,单位是毫秒,默认值是20000 ms 。 |
10000 |
# !卸载APP
def test_remove_app(start_appium_service):
custom_opts = {
"appium:avd": "testPhone",
}
driver = create_appium_session_by_api(custom_opts)
ContactManagerAppId = "com.example.android.contactmanager"
# 先安装
driver.install_app("/tmp/ContactManager.apk", grantPermissions=True)
assert driver.is_app_installed(ContactManagerAppId) == True
driver.remove_app(ContactManagerAppId) # 移除安装的应用
assert driver.is_app_installed(ContactManagerAppId) == False
driver.quit()
1.5 结束APP
结束正在运行的APP
,并检测状态确保APP
已经被关闭或者检测的超时时间到。当把超时时间设置的很小甚至为0
的时候(UIAutomator
驱动的2.9.0
版本开始支持),可以跳过状态检测。
接口参数说明:
参数名称 | 参数类型 | 参数是否必须提供 | 描述 | 举例说明 |
---|---|---|---|---|
appId |
string |
yes |
appId 是待结束的应用ID ,和package 名称一致,可以通过ADB 或者current_package 属性获取。 |
com.example.android.contactmanager |
timeout |
int |
no |
等待应用结束的超时时间,单位是毫秒,默认值是500 ms 。 |
10000 |
# !结束APP
def test_terminate_app(start_appium_service):
custom_opts = {
"appium:avd": "testPhone",
}
driver = create_appium_session_by_api(custom_opts)
ContactManagerAppId = "com.example.android.contactmanager"
# 先安装
driver.install_app("/tmp/ContactManager.apk", grantPermissions=True)
assert driver.is_app_installed(ContactManagerAppId) == True
# 启动
driver.activate_app(ContactManagerAppId)
time.sleep(1) # 延时1S等待应用启动
assert driver.current_package == ContactManagerAppId
driver.terminate_app(ContactManagerAppId) # 结束应用
assert driver.current_package != ContactManagerAppId
driver.quit()
1.6 启动APP
的activity
(Android
应用的activity
参考关于intent
和activity
的简介)
接口参数说明:
参数名称 | 参数类型 | 参数是否必须提供 | 描述 | 举例说明 |
---|---|---|---|---|
intent |
string |
yes |
待启动activity 的全称。 |
com.example.android.contactmanager/.ContactManager |
user |
number 或string
|
no |
用于启动服务的用户ID ,默认使用当前的用户ID 。 |
1001 |
wait |
boolean |
no |
如果设置为true ,则阻塞该调用,直到activity 处理完成后返回,默认是false 。 |
false |
stop |
boolean |
no |
如果设置为true ,则启动activity 之前强制停止APP 。 |
false |
windowingMode |
integer |
no |
启动activity 使用的窗口模式,具体请参考这里
|
1 |
activityType |
integer |
no |
activity 类型,具体请参考这里
|
1 |
action |
string |
no |
动作名称,为am (Activity Manager )的-a 参数指定的值。 |
android.intent.action.MAIN |
uri |
string |
no |
唯一资源标识符,为am 的-d 参数指定的值。 |
https://appium.io/ |
mimeType |
string |
no |
Mime 类型,为am 的-t 参数指定的值。 |
application/json |
identifier |
string |
no |
可选标识符,为am 的-i 参数指定的值。 |
my_identifier |
categories |
string 或Array<string>
|
no |
一个或多个项目名称,为am 的-c 参数指定的值。 |
android.intent.category.LAUNCHER |
component |
string |
no |
组件名称,为am 的-n 参数指定的值。 |
com.myapp/com.myapp.SplashActivity |
package |
string |
no |
包名称,为am 的-p 参数指定的值。 |
com.myapp |
extras |
Array<Array<string>> |
no |
可选intent 参数,必须表示成二维数组的形式。细节请参考官方文档
|
[['s', 'varName1', 'My String1'], ['s', 'varName2', 'My String2'], ['ia', 'arrName', '1,2,3,4']] |
flags |
string |
no |
intent 的特定启动标志,以十六进制字符串表示。具体请参考官方文档
|
0x10200000 是两个标志的组合: 0x10000000 FLAG_ACTIVITY_NEW_TASK
|
举例:
# !启动activity
def test_start_activity(start_appium_service):
custom_opts = {
"appium:avd": "testPhone",
}
driver = create_appium_session_by_api(custom_opts)
# 先安装
driver.install_app("/tmp/ContactManager.apk", grantPermissions=True)
driver.start_activity("com.example.android.contactmanager", ".ContactManager")
assert driver.current_activity == ".ContactManager"
driver.quit()
1.7 查询APP
的状态
接口参数说明:
参数名称 | 参数类型 | 参数是否必须提供 | 描述 | 举例说明 |
---|---|---|---|---|
appId |
string |
yes |
appId 是被检查的应用ID ,和package 名称一致,可以通过ADB 或者current_package 属性获取。 |
com.example.android.contactmanager |
返回值的状态说明:
0
:应用未安装
1
:应用已安装单未运行
3
:应用在后台运行
4
:应用在前台运行
举例:
# !查询APP运行状态
def test_query_app_state(start_appium_service):
custom_opts = {
"appium:avd": "testPhone",
}
driver = create_appium_session_by_api(custom_opts)
ContactManagerAppId = "com.example.android.contactmanager"
# 卸载
driver.remove_app(ContactManagerAppId)
assert driver.query_app_state(ContactManagerAppId) == 0
# 安装
driver.install_app("/tmp/ContactManager.apk", grantPermissions=True)
assert driver.query_app_state(ContactManagerAppId) == 1
# 启动
driver.start_activity(ContactManagerAppId, ".ContactManager")
assert driver.query_app_state(ContactManagerAppId) == 4
driver.quit()
1.8 后台运行APP
将APP
置于后台运行,并等待指定的时间(单位是秒),然后尝试恢复到前台运行,该调用的阻塞的,从UIAutomator
驱动2.19.0
版本开始支持。
接口参数说明:
参数名称 | 参数类型 | 参数是否必须提供 | 描述 | 举例说明 |
---|---|---|---|---|
seconds |
number |
no |
将APP 置于后台运行到恢复前台运行等待的秒数,任何负值表示将APP 置于后台运行且不恢复(也是默认行为),当使用负数的值时,调用不会阻塞,会立即返回。 |
com.example.android.contactmanager |
举例:
# !将APP置于后台运行
def test_put_app_to_background(start_appium_service):
custom_opts = {
"appium:avd": "testPhone",
}
driver = create_appium_session_by_api(custom_opts)
ContactManagerAppId = "com.example.android.contactmanager"
# 安装
driver.install_app("/tmp/ContactManager.apk", grantPermissions=True)
assert driver.query_app_state(ContactManagerAppId) == 1
# 启动
driver.start_activity(ContactManagerAppId, ".ContactManager")
assert driver.query_app_state(ContactManagerAppId) == 4
# 置于后台运行3秒
driver.background_app(3)
time.sleep(5)
# background_app接口会阻塞,超时时间到了之后会恢复到前台运行
assert driver.query_app_state(ContactManagerAppId) == 4
# 置于后台运行,负数时间,不会恢复到前台了
driver.background_app(-1)
time.sleep(10)
assert driver.query_app_state(ContactManagerAppId) == 3
driver.quit()