此文章摘抄于http://www.cnblogs.com/vowei/archive/2012/07/30/2614353.html

与大家共勉:

HierarchyViewer是Android SDK包中一个非常好用的工具,你在 android-sdks/tools目录下可以找到它。通过HierarchyViewer,即使没有应用的源代码,我们也可以非常直观地浏览Activity中控件的层次结构图,以及每个控件的属性和截图,这对于测试人员编写自动化测试用例是极有帮助的。这个系列的文章,我们将通过阅读和解析HierarchyViewer的代码,来了解HierarchyViewer是如何工作的,也可以加深Android提供给开发者的各种接口的了解。本系列文章代码基于android4.0的源代码,还没有下载源代码的同学快去下载吧,旅程这就开始了。

本文首先并不直接从源代码阅读开始,而是demo和解释HierarchyViewer的主要工作原理,这可是作者从源代码中抽取的精华啊:)。看完本文,你就可以写一个自己简单的HierarchyViewer了。我们主要讲解如下几个部分:

1,如何连接ViewServer

2,如何获取活动的Activities

3,如何获取Activity的控件树

4,如何获取截图

如何连接ViewServer

ViewServer是Android通过4939端口提供的服务,HierarchyViewer主要是通过它来获取获取Activity信息的, HierarchyViewer主要做下面3件事情来连接ViewServer。这需要用到Adb,HierarchyViewer中是直接通过api来调用Adb的,而这里我们先使用命令行adb来实现同样的功能。

(1)Forword端口。就是把Android设备上的4939端口映射到PC的某端口上,这样,向PC的该端口号发包都会转发到Android设备的4939端口上。

首先,输入命令列出所有Android设备

1
adb devices

假设我们有多台设备连接在PC上,该命令的输出为:

1
2
3
List of devices attached
emulator-5554   device
emulator-5556   device

以设备emulator-5556为例,接下来我们把它的4939端口映射到PC的4939端口上:

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

如果连接了多台Android设备,HierarchyViewer将把下一台Android设备的4939端口映射到PC的4940端口,以此类推。

(2)打开ViewServer服务。

首先,需要判断ViewServer是否打开:

1
adb -s emulator-5556 shell service call window 3

如果返回值是"Result: Parcel(00000000 00000000 '........')",说明ViewServer没有打开,那么需要用下面的命令打开ViewServer:

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

反之,关闭ViewServer的命令是:

1
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代码:

1
2
3
4
5
6
7
8
9
10
11
importjava.net.*;
try{
    Socket socket = newSocket();
    socket.connect(newInetSocketAddress("127.0.0.1", 4939),40000);
    BufferedWriter out = newBufferedWriter(newOutputStreamWriter(socket.getOutputStream()));
    BufferedReader in = newBufferedReader(newInputStreamReader(socket.getInputStream(), "utf-8"));
}
} catch( Exception e ) {
      e.printStackTrace();
}

out和in用于发送命令和接受返回数据,需要注意的是,HierarchyViewer和ViewServer的通信采用短连接,所以每发送一次命令,需要重新建立一次连接,所以以上代码需要反复调用。

如何获取活动的Activity

在打开HierarchyViewer时,会显示每个设备当前活动的Activity列表,如下图:

这是怎么实现的呢? 这需要向ViewerServer发送"LIST"命令,看下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//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";
}

我们可以获取到类似如下的列表

1
2
3
4
5
6
7
8
9
10
11
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将获取它的控件并显示为层次图:

获取控件树信息的命令是DUMP,后面要接对应的Activity的hash code,如果使用ffffffff作为参数,那么就是取最前端的Activity。我们以com.android.launcher2.Launcher为例,它的hash code是4507aa28,看代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
//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中,一般文本的内容都非常大,这里我不把它全部打印出来,我们只取其中一行来看:

1
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会显示该控件的截图:

获取截图的命令是CAPTURE,需要传递Activity的hashcode和控件的hashcode作为参数,看下面的代码:

1
2
3
4
5
6
7
8
importorg.eclipse.swt.graphics.Image;
importorg.eclipse.swt.widgets.Display;
out.write("CAPTURE 4507aa28 android.widget.FrameLayout@44edba90");
out.newLine();
out.flush();
Image image = newImage(Display.getDefault(), socket.getInputStream());

HierarchyViewer是Android SDK包中一个非常好用的工具,你在 android-sdks/tools目录下可以找到它。通过HierarchyViewer,即使没有应用的源代码,我们也可以非常直观地浏览Activity中控件的层次结构图,以及每个控件的属性和截图,这对于测试人员编写自动化测试用例是极有帮助的。这个系列的文章,我们将通过阅读和解析HierarchyViewer的代码,来了解HierarchyViewer是如何工作的,也可以加深Android提供给开发者的各种接口的了解。本系列文章代码基于android4.0的源代码,还没有下载源代码的同学快去下载吧,旅程这就开始了。

本文首先并不直接从源代码阅读开始,而是demo和解释HierarchyViewer的主要工作原理,这可是作者从源代码中抽取的精华啊:)。看完本文,你就可以写一个自己简单的HierarchyViewer了。我们主要讲解如下几个部分:

1,如何连接ViewServer

2,如何获取活动的Activities

3,如何获取Activity的控件树

4,如何获取截图

如何连接ViewServer

ViewServer是Android通过4939端口提供的服务,HierarchyViewer主要是通过它来获取获取Activity信息的, HierarchyViewer主要做下面3件事情来连接ViewServer。这需要用到Adb,HierarchyViewer中是直接通过api来调用Adb的,而这里我们先使用命令行adb来实现同样的功能。

(1)Forword端口。就是把Android设备上的4939端口映射到PC的某端口上,这样,向PC的该端口号发包都会转发到Android设备的4939端口上。

首先,输入命令列出所有Android设备

1
adb devices

假设我们有多台设备连接在PC上,该命令的输出为:

1
2
3
List of devices attached
emulator-5554   device
emulator-5556   device

以设备emulator-5556为例,接下来我们把它的4939端口映射到PC的4939端口上:

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

如果连接了多台Android设备,HierarchyViewer将把下一台Android设备的4939端口映射到PC的4940端口,以此类推。

(2)打开ViewServer服务。

首先,需要判断ViewServer是否打开:

1
adb -s emulator-5556 shell service call window 3

如果返回值是"Result: Parcel(00000000 00000000 '........')",说明ViewServer没有打开,那么需要用下面的命令打开ViewServer:

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

反之,关闭ViewServer的命令是:

1
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代码:

1
2
3
4
5
6
7
8
9
10
11
importjava.net.*;
try{
    Socket socket = newSocket();
    socket.connect(newInetSocketAddress("127.0.0.1", 4939),40000);
    BufferedWriter out = newBufferedWriter(newOutputStreamWriter(socket.getOutputStream()));
    BufferedReader in = newBufferedReader(newInputStreamReader(socket.getInputStream(), "utf-8"));
}
} catch( Exception e ) {
      e.printStackTrace();
}

out和in用于发送命令和接受返回数据,需要注意的是,HierarchyViewer和ViewServer的通信采用短连接,所以每发送一次命令,需要重新建立一次连接,所以以上代码需要反复调用。

如何获取活动的Activity

在打开HierarchyViewer时,会显示每个设备当前活动的Activity列表,如下图:

这是怎么实现的呢? 这需要向ViewerServer发送"LIST"命令,看下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//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";
}

我们可以获取到类似如下的列表

1
2
3
4
5
6
7
8
9
10
11
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将获取它的控件并显示为层次图:

获取控件树信息的命令是DUMP,后面要接对应的Activity的hash code,如果使用ffffffff作为参数,那么就是取最前端的Activity。我们以com.android.launcher2.Launcher为例,它的hash code是4507aa28,看代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
//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中,一般文本的内容都非常大,这里我不把它全部打印出来,我们只取其中一行来看:

1
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会显示该控件的截图:

获取截图的命令是CAPTURE,需要传递Activity的hashcode和控件的hashcode作为参数,看下面的代码:

1
2
3
4
5
6
7
8
importorg.eclipse.swt.graphics.Image;
importorg.eclipse.swt.widgets.Display;
out.write("CAPTURE 4507aa28 android.widget.FrameLayout@44edba90");
out.newLine();
out.flush();
Image image = newImage(Display.getDefault(), socket.getInputStream());

到此为止,我相信大家已经对HierarchyViewer的主要实现机制有了基本的了解

Android 之HierarchyViewer - 4939相关推荐

  1. Android工具HierarchyViewer 代码导读(3) -- 后台代码

    在上文中,我们讲解了如何把HierarchyViewer的项目导入到Eclipse中,以便更高效阅读代码.本文将讲解HierarchyViewer的后台代码,建议大家可以先阅读<Android工 ...

  2. android hierarchyViewer 的UI工具的使用

    Hierarchy Viewer 帮你分析应用程序UI布局 Hierarchy Viewer在android的工具文件夹里: /android/tools/hierarchyviewer.bat 1. ...

  3. Android自动化测试之MonkeyRunner MonkeyDevice MonkeyImage API使用详解 脚本编写 脚本录制回放

    MonkeyRunner 系列文章 MonkeyRunner简介 MonkeyRunner 三大模块 MonkeyRunner API MonkeyDevice API MonkeyImage API ...

  4. Android必会的自动化测试

    monkey测试 adb shell  monkey -p com.slicejobs.ailinggong -v 500 monkey running ----------------------- ...

  5. AndroidStudio中如何打开hierarchyviewer.bat

    Hierarchy Viewer在Android的工具文件夹里: \android\tools\hierarchyviewer.bat 但这种启动方式的缺点是无法显示每个View节点的性能指标(颜色点 ...

  6. Android 动画框架详解,第 1 部分

    2019独角兽企业重金招聘Python工程师标准>>> Android 平台提供了一套完整的动画框架,使得开发者可以用它来开发各种动画效果,本文将向读者阐述 Android 的动画框 ...

  7. 入门monkeyrunner7-monkeyrunner demo3 EasyMonkeyDevice+hierarchyviewer +monkeyrunner+截图对比

    1 #该demo为monkeyrunner测试安卓系统自带的计计算器 2 #测试图片对比,测试EasyMonkeyDevice对象,一些他的元素操作 3 #作者:Mads Spiral QQ:7952 ...

  8. Java电子书平滑翻页效果_(转载)Android 平滑和立体翻页效果1

    Android 平台提供了一套完整的动画框架,使得开发者可以用它来开发各种动画效果,本文将向读者阐述 Android 的动画框架是如何实现的.任何一个框架都有其优势和局限性,只有明白了其实现原理,开发 ...

  9. github android

    作者:ruijun 链接:https://www.zhihu.com/question/37160415/answer/79569042 来源:知乎 著作权归作者所有,转载请联系作者获得授权.###开 ...

  10. 使用Monkeyrunner进行Android自动化的总结

    使用Android自动化的方式,不仅可以用来对Android APP进行自动化测试,同样可以用来进行一些其他非常有意思的自动化任务.常用的自动化工具有Monkeyrunner, Robotium, A ...

最新文章

  1. 树——通用树结点数目、高度和度数的实现
  2. Fedora9中的gcc
  3. linux配置文件引用时间,linux时间设置、screen使用、命令分类、hash作用、命令引用及history命令...
  4. Qt5.8 Windows端 关于 Style Plugin Example 官方实例中的错误
  5. shell记录报警系统执行的危险命令
  6. 剑指Offer之平衡二叉树
  7. swiper切换按钮位置改变_2019-01-18左右按钮控制swiper轮播图切换
  8. hdu 4864 task 贪心
  9. MapReduce如何使用多路输出
  10. 身为管理者 会讲的六十八个故事
  11. 《大学美育》大作业——何为美
  12. MyX5TbsDemo【体验腾讯浏览服务Android SDK (完整版)】
  13. Python分组百分比排名
  14. gopher攻击mysql_CTFweb类型(二十七)gopher对mysql的利用及例题讲解
  15. PDF旋转使用的转换器有哪些
  16. C++ endl/ends/flush的区别
  17. 【微信小程序】企业付款接口
  18. 案例研究:什么是自动驾驶?
  19. 奔图Pantum M6608 一体机驱动
  20. 怎么样就是把最新的网址加上最新的日期呢?

热门文章

  1. PHP、TP5生成下载word
  2. gta5怎么设置画质最好_GTA5画面如何设置最好_GTA5画质设置成最高配置推荐-win7之家...
  3. 服务器虚拟化的主要特点,网络虚拟化的七大特征
  4. python面向对象学习
  5. 星号密码查看器原理完全揭秘
  6. Leetcode热门100之两数相加
  7. 再掀融资潮 团购网仍后劲不足(团购现状分析)
  8. 数据库实验(数据库安全管理)
  9. 10003 微信登录失败 redirect_uri域名与后台配置不一致
  10. 百度搜索引擎优化入门篇——来自百度的一封信