溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

UiAutomator源碼分析之UiAutomatorBridge框架

發(fā)布時(shí)間:2020-07-27 20:49:54 來(lái)源:網(wǎng)絡(luò) 閱讀:1116 作者:zhukev 欄目:開(kāi)發(fā)技術(shù)

上一篇文章《UIAutomator源碼分析之啟動(dòng)和運(yùn)行》我們描述了uitautomator從命令行運(yùn)行到加載測(cè)試用例運(yùn)行測(cè)試的整個(gè)流程,過(guò)程中我們也描述了UiAutomatorBridge這個(gè)類的重要性,說(shuō)它相當(dāng)于UiAutomation的代理(我們都知道UiAutomator是通過(guò)UiAutomation和AccessibilityService進(jìn)行連接然后獲取界面空間信息和注入事件的).那么今天開(kāi)始我們就圍繞這個(gè)類以及跟它有關(guān)系的類進(jìn)行進(jìn)一步的分析。


1. UiAutomatorBridge框架

這一章節(jié)我們會(huì)先看UiAutomatorBridge的整體框架,往后我會(huì)編寫(xiě)其他文章通過(guò)一些具體的例子把它們串起來(lái)。因?yàn)槲业膍ackbook pro上沒(méi)有安裝類圖軟件,所以下圖是手畫(huà)的

UiAutomator源碼分析之UiAutomatorBridge框架

往下我們就去初步描述下UiAutomatorBridge跟每一個(gè)相關(guān)的類的關(guān)系。


2. UiAutomatorBridge與UiAutomation的聚合關(guān)系

UiAutomatorBridge擁有一個(gè)UiAutomation的成員變量,它們是聚合的關(guān)系,注意不是組合,因?yàn)閁iAutomation不一定只能依賴UiAutomatorBridge而存在,我們上一章節(jié)的UiAutomatorTestRunner就擁有一個(gè)UiAutomation的成員變量。

一旦UiAutomator工具需要通過(guò)UiAutomatorBridge獲取界面或者注入事件的時(shí)候,就會(huì)調(diào)用該成員變量.比如下面這個(gè)很關(guān)鍵的去獲取當(dāng)前界面的Root Node的方法:

/*     */   public AccessibilityNodeInfo getRootInActiveWindow() { /*  66 */     return this.mUiAutomation.getRootInActiveWindow(); /*     */   }


3. UiAutomatorBridge與QueryController的關(guān)聯(lián)關(guān)系

QueryController做的所有事情就是去把UiSelector這個(gè)UI控件選擇子翻譯成真實(shí)的適合我們使用的android.view.accessibility.AccessibilityNodeInfo。 UiAutomatorBridge擁有一個(gè)成員變量mQueryController保存了QueryController的一個(gè)實(shí)例:

/*     */   private final QueryController mQueryController; /*     */   
當(dāng)UiObject需要獲取一個(gè)UiSelector指定的控件信息時(shí),會(huì)去調(diào)用UiAutomatorBridge的getQueryController方法來(lái)獲得這個(gè)mQueryController對(duì)象來(lái)進(jìn)行相應(yīng)的操作,如以下的UiObject的方法findAccessibilityNodeInfo就是這樣做的:

/*      */   protected AccessibilityNodeInfo findAccessibilityNodeInfo(long timeout) /*      */   { /*  164 */     AccessibilityNodeInfo node = null; /*  165 */     long startMills = SystemClock.uptimeMillis(); /*  166 */     long currentMills = 0L; /*  167 */     while (currentMills <= timeout) { /*  168 */       node = getQueryController().findAccessibilityNodeInfo(getSelector()); /*  169 */       if (node != null) { /*      */         break; /*      */       } /*      */        /*  173 */       UiDevice.getInstance().runWatchers(); /*      */        /*  175 */       currentMills = SystemClock.uptimeMillis() - startMills; /*  176 */       if (timeout > 0L) { /*  177 */         SystemClock.sleep(1000L); /*      */       } /*      */     } /*  180 */     return node; /*      */   }

該getQueryController方法會(huì)去調(diào)用UiAutomatorBridge的getQueryController方法:

/*      */   QueryController getQueryController() /*      */   { /*  100 */     return UiDevice.getInstance().getAutomatorBridge().getQueryController(); /*      */   }
從上面的類圖我們可以看到,除了UiAutomatorBridge會(huì)調(diào)用QueryController做事情外,QueryController又會(huì)反過(guò)來(lái)調(diào)用UiAutomatorBridge來(lái)做事情,因?yàn)槿鐖D所描述的,只有UiAutomatorBridge擁有UiAutomation的實(shí)例,所以QueryController會(huì)持有一個(gè)UiAutomatorBridge的實(shí)例:

/*     */   private final UiAutomatorBridge mUiAutomatorBridge;
然后在需要的時(shí)候再調(diào)用UiAutomatorBridge,如下面的獲得Root Node的方法:

/*     */   protected AccessibilityNodeInfo getRootNode() /*     */   { /* 168 */     int maxRetry = 4; /* 169 */     long waitInterval = 250L; /* 170 */     AccessibilityNodeInfo rootNode = null; /* 171 */     for (int x = 0; x < 4; x++) { /* 172 */       rootNode = this.mUiAutomatorBridge.getRootInActiveWindow(); /* 173 */       if (rootNode != null) { /* 174 */         return rootNode; /*     */       } /* 176 */       if (x < 3) { /* 177 */         Log.e(LOG_TAG, "Got null root node from accessibility - Retrying..."); /* 178 */         SystemClock.sleep(250L); /*     */       } /*     */     } /* 181 */     return rootNode; /*     */   }

4. UiAutomatorBridge與InteractionController的關(guān)聯(lián)關(guān)系

道理與以上的QueryController一樣,只是UiAutomatorBridge需要通過(guò)InteractionController做的事情不是去獲得控件信息,而是去注入事件。

5. UiAutomatorBridge與ShellUiAutomatorBridge的繼承關(guān)系

UiAutomatorBridge是一個(gè)抽象類,里面的方法有以下幾個(gè):

  • getRootInActiveWindow :通過(guò)UiAutomation獲取當(dāng)前窗口控件xml信息的根節(jié)點(diǎn)(通過(guò)它可以循環(huán)獲取所有控件)
  • injectInputEvent :通過(guò)UiAutomation注入事件
  • waitForIdle :   通過(guò)UiAutomation睡眠指定時(shí)間

  • executeCommandAndWaitForAccessibilityEvent:通過(guò)UiAutomation執(zhí)行指定線程的操作然后等待預(yù)期的時(shí)間返回

  • takeScreenshot :通過(guò)UiAutomation進(jìn)行截圖

  • performGlobalAction :  通過(guò)UiAutomation去執(zhí)行一些全局的動(dòng)作,如打開(kāi)最近打開(kāi)過(guò)的app列表,回到home界面等

從中可以看到這些動(dòng)過(guò)都是需要通過(guò)UiAutomation來(lái)執(zhí)行的,但也有一些動(dòng)作是不需要用UiAutomation執(zhí)行的,所以我相信google是為了代碼清晰和可維護(hù)性,提供了子類ShellUiAutomatorBridge來(lái)專門(mén)處理那些不需要用到UiAutomation的情況,比如以下的isScreenOn方法就不需要用到UiAutomation,而是直接用PowerManager服務(wù)來(lái)判斷當(dāng)前屏幕是否是打開(kāi)的:

/*     */   public boolean isScreenOn() /*     */   { /* 111 */     IPowerManager pm = IPowerManager.Stub.asInterface(ServiceManager.getService("power")); /*     */      /* 113 */     boolean ret = false; /*     */     try { /* 115 */       ret = pm.isScreenOn(); /*     */     } catch (RemoteException e) { /* 117 */       Log.e(LOG_TAG, "Error getting screen status", e); /* 118 */       throw new RuntimeException(e); /*     */     } /* 120 */     return ret; /*     */   }


<optgroup id="cckvk"></optgroup>
<s id="cckvk"></s>
 

作者

自主博客

微信

CSDN

天地會(huì)珠海分舵

http://techgogogo.com


服務(wù)號(hào):TechGoGoGo

掃描碼:

UiAutomator源碼分析之UiAutomatorBridge框架

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI