Appium UiAutomator2驱动:平台相关的mobile扩展介绍之APP管理

除了标准的W3C API接口,Uiautomator2还提供了一系列扩展接口来支持Android平台相关的操作。本文所有测试代码的前提是已经安装Appium和相关环境(例如JDKAndroid SDKAVD模拟器),可以参考Appium环境搭建

应用程序(APP)管理

1.1 检查被测应用是否已经安装

接口参数说明:

参数名称 参数类型 参数是否必须提供 描述 举例说明
appId string yes appId是待检测的应用ID,和package名称一致,可以通过ADB或者current_package属性获取。 com.example.android.contactmanager

接口返回值:TrueFalse

举例:

# -*- 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必须大于等于23Android版本需要6API 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指定appIdactivity来启动应用。

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 启动APPactivityAndroid应用的activity参考关于intentactivity的简介

接口参数说明:

参数名称 参数类型 参数是否必须提供 描述 举例说明
intent string yes 待启动activity的全称。 com.example.android.contactmanager/.ContactManager
user numberstring 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 动作名称,为amActivity 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 stringArray<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()
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,504评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,434评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,089评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,378评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,472评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,506评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,519评论 3 413
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,292评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,738评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,022评论 2 329
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,194评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,873评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,536评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,162评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,413评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,075评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,080评论 2 352

推荐阅读更多精彩内容