Uiautomator2應用詳解


連接ADB設備:

可以通過USB或Wifi與ADB設備進行連接,進而調用Uiautomator2框架,支持同時連接單個或多個ADB設備。

  1. USB連接:只有一個設備也可以省略參數,多個設備則需要序列號來區分
import uiautomator2 as u2 d = u2.connect("--serial-here--") 
2、USB連接:一個設備時,可簡寫
d = u2.connect() 
3、無線連接:通過設備的IP連接(需要在同一局域網且設備上的atx-agent已經安裝並啟動)
d = u2.connect("10.1.2.3") 
4、無線連接:通過ABD wifi 等同於下面的代碼
d = u2.connect_adb_wifi("10.0.0.1:5555") #等同於 + Shell: adb connect 10.0.0.1:5555 + Python: u2.connect_usb("10.0.0.1:5555")

APP操作:用於啟動或停止某個APP

1、獲取前台應用 packageName, activity

d.app_current() 
2.1 啟動應用( 默認的這種方法是先通過atx-agent解析apk包的mainActivity,然后調用 am start -n $package/$activity啟動)
d.app_start("com.example.app") 
2.2. 通過指定main activity的方式啟動應用,等價於調用 am start -n com.example.hello_world/.MainActivity
d.app_start("com.example.hello_world", ".MainActivity")
2.3使用  monkey -p com.example.hello_world -c android.intent.category.LAUNCHER 1 啟動,這種方法有個副作用,它自動會將手機的旋轉鎖定給關掉
d.app_start("com.example.hello_world", use_monkey=True)
3、啟動應用前停止此應用
d.app_start("com.example.app", stop=True) 
4.1 停止應用, 等價於 am force-stop,此方法會丟失應用數據
d.app_stop("com.example.app")
4.2 停止應用, 等價於 pm clear
d.app_clear('com.example.hello_world')
4.3 停止所有應用
d.app_stop_all()
4.4 停止所有應用,除了某個應用
d.app_stop_all(excludes=['com.examples.demo'])
5、得到APP圖標
img = d.app_icon("com.examples.demo") img.save("icon.png")
6、列出所有運行中的應用
d.app_list_running()
7、確定APP是否啟動,也可以通過Session來判斷
pid = d.app_wait("com.example.android") # 等待應用運行, return pid(int) if not pid: print("com.example.android is not running") else: print("com.example.android pid is %d" % pid) d.app_wait("com.example.android", front=True) # 等待應用前台運行 d.app_wait("com.example.android", timeout=20.0) # 最長等待時間20s(默認) or d.wait_activity(".ApiDemos", timeout=10) # default timeout 10.0 seconds

Session操作:一般用於測試某個特定的APP,首先將某個APP設定為一個Session,所有的操作都基於此Session,當Session退出時,代表APP退出

1、啟動應用並獲取session

session的用途是操作的同時監控應用是否閃退,當閃退時操作,會拋出SessionBrokenError
sess = d.session("com.example.app") # start app
2.停止或重啟session,即app
sess.close() # 停止app sess.restart() # 冷啟app
3.python with 功能,開啟某個APP執行某個操作后,自動退出某個session
with d.session("com.netease.cloudmusic") as sess: sess(text="Play").click()
4.1 當APP已運行時自動跳過啟動
# launch app if not running, skip launch if already running sess = d.session("com.netease.cloudmusic", attach=True)
4.2 當某個APP沒有啟動時,報錯
# raise SessionBrokenError if not running sess = d.session("com.netease.cloudmusic", attach=True, strict=True)
5.1 確定session對應的APP是否運行
# check if session is ok. # Warning: function name may change in the future sess.running() # True or False
5.2 確定session對應的APP是否運行,當不在運行將報錯
# When app is still running sess(text="Music").click() # operation goes normal # If app crash or quit sess(text="Music").click() # raise SessionBrokenError # other function calls under session will raise SessionBrokenError too

截圖與hierarchy提取:用於獲取Android當前的截圖和界面元素。

1、截圖

# take screenshot and save to a file on the computer, require Android>=4.2. d.screenshot("home.jpg") # get PIL.Image formatted images. Naturally, you need pillow installed first image = d.screenshot() # default format="pillow" image.save("home.jpg") # or home.png. Currently, only png and jpg are supported # get opencv formatted images. Naturally, you need numpy and cv2 installed first import cv2 image = d.screenshot(format='opencv') cv2.imwrite('home.jpg', image) # get raw jpeg data imagebin = d.screenshot(format='raw') open("some.jpg", "wb").write(imagebin)

2、獲取hierarchy

# get the UI hierarchy dump content (unicoded). xml = d.dump_hierarchy()

模擬觸控操作:用於模擬用戶對手機的點擊或滑動等操作

1.1 XY坐標點擊

d.click(10, 20) 

1.2 XY坐標雙擊

d.double_click(x, y) d.double_click(x, y, 0.1) # default duration between two click is 0.1s
1.3 長按某個坐標
d.long_click(x, y) d.long_click(x, y, 0.5) # long click 0.5s (default)
2、通過元素中的Text信息來點擊,程序會點擊Text所在layout的中心位置,

# click on the center of the specific ui object d(text="Settings").click() d(Text="Settings").double_click() d(Text="Settings").long_click() # wait element to appear for at most 10 seconds and then click d(text="Settings").click(timeout=10) # click with offset(x_offset, y_offset) # click_x = x_offset * width + x_left_top # click_y = y_offset * height + y_left_top d(text="Settings").click(offset=(0.5, 0.5)) # Default center d(text="Settings").click(offset=(0, 0)) # click left-top d(text="Settings").click(offset=(1, 1)) # click right-bottom # click when exists in 10s, default timeout 0s clicked = d(text='Skip').click_exists(timeout=10.0) # click until element gone, return bool is_gone = d(text="Skip").click_gone(maxretry=10, interval=1.0) # maxretry default 10, interval default 1.0
3、滑動操作,從(10, 20)滑動到(80, 90)
d.swipe(10, 20, 80, 90) d.swipe(sx, sy, ex, ey, 0.5) d(text="Settings").swipe("right") d(text="Settings").swipe("left", steps=10) d(text="Settings").swipe("up", steps=20) # 1 steps is about 5ms, so 20 steps is about 0.1s d(text="Settings").swipe("down", steps=20) # swipe from point(x0, y0) to point(x1, y1) then to point(x2, y2) # time will speed 0.2s bwtween two points d.swipe_points([(x0, y0), (x1, y1), (x2, y2)], 0.2))
4、整個屏幕右滑動
d.swipe_ext("right") 
5、屏幕右滑,滑動距離為屏幕寬度的90%
d.swipe_ext("right", scale=0.9) 
6、從一個坐標拖拽到另一個坐標
d.drag(sx, sy, ex, ey) d.drag(sx, sy, ex, ey, 0.5) # swipe for 0.5s(default)
7.模擬按下后的連續操作,如九宮格解鎖
d.touch.down(10, 10) # 模擬按下 time.sleep(.01) # down 和 move 之間的延遲,自己控制 d.touch.move(15, 15) # 模擬移動 d.touch.up() # 模擬抬起
8.模擬兩指縮放操作
# notes : pinch can not be set until Android 4.3. # from edge to center. here is "In" not "in" d(text="Settings").pinch_in(percent=100, steps=10) # from center to edge d(text="Settings").pinch_out() or d().pinch_in(percent=100, steps=10) d().pinch_out()

硬按鍵操作:用於模擬用戶對手機硬按鍵或系統按鍵的操作。

1、模擬按 Home 或 Back 鍵

目前支持以下關鍵字,但並非所有設備都支持:
home
back
left
right
up
down
center
menu
search
enter
delete ( or del)
recent (recent apps)
volume_up
volume_down
volume_mute
camera
power
d.press("back") d.press("home") 
2、模擬按Android定義的硬鍵值
d.press(0x07, 0x02) # press keycode 0x07('0') with META ALT(0x02) #具體可查詢: #https://developer.android.com/reference/android/view/KeyEvent.html
3、解鎖屏幕
d.unlock()
# This is equivalent to # 1. launch activity: com.github.uiautomator.ACTION_IDENTIFY # 2. press the "home" key
4、模擬輸入,需要光標已經在輸入框中才可以
d.set_fastinput_ime(True) # 切換成FastInputIME輸入法 d.send_keys("你好123abcEFG") # adb廣播輸入 d.clear_text() # 清除輸入框所有內容(Require android-uiautomator.apk version >= 1.0.7) d.set_fastinput_ime(False) # 切換成正常的輸入法 d.send_action("search") # 模擬輸入法的搜索
5、清空輸入框
d.clear_text()

執行ADB shell命令:直接通過Python來執行ADB shell中的指令,並得到反饋。

1、執行shell命令,獲取輸出和exitCode

output, exit_code = d.shell("ps -A", timeout=60) 

2、僅得到輸出

output = d.shell("pwd").output 

3、僅得到Exitcode

exit_code = d.shell("pwd").exit_code

4、推送文件到ADB設備中

# push to a folder d.push("foo.txt", "/sdcard/") # push and rename d.push("foo.txt", "/sdcard/bar.txt") # push fileobj with open("foo.txt", 'rb') as f: d.push(f, "/sdcard/") # push and change file access mode d.push("foo.sh", "/data/local/tmp/", mode=0o755)

5、獲取文件到本地

d.pull("/sdcard/tmp.txt", "tmp.txt") # FileNotFoundError will raise if the file is not found on the device d.pull("/sdcard/some-file-not-exists.txt", "tmp.txt")

元素操作或Selector:這是Uiautomator2最為關鍵的核心功能,測試者可以根據界面中的元素來判斷當前畫面是否符合預期或基於界面元素進行點按滑動等操作。

目前Uiautomator2支持以下種類的關鍵字參數:
text, textContains, textMatches, textStartsWith
className, classNameMatches
description, descriptionContains, descriptionMatches, descriptionStartsWith
checkable, checked, clickable, longClickable
scrollable, enabled,focusable, focused, selected
packageName, packageNameMatches
resourceId, resourceIdMatches
index, instance

舉個例子,測試者可以通過以上關鍵字的組合,來實現特定界面元素的定位,如下面這段代碼是要求UT2去點擊界面中,元素text信息為clock,className為'android.widget.TextView'的元素:
# Select the object with text 'Clock' and its className is 'android.widget.TextView' d(text='Clock', className='android.widget.TextView').click()
除了,可以使用關鍵字的組合來限定特定UI元素,UT2也支持通過子節點或兄弟節點來限定特定UI元素。如下面這幾段代碼分別是通過某個元素,獲取其子元素或同胞元素中的信息或進行后續操作。
# children # get the children or grandchildren d(className="android.widget.ListView").child(text="Bluetooth")
# get the children or grandchildren d(className="android.widget.ListView").child(text="Bluetooth")

也可以根據子節點的Text或 Description或Instance來定位元素, 特別提下下面代碼中的這個allow_scroll_search功能,它調用UT2自動滾動直到找到對應元素:

# get the child matching the condition className="android.widget.LinearLayout" # and also its children or grandchildren with text "Bluetooth" d(className="android.widget.ListView", resourceId="android:id/list") \ .child_by_text("Bluetooth", className="android.widget.LinearLayout") # get children by allowing scroll search d(className="android.widget.ListView", resourceId="android:id/list") \ .child_by_text( "Bluetooth", allow_scroll_search=True, className="android.widget.LinearLayout" )

例子:

下面有另一個實例來展示UT2的定位,以下為Android的系統設置界面及它的hierarchy:
系統設置界面:

 

hierarchy:

<node index="0" text="" resource-id="android:id/list" class="android.widget.ListView" ...> <node index="0" text="WIRELESS & NETWORKS" resource-id="" class="android.widget.TextView" .../> <node index="1" text="" resource-id="" class="android.widget.LinearLayout" ...> <node index="1" text="" resource-id="" class="android.widget.RelativeLayout" ...> <node index="0" text="Wi‑Fi" resource-id="android:id/title" class="android.widget.TextView" .../> </node> <node index="2" text="ON" resource-id="com.android.settings:id/switchWidget" class="android.widget.Switch" .../> </node> ... </node>

通過child_by_text + child組合后可以定位到WIFI的開關。

d(className="android.widget.ListView", resourceId="android:id/list") \ .child_by_text("Wi‑Fi", className="android.widget.LinearLayout") \ .child(className="android.widget.Switch") \ .click()
也可以通過,位置關系來定位元素:
d(A).left(B), selects B on the left side of A.
d(A).right(B), selects B on the right side of A.
d(A).up(B), selects B above A.
d(A).down(B), selects B under A.
## select "switch" on the right side of "Wi‑Fi" d(text="Wi‑Fi").right(className="android.widget.Switch").click()

還有可以通過元素的instances來定位,比如一個界面中有多個switch,我們可以通過下面的形式來定位是第一個還是第二個

d(className="android.widget.Switch", instance=0) d(className="android.widget.Switch")[0] or # get the count of views with text "Add new" on current screen d(text="Add new").count # same as count property len(d(text="Add new")) # get the instance via index d(text="Add new")[0] d(text="Add new")[1] ... # iterator for view in d(text="Add new"): view.info # ...


連接ADB設備:

可以通過USB或Wifi與ADB設備進行連接,進而調用Uiautomator2框架,支持同時連接單個或多個ADB設備。

  1. USB連接:只有一個設備也可以省略參數,多個設備則需要序列號來區分
import uiautomator2 as u2 d = u2.connect("--serial-here--") 
  1. USB連接:一個設備時,可簡寫
d = u2.connect() 
  1. 無線連接:通過設備的IP連接(需要在同一局域網且設備上的atx-agent已經安裝並啟動)
d = u2.connect("10.1.2.3") 
  1. 無線連接:通過ABD wifi 等同於下面的代碼
d = u2.connect_adb_wifi("10.0.0.1:5555") #等同於 + Shell: adb connect 10.0.0.1:5555 + Python: u2.connect_usb("10.0.0.1:5555") 



APP操作:

用於啟動或停止某個APP

  1. 獲取前台應用 packageName, activity
d.app_current() 

2.1 啟動應用( 默認的這種方法是先通過atx-agent解析apk包的mainActivity,然后調用am start -n $package/$activity啟動)

d.app_start("com.example.app") 

2.2. 通過指定main activity的方式啟動應用,等價於調用am start -n com.example.hello_world/.MainActivity

d.app_start("com.example.hello_world", ".MainActivity") 

2.3. 使用 monkey -p com.example.hello_world -c android.intent.category.LAUNCHER 1 啟動,這種方法有個副作用,它自動會將手機的旋轉鎖定給關掉

d.app_start("com.example.hello_world", use_monkey=True) 
  1. 啟動應用前停止此應用
d.app_start("com.example.app", stop=True) 

4.1 停止應用, 等價於am force-stop,此方法會丟失應用數據

d.app_stop("com.example.app") 

4.2 停止應用, 等價於pm clear

d.app_clear('com.example.hello_world') 

4.3 停止所有應用

d.app_stop_all() 

4.4 停止所有應用,除了某個應用

d.app_stop_all(excludes=['com.examples.demo']) 
  1. 得到APP圖標
img = d.app_icon("com.examples.demo") img.save("icon.png") 
  1. 列出所有運行中的應用
d.app_list_running() 
  1. 確定APP是否啟動,也可以通過Session來判斷
pid = d.app_wait("com.example.android") # 等待應用運行, return pid(int) if not pid: print("com.example.android is not running") else: print("com.example.android pid is %d" % pid) d.app_wait("com.example.android", front=True) # 等待應用前台運行 d.app_wait("com.example.android", timeout=20.0) # 最長等待時間20s(默認) or d.wait_activity(".ApiDemos", timeout=10) # default timeout 10.0 seconds 



Session操作

一般用於測試某個特定的APP,首先將某個APP設定為一個Session,所有的操作都基於此Session,當Session退出時,代表APP退出。

  1. 啟動應用並獲取session
    session的用途是操作的同時監控應用是否閃退,當閃退時操作,會拋出SessionBrokenError
sess = d.session("com.example.app") # start app 
  1. 停止或重啟session,即app
sess.close() # 停止app sess.restart() # 冷啟app 
  1. python with 功能,開啟某個APP執行某個操作后,自動退出某個session
with d.session("com.netease.cloudmusic") as sess: sess(text="Play").click() 

4.1 當APP已運行時自動跳過啟動

# launch app if not running, skip launch if already running sess = d.session("com.netease.cloudmusic", attach=True) 

4.2 當某個APP沒有啟動時,報錯

# raise SessionBrokenError if not running sess = d.session("com.netease.cloudmusic", attach=True, strict=True) 

5.1 確定session對應的APP是否運行

# check if session is ok. # Warning: function name may change in the future sess.running() # True or False 

5.2 確定session對應的APP是否運行,當不在運行將報錯

# When app is still running sess(text="Music").click() # operation goes normal # If app crash or quit sess(text="Music").click() # raise SessionBrokenError # other function calls under session will raise SessionBrokenError too 



截圖與hierarchy提取:

用於獲取Android當前的截圖和界面元素。

  1. 截圖
# take screenshot and save to a file on the computer, require Android>=4.2. d.screenshot("home.jpg") # get PIL.Image formatted images. Naturally, you need pillow installed first image = d.screenshot() # default format="pillow" image.save("home.jpg") # or home.png. Currently, only png and jpg are supported # get opencv formatted images. Naturally, you need numpy and cv2 installed first import cv2 image = d.screenshot(format='opencv') cv2.imwrite('home.jpg', image) # get raw jpeg data imagebin = d.screenshot(format='raw') open("some.jpg", "wb").write(imagebin) 
  1. 獲取hierarchy
# get the UI hierarchy dump content (unicoded). xml = d.dump_hierarchy() 



模擬觸控操作:

用於模擬用戶對手機的點擊或滑動等操作

1.1 XY坐標點擊

d.click(10, 20) 

1.2 XY坐標雙擊

d.double_click(x, y) d.double_click(x, y, 0.1) # default duration between two click is 0.1s 

1.3 長按某個坐標

d.long_click(x, y) d.long_click(x, y, 0.5) # long click 0.5s (default) 
  1. 通過元素中的Text信息來點擊,程序會點擊Text所在layout的中心位置,

# click on the center of the specific ui object d(text="Settings").click() d(Text="Settings").double_click() d(Text="Settings").long_click() # wait element to appear for at most 10 seconds and then click d(text="Settings").click(timeout=10) # click with offset(x_offset, y_offset) # click_x = x_offset * width + x_left_top # click_y = y_offset * height + y_left_top d(text="Settings").click(offset=(0.5, 0.5)) # Default center d(text="Settings").click(offset=(0, 0)) # click left-top d(text="Settings").click(offset=(1, 1)) # click right-bottom # click when exists in 10s, default timeout 0s clicked = d(text='Skip').click_exists(timeout=10.0) # click until element gone, return bool is_gone = d(text="Skip").click_gone(maxretry=10, interval=1.0) # maxretry default 10, interval default 1.0 
  1. 滑動操作,從(10, 20)滑動到(80, 90)
d.swipe(10, 20, 80, 90) d.swipe(sx, sy, ex, ey, 0.5) d(text="Settings").swipe("right") d(text="Settings").swipe("left", steps=10) d(text="Settings").swipe("up", steps=20) # 1 steps is about 5ms, so 20 steps is about 0.1s d(text="Settings").swipe("down", steps=20) # swipe from point(x0, y0) to point(x1, y1) then to point(x2, y2) # time will speed 0.2s bwtween two points d.swipe_points([(x0, y0), (x1, y1), (x2, y2)], 0.2)) 
  1. 整個屏幕右滑動
d.swipe_ext("right") 
  1. 屏幕右滑,滑動距離為屏幕寬度的90%
d.swipe_ext("right", scale=0.9) 
  1. 從一個坐標拖拽到另一個坐標
d.drag(sx, sy, ex, ey) d.drag(sx, sy, ex, ey, 0.5) # swipe for 0.5s(default) 
  1. 模擬按下后的連續操作,如九宮格解鎖
d.touch.down(10, 10) # 模擬按下 time.sleep(.01) # down 和 move 之間的延遲,自己控制 d.touch.move(15, 15) # 模擬移動 d.touch.up() # 模擬抬起 
  1. 模擬兩指縮放操作
# notes : pinch can not be set until Android 4.3. # from edge to center. here is "In" not "in" d(text="Settings").pinch_in(percent=100, steps=10) # from center to edge d(text="Settings").pinch_out() or d().pinch_in(percent=100, steps=10) d().pinch_out() 



硬按鍵操作

用於模擬用戶對手機硬按鍵或系統按鍵的操作。

  1. 模擬按 Home 或 Back 鍵
    目前支持以下關鍵字,但並非所有設備都支持:
    home
    back
    left
    right
    up
    down
    center
    menu
    search
    enter
    delete ( or del)
    recent (recent apps)
    volume_up
    volume_down
    volume_mute
    camera
    power
d.press("back") d.press("home") 
  1. 模擬按Android定義的硬鍵值
d.press(0x07, 0x02) # press keycode 0x07('0') with META ALT(0x02) #具體可查詢: #https://developer.android.com/reference/android/view/KeyEvent.html 
  1. 解鎖屏幕
d.unlock()
# This is equivalent to # 1. launch activity: com.github.uiautomator.ACTION_IDENTIFY # 2. press the "home" key 
  1. 模擬輸入,需要光標已經在輸入框中才可以
d.set_fastinput_ime(True) # 切換成FastInputIME輸入法 d.send_keys("你好123abcEFG") # adb廣播輸入 d.clear_text() # 清除輸入框所有內容(Require android-uiautomator.apk version >= 1.0.7) d.set_fastinput_ime(False) # 切換成正常的輸入法 d.send_action("search") # 模擬輸入法的搜索 
  1. 清空輸入框
d.clear_text() 



執行ADB shell命令

直接通過Python來執行ADB shell中的指令,並得到反饋。

  1. 執行shell命令,獲取輸出和exitCode
output, exit_code = d.shell("ps -A", timeout=60) 
  1. 僅得到輸出
output = d.shell("pwd").output 
  1. 僅得到Exitcode
exit_code = d.shell("pwd").exit_code 
  1. 推送文件到ADB設備中
# push to a folder d.push("foo.txt", "/sdcard/") # push and rename d.push("foo.txt", "/sdcard/bar.txt") # push fileobj with open("foo.txt", 'rb') as f: d.push(f, "/sdcard/") # push and change file access mode d.push("foo.sh", "/data/local/tmp/", mode=0o755) 
  1. 獲取文件到本地
d.pull("/sdcard/tmp.txt", "tmp.txt") # FileNotFoundError will raise if the file is not found on the device d.pull("/sdcard/some-file-not-exists.txt", "tmp.txt") 



元素操作或Selector

這是Uiautomator2最為關鍵的核心功能,測試者可以根據界面中的元素來判斷當前畫面是否符合預期或基於界面元素進行點按滑動等操作。

目前Uiautomator2支持以下種類的關鍵字參數:
text, textContains, textMatches, textStartsWith
className, classNameMatches
description, descriptionContains, descriptionMatches, descriptionStartsWith
checkable, checked, clickable, longClickable
scrollable, enabled,focusable, focused, selected
packageName, packageNameMatches
resourceId, resourceIdMatches
index, instance

舉個例子,測試者可以通過以上關鍵字的組合,來實現特定界面元素的定位,如下面這段代碼是要求UT2去點擊界面中,元素text信息為clock,className為'android.widget.TextView'的元素:

# Select the object with text 'Clock' and its className is 'android.widget.TextView' d(text='Clock', className='android.widget.TextView').click()

除了,可以使用關鍵字的組合來限定特定UI元素,UT2也支持通過子節點或兄弟節點來限定特定UI元素。如下面這幾段代碼分別是通過某個元素,獲取其子元素或同胞元素中的信息或進行后續操作。

# children # get the children or grandchildren d(className="android.widget.ListView").child(text="Bluetooth") 
# get the children or grandchildren d(className="android.widget.ListView").child(text="Bluetooth") 
# siblings # get siblings d(text="Google").sibling(className="android.widget.ImageView") 

也可以根據子節點的Text或 Description或Instance來定位元素, 特別提下下面代碼中的這個allow_scroll_search功能,它調用UT2自動滾動直到找到對應元素:

# get the child matching the condition className="android.widget.LinearLayout" # and also its children or grandchildren with text "Bluetooth" d(className="android.widget.ListView", resourceId="android:id/list") \ .child_by_text("Bluetooth", className="android.widget.LinearLayout") # get children by allowing scroll search d(className="android.widget.ListView", resourceId="android:id/list") \ .child_by_text( "Bluetooth", allow_scroll_search=True, className="android.widget.LinearLayout" ) 

下面有另一個實例來展示UT2的定位,以下為Android的系統設置界面及它的hierarchy:
系統設置界面:


 
 
Setting.png

hierarchy:

<node index="0" text="" resource-id="android:id/list" class="android.widget.ListView" ...> <node index="0" text="WIRELESS & NETWORKS" resource-id="" class="android.widget.TextView" .../> <node index="1" text="" resource-id="" class="android.widget.LinearLayout" ...> <node index="1" text="" resource-id="" class="android.widget.RelativeLayout" ...> <node index="0" text="Wi‑Fi" resource-id="android:id/title" class="android.widget.TextView" .../> </node> <node index="2" text="ON" resource-id="com.android.settings:id/switchWidget" class="android.widget.Switch" .../> </node> ... </node> 

通過child_by_text + child組合后可以定位到WIFI的開關。

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

也可以通過,位置關系來定位元素:
d(A).left(B), selects B on the left side of A.
d(A).right(B), selects B on the right side of A.
d(A).up(B), selects B above A.
d(A).down(B), selects B under A.

## select "switch" on the right side of "Wi‑Fi" d(text="Wi‑Fi").right(className="android.widget.Switch").click()

還有可以通過元素的instances來定位,比如一個界面中有多個switch,我們可以通過下面的形式來定位是第一個還是第二個

d(className="android.widget.Switch", instance=0) d(className="android.widget.Switch")[0] or # get the count of views with text "Add new" on current screen d(text="Add new").count # same as count property len(d(text="Add new")) # get the instance via index d(text="Add new")[0] d(text="Add new")[1] ... # iterator for view in d(text="Add new"): view.info # ... 
  1. 等待某個元素出現
d(text="Settings").exists # True if exists, else False d.exists(text="Settings") # alias of above property. # advanced usage d(text="Settings").exists(timeout=3) # wait Settings appear in 3s, same as .wait(3) d.xpath("立即開戶").wait() # 等待元素,最長等10s(默認) d.xpath("立即開戶").wait(timeout=10) # 修改默認等待時間 
  1. xpath操作
    具體可以參考:https://github.com/openatx/uiautomator2/blob/master/XPATH.md
# xpath操作 d.xpath("立即開戶").click() # 包含查找等待+點擊操作,匹配text或者description等於立即開戶的按鈕 d.xpath("//*[@text='私人FM']/../android.widget.ImageView").click() d.xpath('//*[@text="私人FM"]').get().info # 獲取控件信息 for el in d.xpath('//android.widget.EditText').all(): print("rect:", el.rect) # output tuple: (left_x, top_y, width, height) print("bounds:", el.bounds) # output tuple: (left, top, right, bottom) print("center:", el.center()) el.click() # click operation print(el.elem) # 輸出lxml解析出來的Node 

3.輸入框的操作

d(text="Settings").get_text() # get widget text d(text="Settings").set_text("My text...") # set the text d(text="Settings").clear_text() # clear the text 
  1. 等待某個元素出現或消失
# wait until the ui object appears d(text="Settings").wait(timeout=3.0) # return bool # wait until the ui object gone d(text="Settings").wait_gone(timeout=1.0) 



Setting

  1. 默認控件等待時間(原生操作,xpath插件的等待時間)
d.settings['wait_timeout'] = 20.0 or d.implicitly_wait(20.0) 
  1. 點擊的等待延時
d.click_post_delay = 1.5 # default no delay 
  1. 配置accessibility服務的最大空閑時間,超時將自動釋放。默認3分鍾。(如果兩個步驟需要等待較長時間,且不希望下一次發送指令時重啟UT2,則可以將此時間加大)
d.set_new_command_timeout(300) 



守護

用於處理非預期的彈出框,如崩潰窗口,一些確定或取消彈出框。

  1. 監控彈窗(在線程中監控)
# 常用寫法,注冊匿名監控 d.watcher.when("安裝").click() # 注冊名為ANR的監控,當出現ANR和Force Close時,點擊Force Close d.watcher("ANR").when(xpath="ANR").when("Force Close").click() # 其他回調例子 d.watcher.when("搶紅包").press("back") d.watcher.when("//*[@text = 'Out of memory']").call(lambda d: d.shell('am force-stop com.im.qq')) # 移除ANR的監控 d.watcher.remove("ANR") # 移除所有的監控 d.watcher.remove() # 開始后台監控 d.watcher.start() d.watcher.start(2.0) # 默認監控間隔2.0s # 強制運行所有監控 d.watcher.run() # 停止監控 d.watcher.stop() # 停止並移除所有的監控,常用於初始化 d.watcher.reset() 



插件

Performance 性能采集(記錄CPU,RAM等數據)
https://github.com/openatx/uiautomator2/blob/6e0d75d778a86c626df778e0432c8e339e3d9be4/uiautomator2/ext/perf/README.md

Aircv 圖像比對插件(有較多限制,推薦自己單獨截圖后調用Aircv來實現圖像比對或點擊等功能,或用ATX來實現)
https://github.com/openatx/uiautomator2/blob/436404119fafce303ad8f3a07811c044d101b9eb/uiautomator2/ext-archived/aircv/README.md

Htmlreport插件(將操作生成HTML文件)
https://github.com/openatx/uiautomator2/tree/6e0d75d778a86c626df778e0432c8e339e3d9be4/uiautomator2/ext/htmlreport

 


免責聲明!

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



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