Appium+python自动化(二十五)- 那些让人抓耳挠腮、揪头发和掉头发的事 - 获取控件ID(超详解)

简介

  在前边的第二十二篇文章里,已经分享了通过获取控件的坐标点来获取点击事件的所需要的点击位置,那么还有没有其他方法来获取控件点击事件所需要的点击位置呢?答案是:Yes!因为在不同的大小屏幕的手机上获取控件的坐标点,不是一样的,而是有变化的,因此在不同的手机机型上,我们可能都需要重新获取坐标点,这么操作起来,如果操作控件特别的多,那么获取控件的坐标点就会显得特别的繁琐。因此我们可以通过获取控件的ID来避免获取控件坐标点的这种弊端。   通过控件ID实现自动化脚本的运行,就性能而言,会比控件坐标的实现差一些;但是对于不同分辨率的设备都通用,不需要动态变换坐标。控件ID的获取主要是通过HierarchyViewer。下面就HierarchyViewer从打开方式和使用两方面进行讲解。

HierarchyViewer的打开方式

  HierarchyViewer的打开方式有两种:一种是eclipse中打开HierarchyView视图,另外一种是命令行中执行sdk/tools/hierarchyviewer.bat。   HierarchyViewer默认只能在非加密设备使用,例如工程机,工程平板或者模拟器。如果要在手机上使用HierarchyViewer,你需要在你的应用中添加一个开源库View Server。链接地址:https://github.com/romainguy/ViewServer。该篇文章中有讲解如何启动真机View Server,大家如果有兴趣,可参考:https://dup2.org/node/1538。

方式一:

连接您的真机设备,或打开模拟器,在eclipse中, 依次选择Window-Open Perspective-Other,在Other中,选择HierarchyView视图,即可打开。

方式二:

连接您的真机设备或打开模拟器,运行cmd窗口,进入到sdk/tools目录下,输入命令hierarchyviewer.bat,运行hierarchyviewer。

或者直接在sdk/tools目录下,找到hierarchyviewer.bat,双击运行。

未开启夜神模拟器的HierarchyViewer,如下图:

开启夜神模拟器后的HierarchyViewer,如下图:

那么接下来看一下今天的重头戏:讲解利用HierarchyViewer获取控件ID的方法。

HierarchyViewer获取控件ID

  HierarchyViewer启动后,首先会看到的第一个窗口显示了设备和模拟器的列表。点击左边的箭头,就会展开当前设备或模拟器的Activity对象列表。列表中显示了设备或模拟器上,UI当前可视的所有Activity对象。这些对象按照它们的Android组件名称列出来。列表中的内容包含应用的Activity对象和系统的Activity对象。 当模拟器activity画面变更后,点击refresh可以加载新的页面布局信息。

  从列表中选择你的activity名称,双击,或点击菜单栏的Load View Hierarchy按钮,进入View Hierarchy窗口,查看它的view层次结构;或者点击Inspect Screenshot按钮,进入Pixel Perfect窗口,从而查看UI的一个放大图像。我们这里点击进入View Hierarchy窗口。 可以从下图中看到模拟器此activity的画面布局信息,左边部分是hierarchy通过树形结构展示的布局形式,右下角是模拟器上当前页面的UI布局信息。

  通过滚动鼠标,可以放大每个树节点;拖拽鼠标,移动树形结构布局。双击树节点可以展示单独的UI部分。从下图中,可以看到,id/btn_login即为登录按钮的ID。依次类推,可以查看其它控件ID。 注:对于列表、或者弹出框则无法直接通过点击ID操作成功,需要计算ID的坐标。

控件ID之Monkeyrunner脚本演示

同样的,我们将下面一段Monkeyrunner脚本写到一个test.py文件中,然后运行test.py文件,查看模拟器上是不是做相应的操作。

 1 # coding=utf-8
 2 # 1.先设置编码,utf-8可支持中英文,如上,一般放在第一行
 3 
 4 # 2.注释:包括记录创建时间,创建人,项目名称。
 5 '''
 6 Created on 2019-7-30
 7 @author: 北京-宏哥   QQ交流群:707699217
 8 Project:学习和使用appium自动化测试-获取控件的ID
 9 '''
10 # 3.导入模块
11 
12 from com.android.monkeyrunner import MonkeyRunner,MonkeyDevice
13 
14 from com.android.monkeyrunner.easy import EasyMonkeyDevice #提供了根据ID进行访问
15 
16 from com.android.monkeyrunner.easy import By #根据ID返回PyObject的方法
17 
18 device=MonkeyRunner.waitForConnection()
19 
20 #启动activity(这里启动qq)
21 
22 device.startActivity(component="com.tencent.mobileqq/.activity.SplashActivity")
23 
24 easy_device=EasyMonkeyDevice(device) #必须在activity启动之后
25 
26 #登录界面,点击账号输入框
27 
28 easy_device.touch(By.id('id/0x20e'),MonkeyDevice.DOWN_AND_UP)
29 
30 device.type('1918991791') #输入qq账号

至此,获取控件ID的方式已经介绍完,由于没有深入研究,肯定有不少功能点没有介绍到,有时间的话再做完善。

控件ID不存在或重复  

  我们在用monkeyrunner进行Android自动化时,通过获取坐标点或控件ID进行一系列操作。由于使用坐标点时,屏幕分辨率一旦更改,则代码中用到坐标的地方都要修改,这样导致代码的复用率较低。因此,我们多采用控件ID操作(注:控件ID需要在模拟器中使用,对于绝大多数真机不适用)。但是,某些控件的ID是不存在的或重复存在,那么,遇到这种情况,我们怎样继续使用控件ID进行自动化测呢?   例如,下图中,我想要获取最右侧红框中的id/tv,但是,大家会发现,和它并列的也有重复的控件id值。现在我们就讲述一下这种情况(控件ID不存在同样处理)。

  我们从这个控件树的节点角度来思考如何获得控件的引用。我们可以看到在上图hierarchy viewer中的每个控件所对应的框形中,右下角都有一个数字。其实这个数字就是该控件在同级兄弟节点中的索引值,我们知道这个索引值后,就可以根据parentView.children[index]属性来获取任意父节点所对应的子节点的对象引用。其中的parentView可以是树形图中有效ID的任意父节点(父节点要保证唯一有效),然后利用python函数的可变参数列表特性来传入所需控件的索引列表即可构造出得到任意节点引用的字符串,从而得到其引用。   核心代码如下,把如下代码加入自己的python脚本中,直接调用该函数即可。

 1 #定义获取重复或不存在控件id,寻找子节点函数
 2 def getChildView(parentId, *childSeq):
 3     hierarchyViewer = device.getHierarchyViewer()
 4     childView="hierarchyViewer.findViewById('" + parentId +"')"
 5     for index in childSeq:
 6         childView += ('.children[' + str(index) + ']')
 7     print childView
 8     return eval(childView) 
 9 
10 #获取id的文本
11 def getText(view):  
12     if view != None:           
13         return (view.namedProperties.get('text:mText').value)

有了以上代码之后,我们可以获取上图中的id/tv,方法如下:

1 getChildView('id/province_list',5,0,0)

其中结合上图可知,getChildView的第一个参数即:有效且唯一的父节点

参数二、三依次为要获取的控件ID的父节点的父节点

注:用到的父节点即图中的id/province_list,有效且唯一的值。当前的父节点右下角的角标,不需要在getChildView函数中显示。

这样,通过以上函数,再结合Hierarchyviewer图形,我们获取到了重复的控件ID。

由于Hierarchyviewer看起来不是特别方便,这里再推荐一款和Hierarchyviewer类似功能的工具:uiautomatorviewer(存储在sdk\tools中,双击打开即可)

由上图中,uiautomatorviewer每个控件前面的数字即相当于Hierarchyviewer的角标,我们同样可以获取到目标ID的最终有效且唯一的父节点,从而调用函数getChildView('id/province_list',5,0,0)

获取到了不存在或重复的控件ID后,我们可以通过其坐标,进行点击操作。

首先,定义一个“获取指定按钮坐标”的函数

1 def getBtnPoint(btn):
2     print btn
3     point = device.getHierarchyViewer().getAbsoluteCenterOfView(btn);
4     return point

然后我们可以通过坐标,实现点击操作,例如:

1 askView = getChildView('id/tabs',1)
2 askPpoint = getBtnPoint(askView)
3 device.touch(askPpoint.x,askPpoint.y,'DOWN_AND_UP')

至此,我们介绍完了处理控件ID不存在或重复时的方法,有兴趣的小伙伴或者童鞋们可以自己动手实践一把,就会更能体会Hierarchyviewer/uiautomatorviewer+getChildView()获取不存在或重复控件ID的用法、乐趣及其奥秘。

小结

一、直接在sdk>tools下面找到hierarchyviewer.bat双击运行,然后运行成功了。

但是出现这个提示:

The standalone version of hieararchyviewer is deprecated.

Please use Android Device Monitor (tools/monitor.bat) instead.

大概意思是说,单独版本的 hieararchyviewer 已经被弃用了。请使用 Android Device Monitor来代替。Android Device Monitortools目录下面找到monitor.bat即可。

为了紧跟时代潮流,就决定用Android Device Monitor启动即可。

具体操作启动步骤:

1、运行命令monitor.bat,如下图

2、运行命令后出现,如下图的界面

3、点击“Window->Open Perspective”。如图

4、按第三步操作完以后,出现如下图:

5、选择“hieararchyviewer ”,点击“OK”,即可,如下图

二、如何在真机上正常使用Hierarchy View

Hierarchy Viewer如果不进行“特殊”配置的话是无法连接真机,会报以下错误:


[hierarchyviewer]Unable to get view server version from device XXXXX

[hierarchyviewer]Unable to get view server protocol version from device XXXXXX

[ViewServerDevice]Unable to debug device: XXXXX

[hierarchyviewer]Missing forwarded port for XXXXX

[hierarchyviewer]Unable to get the focused window from device XXXXX


无法连接真机的原因是:To preserve security, Hierarchy Viewer can only connect to devices running a developer version of the Android system.出于安全性考虑, Hierarchy Viewe 只能连接开发版手机或模拟器。

Android源码实现这一限制的地方在/frameworks/base/services/core/java/com/android/server/wm/WindowManageService.java:



检验一台手机/模拟器是否开启了View Server的办法是:


adb shell service call window 3

若返回值是:Result: Parcel(00000000 00000000 '........')" 说明View Server处于关闭状态

若返回值是:Result: Parcel(00000000 00000001 '........')" 说明View Server处于开启状态


有时碰到模拟器或开发发版手机, view Hierarchy 还是无法连接,可以先使用以上方法检查一下View Server状态。如果没有开启,则使用以下命令打开View Server:


adb shell service call window 1 i32 4939

也可以使用使用以下命令关闭View Server:

adb shell service call window 2 i32 4939


那么如何在真机能够正常使用Hierarchy Viewer了?通过实践目前总结了以下三种方法:

方法一。

1,配置设备,打开手机的开发者选项

如果你的手机是android 4。0 或者以下,请根据开源项目 View Server(https://github.com/romainguy/ViewServer) 进行安装和配置

如果你的手机是4.1或以上,则必须进行以下环境变量配置:

1.点击 计算机属性-》高级系统设置-》环境变量

2.新建环境变量ANDROID_HVPROTO, 并设置其值为 ddm, 保存重启

PS:该方法参考android 官方文档《Device Setup for Hierachy Viewer》https://developer.android.com/studio/profile/hierarchy-viewer-setup.html

然而在本人亲自试用真机(魅族MX4pro android 5.1 和 android 4.4的机顶盒)测试过程中,配置环境变量的方法似乎并没有起到作用,还是连不上。

不过直接在调试app中集成View Server开源项目是没有任何问题的。

方法二:

话说前面Hierarchy Viewer只能连接Android开发版手机或是模拟器,只有ro.secure==0 && ro.debuggable==1的Android系统(这一句是其他网友的文章看到的,没有在android 官方查证到 )。ro.xxxx这种句式大家是不是觉得有点熟悉?不就是android系统的 /system/build.prop文件中的配置样式么。推测如果将ro.secure==0 && ro.debuggable==1这个两个配置添加进来应该能够起作用吧,于是进行以下尝试:

1.先把手机root

2.在进到在/system/build.prop 中添加ro.secure==0 和 ro.debuggable==1, 保存配置并重启手机,Hierarchy Viewer连接正常,终于可以正常调试了。

方法三:

参照《如何在Root的手机上开启ViewServer,使得HierachyViewer能够连接》http://maider.blog.sohu.com/255448342.html。该方法本人没有实践过,一看有18个步骤,

还涉及到 android逆向、smail,瞬间脑仁发紧,有兴趣的同学可以自行尝试一下。

三、好了,关于控件ID的获取,就分享到这里。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券