Android工具HierarchyViewer 代碼導讀(1) -- 功能實現演示

HierarchyViewer是Android SDK包中一個很是好用的工具,你在 android-sdks/tools目錄下能夠找到它。經過HierarchyViewer,即便沒有應用的源代碼,咱們也能夠很是直觀地瀏覽Activity中控件的層次結構圖,以及每一個控件的屬性和截圖,這對於測試人員編寫自動化測試用例是極有幫助的。這個系列的文章,咱們將經過閱讀和解析HierarchyViewer的代碼,來了解HierarchyViewer是如何工做的,也能夠加深Android提供給開發者的各類接口的瞭解。本系列文章代碼基於android4.0的源代碼,尚未下載源代碼的同窗快去下載吧,旅程這就開始了。html

本文首先並不直接從源代碼閱讀開始,而是demo和解釋HierarchyViewer的主要工做原理,這但是做者從源代碼中抽取的精華啊:)。看完本文,你就能夠寫一個本身簡單的HierarchyViewer了。咱們主要講解以下幾個部分:前端

1,如何鏈接ViewServerjava

2,如何獲取活動的Activitiesandroid

3,如何獲取Activity的控件樹shell

4,如何獲取截圖api

 

如何鏈接ViewServerbash

ViewServer是Android經過4939端口提供的服務,HierarchyViewer主要是經過它來獲取獲取Activity信息的, HierarchyViewer主要作下面3件事情來鏈接ViewServer。這須要用到Adb,HierarchyViewer中是直接經過api來調用Adb的,而這裏咱們先使用命令行adb來實現一樣的功能。eclipse

(1)Forword端口。就是把Android設備上的4939端口映射到PC的某端口上,這樣,向PC的該端口號發包都會轉發到Android設備的4939端口上。socket

首先,輸入命令列出全部Android設備tcp

adb devices

 

假設咱們有多臺設備鏈接在PC上,該命令的輸出爲:

List of devices attached 
emulator-5554	device
emulator-5556	device

 

以設備emulator-5556爲例,接下來咱們把它的4939端口映射到PC的4939端口上:

adb -s emulator-5556 forward tcp:4939 tcp:4939

若是鏈接了多臺Android設備,HierarchyViewer將把下一臺Android設備的4939端口映射到PC的4940端口,以此類推。

 

(2)打開ViewServer服務。

首先,須要判斷ViewServer是否打開:

adb -s emulator-5556 shell service call window 3

 

若是返回值是"Result: Parcel(00000000 00000000 '........')",說明ViewServer沒有打開,那麼須要用下面的命令打開ViewServer:

adb -s emulator-5556 shell service call window 1 i32 4939

 

反之,關閉ViewServer的命令是:

adb -s emulator-5556 shell service call window 2 i32 4939

 

(3)鏈接ViewServer,既然ViewServer已經打開,那麼下一步咱們就須要鏈接它了。因爲咱們已經把設備emulator-5556的4939端口映射爲PC的4939端口上,因此咱們須要鏈接的是127.0.0.1:4939。這須要寫一些java代碼:

import java.net.*;

try{
	Socket socket = new Socket();
	socket.connect(new InetSocketAddress("127.0.0.1", 4939),40000);
	BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
	BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "utf-8"));
} 
} catch ( Exception e ) {
	  e.printStackTrace(); 
}

out和in用於發送命令和接受返回數據,須要注意的是,HierarchyViewer和ViewServer的通訊採用短鏈接,因此每發送一次命令,須要從新創建一次鏈接,因此以上代碼須要反覆調用。

 

如何獲取活動的Activity

在打開HierarchyViewer時,會顯示每一個設備當前活動的Activity列表,以下圖:

image

 

這是怎麼實現的呢? 這須要向ViewerServer發送"LIST"命令,看下面的代碼:

//send ‘LIST’ command
out.write("LIST");
out.newLine();
out.flush();

//receive response from viewserver
String context="";
String line;
while ((line = in.readLine()) != null) {
            if ("DONE.".equalsIgnoreCase(line)) { //$NON-NLS-1$
                break;
            }
            context+=line+"\r\n";
}

 

咱們能夠獲取到相似以下的列表

44fd1b78 com.android.internal.service.wallpaper.ImageWallpaper
4507aa28 com.android.launcher/com.android.launcher2.Launcher
45047328 com.tencent.mobileqq/com.tencent.mobileqq.activity.HomeActivity
450b8d18 com.tencent.mobileqq/com.tencent.mobileqq.activity.NotificationActivity
451049c0 com.tencent.mobileqq/com.tencent.mobileqq.activity.NotificationActivity
451167a8 com.tencent.mobileqq/com.tencent.mobileqq.activity.UpgradeActivity
450efef0 com.tencent.mobileqq/com.tencent.mobileqq.activity.UpgradeActivity
4502f2e0 TrackingView
4503f560 StatusBarExpanded
44fe0bb0 StatusBar
44f09250 Keyguard

注意,每行前面的16進制數字,那是一個hashcode,咱們在進一步請求該Activity對應的控件樹時要用到該hashcode。

 

如何獲取Activity的控件樹
選中一個Activity後,HierarchyViewer將獲取它的控件並顯示爲層次圖:

image

 

獲取控件樹信息的命令是DUMP,後面要接對應的Activity的hash code,若是使用ffffffff做爲參數,那麼就是取最前端的Activity。咱們以com.android.launcher2.Launcher爲例,它的hash code是4507aa28,看代碼:

//out.write("DUMP ffffffff");
out.write("DUMP 4507aa28");
out.newLine();
out.flush();
	    
String context1="";
line="";
while ((line = in.readLine()) != null) {
	if ("DONE.".equalsIgnoreCase(line)) { //$NON-NLS-1$
		break;
	}
	context1+=line+"\r\n";
}

 

返回的控件樹被保存文本context1中,通常文本的內容都很是大,這裏我不把它所有打印出來,咱們只取其中一行來看:

android.widget.FrameLayout@44edba90 mForeground=52,android.graphics.drawable.NinePatchDrawable@44edc1e0 mForegroundInPadding=5,false mForegroundPaddingBottom=1,0 mForegroundPaddingLeft=1,0 mForegroundPaddingRight=1,0 mForegroundPaddingTop=1,0 mMeasureAllChildren=5,false mForegroundGravity=2,55 getDescendantFocusability()=24,FOCUS_BEFORE_DESCENDANTS getPersistentDrawingCache()=9,SCROLLING isAlwaysDrawnWithCacheEnabled()=4,true isAnimationCacheEnabled()=4,true isChildrenDrawingOrderEnabled()=5,false isChildrenDrawnWithCacheEnabled()=5,false mMinWidth=1,0 mPaddingBottom=1,0 mPaddingLeft=1,0 mPaddingRight=1,0 mPaddingTop=2,38 mMinHeight=1,0 mMeasuredWidth=3,480 mMeasuredHeight=3,800 mLeft=1,0 mPrivateFlags_DRAWING_CACHE_INVALID=3,0x0 mPrivateFlags_DRAWN=4,0x20 mPrivateFlags=8,16911408 mID=10,id/content mRight=3,480 mScrollX=1,0 mScrollY=1,0 mTop=1,0 mBottom=3,800 mUserPaddingBottom=1,0 mUserPaddingRight=1,0 mViewFlags=9,402653186 getBaseline()=2,-1 getHeight()=3,800 layout_bottomMargin=1,0 layout_leftMargin=1,0 layout_rightMargin=1,0 layout_topMargin=1,0 layout_height=12,MATCH_PARENT layout_width=12,MATCH_PARENT getTag()=4,null getVisibility()=7,VISIBLE getWidth()=3,480 hasFocus()=5,false isClickable()=5,false isDrawingCacheEnabled()=5,false isEnabled()=4,true isFocusable()=5,false isFocusableInTouchMode()=5,false isFocused()=5,false isHapticFeedbackEnabled()=4,true isInTouchMode()=4,true isOpaque()=5,false isSelected()=5,false isSoundEffectsEnabled()=4,true willNotCacheDrawing()=5,false willNotDraw()=5,false

返回的文本中的每一行是Activity中的一個控件,裏面包含了該控件的全部信息,HierarchyViewer正是經過解析這些信息並把它們顯示在屬性列表中的。須要注意每行的開始處都包含一個「控件類型@hash code」的字段,如android.widget.FrameLayout@44edba90 ,這個字段在獲取該控件的屏幕截圖時將被用到。

HierarchyViewer是怎麼把這個文本解析成層次圖的呢? 原來,每行前面都有若干空格的縮進,好比縮進5個空格表示該控件在第六層,那麼往上找,最近的縮進4個空格的控件就是它的父控件。在該系列後面的文章中,咱們將具體閱讀HierarchyViewer是怎麼解析該文本,又是如何顯示層次圖的。

 

如何獲取截圖

在層次圖上選中控件時,HierarchyViewer會顯示該控件的截圖:

image

 

獲取截圖的命令是CAPTURE,須要傳遞Activity的hashcode和控件的hashcode做爲參數,看下面的代碼:

import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Display;

out.write("CAPTURE 4507aa28 android.widget.FrameLayout@44edba90");
out.newLine();
out.flush();

Image image = new Image(Display.getDefault(), socket.getInputStream());

 

到此爲止,我相信你們已經對HierarchyViewer的主要實現機制有了基本的瞭解,接下來咱們就要真正開始閱讀HierarchyViewer的代碼了,後面幾章的內容大概是:

使用Eclipse閱讀和調試HierarchyViewer

HierarchyViewer的後臺代碼導讀

HierarchyViewer的前臺代碼導讀

 

本文爲知平軟件公司劉斌華原創做品,轉載請註明出處。

相關文章
相關標籤/搜索