pyadb關於python操作adb的資料


3.最后adb命令由於是android的原生操作命令,支持實現的功能非常多。這里舉幾個pyapp里實現的功能例子:獲取,修改手機當前使用的輸入法(adb shell ime list),獲取當前手機界面的活動activity(adb shell dumpsys activity activities),安裝,卸載,啟動app,點擊,划屏,長按,硬件輸入,截屏等。

所以最后總結一下,這里只是說明adb命令更適合我開發pyapp測試框架,而不是說appium不好。針對只是單純的使用python開發自動化腳本的同學來說,appium更為簡單些。

1.3 python如何調用adb命令

Python中執行cmd命令可以用到os和subprocess兩個模塊。區別在於os是阻塞式的,subprocess是非阻塞式的,所以我們使用subprocess是比較適合的。接下來我先舉一個查詢連接設備的命令來看看python中怎么樣的寫法。用到的命令為 adb devices。

import subprocess

order='adb devices' #獲取連接設備

pi= subprocess.Popen(order,shell=True,stdout=subprocess.PIPE)

print pi.stdout.read() #打印結果

實際打印結果,可以看到當前電腦連接了三台設備。這里需要再說明一下adb devices 命令的結果返回是一次性的,所以我們用read方法讀取數據是沒有問題的,然而adb命令里還有一些是實時返回結果的,比如輸出手機日志的命令logcat,結果會不斷的打印出來當前的設備操作日志信息內容,這種類型的命令我們在python中如果需要獲取打印結果,如果還是用read方法的話,等待結果的返回時間會非常長,這里我們就要換一種方法讀取結果,寫法如下。

import subprocess
order='adb logcat'
pi= subprocess.Popen(order,shell=True,stdout=subprocess.PIPE)
for i in iter(pi.stdout.readline,'b'):
    print i

這樣的打印效果,如同cmd里操作一致,實時的打印出日志信息。這里我們就用到了readline方法,其實這種寫法類似我們讀取文件,單行讀取和全部內容讀取。因為目前pyapp的框架已經基本寫完了,所以有了寫這篇文章的想法,分享一些python在處理adb命令上的一些心得,就目前來看python在調用adb命令上區別主要就是這兩點,最終目的是我們找到需要的功能命令獲取結果數據,然后再去通過python處理這些返回數據,實現自動化測試的目的。大家要用好adb命令,還要注意一點的是每條命令的各種參數的搭配使用,比如pyapp的實現是支持多設備連接的,那么我們在針對某個手機進行adb命令操作時,就需要帶上-s 加設備號,表示操作的具體設備否則命令會報錯。比如我們針對一個設備去進行點擊操作,命令的寫法應該是這樣:adb -s 49dsd4554wdsa shell input tap 600 900,其中‘49dsd4554wdsa’是設備號,‘600 900’點擊屏幕坐標。所以可以看到增加了-s之后就可以很方便的同時操作多台設備。

至於adb的相關的命令,本篇文章不會再過多的介紹,因為網上有很多相關的帖子博客都有介紹adb命令的,大家可以自己查閱然后通過python去操作實現。而后續我還要將花一篇的文章的時間去介紹一下我在編寫pyapp框架時,遇到的一些adb命令需要注意的地方。可能大家在網上查閱一些adb命令后,嘗試這自己去執行一下,發現“誒,怎么不起作用?”,這里可能就要注意一些命令的參數搭配或者是自己所使用的設備具體的情況來定,因為目前市面上的安卓手機設備種類非常多,需要做一些適配。這里如果大家在每條的命令后加一句 –h 或是-help,可以查詢一下該條命令的相關使用幫助信息。比如我們在cmd中輸入 adb shell input –help,會返回命令相關的使用方法,我這里大概講解一下,大家遇到其他的命令也可以自己看明白每條命令的用法了。在Usage這行具體告訴我們input后面跟的寫法,[]中括號里的內容表示可以帶也可以不帶,<>尖括號就是必須帶上的內容。然后接下來給我們了sources的一些常見可用的用法,這里有看到trackball(軌跡球),joystick(手柄),mouse(鼠標)等等,表示模擬輸入的源硬件的意思,而最后是具體的命令,有text(輸入文本),keyevent(硬件操作),tap(點擊)等等,這里還需要注意在具體的命令后還需要跟上具體的命令參數,怎么理解呢?比如我們是要操作tap命令,點擊屏幕,那么我們肯定要告訴設備我們要點擊的位置(坐標),所以在tap后把我們點擊的坐標x,y傳進去。
1.2 那些需要注意的adb命令
1.2.1 “adb shell input ……”

這條命令,在測試過程中也是經常用到的,它后面可以跟 tap,text,swipe,進行點擊屏幕,輸入文本,滑屏的操作,具體在python中使用按照命令格式執行也不會出現什么問題。但是如果我們要長按某個元素,從而實現具體功能呢?下面給出實現代碼。
def long_press(dev,data,hold_time):
    action='adb -s '+dev+' shell input touchscreen swipe '+'%d'%data[0][0]+' '+'%d'%(data[0][1])+' '+'%d'%data[-1][0]+' '+'%d'%(data[-1][1])+' '+hold_time

    print action

    pi= subprocess.Popen(action,shell=True,stdout=subprocess.PIPE)
long_press('4d0041b1be98b01f',[[540,716],[545,718]],'1000')

可以看到我定義的long_press方法,action里用到的仍然是swipe命令,大家知道swipe是滑動屏幕的操作,那么如果我們在傳遞滑動范圍坐標的時候,設定的滑動范圍非常小,那么是不是就是間接的達到了長按某一個區域的目的,然后配合一個整個命令的執行時間的參數,是不是就完美解決了長按這個動作。

我們看一看完整的adb命令:

adb -s 4d0041b1be98b01f shell input touchscreen swipe 540 716 545 718 1000

解釋:-s 后跟設備號 ,swipe 先傳移動坐標范圍“540 716 545 718”,然后1000是長按的時間,1000的單位是毫秒(注意)。

大家不要以為這條命令就這樣介紹結束了,還沒有。按道理來說input后面的source源在swipe命令里默認就是touchscreen,所以一般我們在寫這條命令時是可以省略touchscreen的,但是實際我在編寫pyapp框架的時候(由於pyapp設計需要支持多台設備),拿了不同型號品牌(分辨率)的手機做適配,畢竟框架要照顧的范圍要必須廣要有一定的普適性。我發現,在pyapp的僚機模式下(就是一台主設備操控多台附屬設備歡迎關入群”631466916“,獲取最新pyswat和pyapp程序),主設備的長按操作在有些副設備上實現不成功,開始我也是在命令里省略了touchscreen。開始也想不到什么原因,因為命令來說也不復雜不存在寫錯的情況,畢竟有些副設備還是能正確響應動作的,后來我把shell input命令的幫助結果打印出來研究了一下(見上一篇文中有截圖),在swipe命令的參數傳遞中說明了touchscreen是缺省,默認屬性,所以正常來說我們是不用在命令中明確指定該參數值的,然而我也是瞎貓碰到死耗子,試着在命令里加入了touchscreen,最后執行結果每一台副設備在長按命令的執行上都成功了。

1.2.2 adb命令如何輸入中文?

adb命令里進行輸入文本輸入‘adb -s 設備號shell input text 輸入的內容’。在原生的adb命令里是不支持中文輸入的,所以我們在測試的時候只能輸入英文字符。然而實際我們在做app測試的時候避免不了需要輸入中文字符的情況,這里給大家介紹一種曲線救國的辦法。利用“ADBKeyBoard”輸入法來進行中文的輸入,通過廣播的方式達到輸入中文字符,具體命令:adb shell am broadcast -a ADB_INPUT_TEXT --es msg “內容”。
1.2.3 啟動應用

在appium的應用中每次只能開啟一個app,而如果用adb命令的話就靈活許多,輸入:adb shell am start –n package名/.activity名,這里的package名和activity名和appium中配置的一致。比如我們啟動計算器程序,對應的命令就是“adb shell am start -n com.android.calculator2/.Calculator”。這里要再提醒大家一點,APP的package名和activity名一定要找對特別是activity名,具體的找發大家可以參看我的《python自動化測試應用-第2篇(APP測試)--Appium初識篇》里邊講解了具體的查找方法。當然大家也是可以根據adb命令去進行查找,在pyapp測試框架中我就是根據adb命令進行名稱的查找啟動應用的。這里我講解一下思路,利用命令adb shell pm list packages -3,將手機中安裝的第三方app列舉出來,然后通過時間比對找到新安裝的app從而確定名稱。其實大家只要有了思路可以在百度中查找對應的命令即可。
1.2.4 只會發短信,那么查看短信呢?不會你就out了!

網上你可能找到如何發短信,打電話的相關adb命令的介紹,其實原理也就是1.2.3中介紹的,還是啟動對應的應用程序來實現。比如發短息:adb shell am start -a android.intent.action.SENDTO -d smsto:發送號碼 --es sms_body 短信內容。那么如何讀取一條短信內容呢?

在編寫pyapp框架的過程中為了實現app的驗證碼自動填寫功能,着實費了一番功夫。目前大部分的注冊登錄都是可以用動態短信驗證碼來進行操作的,當然app開發者本身是可以實現在收到短信后讀取驗證碼進行自動填寫,遇到沒有這種功能的app我們當然也可以按照此原理去實現。由於安卓手機的所有短信都是存儲在數據庫中,那么我們只要找到短信的這個數據庫文件,自然就可以輕松的通過python的數據庫操作讀取到短信內容了。'/data/data/com.android.providers.telephony/databases/mmssms.db'這個路徑下“mmssms.db”文件就是保存短信內容的數據庫文件,那么剩下的工作自然就是數據庫的讀操作了,用正則表達式匹配到驗證碼即可,最后通過adb的input命令寫入到app中即可。這里還需要注意的是,操作“mmssms.db”文件需要root權限,所以你要想在pyapp框架里使用這個功能必須是使用root過的手機設備。
1.2.5 adb命令su權限如何使用?

什么是adb命令的su權限,舉個簡單的例子,比如說你要訪問手機的內存/data/system路徑下的文件。在cmd命令窗中你需要執行三步:

1. 在cmd窗體中輸入命令:adb shell回車
2. 輸入su回車

可以看到命令符由$變成了#符號。

3. 輸入cd /data/system

這樣就完成了/data/system路徑的訪問,如果遇到那些需要權限的文件你沒有執行su的話,可能就會給你返回一句Permission denied(權限拒絕)。
好了,說了這么多上面都是在cmd窗口中去分步執行的,那么在python中怎么去實現呢?如果按照之前講解的方式在python腳本中分別執行這三條命令,肯定是不行的。因為程序執行一次adb命令,就會建立一個獨立的進程,所以我們在腳本中不能按順序執行三次adb命令,這樣是達不到效果的。我們必須讓一條adb命令一次完成所有的步驟的執行才對,那么我們這條命令該怎么寫呢?簡單暴力點,像這樣:adb shell su cd data\system
肯定是不行的,不過大致意思是對的,只是具體寫法上要按照正確的格式在su后面加上-c就行了。如:adb shell su –c cd “data\system”。我們看看這條命令,注意以后需要su權限的adb命令都可以這樣寫,-c后面跟着具體的操作命令即可。

1.2.6 uiautomatorviewer 和 hierarchyviewer傻傻分不清楚?

大家在做android自動化測試時,必定會需要知道界面元素/控件的相關屬性,如id,class等,這時在androidsdk的tool工具中就會用到uiautomatorviewer 和 hierarchyviewer。這兩個工具都可以很直觀的方便大家去查找界面元素,而這樣只是單純的人工借助工具去查看,既然是要做自動化測試,必然我們要去通過代碼編程去代替手工操作了。在pyapp框架中,我也是利用uiautomatorviewer來捕獲app界面的從而獲取對應的元素/控件。接下來我們就來看看python是如何做到的。相對來說uiautomatorviewer的實現更容易些,一條adb命令就可以了。
order='adb -s device shell uiautomator dump'
運行成功后會返回:
“UI hierchary dumped to: /storage/emulated/legacy/window_dump.xml“
結果很直觀了,這個window_dump.xml里就是整個界面的布局層級信息,從中我們就可以獲取到各個元素/控件的屬性信息。如果利用瀏覽器打開xml文件大家也可以直觀的看到界面的層級關系,如果大家只關心具體的元素控件,我們可以在命令后面加上—compressed,這樣獲取的xml就會清爽許多。
我們接着看看怎么在python中利用hierarchyviewer實現元素/控件獲取,首先我們要知道要實現hierarchyviewer的元素獲取我們要打開手機的View Server服務,並與其進行socket通信,從而獲取到元素/控件信息。那么接下來我們將通過幾條不同的adb命令來准備好與View Server進行通信的環境。
第一步:
通過“adb shell service call window 3”命令得到返回值Result: Parcel(00000000 00000001   '........')或者Result: Parcel(00000000 00000000   '........')如果是00000001表示View Server是開啟的,反之我們就要開啟View Server服務。

第二步:
如果View Server沒有打開,我們就通過“adb shell service call window 1 i32 4939”命令打開。然后再通過第一步的命令確認是否開啟了View Server。
第三步:

當我們開啟了服務后,需要再將手機的4939端口映射到電腦的4939端口,這樣就可以進行socket通信了。命令為“adb forward tcp:4939 tcp:4939”
以上這三步完成后,接下來我們就可以在python腳本中與View Server建立socket通信了。由於已經有服務端View Server,我們只需要用python實現客戶端的socket代碼即可。
import socket#導入socket模塊
sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#建立TCP連接
sock.connect(('127.0.0.1',4939))#連接服務端地址及端口並建立連接
sock.send('list')#發送list命令向服務端
sock.recv(1024)#接收返回結果

這里就不去講解python的socket用法了,重點講解一下這里的list指令。當我們建立好與View Server的通信后,就可以發送不同的指令向服務端,獲取信息了,這里的list意思就是獲取當前手機活動界面的信息。如下圖
有了這個信息,我們就可以繼續發送dump命令去獲取具體某個界面的詳細層級信息了。舉個例子比如我們要打印出上圖中第二行
“432b8608 com.miui.home/com.miui.home.launcher.Launcher”
的界面信息,在我們發送內容中應該這樣寫sock.send(“dump 432b8608”),獲取結果如下圖。由於內容會比較多,建議大家在代碼中將返回值寫入txt文件中,方便查看。具體的內容中每一段表示一個元素,里邊詳細的列舉了元素的各種屬性信息,如id,class,坐標等。
至此,我們了解到通過發送list,dump兩個命令可以進行元素信息的獲取。另外還有一個capture命令可以獲取到元素在界面中的截圖,這里就不再贅述了。至於到底是用uiautomatorviewer 還是 hierarchyviewer去實現元素的獲取,決定權就在你的手上了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM