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的前台代码导读

 

本文为知平软件公司刘斌华原创做品,转载请注明出处。

相关文章
相关标签/搜索