初衷
最近在編寫Android App自動化用例,其中元素定位相對來說耗費的時間比較長。我們都知道Appium-desktop擁有自己的錄制功能,我們就在想是不是可以把錄制功能跟我司的自動化框架(ATK)打通,直接生成我們框架可以識別的自動化腳本,甚至可以產出java版的IDE。這樣就可以節省大量的元素定位和腳本編寫時間。所以最近通過debug分析Appium-desktop的源碼,梳理了Appium-desktop定位/查找元素的原理。
由於appium-desktop使用react編寫了大量的組件,且使用的是electron框架,所以先來了解一下幾個概念以及調試代碼需要的環境准備
一、寫在前面
1、區分幾個概念
名稱 | 概念 | 下載鏈接 | 現狀 |
---|---|---|---|
appium/appium server | 這是appium體系的核心,它本身也是一個web接口服務,所以也會被稱為appium server,對外默認開啟包括4723等多個端口 | 1、安裝nodejs;2、安裝appium server,命令npm install -g appium;3、運行appium server appium --session-override |
appium Server不在更新,后續使用Appium Desktop |
Appium Desktop | 為了Appium更好用、入門更容易、讓調試和界面分析更方便,官方開發了GUI的工具,因為它內嵌了appium,很多人會以為它叫appium,其實它是個綜合性的桌面工具。只有分析時候才用,平時都是用appium。 | https://github.com/appium/appium-desktop/releases/ | 按照自己的節奏發布,並擁有自己的版本控制系統 |
Appium Client | appium只是一個web接口,他接受http請求,所以各個語言都可以自己封裝發送請求,於是就有appium下的各個子項目 | https://github.com/appium/appium/blob/master/docs/en/about-appium/appium-clients.md | 每個子項目各自迭代 |
Appium GUI | 也是把Appium server封裝成一個圖形界面,降低使用門檻。前幾年開始接觸appium,大部分教程都是基於這個GUI來講解的,所以很多人說起Appium就認為是這個 | https://bitbucket.org/appium/appium.app/downloads/ | 2015停止更新 |
2、一門語言(react)、一個框架(electron)
2.1、React
2.1.1、概念
React是Facrbook內部的一個JavaScript類庫,不是一個完整的MVC框架,最多可以認為是MVC中的V。React推薦以組件的方式去重新思考UI構成,將UI上每一個功能相對獨立的模塊定義成組件,然后將小的組件通過組合或者嵌套的方式構成大的組件,最終完成整體UI的構建。
2.1.2、專注
它專注於兩件事情--更新DOM和響應事件。
2.1.3、工作流
React以渲染函數為基礎。這些函數讀入當前的狀態,將其轉換為目標頁面上的一個虛擬表現。只要React被告知狀態有變化,他就會重新運行這些函數,計算出頁面的一個新的虛擬表現,接着自動把結果轉換成必要的DOM更新來反映新的表現
2.1.4、more
更多介紹:https://react.docschina.org
使用教程:http://www.runoob.com/react/react-component-life-cycle.html
2.2、electron
2.2.1、概念
Electron是用HTML,CSS和JavaScript來構建跨平台桌面應用程序的一個開源庫。 Electron通過將Chromium和Node.js合並到同一個運行時環境中,並將其打包為Mac,Windows和Linux系統下的應用來。
2.2.2、核心
electron核心可以分成2個部分,主進程和渲染進程。主進程連接着操作系統和渲染進程,可以把它看做頁面和計算機溝通的橋梁。渲染進程就是我們所熟悉前端環境了。主進程與渲染進程之間不能直接互相訪問,需要通過ipcMain和ipcRenderer進行通信。
主進程:有且只有一個主進程, package.json
中的main
字段標明腳本的進程稱為主進程.比如appium-desktop的主進程為dist/main.js的進程。
渲染進程:每個頁面都運行在自己的渲染進程。
通信:主進程和渲染進程通過消息監聽機制通信。其中主進程通過ipcMain.on和event.sender.send實現監聽渲染進程發來的消息和向渲染進程發送消息;渲染進程通過ipcRenderer.on和ipcRenderer.send實現監聽主進程發來的消息和向主進程發送消息。
2.2.3、調試
渲染進程調試:可以在開發者工具里的 Sources進行斷點調試。開發者工具通過這段代碼開啟mainWindow.webContents.openDevTools(),需要查看該段斷碼是否被注釋。appium-desktop是通過是否dev環境來判斷是否開啟,啟動腳本傳遞NODE_ENV=development即為dev環境。package.json中有寫好的腳本(start-dev),直接npm run start-dev即可。
主進程調試:通過electron進行調試,配置在Run/Debug Configurations中的Node.js運行環境中。如下圖
2.2.4、more
使用教程:https://www.w3cschool.cn/electronmanual/
2.3、環境
2.3.1、安裝cnpm
因為npm安裝插件是從國外服務器下載,受網絡影響大,可能出現異常,我們一般使用淘寶cnpm。
命令:
npm install -g cnpm --registry=https://registry.npm.taobao.org
npm config set registry http://registry.cnpmjs.org
2.3.2、install和build
下載依賴:cnpm install
編譯:cnpm run build. 一般Electron工程不需要build,直接運行就可以,appium-desktop因為主進程在build后的dist目錄下,所以需要build。
二、流程圖
獲取頁面dom文件,重新解析並渲染出來
三、主要步驟源碼解析
appium-desktop定位元素主要是把獲取到的當前頁面的DOM文件解析為json,並增加key字段作為后續操作的唯一標示,然后通過React把解析后的DOM文件重新渲染出來。通過事件點擊獲取到key,通過唯一key就可以從json中獲取到控件的所有屬性信息
3.1、獲取頁面dom文件
通過bootstrap腳本執行命令 獲取頁面dom文件,返回文件類似:
<?xml version=\"1.0\" encoding=\"UTF-8\"?><hierarchy rotation=\"0\"><android.widget.FrameLayout index=\"0\" text=\"\" class=\"android.widget.FrameLayout\" package=\"com.zhangdan.app\" content-desc=\"\" checkable=\"false\" checked=\"false\" clickable=\"false\" enabled=\"true\" focusable=\"false\" focused=\"false\" scrollable=\"false\" long-clickable=\"false\" password=\"false\" selected=\"false\" bounds=\"[0,0][1080,1920]\" resource-id=\"\" instance=\"0\">
可以看出文件中顯示關於控件的所有信息
3.2、把dom文件解析為json
3.2.1、xmlDoc
通過xmlDoc = (new DOMParser()).parseFromString(source, 'application/xml'); 獲取到的xmlDoc其實已經是樹狀的控件信息,如圖
3.2.2、element
返回元素信息包括 children,tagname,attributes,xpath,path. xpath是元素的全路徑;path是控件在json中的順序,這個是后面識別的唯一標示;attributes元素的屬性信息
3.3、重新定義元素
appium-desktop 重新根據自己的需求增加了key=path的屬性作為后續操作的標示,並使用react的功能渲染一個虛擬DOM顯示。
3.4、加載各個功能組件
appium-desktop 把各個功能點都作為組件來使用,所以源碼中compenents下面都是功能組件,然后利用react動態渲染DOM。如圖: