Appium+python自動化(二十五)- 那些讓人抓耳撓腮、揪頭髮和掉頭髮的事 – 獲取控制項ID(超詳解)

  • 2019 年 10 月 3 日
  • 筆記

簡介

  在前邊的第二十二篇文章里,已經分享了通過獲取控制項的坐標點來獲取點擊事件的所需要的點擊位置,那麼還有沒有其他方法來獲取控制項點擊事件所需要的點擊位置呢?答案是: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(存儲在sdktools中,雙擊打開即可)

由上圖中,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的獲取,就分享到這裡。

您的肯定就是我進步的動力。如果你感覺還不錯,就請鼓勵一下吧!記得點波 推薦 哦!!!(點擊右邊的小球即可,膽子大的可以嘗試一下哦! :)

個人公眾號

微信群