liunx下運行./uiautomatorviewer 啟動該工具。

2.uiautomator APIs
uiautomator是一個包含一套UI測試API,和支持運行測試程序的JAR包。該JAR包位於sdk/platforms/android-* /uiautomator.jar. 使用時需要注意自己的SDK版本需要大於16, SDK Tools版本需要大於21.Android版本需要高於4.3。一、UiSelector作用
按照一定的條件(例如控件的text值,資源id),定位界面上的元素。UiSelector對象的最終目的是去構造一個UiObject對象。
二、元素定位
1、根據text定位:
函數返回值 | 函數體 | 說明 | 用法 |
UiSelector | text(String text) | 根據“控件text屬性的內容”構造出UiSelector對象 | 例如,一個控件text的值是“發現”,UiSelector s = new UiSelector().text("發現"); |
UiSelector | textContains(String text) | 根據“控件text屬性包含的內容”構造出UiSelector對象 | 同上例子:UiSelector s = new UiSelector().textContains("現"); |
UiSelector | textMatches(String regex) | 根據“控件text屬性正則表達式的內容”構造出UiSelector對象 | 正則表達式語法參考網上資料即可。 |
UiSelector | textStartsWith(String text) | 根據“控件text屬性開始的內容”構造出UiSelector對象 | 同上例子:UiSelector s = new UiSelector().textStartsWith("發"); |
比較常用,准確度也比較高,中文查找的時候,有時候text元素是中文的,比如例如,一個控件text的值是“發現”,UiSelector s = new UiSelector().text("發現");此時運行的時候可能會報錯 “UiOjbectNotFoundException” ,這時候只要把項目的編碼格式改為utf-8就可以了。
2、根據description構造:
UiSelector | description(String desc) | 根據“控件content-desc屬性的內容”構造出UiSelector對象 |
UiSelector | descriptionContains(String desc) | 包含** |
UiSelector | descriptionMatches(String regex) | 正則 |
UiSelector | descriptionStartsWith(String desc) | 以**開始 |
同text的用法基本一致,也是比較靠譜的一種方式。
3、根據資源id:
UiSelector | resourceId(String id) | 根據資源id獲取對象,例如:UiSelector s = new UiSelector().resourceId("com.tencent.mm:id/b8m") |
UiSelector | resourceIdMatches(String regex) | 根據資源id的正則表達式獲取對象 |
4、根據類:
1)UiSelector className(String className):
根據控件的類名來找到UiSelector對象。如圖
這時候會出現問題:
因為一般Android布局的時候,同樣的控件類名都是一樣的。
因此我在微信的登錄界面調用: UiSelector s = new UiSelector().className("android.widget.TextView"),它得到的就是我左上開始算第一個class名稱為“android.widget.TextView”的控件。
2)UiSelector instance (int instance):
上面提到的假如我們想獲取屏幕上電話號碼的那個TextView使用這樣方法,就可以使用instance:
UiSelector s = new UiSelector().className("android.widget.TextView").instance(1);
3)UiSelector index(int index):
用法和上面的instance差不多,谷歌的原文說這個方法是unreliable的,推薦使用instance方法。
4)UiSelector childSelector(UiSelector selector):
有的時候假如子控件不好獲得,而其父控件比較好獲得的時候,我們通常采用這樣的方式,例如下面:
如圖,LinearLayout就是ImageView和EditText的父控件,當子空間text、resource-id為空的時候,這種時候子控件定位比較困難。很明顯,父控件id已經給定,那我們就可以先定位到父控件,再定位到子控件這種方法。
在它的父控件的childSelector方法中傳入一個帶有一定特征的UiSelector對象,即可得到子控件
UiObject wx_input= new UiObject(new UiSelector().className("android.widget.RelativeLayout").childSelector(new UiSelector().className("android.widget.EditText")));
5)UiSelector fromParent(UiSelector selector):
有的時候父控件也不好獲得,而是同級的控件(同屬一個parent)比較好獲取,那么使用這樣方法,還拿上面的舉例:
我們先得到EditText的UiSelector對象:UiSelector s1 = new UiSelector().resourceId("com.tencent.mm:id/axc");
得到和它同樣一個父控件的ImageView的UiSelector對象:UiSelector s2 = fromParent( new UiSelector().className("android.widget.ImageView") );
更多詳情見:https://developer.android.com/reference/android/support/test/uiautomator/UiSelector.html
UiObject類:安卓組件對象,類似於webdriver中的webelement隊形,提供了元素的屬性獲取和元素的各種操作。對象有許多模擬實際操作手機的方法和屬性。比如文本的編輯、點擊、輸入、手勢操作等。
1、點擊與長按
(1)相關API
返回值 | API | 說明 |
boolean | click() | 點擊對象 |
boolean | clickAndWaitForNewWindow(long timeout) | 點擊對象,等待新窗口出現,參數為等待超時時長 |
boolean | clickAndWaitForNewWindow() | 點擊對象,等待新窗口出現 |
boolean | clickBottomRight() | 點擊對象的右下角 |
boolean | clickTopLeft() | 點擊對象的左上角 |
boolean | longClick() | 長按對象,對對象執行長按操作 |
boolean | longClickBottomRight() | 長按對象的右下角 |
boolean | longClickTopLeft() | 長按對象的左上角 |
(2)示例
new UiObject(new Selector().resourceId("xxxxx")).click();//對指定資源id的組件執行點擊操作
2、拖拽與滑動
(1)區別
拖拽:將控件從當前位置移動到指定位置
滑動:向某一方向(上、下、左、右)移動一小段距離
(2)相關API
返回值 | API | 說明 |
boolean | dragTo(UiObject destObj, int steps) | 拖拽對象到另一個對象位置上,步長可設置拖動的速度 |
boolean | dragTo(int destX, int destY, int steps) | 拖拽對象到屏幕某個坐標位置上,步長可設置拖動速度 |
boolean | swipeDown(int steps) | 拖動對象往下滑動 |
boolean | swipeLeft(int steps) | 拖動對象往左滑動 |
boolean | swipeRight(int steps) | 拖動對象往右滑動 |
boolean | swipeUp(int steps) | 拖動對象往上滑動 |
3、輸入文本與清除文本
(1)相關API
返回值 | API | 說明 |
boolean | setText(String text) | 在對象中輸入文本(實現方式:先清除文本再輸入) |
void | clearTextField() | 清除編輯框中的文本(實現方式:長按再清除) |
(2)補充說明
clearTextField()的內部實現方式是先長按文本框然后全選刪除,導致有些編輯框無法通過調用該方法清除文本內容。這時最好自己寫代碼實現清除文本功能。
示例代碼:
//將光標移動到行尾,使用backspace進行逐個刪除
UiDevice.getInstance().pressKeyCode(KeyEvent.KEYCODE_MOVE_END);
//判斷條件中w是編輯框為空時所顯示的hint文本對象;當hint出現時,說明該編輯框內的文本已清空
while(!w.exists()){
UiDevice.getInstance().pressKeyCode(KeyEvent.KEYCODE_DEL);
}
4、獲取對象的屬性與屬性的判斷
(1)獲取對象的屬性-相關API
返回值 | API | 說明 |
Rect | getBounds() | 獲得對象矩形坐標,矩形左上角坐標與右下角坐標 |
int | getChildCount() | 獲得下一級子類數量 |
String | getClassName() | 獲得對象類名屬性的類名文本 |
String | getContentDescription() | 獲得對象的描述屬性的描述文本 |
String | getPackageName() | 獲得對象包名屬性的包名文本 |
String | getText() | 獲得對象的文本屬性中的文本 |
Rect | getVisibleBounds() | 返回可見視圖的范圍,如果視圖的部分是可見的,只有可見部分報告的范圍 |
(2)獲取父類與子類節點-相關API
返回值 | API | 說明 |
UiObject | getChild(UiSelector selector) | 獲得對象的子類對象,可以遞歸獲取子孫當中某個對象 |
UiObject | getFromParent(UiSelector selector) | 從父類獲取子類,按照UiSeletor獲取兄弟類(遞歸) |
(3)屬性的判斷-相關API
返回值 | API | 說明 |
boolean | isCheckable() | 檢查對象的checkable屬性是否為true |
boolean | isChecked() | 檢查對象的checked屬性是否為true |
boolean | isClickable() | 檢查對象的clickable屬性是否為true |
boolean | isEnabled() | 檢查對象的enabled屬性是否為true |
boolean | isFocusable() | 檢查對象的focusable屬性是否為true |
boolean | isFocused() | 檢查對象的focused屬性是否為true |
boolean | isLongClickable() | 檢查對象的longclickable屬性是否為true |
boolean | isScrollable() | 檢查對象的scrollable屬性是否為true |
boolean | isSelected() | 檢查對象的selected屬性是否為true |
5、手勢的操作
(1)手勢相關操作
兩指平移
多指平移
兩指合攏 o---> <---o
兩指擴張 <---oo--->
(2)相關API
返回值 | API | 說明 |
boolean | performMultiPointerGesture(PointerCoords[]... touches) | 執行單手指觸控手勢,可定義任意手勢,與形狀 |
boolean |
performTwoPointerGesture(Point startPoint1, Point startPoint2, |
執行任意兩個手指觸控手勢,模擬兩個手指手勢 |
boolean | pinchIn(int percent, int steps) | 手勢操作,兩點向內收縮 |
boolean | pinchOut(int percent, int steps) | 手勢操作,兩點向外張開 |
6、判斷對象是否存在
(1)相關API
返回值 | API | 說明 |
boolean | waitForExists(long timeout) | 等待對象出現 |
boolean | waitUntilGone(long timeout) | 等待對象消失 |
boolean | exists() | 檢查對象是否存在 |
UiDevices類:提供了一些列方法和屬性來模擬在手機上的實際操作,獲取設備信息:屏幕分辨率、選裝狀態、亮屏、滅屏...操作:按鍵、坐標操作、滑動、拖拽、截圖
1、UiDevice代表設備狀態。如屏幕的大小、旋轉方向、按壓各種按鍵等。
2、UiDevice為單例模式,可有2種方式獲取其實例。
(1)UiDevice.getInstance();--->推薦
(2)getUiDevice.pressHome();---->在類A中封裝方法,方法被類B調用的時候會出現空指針異常
(1)獲取設備信息:屏幕分辨率、選裝狀態、亮滅屏......
(2)操作:按鍵、坐標操作、滑動、拖拽、截圖......
(3)監聽器功能
二、按鍵與KEYCODE使用
1、點擊按鍵 相關API
UiDevice實例調用以下方法即可實現點擊按鍵操作。
返回值 | 方法名 | 描述 |
boolean | pressBack() | 模擬短按返回back鍵 |
boolean | pressDPadCenter() | 模擬按軌跡球中點按鍵 |
boolean | pressDPadDown() | 模擬軌跡球向下按鍵 |
boolean | pressDPadLeft() | 模擬軌跡球向左按鍵 |
boolean | pressDPadRight() | 模擬軌跡球向右按鍵 |
boolean | pressDPadUp() | 模擬軌跡球向上按鍵 |
boolean | pressDelete() | 模擬短按刪除delete按鍵 |
boolean | pressEnter() | 模擬短按回車鍵 |
boolean | pressHome() | 模擬短按HOME鍵 |
boolean | pressKeyCode(int keyCode, int metaState) | 模擬短按鍵盤代碼keycode |
boolean | pressKeyCode(int keyCode) | 模擬短按鍵盤代碼keycode |
boolean | pressMenu() | 模擬短按menu鍵 |
boolean | pressRecentApps() | 模擬短按最近使用程序 |
boolean | pressSearch() | 模擬短按搜索鍵 |
2、KEYCODE 鍵盤映射碼
(1)KeyEvent:按鍵事件,每個鍵盤映射碼都保存在keyEvent的常量中。(2)META Key
<1>輔助功能鍵: ALT、SHIFT、CAPS_LOCK
<2>輔助功能鍵的狀態
激活狀態 | metaState | |
base | META_key未被激活 | 0 |
caps | SHIFT或CAPS_LOCK被激活時 | 1 |
fn | ALT被激活 | 2 |
caps_fn | ALT,SHIFT或CAPS_LOCK同時被激活時 | 3 |
<3>示例
UiDevice.getInstance().pressKeyCode(KeyEvent.KEYCODE_A);//點擊輸入小寫字母aUiDevice.getInstance().pressKeyCode(KeyEvent.KEYCODE_A,1);//點擊輸入大寫字母A
三、獲取坐標與坐標點擊
1、坐標相關知識
(1)手機屏幕坐標:從左上角(0,0)開始到右下角(X,Y)(2)dp:設備獨立像素,例如,320像素顯示到640像素上要拉伸一倍
(3)Point:代表一個點(x,y)
2、坐標相關API
UiDevice實例調用以下方法即可實現獲取坐標和點擊操作。返回值 | 方法名 | 描述 |
boolean | click(int x, int y) | 使用坐標點擊屏幕 |
int | getDisplayHeight() | 獲取屏幕高度 |
Point | getDisplaySizeDp() | 獲取顯示尺寸返回顯示大小(設備獨立像素);屏幕旋轉返回的顯示大小調整 |
int | getDisplayWidth() | 獲得屏幕寬度 |
3、Uiautomator Viewer
(1)功能:獲取屏幕快照,並通過快照獲取到控件的屬性。(2)啟用方式
方式一、啟動路徑:adt/sdk/tools/UiautomatorViewer
方式二、Eclipse/DDMS/Devices/UiautomatorViewer
(3)屏幕快照參數之控件坐標
通過UiautomatorViewer獲取屏幕快照,選中目標控件,通過Node Detail / bounds[左上角頂點坐標][右下角頂點坐標] 可獲取到控件的位置。

4、示例
(1)
UiDevice.getInstance().click(399,355);//點擊[399,355]坐標點
(2)int h = UiDevice.getInstance().getDisplayHeight();
int w = UiDevice.getInstance().getDisplayWidth();
UiDevice.getInstance().click(w/2,h/2); //點擊屏幕的中心點
(3)
UiObject object = new UiObject(new UiSelector.resoutceId("com.andr....控件Id"));//根據ID獲取控件
Rect r = object.getBounds();//獲取控件對應的矩形區域相關屬性r.left; //矩形左上角頂點X坐標
r.top; //矩形左上角頂點Y坐標
r.right; //矩形右下角頂點X坐標
r.bottom; //矩形右下角頂點Y坐標
r.centerX(); //矩形的中心點X坐標
r.centerY(); //矩形的中心點Y坐標
四、拖拽與滑動
1、相關概念
(1)拖拽:將一個組件從一個坐標移動到另一個坐標處。
(2)滑動:手指從一個坐標點移動到另一個坐標點。
(3)步長:從一點滑動到另一點使用的時間,步長越短說明移動越快。
2、拖拽與滑動相關API
返回值 | 方法名 | 描述 |
boolean | drag(int startX, int startY, int endX, int endY, int steps) | 拖動對象從一個坐標拖動到另一個坐標,step表示拖拽過程使用的時間(ms) |
boolean | swipe(Point[] segments, int segmentSteps) | 在點陣列中滑動,5ms一步 |
boolean | swipe(int startX, int startY, int endX, int endY, int steps) | 通過坐標滑動屏幕 |
3、示例:按照一個矩形的路徑滑動
Point p1 = new Point();
Point p2 = new Point();
Point p3 = new Point();
Point p4 = new Point();
p1.x =277;
p1.y =318;
...... //設置四個頂點的橫縱坐標
Point[] pp = {p1,p2,p3,p4};
UiDevice.getInstance().swipe(pp,50); //每50毫秒走一步(從一個點滑動到下一個點)
五、旋轉屏幕
1 、旋轉屏幕相關知識
(1)旋轉方向:4個方向,分別為 0度,90度,180度,270度
(2)重力感應器
(3)固定位置與物理旋轉
固定位置:屏幕的方向固定在0、90、180、270度;
物理旋轉:與重力感應器連接,關閉了物理旋轉就是關閉了重力感應器。
2、屏幕旋轉相關API
返回值 | 方法名 | 描述 |
void | setOrientationLeft() | 通過禁用傳感器,然后模擬設備向左轉,並且固定位置 |
void | setOrientationNatural() | 通過禁用傳感器,然后模擬設備轉到其自然默認的方向,並且固定位置 |
void | setOrientationRight() | 通過禁用傳感器,然后模擬設備向右轉,並且固定位置 |
void | unfreezeRotation() | 重新啟用傳感器和允許物理旋轉 |
boolean | isNaturalOrientation() | 檢測設置是否處於默認旋轉狀態 |
int | getDisplayRotation() | 返回當前的顯示旋轉,0度,90度,180度,270度值分別為:0(Surface.ROTATION_0)、1(Surface.ROTATION_90)、2(類推)、3(類推) |
void | freezeRotation() | 禁用傳感器和凍結裝置物理旋轉在其當前旋轉狀態 |
六、滅屏與喚醒
滅屏與喚醒相關API
返回值 | 方法名 | 描述 |
void | wakeUp() | 模擬按電源鍵,如果屏幕是喚醒的沒有任何作用 |
void | sleep() | 模擬按電源鍵,如果屏幕已經是關閉的則沒有任何作用 |
boolean | isScreenOn() | 檢查屏幕是否亮屏 |
七、截圖與等待空閑
1 、截圖與等待空閑相關知識
(1)圖片縮放比例:如縮小1/2,即將100*100px的圖片長寬都縮小為原來的1/2,50*50px。
(2)圖片質量:一般是指圖片的大小,質量越高圖片越大。
(3)File 類:文件或者文件夾。
(4)圖片格式 :截圖的格式都是PNG。
(5)空閑狀態:窗口沒有更新或界面無動作。
(6)窗口更新事件。
2、截圖相關API
返回值 | 方法名 | 描述 |
boolean | takeScreenshot(File storePath) | 把當前窗口截圖並將其存儲為png默認1.0f的規模(原尺寸)和90%質量,參數為file類的文件路徑。 |
boolean | takeScreenshot(File storePath, float scale, int quality) | 把當前窗口截圖為png格式圖片,可以自定義縮放比例與圖片質量。 |
參數說明:
storePath:存儲路徑,必須為png格式。
scale:縮放比例,1.0為原圖。
quality:圖片壓縮質量,范圍為0-100。
3、等待空閑相關API
返回值 | 方法名 | 描述 |
void | waitForIdle(long timeout) | 自定義超時等待當前應用處於空閑狀態 |
void | waitForIdle() | 等待當前應用處於空閑狀態,默認等待10s;即10s后還不處於空閑狀態則報錯,程序在該句代碼處中斷;10s內程序處於空閑狀態,則該句代碼執行完畢。 |
boolean | waitForWindowUpdate(String packageName, long timeout) | 等待窗口內容更新事件的發生 |
八、獲取包名&開啟通知欄&快速設置&獲取布局文件
1、相關知識
包名:應用的唯一標識。
通知欄:從手機頂部下滑,出現的下拉界面即通知欄。
快速設置:即通知欄中的快速設置控件,快速設置界面可設置網絡、屏幕亮度、飛行模式等。
2、相關API
返回值 | 方法名 | 描述 |
void | getCurrentPackageName() | 獲取當前界面的包名,即目前處於手機前台的應用的包名 |
void | dumpWindowHierarchy(String fileName) | 獲取當前界面的布局文件,fileName給布局文件命名如“layout.xml”,保存在/data/local/tmp/目錄下 |
boolean | openNotification() | 打開通知欄 |
boolean | openQuickSettings() | 打開快速設置 |
更多具體用法見官方文檔:https://developer.android.google.cn/training/testing/ui-automator#ui-automator-apis