UIAutomator2 常用命令整理

https://github.com/openatx/uiautomator2

平時用的最多也最順手的一個Android系統(tǒng)APP控制Python庫咧纠,它不僅可以幫我在工作上實現(xiàn)基于Android車載娛樂系統(tǒng)的自動化操控和測試拐格,也可以在雙十一為你自動開搶心儀的商品询筏。以下對常用功能進行了整理和總結(jié)。

連接ADB設備:

可以通過USB或Wifi與ADB設備進行連接钱反,進而調(diào)用Uiautomator2框架刽漂,支持同時連接單個或多個ADB設備芹枷。

  1. USB連接:只有一個設備也可以省略參數(shù),多個設備則需要序列號來區(qū)分
import uiautomator2 as u2


d = u2.connect("--serial-here--") 
  1. USB連接:一個設備時膝擂,可簡寫
d = u2.connect() 
  1. 無線連接:通過設備的IP連接(需要在同一局域網(wǎng)且設備上的atx-agent已經(jīng)安裝并啟動)
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虑啤,然后調(diào)用am start -n $package/$activity啟動)

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

2.2. 通過指定main activity的方式啟動應用隙弛,等價于調(diào)用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 啟動,這種方法有個副作用,它自動會將手機的旋轉(zhuǎn)鎖定給關掉

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

4.1 停止應用, 等價于am force-stop狞山,此方法會丟失應用數(shù)據(jù)

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的用途是操作的同時監(jiān)控應用是否閃退,當閃退時操作驳遵,會拋出SessionBrokenError
sess = d.session("com.example.app") # start app
  1. 停止或重啟session腌逢,即app
sess.close() # 停止app
sess.restart() # 冷啟app
  1. python with 功能,開啟某個APP執(zhí)行某個操作后超埋,自動退出某個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. 模擬按下后的連續(xù)操作月弛,如九宮格解鎖
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()




硬按鍵操作

用于模擬用戶對手機硬按鍵或系統(tǒng)按鍵的操作。

  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. 模擬輸入菜皂,需要光標已經(jīng)在輸入框中才可以
d.set_fastinput_ime(True) # 切換成FastInputIME輸入法
d.send_keys("你好123abcEFG") # adb廣播輸入
d.clear_text() # 清除輸入框所有內(nèi)容(Require android-uiautomator.apk version >= 1.0.7)
d.set_fastinput_ime(False) # 切換成正常的輸入法
d.send_action("search") # 模擬輸入法的搜索
  1. 清空輸入框
d.clear_text()




執(zhí)行ADB shell命令

直接通過Python來執(zhí)行ADB shell中的指令,并得到反饋厉萝。

  1. 執(zhí)行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最為關鍵的核心功能,測試者可以根據(jù)界面中的元素來判斷當前畫面是否符合預期或基于界面元素進行點按滑動等操作谴垫。

目前Uiautomator2支持以下種類的關鍵字參數(shù):
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

舉個例子章母,測試者可以通過以上關鍵字的組合,來實現(xiàn)特定界面元素的定位翩剪,如下面這段代碼是要求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也支持通過子節(jié)點或兄弟節(jié)點來限定特定UI元素秫逝。如下面這幾段代碼分別是通過某個元素,獲取其子元素或同胞元素中的信息或進行后續(xù)操作椿胯。

# 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")

也可以根據(jù)子節(jié)點的Text或 Description或Instance來定位元素筷登, 特別提下下面代碼中的這個allow_scroll_search功能,它調(diào)用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的系統(tǒng)設置界面及它的hierarchy:
系統(tǒng)設置界面:


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. 等待某個元素出現(xiàn)
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("http://*[@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. 等待某個元素出現(xiàn)或消失
# 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分鐘抱慌。(如果兩個步驟需要等待較長時間,且不希望下一次發(fā)送指令時重啟UT2眨猎,則可以將此時間加大)
d.set_new_command_timeout(300)




守護

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

  1. 監(jiān)控彈窗(在線程中監(jiān)控)
# 常用寫法寺渗,注冊匿名監(jiān)控
d.watcher.when("安裝").click()

# 注冊名為ANR的監(jiān)控,當出現(xiàn)ANR和Force Close時兰迫,點擊Force Close
d.watcher("ANR").when(xpath="ANR").when("Force Close").click()

# 其他回調(diào)例子
d.watcher.when("搶紅包").press("back")
d.watcher.when("http://*[@text = 'Out of memory']").call(lambda d: d.shell('am force-stop com.im.qq'))

# 移除ANR的監(jiān)控
d.watcher.remove("ANR")

# 移除所有的監(jiān)控
d.watcher.remove()

# 開始后臺監(jiān)控
d.watcher.start()
d.watcher.start(2.0) # 默認監(jiān)控間隔2.0s

# 強制運行所有監(jiān)控
d.watcher.run()

# 停止監(jiān)控
d.watcher.stop()

# 停止并移除所有的監(jiān)控信殊,常用于初始化
d.watcher.reset()




插件

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

Aircv 圖像比對插件(有較多限制汁果,推薦自己單獨截圖后調(diào)用Aircv來實現(xiàn)圖像比對或點擊等功能涡拘,或用ATX來實現(xiàn))
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

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市须鼎,隨后出現(xiàn)的幾起案子鲸伴,更是在濱河造成了極大的恐慌,老刑警劉巖晋控,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異姓赤,居然都是意外死亡赡译,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進店門不铆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蝌焚,“玉大人裹唆,你說我怎么就攤上這事≈蝗鳎” “怎么了许帐?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長毕谴。 經(jīng)常有香客問我成畦,道長,這世上最難降的妖魔是什么涝开? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任循帐,我火速辦了婚禮,結(jié)果婚禮上舀武,老公的妹妹穿的比我還像新娘拄养。我一直安慰自己,他們只是感情好银舱,可當我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布瘪匿。 她就那樣靜靜地躺著,像睡著了一般寻馏。 火紅的嫁衣襯著肌膚如雪棋弥。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天操软,我揣著相機與錄音嘁锯,去河邊找鬼。 笑死聂薪,一個胖子當著我的面吹牛家乘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播藏澳,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼仁锯,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了翔悠?” 一聲冷哼從身側(cè)響起业崖,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蓄愁,沒想到半個月后双炕,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡撮抓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年妇斤,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡站超,死狀恐怖荸恕,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情死相,我是刑警寧澤融求,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站算撮,受9級特大地震影響生宛,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜钮惠,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一茅糜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧素挽,春花似錦蔑赘、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至撰糠,卻和暖如春酥馍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背阅酪。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工旨袒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人术辐。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓砚尽,卻偏偏與公主長得像,于是被迫代替她去往敵國和親辉词。 傳聞我的和親對象是個殘疾皇子必孤,可洞房花燭夜當晚...
    茶點故事閱讀 45,047評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 在平時的工作中,會經(jīng)常用到adb命令瑞躺,在這里稍微整理了一下敷搪。 一.概要 1.什么是adb? adb全稱為Andro...
    堅固的浮沙閱讀 797評論 0 3
  • adb 即 Android Debug Bridge 安卓調(diào)試橋幢哨,adb 是一個C/S架構的命令行工具赡勘,主要由 3...
    堅持未來閱讀 2,742評論 0 2
  • Tcp/IP通信也是不安全的,在傳輸?shù)臅r候也可能出現(xiàn)漏洞 查看正在運行的進程 adb shell ps -A |g...
    遠遠飄著云閱讀 4,425評論 0 0
  • Android 調(diào)試橋 Android 調(diào)試橋 (adb) 是一個通用命令行工具捞镰,其允許您與模擬器實例或連接的 A...
    guanjm閱讀 1,473評論 0 1
  • 1狮含、日志相關: adb logcat //顯示全部日志 adb logcat > c:\test.log //...
    學習不斷閱讀 59,093評論 0 11