1. 程式人生 > >Appium+python自動化(二十五)- 那些讓人抓耳撓腮、揪頭髮和掉頭髮的事 - 獲取控制元件ID(超詳解)

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 Monitor在tools目錄下面找到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的獲取,就分享到這裡。

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

個人公眾號

微信群