1. 程式人生 > 實用技巧 >乾貨|一文搞定 uiautomator2 自動化測試工具使用

乾貨|一文搞定 uiautomator2 自動化測試工具使用

一、背景簡介

Google 官方提供了一個 Android 自動化測試工具(Java 庫),基於 Accessibility 服務,功能很強,可以對第三方 App 進行測試,獲取螢幕上任意一個 App 的任意一個控制元件屬性,並對其進行任意操作,但有兩個缺點:

  1. 測試指令碼只能使用 Java 語言;
  2. 測試指令碼要打包成 jar 或者 apk 包上傳到裝置上才能執行;

實際工作中,我們希望測試邏輯能夠用 Python 編寫,能夠在電腦上執行的時候就控制手機。所以基於這個目的開發了 python-uiautomator2 自動化測試開源工具,其封裝了谷歌自帶的 uiautomator2 測試框架,可以執行在支援 Python 的任一系統上,目前版本為 V2.10.2。

GitHub 開源地址:

https://github.com/openatx/uiautomator2

二、工作原理

如圖所示,python-uiautomator2 主要分為兩個部分,python 客戶端,移動裝置

  • python 端: 執行指令碼,並向移動裝置傳送 HTTP 請求;
  • 移動裝置:移動裝置上運行了封裝了 uiautomator2 的 HTTP 服務,解析收到的請求,並轉化成 uiautomator2 的程式碼;

整個過程:

  1. 在移動裝置上安裝 atx-agent(守護程序),隨後 atx-agent 啟動 uiautomator2 服務(預設 7912 埠)進行監聽;
  2. 在 PC 上編寫測試指令碼並執行(相當於傳送 HTTP 請求到移動裝置的 server 端);
  3. 移動裝置通過 WIFI 或 USB 接收到 PC 上發來的 HTTP 請求,執行制定的操作;

三、安裝與啟動

3.1 安裝 uiautomator2

使用 pip 安裝

pip install -U uiautomator2

安裝完成後,使用如下 python 程式碼檢視環境是事配置成功

說明:後文中所有程式碼都需要匯入 uiautomator2 庫,為了簡化我使用 u2 代替,d 代表 driver

import uiautomator2 as u2# 連線並啟動d = u2.connect() print(d.info)

能正確打印出裝置的資訊則表示安裝成功

注意:需要安裝 adb 工具,並配置到系統環境變數,才能操作手機。

安裝有問題可以到 issue 列表查詢:

https://github.com/openatx/uiautomator2/wiki/Common-issues

3.2 安裝 weditor

weditor 是一款基於瀏覽器的 UI 檢視器,用來幫助我們檢視 UI 元素定位。

因為 uiautomator 是獨佔資源,所以當 atx 執行的時候 uiautomatorviewer 是不能用的,為了減少 atx 頻繁的啟停,就需要用到此工具

使用 pip 安裝

pip install -U weditor

  檢視安裝是否成功

weditor --help

  出現如下資訊表示安裝成功

執行 weditor

python -m weditor#或者直接在命令列執行weditor

  

四、元素定位

4.1 使用方法

d(定位方式 = 定位值)#例:element = d(text='Phone')#這裡返回的是一個列表,當沒找到元素時,不會報錯,只會返回一個長度為 0 的列表#當找到多個元素時,會返回多個元素的列表,需要加下標再定位element[0].click()#獲取元素個數print(element.count)

  

4.2 支援的定位方式

ui2 支援 android 中 UiSelector 類中的所有定位方式,詳細可以在這個網址檢視 developer.android.com/reference/a…

整體內容如下 , 所有的屬性可以通過 weditor 檢視到

名稱描述

texttext 是指定文字的元素textContainstext 中包含有指定文字的元素textMatchestext 符合指定正則的元素textStartsWithtext 以指定文字開頭的元素classNameclassName 是指定類名的元素classNameMatchesclassName 類名符合指定正則的元素descriptiondescription 是指定文字的元素descriptionContainsdescription 中包含有指定文字的元素descriptionMatchesdescription 符合指定正則的元素descriptionStartsWithdescription 以指定文字開頭的元素checkable可檢查的元素,引數為 True,Falsechecked已選中的元素,通常用於複選框,引數為 True,Falseclickable可點選的元素,引數為 True,FalselongClickable可長按的元素,引數為 True,Falsescrollable可滾動的元素,引數為 True,Falseenabled已啟用的元素,引數為 True,Falsefocusable可聚焦的元素,引數為 True,Falsefocused獲得了焦點的元素,引數為 True,Falseselected當前選中的元素,引數為 True,FalsepackageNamepackageName 為指定包名的元素packageNameMatchespackageName 為符合正則的元素resourceIdresourceId 為指定內容的元素resourceIdMatchesresourceId 為符合指定正則的元素

4.3 子元素和兄弟定位

子**元素定位**

child()

#查詢類名為 android.widget.ListView 下的 Bluetooth 元素d(className="android.widget.ListView").child(text="Bluetooth")# 下面這兩種方式定位有點不準確,不建議使用d(className="android.widget.ListView")\.child_by_text("Bluetooth",allow_scroll_search=True)d(className="android.widget.ListView").child_by_description("Bluetooth")

  

兄弟元素定位

sibling()

#查詢與 google 同一級別,類名為 android.widget.ImageView 的元素d(text="Google").sibling(className="android.widget.ImageView")

  

鏈式呼叫

d(className="android.widget.ListView", resourceId="android:id/list") \  .child_by_text("Wi‑Fi", className="android.widget.LinearLayout") \  .child(className="android.widget.Switch") \  .click()

  

4.4 相對定位

相對定位支援在left, right, top, bottom, 即在某個元素的前後左右

d(A).left(B),# 選擇 A 左邊的 Bd(A).right(B),# 選擇 A 右邊的 Bd(A).up(B), #選擇 A 上邊的 Bd(A).down(B),# 選擇 A 下邊的 B#選擇 WIFI 右邊的開關按鈕d(text='Wi‑Fi').right(resourceId='android:id/widget_frame')

  

4.5 元素常用 API

表格標註有 @property 裝飾的類屬性方法,均為下方示例方式

d(test="Settings").exists

  

方法

描述返回值備註

exists()判斷元素是否存在True,Flase@propertyinfo()返回元素的所有資訊字典@propertyget_text()返回元素文字字串

set_text(text)設定元素文字None

clear_text()清空元素文字None

center()返回元素的中心點位置(x,y)基於整個螢幕的點

exists 其它使用方法:

d.exists(text='Wi‑Fi',timeout=5)

  info() 輸出資訊:

{  "bounds": {    "bottom": 407,    "left": 216,    "right": 323,    "top": 342  },  "childCount": 0,  "className": "android.widget.TextView",  "contentDescription": null,  "packageName": "com.android.settings",  "resourceName": "android:id/title",  "text": "Wi‑Fi",  "visibleBounds": {    "bottom": 407,    "left": 216,    "right": 323,    "top": 342  },  "checkable": false,  "checked": false,  "clickable": false,  "enabled": true,  "focusable": false,  "focused": false,  "longClickable": false,  "scrollable": false,  "selected": false}

  

可以通過上方資訊分別獲取元素的所有屬性

4.6 XPATH 定位

因為 Java uiautoamtor 中預設是不支援 xpath,這是屬於 ui2 的擴充套件功能,速度會相比其它定位方式慢一些

在 xpath 定位中,ui2 中的 description 定位需要替換為 content-desc,resourceId 需要替換為 resource-id

使用方法

# 只會返回一個元素,如果找不到元素,則會報 XPathElementNotFoundError 錯誤# 如果找到多個元素,預設會返回第 0 個d.xpath('//*[@resource-id="com.android.launcher3:id/icon"]')# 如果返回的元素有多個,需要使用 all() 方法返回列表# 使用 all 方法,當未找到元素時,不會報錯,會返回一個空列表d.xpath('//*[@resource-id="com.android.launcher3:id/icon"]').all()

  

五、裝置互動

5.1 單擊

d(text='Settings').click()#單擊直到元素消失 , 超時時間 10,點選間隔 1d(text='Settings').click_gone(maxretry=10, interval=1.0)

  

5.2 長按

d(text='Settings').long_click()

  

5.3 拖動

Android<4.3 時不能使用拖動

# 在 0.25S 內將 Setting 拖動至 Clock 上,拖動元素的中心位置# duration 預設為 0.5, 實際拖動的時間會比設定的要高d(text="Settings").drag_to(text="Clock", duration=0.25)# 拖動 settings 到螢幕的某個點上d(text="Settings").drag_to(877,733, duration=0.25)#兩個點之間的拖動 , 從點 1 拖動至點 2d.drag(x1,y1,x2,y2)

  

5.4 滑動

滑動有兩個,一個是在 driver 上操作,一個是在元素上操作

元素上操作

從元素的中心向元素邊緣滑動

# 在 Setings 上向上滑動。steps 預設為 10# 1 步約為 5 毫秒,因此 20 步約為 0.1 sd(text="Settings").swipe("up", steps=20) 

  

driver 上操作

即對整個螢幕操作

# 實現下滑操作x,y = d.window_size()x1 = x / 2y1 = y * 0.1y2 = y * 0.9d.swipe(x1,y1,x1,y2)

  driver 滑動的擴充套件方法,可以直接實現滑動,不需要再自己封裝定位點

# 支援前後左右的滑動# "left", "right", "up", "down"# 下滑操作d.swipe_ext("down")

  

5.5 雙指操作

android>4.3

對元素操作

d(text='Settings').gesture(start1,start2,end1,end2,)# 放大操作d(text='Settings').gesture((525,960),(613,1121),(135,622),(882,1540))

  封裝好的放大縮小操作

# 縮小d(text="Settings").pinch_in()# 放大d(text="Settings").pinch_out()

  

5.6 等待元素出現或者消失

# 等待元素出現d(text="Settings").wait(timeout=3.0)# 等待元素消失,返回 True False,timout 預設為全域性設定的等待時間d(text='Settings').wait_gone(timeout=20)

  

5.7 滾動介面

設定 scrollable 屬性為 True;

滾動型別:horiz 為水平,vert 為垂直;

滾動方向:

  • forward 向前
  • backward 向後
  • toBeginning 滾動至開始
  • toEnd 滾動至最後
  • to 滾動直接某個元素出現

所有方法均返回 Bool 值;

# 垂直滾動到頁面頂部 / 橫向滾動到最左側d(scrollable=True).scroll.toBeginning()d(scrollable=True).scroll.horiz.toBeginning()# 垂直滾動到頁面最底部 / 橫向滾動到最右側d(scrollable=True).scroll.toEnd()d(scrollable=True).scroll.horiz.toEnd()# 垂直向後滾動到指定位置 / 橫向向右滾動到指定位置d(scrollable=True).scroll.to(description=" 指定位置 ")d(scrollable=True).scroll.horiz.to(description=" 指定位置 ")# 垂直向前滾動(橫向同理)d(scrollable=True).scroll.forward()# 垂直向前滾動到指定位置(橫向同理)d(scrollable=True).scroll.forward.to(description=" 指定位置 ")# 滾動直到 System 元素出現d(scrollable=True).scroll.to(text="System")

Take screenshot of widgetim = d(text="Settings").screenshot()im.save("settings.jpg")

  

5.8 輸入

5.8.1 輸入自定義文字

# 使用 adb 廣播的方式輸入d.send_keys('hello')# 清空輸入框d.clear_text()

  

5.8.2 輸入按鍵

兩種方法

# 傳送回車d.press('enter')# 第二種d.keyevent('enter')

  目前 press 支援的按鍵如下

"""        press key via name or key code. Supported key name includes:            home, back, left, right, up, down, center, menu, search, enter,            delete(or del), recent(recent apps), volume_up, volume_down,            volume_mute, camera, power.        """

  

keyevent 是通過 “adb shell input keyevent” 方式輸入,支援按鍵更加豐富

更多詳細的按鍵資訊 developer.android.com/reference/a…

5.8.3 輸入法切換

# 切換成 ui2 的輸入法,這裡會隱藏掉系統原本的輸入法 , 預設是使用系統輸入法# 當傳入 False 時會使用系統預設輸入法,預設為 Fasled.set_fastinput_ime(True)# 檢視當前輸入法d.current_ime()#返回值('com.github.uiautomator/.FastInputIME', True)

  

5.8.4 模擬輸入法功能

可以模擬的功能有 go ,search ,send ,next, done ,previous。

如果使用 press 輸入按鍵無效,可以嘗試使用此方法輸入

# 搜尋功能d.send_action("search")

  

5.9 toast 操作

# 獲取 toast, 當沒有找到 toast 訊息時,返回 default 內容d.toast.get_message(timout=5,default='no toast')# 清空 toast 快取d.toast.reset()

  

5.10 監控介面

使用 wather 進行介面的監控,可以用來實現跳過測試過程中的彈框

當啟動 wather 時,會新建一個執行緒進行監控

可以新增多個 watcher

用法

# 註冊監控 , 當介面內出現有 allow 字樣時,點選 allowd.watcher.when('allow').click()# 移除 allow 的監控d.watcher.remove("allow")# 移除所有的監控d.watcher.remove()# 開始後臺監控d.watcher.start()d.watcher.start(2.0) # 預設監控間隔 2.0s# 強制執行所有監控d.watcher.run()# 停止監控d.watcher.stop()# 停止並移除所有的監控,常用於初始化d.watcher.reset()

  2.11.0 版本新增了一個 watch_context 方法 , 寫法相比 watcher 更簡潔,官方推薦使用此方法來實現監控,目前只支援 click() 這一種方法。

wct = d.watch_context()# 監控 ALLOWwct.when("ALLOW").click()# 監控 OKwct.when('OK').click() # 開啟彈窗監控,並等待介面穩定(兩個彈窗檢查週期內沒有彈窗代表穩定)wct.wait_stable()#其它實現程式碼# 停止監控wct.stop()

  

5.11 多點滑動

這裡可以用來實現圖案解鎖

使用 touch 類

# 模擬按下不放手touch.down(x,y)# 停住 3Stouch.sleep(x,y)# 模擬移動touch.move(x,y)# 模擬放開touch.up(x,y)#實現長按 , 同一個點按下休眠 5S 後抬起d.touch.down(252,1151).sleep(5).up(252,1151)# 實現四點的圖案解鎖,目前只支援座標點d.touch.down(252,1151).move(559,1431).move(804,1674).move(558,1666).up(558,1666)

  

六、影象操作

6.1 截圖

d.screenshot('test.png')

  

6.2 錄製視訊

這個感覺是比較有用的一個功能,可以在測試用例開始時錄製,結束時停止錄製,然後如果測試 fail。則上傳到測試報告,完美復原操作現場,具體原理後面再去研究。

首先需要下載依賴,官方推薦使用映象下載:

pip3 install -U "uiautomator2[image]" -i https://pypi.doubanio.com/simple

  執行錄製:

# 啟動錄製,預設幀率為 20d.screenrecord('test.mp4')# 其它操作time.sleep(10)#停止錄製,只有停止錄製了才能看到視訊 d.screenrecord.stop()

  

6.3 圖片識別點選

下載與錄製視訊同一套依賴。

這個功能是首先手動擷取需要點選目標的圖片,然後 ui2 在介面中去匹配這個圖片,目前我嘗試了精確試不是很高,誤點率非常高,不建議使用。

# 點選 d.image.click('test.png')# 匹配圖片,返回相似度和座標# {'similarity': 0.9314796328544617, 'point': [99, 630]}d.image.match('test.png')

  

七、應用管理

7.1 獲取當前介面的 APP 資訊

d.app_current()#返回當前介面的包名,activity 及 pid{    "package": "com.xueqiu.android",    "activity": ".common.MainActivity",    "pid": 23007}

  

7.2 安裝應用

可以從本地路徑及 url 下載安裝 APP,此方法無返回值,當安裝失敗時,會丟擲 RuntimeError 異常

# 本地路徑安裝 d.app_install('test.apk')# url 安裝 d.app_install('http://s.toutiao.com/UsMYE/')

  

7.3 執行應用

預設當應用在執行狀態執行 start 時不會關閉應用,而是繼續保持當前介面。

如果需要消除前面的啟動狀態,則需要加 stop=True 引數。

# 通過包名啟動d.app_start("com.xueqiu.android",stop=True)#原始碼說明    def app_start(self, package_name: str,                   activity: Optional[str]=None,                   wait: bool = False,                   stop: bool=False,                   use_monkey: bool=False):        """ Launch application        Args:            package_name (str): package name            activity (str): app activity            stop (bool): Stop app before starting the activity. (require activity)            use_monkey (bool): use monkey command to start app when activity is not given            wait (bool): wait until app started. default False        """

  

7.4 停止應用

stop 和 clear 的區別是結束應用使用的命令不同

stop 使用的是 “am force-stop”

clear 使用的是 “pm clear”

# 通過包名結束單個應用d.app_stop("com.xueqiu.android")d.app_clear('com.xueqiu.android')# 結束所有應用 , 除了 excludes 引數列表中的應用包名# 如果不傳參,則會只保留兩個依賴服務應用# 會返回一個結束應用的包名列表d.app_stop_all(excludes=['com.xueqiu.android'])

 

7.5 獲取應用資訊

 

d.app_info('com.xueqiu.android')#輸出{    "packageName": "com.xueqiu.android",    "mainActivity": "com.xueqiu.android.common.splash.SplashActivity",    "label": " 雪球 ",    "versionName": "12.6.1",    "versionCode": 257,    "size": 72597243}

  

7.6 獲取應用圖示

img = d.app_icon('com.xueqiu.android')img.save('icon.png')

  

7.7 等待應用啟動

# 等待此應用變為當前應用,返回 pid,超時未啟動成功則返回 0# front 為 true 表示等待 app 成為當前 app,# 預設為 false,表示只要後臺有這個應用的程序就會返回 PIDd.app_wait('com.xueqiu.android',60,front=True)

  

7.8 解除安裝應用

# 解除安裝成功返回 true, 沒有此包或者解除安裝失敗返回 Falsed.app_uninstall('com.xueqiu.android')# 解除安裝所有自己安裝的第三方應用 , 返回解除安裝 app 的包名列表# excludes 表示不解除安裝的列表# verbose 為 true 則會列印解除安裝資訊d.app_uninstall_all(excludes=[],verbose=True)

  解除安裝全部應用返回的包名列表並一定是解除安裝成功了,最好使用 verbose=true 列印一下資訊,這樣可以檢視到是否解除安裝成功

uninstalling com.xueqiu.android  OKuninstalling com.android.cts.verifier  FAIL

  或者可以修改一下原始碼,使其只輸出成功的包名,註釋的為增加的程式碼,未註釋的是原始碼

def app_uninstall_all(self, excludes=[], verbose=False):        """ Uninstall all apps """        our_apps = ['com.github.uiautomator', 'com.github.uiautomator.test']        output, _ = self.shell(['pm', 'list', 'packages', '-3'])        pkgs = re.findall(r'package:([^\s]+)', output)        pkgs = set(pkgs).difference(our_apps + excludes)        pkgs = list(pkgs)        # 增加一個解除安裝成功的列表        #sucess_list = []        for pkg_name in pkgs:            if verbose:                print("uninstalling", pkg_name, " ", end="", flush=True)            ok = self.app_uninstall(pkg_name)            if verbose:                print("OK" if ok else "FAIL")                # 增加如下語句,當成功則將包名加入 list                #if ok:                 #   sucess_list.append(pkg_name)     # 返回成功的列表    #    return sucess_list        return pkgs

  

八、其它實用方法

8.1 連線裝置

#當 PC 只連線了一個裝置時,可以使用此種方式d = u2.connect()#返回的是 Device 類 , 此類繼承方式如下class Device(_Device, _AppMixIn, _PluginMixIn, _InputMethodMixIn, _DeprecatedMixIn):    """ Device object """# for compatible with old codeSession = Device

  connect() 可以使用如下其它方式進行連線

#當 PC 與裝置在同一網段時,可以使用 IP 地址和埠號通過 WIFI 連線,無需連線 USB 線connect("10.0.0.1:7912")connect("10.0.0.1") # use default 7912 portconnect("http://10.0.0.1")connect("http://10.0.0.1:7912")#多個裝置時,使用裝置號指定哪一個裝置connect("cff1123ea")  # adb device serial number

  

8.2 獲取裝置及 driver 資訊

8.2.1 獲取 driver 資訊

d.info#輸出{    "currentPackageName": "com.android.systemui",    "displayHeight": 2097,    "displayRotation": 0,    "displaySizeDpX": 360,    "displaySizeDpY": 780,    "displayWidth": 1080,    "productName": "freedom_turbo_XL",    "screenOn": true,    "sdkInt": 29,    "naturalOrientation": true}

  

8.2.2 獲取裝置資訊

會輸出測試裝置的所有資訊,包括電池,CPU,記憶體等

d.device_info#輸出{    "udid": "61c90e6a-ba:1b:ba:46:91:0e-freedom_turbo_XL",    "version": "10",    "serial": "61c90e6a",    "brand": "Schok",    "model": "freedom turbo XL",    "hwaddr": "ba:1b:ba:46:91:0e",    "port": 7912,    "sdk": 29,    "agentVersion": "0.9.4",    "display": {        "width": 1080,        "height": 2340    },    "battery": {        "acPowered": false,        "usbPowered": true,        "wirelessPowered": false,        "status": 2,        "health": 2,        "present": true,        "level": 98,        "scale": 100,        "voltage": 4400,        "temperature": 292,        "technology": "Li-ion"    },    "memory": {        "total": 5795832,        "around": "6 GB"    },    "cpu": {        "cores": 8,        "hardware": "Qualcomm Technologies, Inc SDM665"    },    "arch": "",    "owner": null,    "presenceChangedAt": "0001-01-01T00:00:00Z",    "usingBeganAt": "0001-01-01T00:00:00Z",    "product": null,    "provider": null}

  

8.2.3 獲取螢幕解析度

# 返回(寬,高)元組d.window_size()# 例 解析度為 1080*1920# 手機豎屏狀態返回 (1080,1920)# 橫屏狀態返回 (1920,1080)

  

8.2.4 獲取 IP 地址

# 返回(寬,高)元組d.window_size()# 例 解析度為 1080*1920# 手機豎屏狀態返回 (1080,1920)# 橫屏狀態返回 (1920,1080)

  

8.2.4 獲取 IP 地址

# 返回 ip 地址字串,如果沒有則返回 Noned.wlan_ip

  

8.3 driver 全域性設定

8.3.1 使用 settings 設定

檢視 settings 預設設定

d.settings#輸出{    #點選後的延遲,(0,3)表示元素點選前等待 0 秒,點選後等待 3S 再執行後續操作    'operation_delay': (0, 3),    # opretion_delay 生效的方法,預設為 click 和 swipe    # 可以增加 press,send_keys,long_click 等方式    'operation_delay_methods': ['click', 'swipe'],    # 預設等待時間,相當於 appium 的隱式等待    'wait_timeout': 20.0,    # xpath 日誌    'xpath_debug': False}

  修改預設設定,只需要修改 settings 字典即可

#修改延遲為操作前延遲 2S 操作後延遲 4.5Sd.settings['operation_delay'] = (2,4.5)#修改延遲生效方法d.settings['operation_delay_methods'] = {'click','press','send_keys'}# 修改預設等待d.settings['wait_timeout'] = 10

  

8.3.2 使用方法或者屬性設定

  • http 預設請求超時時間

    預設值 60s, d.HTTP_TIMEOUT = 60

  • 當裝置掉線時,等待裝置線上時長

    僅當 TMQ=true 時有效,支援通過環境變數 WAIT_FOR_DEVICE_TIMEOUT 設定d.WAIT_FOR_DEVICE_TIMEOUT = 70

  • 元素查詢預設等待時間

    打不到元素時,等待 10 後再報異常d.implicitly_wait(10.0)

  • 開啟 HTTP debug 資訊

    d.debug = Trued.info#輸出15:52:04.736 $ curl -X POST -d '{"jsonrpc": "2.0", "id": "0eed6e063989e5844feba578399e6ff8", "method": "deviceInfo", "params": {}}' 'http://localhost:51046/jsonrpc/0'15:52:04.816 Response (79 ms) >>>{"jsonrpc":"2.0","id":"0eed6e063989e5844feba578399e6ff8","result":{"currentPackageName":"com.android.systemui","displayHeight":2097,"displayRotation":0,"displaySizeDpX":360,"displaySizeDpY":780,"displayWidth":1080,"productName":"freedom_turbo_XL","screenOn":true,"sdkInt":29,"naturalOrientation":true}}<<< END

  • 休眠

    相當於 time.sleep(10)d.sleep(10)

8.4 亮滅屏

# 亮屏d.screen_on()# 滅屏d.screen_off()

  

8.5 螢幕方向

# 設定螢幕方向d.set_orientation(value)# 獲取當前螢幕方向d.orientation

  value 值參考,只要是元組中的任一一個值就可以。

# 正常豎屏(0, "natural", "n", 0), # 往左橫屏,相當於手機螢幕順時針旋轉 90 度# 現實中如果要達到此效果,需要將手機逆時針旋轉 90 度 (1, "left", "l", 90),# 倒置,這個需要看手機系統是否支援 , 倒過來顯示  (2, "upsidedown", "u", 180), # 往右橫屏,調整與往左相反,螢幕順時針旋轉 270 度 (3, "right", "r", 270))

  

8.6 開啟通知欄與快速設定

開啟通知欄

d.open_notification()

  開啟快速設定

d.open_quick_settings()

  

8.7 檔案匯入匯出

8.7.1 匯入檔案

# 如果是目錄,這裡 "/sdcrad/" 最後一個斜槓一定要加,否則會報錯d.push("test.txt","/sdcrad/")d.push("test.txt","/sdcrad/test.txt")

  

8.7.2 匯出檔案

d.pull('/sdcard/test.txt','text.txt')

  

8.8 執行 shell 命令

使用 shell 方法執行

8.8.1 執行非阻塞命令

output 返回的是一個整體的字串,如果需要抽取值,需要對 output 進行解析提取處理

# 返回輸出和退出碼,正常為 0,異常為 1output,exit_code = d.shell(["ls","-l"],timeout=60)

  

8.8.2 執行阻塞命令(持續執行的命令)

# 返回一個命令的資料流 output 為 requests.models.Responseoutput = d.shell('logcat',stream=True)try:    # 按行讀取,iter_lines 為迭代響應資料,一次一行    for line in output.iter_lines():        print(line.decode('utf8'))finally:    output.close()

  原始碼描述

def shell(self, cmdargs: Union[str, List[str]], stream=False, timeout=60):        """        Run adb shell command with arguments and return its output. Require atx-agent >=0.3.3        Args:            cmdargs: str or list, example: "ls -l" or ["ls", "-l"]            timeout: seconds of command run, works on when stream is False            stream: bool used for long running process.        Returns:            (output, exit_code) when stream is False            requests.Response when stream is True, you have to close it after using        Raises:            RuntimeError        For atx-agent is not support return exit code now.        When command got something wrong, exit_code is always 1, otherwise exit_code is always 0        """

  

8.9 session(目前已經被棄用)

8.10 停止 UI2 服務

因為有 atx-agent 的存在,Uiautomator 會被一直守護著,如果退出了就會被重新啟動起來。但是 Uiautomator 又是霸道的,一旦它在執行,手機上的輔助功能、電腦上的 uiautomatorviewer 就都不能用了,除非關掉該框架本身的 uiautomator

使用程式碼停止

d.service("uiautomator").stop()

  

手動停止

直接開啟 ATX APP(init 成功後,就會安裝上),點選關閉 UIAutomator

以上,歡迎大家一起交流探討。