Appium 选择 APP 界面元素

4.1 查看工具

Web 自动化开发的时候,要找到元素,我们是通过浏览器的开发者工具栏来查看元素的特性,根据这些特性,比如:id、classname、tagname,或者 cssxpath 选择到元素。那么安卓的移动 app 我们怎么查看元素呢?安卓查看页面元素,最常用的就是 Android SDK 中的 uiautomateviewer,我的目录在 .\tools\tools\bin 下面。

image.png

双击打开,然后手机打开要查看app的界面,然后点击

image.png

它就会到当前连接手机的设备上去获取,当前界面的信息。


image.png

然后我们就可以去查看了。uiautomatorviewer 查看的是手机当前界面的元素,我们可以点击手机的界面,进入到不同的界面,查看我们要查看界面的元素。进入到一个新界面的时候,需要再次点击按钮。和 web 不同,它不能自动刷新,需要我们手动点击重新获取当前界面。我们要查找某个元素,可以把鼠标移动到某个元素上,某个元素就有虚线红框子,同时右边会高亮当前的元素,如果确定了要查看的元素,就点击一下该元素,虚线变成实线,就是确定了查看这个元素的信息。同时,右边下面就显示出该元素的具体的属性信息,这时候再异动鼠标就不会根据经过的元素而变化了。它认为已经确定了要看的元素了。如果我们想再次查看别的元素,就需要随便点击一下界面某个地方,实线又变成虚线。就可以再次移动选择别的元素,确定下来就点击它。

可能还有人看到了整个按钮。


image.png

它也可以获取当前界面的信息,它获取的相对来说是一个精简的目录数,它把中间一些没有具体信息的层次会去掉。比如:


image.png

它就比刚才精简了好多,去掉一些没有包含实际信息的层次的信息,通常还是用前面方法的多。

下面介绍一些元素的属性:

  • index: 就是该元素是其父元素的第几个子节点(从0开始)。
  • text: 就是如果该元素对应的界面上有文本内容,就是其文本内容的字符串值。显然这是我们将来非常关心的属性,因为可能要分析内容,判断是否与预期相等。
  • resource-id: 是该元素的资源 id,一般来说唯一的决定了一个元素,有点像 webid
  • class: 就是该元素的类型,类似 htmltag
  • package: 就是所在 app 的包名。
  • content-desc: 这个属性用来描述该元素的用途,特性等。
  • bounds: 就是这个元素在界面上的位置,左下角和右小角的坐标。这个属性也很重要,以后如果我们黔驴技穷,是在选择不到元素的时候,就根据这个属性直接去根据坐标操作元素了。

对于 bounds 看下面截图,一目了然

image.png

注意:是像素

4.2 选择元素的代码

选择元素的代码也和 Selenium 本相同,可以通过:

  • find_element_by_XXX 符合条件的第一个元素,找不到这样的元素,会抛出异常。
  • find_elements_by_XXX 符合条件的所有元素的列表,找不到会返回空列表。
  • 通过 WebDriver 对象调用这样的方法。查找范围是整个界面树形结构。
  • 通过 WebElement 对象调用这样的方法,查找范围是该元素的子节点。

4.3 选择元素的方式

4.3.1 ID

我们在学习 Web 自动化的时候就说过,能根据 id 最好根据 id,因为是唯一的,效率高、表达式又简单,在安卓应用自动化的时候,同样可以根据 id 查找,但是这个 id 其实安卓应用元素的 resource id 属性,比如上个章节代码中的:

# 根据id找到元素,并点击
driver.find_element_by_id("io.manong.developerdaily:id/tab_bar_plus").click()
image.png

注意这里io.manong.developerdaily:id/tab_bar_plus这里的 id 可以写全,也可以 :id/ 后面的内容就是 driver.find_element_by_id("tab_bar_plus").click() 。光有 id 去选择元素是远远不够的,有很多元素没有 id,也有很多 id 根据规范是唯一的,但是它不唯一,比如我们看一下开发者头条消息id

image.png

我们再看发现id

image.png

是不是也叫 tv_tab_title ,点击我的它的 id 也是一样的。所以下面四个id 都是一样的。由于开发人员的疏忽。如果有这种错误的话,我们就不能通过 id 定位了。就要通过一些其它的方式。有的人会问我们怎么知道 id 是不是唯一的,以前做 web 自动化的时候我们可以按 F12 然后 Ctrl + F 一系列操作可以验证。我们在这里面要怎么验证呢?很遗憾它这里面就没有查询框了。一种方式就是根据名字来判断,通常 id 跟它的名字如果形成了一种直接的对应关系,通常就是唯一的,可以根据一种直觉,比如这个 idtv_tab_titletabtitile 名,但是你想想下面几个元素全是 tab 。这个时候就要小心了。这个只是一种猜测法还有一种唯一确认的方法,就是把整个界面对应的 xml 文档全部导出来查看一下,怎么导出呢,看截图

image.png

选择保存路径。


image.png

然后去路径里查看,会发现有两个文件。


image.png

第一个 dump 是它所对应的图片,整个不关心,我们关心的是第二个我们可以用 Notepad++ 打开。之后把要查找的 id 复制按 Ctrl + F 点击计数。

image.png

这里显示4次匹配,怀疑它不是唯一的。可以通过这种方式来确定是不是唯一,有些麻烦。

4.3.2 Class Name

class 属性决定了界面元素的类型。 通常 class 就是类似 web 里面 tagname, 所以通常不是唯一的。所以大部分情况,我们根据 classname 是要选择多个而不是一个。如果你确定,我们要查找的是某种类型的界面元素,而且这种类型的界面元素在当前界面中只有一个,就可以根据它来查找写法是:

driver.find_element_by_class_name('XXX')

大家看一个例子:开发者头条里面的 底部的大加号 android.widget.ImageButton ,这个在当前界面上就是一个唯一的,我们可以根据它查找。

image.png

代码是:

driver.find_element_by_class_name("android.widget.ImageButton").click()

有的时候,我们需要根据 classname 查找所有匹配的元素,这时候可以用:

driver.find_elements_by_class_name("XXX")

比如我们要获取界面上所有的 TextView 里面的文本内容,就可以写出如下代码:

tvs = driver.find_elements_by_class_name("android.widget.TextView")
for tv in tvs:
    print(tv.text)

4.3.3 content-desc

content-desc 属性时用来描述该元素的作用的。 要查询的界面元素的 content-desc 属性在当前界面中唯一我们可以通过它来定位。

image.png

它的 content-desc 有个 unique name 的,唯一的姓名,如果它有值,并且这个值它在当前这个 content-desc 属性里面它是唯一的,就可以根据这个值来选择,根据 content-desc 来选择的写法如下。

driver.find_element_by_accessibility_id('xxx')

不幸的是,基本上开发人员都不喜欢填写它。


1. 到如下网址下载 多多计算器
http://android.myapp.com/myapp/detail.htm?apkName=com.ibox.calculators&ADTAG=mobile

2.aapt.exe 命令查看 apk 包的 appPackage 信息和主 Activity 信息
3.UIAutomator Viewer 查看应用界面元素信息
4. 编写 python 程序,完成一个 计算 3+9 ,结果 再乘以 5 的自动化功能. 最后判断计算结果是否为 60,如果是,测试通过;否则测试不通过

示例代码:

from appium import webdriver
import time,traceback

desired_caps = {}
desired_caps['platformName'] = 'Android'
desired_caps['platformVersion'] = '7'
desired_caps['deviceName'] = 'test'
desired_caps['app'] = r'E:\tools\com.ibox.calculators_3.0.5_1305.apk'
desired_caps['appPackage'] = 'com.ibox.calculators'
desired_caps['appActivity'] = 'com.ibox.calculators.SplashActivity'
#desired_caps['unicodeKeyboard']  = True
desired_caps['noReset'] = True
desired_caps['newCommandTimeout'] = 6000
#启动Remote RPC
driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
driver.implicitly_wait(10)

try:
    # -----------------


    num3 = driver.find_element_by_id("com.ibox.calculators:id/digit3")
    num5 = driver.find_element_by_id("com.ibox.calculators:id/digit5")
    num9 = driver.find_element_by_id("com.ibox.calculators:id/digit9")
    plus = driver.find_element_by_id("com.ibox.calculators:id/plus")
    mul = driver.find_element_by_id("com.ibox.calculators:id/mul")
    equal = driver.find_element_by_id("com.ibox.calculators:id/equal")

    num3.click()
    plus.click()
    num9.click()
    equal.click()
    mul.click()
    num5.click()
    equal.click()


    # 检查结果,需要我们去找结果对应的界面元素,发现是下面这个TextView
    # 研究发现没有特点,大家想想我们该怎么办
    # 可以看看父节点有没有唯一标识,发现 父节点是有id的,
    # 就可以怎么样?
    # 先查找父节点,
    # 再根据父节点元素 调用 find element 就是在父节点的范围内 查找
    retLayout = driver.find_element_by_id('com.ibox.calculators:id/cv')
    retTvs = retLayout.find_elements_by_class_name('android.widget.TextView')
    retStr = retTvs[1].text
    print(retStr)

    if retStr == '60':
        print('pass')
    else:
        print('fail')


        # -----------------

except:
    print(traceback.format_exc())

input('**** Press to quit..')
driver.quit()
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,084评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,623评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,450评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,322评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,370评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,274评论 1 300
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,126评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,980评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,414评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,599评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,773评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,470评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,080评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,713评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,852评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,865评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,689评论 2 354

推荐阅读更多精彩内容

  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,404评论 0 17
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,098评论 1 32
  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5? 答:HTML5是最新的HTML标准。 注意:讲述HT...
    kismetajun阅读 27,476评论 1 45
  • 问答题47 /72 常见浏览器兼容性问题与解决方案? 参考答案 (1)浏览器兼容问题一:不同浏览器的标签默认的外补...
    _Yfling阅读 13,751评论 1 92
  • 火车轰隆隆,我一直从午夜看到黎明,然后太阳升起。 一夜的火车,从一个陌生的城市到另一个陌生的城市,车厢里没有一个熟...
    枝小花阅读 291评论 0 1