## 1.背景
使用SDK自带的NotePad应用作为实践目标应用,目的是对MonkeyDevice拥有的成员方法做一个初步的了解。
以下是官方列出的方法的Overview。
<table border="1" cellspacing="0" cellpadding="0" width="697"><tbody><tr><td valign="top" style="background-color:rgb(191,191,191)"><p align="center"><strong><span style="color:rgb(34,34,34)">Return Type</span></strong></p></td><td valign="top" style="background-color:rgb(191,191,191)"><p align="center"><strong>Methods</strong></p></td><td style="background-color:rgb(191,191,191)"><p align="center"><strong>Comment</strong></p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(34,34,34)">void</span></p></td><td valign="top"><p><a target="_blank" href="http://developer.android.com/tools/help/MonkeyDevice.html#broadcastIntent"><span style="color:rgb(37,138,175)">broadcastIntent</span></a><span style="color:rgb(34,34,34)"> (<em>string</em> uri, <em>string</em> action, <em>string</em> data, <em>string</em> mimetype, </span></p><p><em><span style="color:rgb(34,34,34)">iterable</span></em><span style="color:rgb(34,34,34)"> categories <em>dictionary</em> extras, <em>component</em> component, <em>iterable</em> flags)</span></p><p><span style="color:rgb(34,34,34)">Broadcasts an Intent to this device, as if the Intent were coming from an application.</span></p></td><td><p> </p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(34,34,34)">void</span></p></td><td valign="top"><p><a target="_blank" href="http://developer.android.com/tools/help/MonkeyDevice.html#drag"><span style="color:rgb(37,138,175)">drag</span></a><span style="color:rgb(34,34,34)"> (<em>tuple</em> start, <em>tuple</em> end, <em>float</em> duration, <em>integer</em> steps)</span></p><p><span style="color:rgb(34,34,34)">Simulates a drag gesture (touch, hold, and move) on this device's screen.</span></p></td><td><p> </p></td></tr><tr><td valign="top"><p align="center"><em><span style="color:rgb(34,34,34)">object</span></em></p></td><td valign="top"><p><a target="_blank" href="http://developer.android.com/tools/help/MonkeyDevice.html#getProperty"><span style="color:rgb(37,138,175)">getProperty</span></a><span style="color:rgb(34,34,34)"> (<em>string</em> key)</span></p><p><span style="color:rgb(34,34,34)">Given the name of a system environment variable, returns its value for this device.</span></p><p><span style="color:rgb(34,34,34)">The available variable names are listed in the </span><a target="_blank" href="http://developer.android.com/tools/help/MonkeyDevice.html#getProperty"><span style="color:rgb(37,138,175)">detailed description</span></a><span style="color:rgb(34,34,34)"> of this method.</span></p></td><td><p> </p></td></tr><tr><td valign="top"><p align="center"><em><span style="color:rgb(34,34,34)">object</span></em></p></td><td valign="top"><p><a target="_blank" href="http://developer.android.com/tools/help/MonkeyDevice.html#getSystemProperty"><span style="color:rgb(37,138,175)">getSystemProperty</span></a><span style="color:rgb(34,34,34)"> (<em>string</em> key)</span></p><p><span style="color:rgb(34,34,34)">. The API equivalent of </span><span style="color:rgb(0,102,0)">adb shell getprop <key>. This is provided for</span></p><p><span style="color:rgb(0,102,0)">use by platform developers.</span></p></td><td><p> </p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(34,34,34)">void</span></p></td><td valign="top"><p><a target="_blank" href="http://developer.android.com/tools/help/MonkeyDevice.html#installPackage"><span style="color:rgb(34,34,34)">installPackage</span></a><span style="color:rgb(34,34,34)"> (string path)</span></p><p><span style="color:rgb(34,34,34)">Installs the Android application or test package contained in packageFile onto this device.</span></p><p><span style="color:rgb(34,34,34)">If the application or test package is already installed, it is replaced.</span></p></td><td><p><span style="color:red">Obsolete,</span><span style="color:red">返回值是</span><span style="color:red">Boolean</span></p></td></tr><tr><td valign="top"><p align="center"><em><span style="color:rgb(34,34,34)">dictionary</span></em></p></td><td valign="top"><p><a target="_blank" href="http://developer.android.com/tools/help/MonkeyDevice.html#instrument"><span style="color:rgb(37,138,175)">instrument</span></a><span style="color:rgb(34,34,34)"> (<em>string</em> className, <em>dictionary</em> args)</span></p><p><span style="color:rgb(34,34,34)">Runs the specified component under Android instrumentation, and returns the results</span></p><p><span style="color:rgb(34,34,34)"> in a dictionary whose exact format is dictated by the component being run.</span></p><p><span style="color:rgb(34,34,34)"> The component must already be present on this device.</span></p></td><td><p> </p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(34,34,34)">void</span></p></td><td valign="top"><p><a target="_blank" href="http://developer.android.com/tools/help/MonkeyDevice.html#press"><span style="color:rgb(37,138,175)">press</span></a><span style="color:rgb(34,34,34)"> (<em>string</em> name, <em>dictionary</em> type)</span></p><p><span style="color:rgb(34,34,34)">Sends the key event specified by type to the key specified by keycode.</span></p></td><td><p> </p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(34,34,34)">void</span></p></td><td valign="top"><p><a target="_blank" href="http://developer.android.com/tools/help/MonkeyDevice.html#reboot"><span style="color:rgb(37,138,175)">reboot</span></a><span style="color:rgb(34,34,34)"> (<em>string</em> into)</span></p><p><span style="color:rgb(34,34,34)">Reboots this device into the bootloader specified by bootloadType.</span></p></td><td><p> </p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(34,34,34)">void</span></p></td><td valign="top"><p><a target="_blank" href="http://developer.android.com/tools/help/MonkeyDevice.html#removePackage"><span style="color:rgb(37,138,175)">removePackage</span></a><span style="color:rgb(34,34,34)"> (<em>string</em> package)</span></p><p><span style="color:rgb(34,34,34)">Deletes the specified package from this device, including its data and cache.</span></p></td><td><p> <span style="font-family:Arial; font-size:14px; line-height:26px; color:red">Obsolete,</span><span style="font-family:Arial; font-size:14px; line-height:26px; color:red">返回值是</span><span style="font-family:Arial; font-size:14px; line-height:26px; color:red">Boolean</span></p></td></tr><tr><td valign="top"><p align="center"><em><span style="color:rgb(34,34,34)">object</span></em></p></td><td valign="top"><p><a target="_blank" href="http://developer.android.com/tools/help/MonkeyDevice.html#shell"><span style="color:rgb(37,138,175)">shell</span></a><span style="color:rgb(34,34,34)"> (<em>string</em> cmd)</span></p><p><span style="color:rgb(34,34,34)">Executes an </span><span style="color:rgb(0,102,0)">adb</span><span style="color:rgb(34,34,34)"> shell command and returns the result, if any.</span></p></td><td><p> </p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(34,34,34)">void</span></p></td><td valign="top"><p><a target="_blank" href="http://developer.android.com/tools/help/MonkeyDevice.html#startActivity"><span style="color:rgb(37,138,175)">startActivity</span></a><span style="color:rgb(34,34,34)"> (<em>string</em> uri, <em>string</em> action, <em>string</em> data, <em>string</em> mimetype, <em>iterable</em> categories </span></p><p><em><span style="color:rgb(34,34,34)">dictionary</span></em><span style="color:rgb(34,34,34)"> extras, <em>component</em> component, <em>flags</em>)</span></p><p><span style="color:rgb(34,34,34)">Starts an Activity on this device by sending an Intent constructed from the supplied arguments.</span></p></td><td><p> </p></td></tr><tr><td valign="top"><p align="center"><a target="_blank" href="http://developer.android.com/tools/help/MonkeyImage.html"><span style="color:rgb(37,138,175)">MonkeyImage</span></a></p></td><td valign="top"><p><a target="_blank" href="http://developer.android.com/tools/help/MonkeyDevice.html#takeSnapshot"><span style="color:rgb(37,138,175)">takeSnapshot</span></a><span style="color:rgb(34,34,34)">()</span></p><p><span style="color:rgb(34,34,34)">Captures the entire screen buffer of this device, yielding a </span><a target="_blank" href="http://developer.android.com/tools/help/MonkeyImage.html"><span style="color:rgb(37,138,175)">MonkeyImage </span></a><span style="color:rgb(34,34,34)">object containing</span></p><p><span style="color:rgb(34,34,34)">a screen capture of the current display.</span></p></td><td><p> </p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(34,34,34)">void</span></p></td><td valign="top"><p><a target="_blank" href="http://developer.android.com/tools/help/MonkeyDevice.html#touch"><span style="color:rgb(37,138,175)">touch</span></a><span style="color:rgb(34,34,34)"> (<em>integer</em> x, <em>integer</em> y, <em>integer</em> type)</span></p><p><span style="color:rgb(34,34,34)">Sends a touch event specified by type to the screen location specified by x and y.</span></p></td><td><p> </p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(34,34,34)">void</span></p></td><td valign="top"><p><a target="_blank" href="http://developer.android.com/tools/help/MonkeyDevice.html#touch"><span style="color:rgb(37,138,175)">type</span></a><span style="color:rgb(34,34,34)"> (<em>string</em> message)</span></p><p><span style="color:rgb(34,34,34)">Sends the characters contained in message to this device, as if they had been typed on</span></p><p><span style="color:rgb(34,34,34)">the device's keyboard. This is equivalent to calling</span><a target="_blank" href="http://developer.android.com/tools/help/MonkeyDevice.html#press"><span style="color:rgb(37,138,175)">press()</span></a><span style="color:rgb(34,34,34)"> for each keycode in </span><span style="color:rgb(0,102,0)">message</span><span style="color:rgb(34,34,34)"> </span></p><p><span style="color:rgb(34,34,34)">using the key event type </span><span style="color:rgb(0,102,0)">DOWN_AND_UP</span><span style="color:rgb(34,34,34)">.</span></p></td><td><p> </p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(34,34,34)">void</span></p></td><td valign="top"><p><a target="_blank" href="http://developer.android.com/tools/help/MonkeyDevice.html#touch"><span style="color:rgb(37,138,175)">wake</span></a><span style="color:rgb(34,34,34)"> ()</span></p><p><span style="color:rgb(34,34,34)">Wakes the screen of this device.</span></p></td><td><p> </p></td></tr></tbody></table>
其实官方这个表是没有及时更新的,我现在手头上用到的MonkeyRunner是当前最新的,里面就拥有好几个官网没有列出来的API,我怀疑是不是自从UIAutomator在03年出来后,google就不打算再继续维护MonkeyRunner了?如果有朋友知道事实的话,还麻烦告知。
以下是我整理出来的源码多出来的可用公共API列表
<table border="1" cellspacing="0" cellpadding="0" width="697"><tbody><tr><td valign="top" style="background-color:rgb(191,191,191)"><p align="center"><strong><span style="color:rgb(34,34,34)">Return Type</span></strong></p></td><td valign="top" style="background-color:rgb(191,191,191)"><p align="center"><strong>Methods</strong></p></td><td style="background-color:rgb(191,191,191)"><p align="center"><strong>Comment</strong></p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(34,34,34)">HierarchyViewer</span></p></td><td valign="top"><p>getHierarchyViewer(PyObject args[], String kws[])</p><p>获取一个HierarchyViewer对象</p></td><td><p> 请查看《<a target="_blank" href="http://blog.csdn.net/zhubaitian/article/details/39851803" style="list-style:none; word-break:break-all; word-wrap:break-word; color:rgb(59,89,152); font-family:Verdana,'Lucida Grande',Arial,Helvetica,sans-serif">MonkenRunner通过HierarchyViewer定位控件的方法和建议</a>》</p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(34,34,34)">PyList</span></p></td><td valign="top"><p>getPropertyList(PyObject args[], String kws[])</p></td><td><p> 取得所有的property属性键值</p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(34,34,34)">PyList</span></p></td><td valign="top"><p>getViewIdList(PyObject args[], String kws[])</p></td><td><p> <span style="color:rgb(255,0,0)">Failed</span></p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(34,34,34)">MonkeyView</span></p></td><td valign="top"><p>getViewById(PyObject args[], String kws[])</p></td><td><p> <span style="color:rgb(255,0,0)">Failed</span></p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(34,34,34)">MonkeyView</span></p></td><td valign="top"><p>getViewByAccessibilityIds(PyObject args[], String kws[])</p></td><td><p> <span style="color:rgb(255,0,0)">Failed</span></p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(34,34,34)">MonkeyView</span></p></td><td valign="top"><p>getRootView(PyObject args[], String kws[])</p></td><td><p> <span style="color:rgb(255,0,0)">Failed</span></p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(34,34,34)">PyList</span></p></td><td valign="top"><p>getViewsByText(PyObject args[], String kws[])</p></td><td><p> <span style="color:rgb(255,0,0)">Failed</span></p></td></tr></tbody></table>
但可惜的是在本人尝试以上多出来的API的时候,发现除了最上面两个可用之外,其他的都不可用并抛出错误。且网上资料少的可怜,别人碰到同样的问题也找不到解决办法。所以本人怀疑这些“隐藏”API是不是并没有完善,或者说google不准备完善,所以才没有列出到官网上面去。本人用的SDK tools和Platform tools已经是当前最新的23.0.2和20.
一个台湾网友碰到的问题描述:[http://imsardine.simplbug.com/note/monkeyrunner/api/hierarchy-viewer.html](http://imsardine.simplbug.com/note/monkeyrunner/api/hierarchy-viewer.html)
## 2.Void broadcastIntent
(string uri, string action,string data, string mimetype, iterable categories dictionary extras, componentcomponent, iterable flags)
### 2.1 分析
本人理解的此方法的本意是想广播一个Intent给我们的AndroidDevice,目标应用接收到该Intent做相应的处理,比如打开一个Activity等。但在我的多次尝试下并没有成功!
~~~
targetDevice.broadcastIntent(action='android.intent.action.INSERT',
mimetype='vnd.android.cursor.dir/contact',
extras = {'name':'user1501488', 'phone':'123-15489'}
~~~
如果使用同样的参数,使用下面的startActivity是没有问题的。
~~~
targetDevice.startActivity(action='android.intent.action.INSERT',
mimetype='vnd.android.cursor.dir/contact',
extras = {'name':'user1501488', 'phone':'123-15489'})
~~~
google了半天网上根本找不到这个方法的使用例子,倒是stackOverFlow上有人建议用Shell来达到同样的效果。
~~~
targetDevice.shell("am start -a android.intent.action.INSERT -t vnd.android.cursor.dir/contact -e name 'Donald Duck' -e phone 555-1234").
~~~
所以可见这个方法并没有多少人在用,原因应该是它完全可以用上面介绍的两个方法替代。
## 3. void startActivity
(string uri, string action, string data, string mimetype, iterable categories dictionary extras, component component, flags)
### 3.1 示例
使用Action和mimetype来启动一个Activity:
~~~
targetDevice.startActivity(action='android.intent.action.VIEW',
mimetype='vnd.android.cursor.dir/vnd.google.note')
~~~
使用component来启动一个Activity:
~~~
targetDevice.startActivity(component="com.example.android.notepad/com.example.android.notepad.NotesList")
~~~
使用action,mimetype和指定extras参数来启动一个Activity:
~~~
targetDevice.startActivity(action='android.intent.action.INSERT',
mimetype='vnd.android.cursor.dir/contact',
extras = {'name':'user1501488', 'phone':'123-15489'})
~~~
### 3.2 分析
这个方法存在和以上的broadcastInt方法一样拥有同样的一大串参数,实例中只给出了本人已经跑通的例子,其他参数怎么用还有待深入研究,不过我相信对于我自己来说暂时这样子已经足够了。
另外需要注意的是参数中如果我们的填写不是按顺序从第一个参数开始的话,记得要在每个参数值前面指定你要传入的是哪个参数,不然默认就会从第一个参数开始算,这是python的基本语法了,这里就不展开了。
## 4. void drag (tuple start, tuple end, floatduration, integer steps)
这个方法的目的是按住一个控件然后把她拖动到其他位置
### 4.1 实例
~~~
viewer = targetDevice.getHierarchyViewer()
note = viewer.findViewById('id/text1')
point = viewer.getAbsoluteCenterOfView(note)
startX = point.x
startY = point.y
targetDevice.drag((startX,startY),(startX,startY),1)
targetDevice.press('KEYCODE_BACK', MonkeyDevice.DOWN_AND_UP)
~~~
### 4.2 分析和建议
以上示例是通过drag的方法来模拟LongPress,只要把参数中的起始坐标和目标坐标都设置成同样一个值,然后时常设置成一个有效的值就好了。
## 5 Object getProperty (string key)
通过环境变量的key来获得其对应的值。以下是官方提供的可用化境变量列表
<table border="1" cellspacing="0" cellpadding="0"><tbody><tr><td valign="top" style="background-color:rgb(191,191,191)"><p align="center">Property Group</p></td><td valign="top" style="background-color:rgb(191,191,191)"><p align="center">Property</p></td><td valign="top" style="background-color:rgb(191,191,191)"><p align="center">Description</p></td><td valign="top" style="background-color:rgb(191,191,191)"><p align="center">Notes</p></td></tr><tr><td rowspan="17" valign="top"><p align="center"><span style="color:rgb(0,102,0)">build</span></p></td><td valign="top"><p align="center"><span style="color:rgb(0,102,0)">board</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)">Code name for the device's system board</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)">See </span><a target="_blank" href="http://developer.android.com/reference/android/os/Build.html"><span style="color:rgb(37,138,175)">Build</span></a></p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(0,102,0)">brand</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)">The carrier or provider for which the OS is customized.</span></p></td><td><p><span style="color:rgb(34,34,34)"> </span></p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(0,102,0)">device</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)">The device design name.</span></p></td><td><p><span style="color:rgb(34,34,34)"> </span></p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(0,102,0)">fingerprint</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)">A unique identifier for the currently-running build.</span></p></td><td><p><span style="color:rgb(34,34,34)"> </span></p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(0,102,0)">host</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)"> </span></p></td><td><p><span style="color:rgb(34,34,34)"> </span></p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(0,102,0)">ID</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)">A changelist number or label.</span></p></td><td><p><span style="color:rgb(34,34,34)"> </span></p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(0,102,0)">model</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)">The end-user-visible name for the device.</span></p></td><td><p><span style="color:rgb(34,34,34)"> </span></p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(0,102,0)">product</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)">The overall product name.</span></p></td><td><p><span style="color:rgb(34,34,34)"> </span></p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(0,102,0)">tags</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)">Comma-separated tags that describe the build, such as "unsigned" and "debug".</span></p></td><td><p><span style="color:rgb(34,34,34)"> </span></p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(0,102,0)">type</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)">The build type, such as "user" or "eng".</span></p></td><td><p><span style="color:rgb(34,34,34)"> </span></p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(0,102,0)">user</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)"> </span></p></td><td><p><span style="color:rgb(34,34,34)"> </span></p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(0,102,0)">CPU_ABI</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)">The name of the native code instruction set, in the form CPU type plus ABI convention.</span></p></td><td><p><span style="color:rgb(34,34,34)"> </span></p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(0,102,0)">manufacturer</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)">The product/hardware manufacturer.</span></p></td><td><p><span style="color:rgb(34,34,34)"> </span></p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(0,102,0)">version.incremental</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)">The internal code used by the source control system to represent this version of the software.</span></p></td><td><p><span style="color:rgb(34,34,34)"> </span></p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(0,102,0)">version.release</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)">The user-visible name of this version of the software.</span></p></td><td><p><span style="color:rgb(34,34,34)"> </span></p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(0,102,0)">version.sdk</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)">The user-visible SDK version associated with this version of the OS.</span></p></td><td><p><span style="color:rgb(34,34,34)"> </span></p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(0,102,0)">version.codename</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)">The current development codename, or "REL" if this version of the software has been released.</span></p></td><td><p><span style="color:rgb(34,34,34)"> </span></p></td></tr><tr><td rowspan="3" valign="top"><p align="center"><span style="color:rgb(0,102,0)">display</span></p></td><td valign="top"><p align="center"><span style="color:rgb(0,102,0)">width</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)">The device's display width in pixels.</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)">See</span><a target="_blank" href="http://developer.android.com/reference/android/util/DisplayMetrics.html"><span style="color:rgb(37,138,175)">DisplayMetrics</span></a><span style="color:rgb(34,34,34)">for details.</span></p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(0,102,0)">height</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)">The device's display height in pixels.</span></p></td><td><p><span style="color:rgb(34,34,34)"> </span></p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(0,102,0)">density</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)">The logical density of the display. This is a factor that scales DIP (Density-Independent Pixel) units to the device's resolution. DIP is adjusted so that 1 DIP is equivalent to one pixel on a 160 pixel-per-inch display. For example, on a 160-dpi screen, density = 1.0, while on a 120-dpi screen, density = .75.</span></p><p><span style="color:rgb(34,34,34)">The value does not exactly follow the real screen size, but is adjusted to conform to large changes in the display DPI. See </span><a target="_blank" href="http://developer.android.com/reference/android/util/DisplayMetrics.html#density"><span style="color:rgb(37,138,175)">density</span></a><span style="color:rgb(34,34,34)"> for more details.</span></p></td><td><p><span style="color:rgb(34,34,34)"> </span></p></td></tr><tr><td rowspan="6" valign="top"><p align="center"><span style="color:rgb(0,102,0)">am.current</span></p></td><td valign="top"><p align="center"><span style="color:rgb(0,102,0)">package</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)">The Android package name of the currently running package.</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)">The </span><span style="color:rgb(0,102,0)">am.current</span><span style="color:rgb(34,34,34)">keys return information about the currently-running Activity.</span></p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(0,102,0)">action</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)">The current activity's action. This has the same format as the </span><span style="color:rgb(0,102,0)">name</span><span style="color:rgb(34,34,34)"> attribute of the </span><span style="color:rgb(0,102,0)">action</span><span style="color:rgb(34,34,34)"> element in a package manifest.</span></p></td><td><p><span style="color:rgb(34,34,34)"> </span></p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(0,102,0)">comp.class</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)">The class name of the component that started the current Activity. See </span><a target="_blank" href="http://developer.android.com/tools/help/MonkeyDevice.html#comppackage"><span style="color:rgb(37,138,175)">comp.package</span></a><span style="color:rgb(34,34,34)"> for more details.</span></p></td><td><p><span style="color:rgb(34,34,34)"> </span></p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(34,34,34)">comp.package</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)">The package name of the component that started the current Activity. A component is specified by a package name and the name of class that the package contains.</span></p></td><td><p><span style="color:rgb(34,34,34)"> </span></p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(0,102,0)">data</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)">The data (if any) contained in the Intent that started the current Activity.</span></p></td><td><p><span style="color:rgb(34,34,34)"> </span></p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(0,102,0)">categories</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)">The categories specified by the Intent that started the current Activity.</span></p></td><td><p><span style="color:rgb(34,34,34)"> </span></p></td></tr><tr><td valign="top"><p align="center"><span style="color:rgb(0,102,0)">clock</span></p></td><td valign="top"><p align="center"><span style="color:rgb(0,102,0)">realtime</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)">The number of milliseconds since the device rebooted, including deep-sleep time.</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)">See</span><a target="_blank" href="http://developer.android.com/reference/android/os/SystemClock.html"><span style="color:rgb(37,138,175)">SystemClock</span></a><span style="color:rgb(34,34,34)"> for more information.</span></p></td></tr></tbody></table>
### 5.1示例
~~~
displayWidth =targetDevice.getProperty ('display.width')
printdisplayWidth.encode('utf-8')
displayHight =targetDevice.getProperty('display.width')
printdisplayHight.encode('utf-8')
~~~
### 5.2 分析和建议
以上示例的目的是获得目标设备的长和高,当我们使用坐标点来操作控件的时候,调试的时候在一台机器上通过了,但是如果换了另外一个屏幕大小不一样的机器的话就会失败,因为控件的坐标点位置可能就变了。这个时候我们就需要用到示例中的连个属性来动态计算控件在不同屏幕大小的设备上面的坐标点了。
这里需要注意参数应该填写的格式是以上列表中前两列的组合PropertyGroup.Property
## 6. Object getSystemProperty (string key)
### 6.1 示例
~~~
displayWidth = targetDevice.getSystemProperty ('service.adb.tcp.port')
print displayWidth.encode('utf-8')
~~~
### 6.2 分析和建议
根据官网的描述,这个函数和getProperty函数应该有同样的功能(Synonym for [getProperty()](http://developer.android.com/tools/help/MonkeyDevice.html#getProperty).),使用的属性表也如上面的属性列表一样。但是按照我的实践并非如此,不过它确实如官方描述的等同于命令“adb shell getprop <key>.”倒是真的。
以上的例子是获取adb这个服务所打开的TCP端口,等同于如下的shell命令:“adb shell getprop service.adb.tcp.port“
如果我尝试使用下面的方法去获得设备的长度,返回的结果其实会是None
~~~
displayWidth = targetDevice.getSystemProperty ('display.width')
print displayWidth.encode('utf-8')
~~~
## 7 Boolean installPackage (string path)
### 7.1示例
~~~
if True == targetDevice.installPackage('D:\\Projects\\Workspace\\PythonMonkeyRunnerDemo\\apps\\MPortal.apk'):
print "Installationfinished successfully"
else:
print "Failedto install the apk"
~~~
### 7.2 分析和建议
这里有两点需要注意的:
- 官方网站描述的这个API是没有返回值的(见背景中的表),而最新版本的API里面是Boolean值。
- 参数输入的应该是PC端这边的Local路径而非目标系统的Local路径。
注意这里碰到一个路径问题,如果我的路径写成:
*'D:\Projects\Workspace\PythonMonkeyRunnerDemo\apps\MPortal.apk'*
那么会出现下图这样的错误:
![](https://box.kancloud.cn/2016-08-15_57b17558b01ca.jpg)
如果在“apps”前面加多个转义符就没有问题:
*'D:\Projects\Workspace\PythonMonkeyRunnerDemo\\apps\MPortal.apk'*
所以这里MonkeyRunner处理路径字串应该是存在Bug的,但是时间问题就先不去研究,建议所有路径的话“\“都加上转义符就好了
*'D:\\Projects\\Workspace\\PythonMonkeyRunnerDemo\\apps\MPortal.apk'*
## 8 boolean removePackage(string package)
### 8.1 示例
~~~
if True == targetDevice.removePackage('com.majcit.portal'):
print "Succeed toremove the package"
else:
print "Failedto remove teh package"
~~~
### 8.2 注意事项
· 如上面的installPackageAPI一样,官网描述的该API是没有返回值的,而最新的是返回boolean值
## 9. dictionary instrument (string className, dictionary args)
### 9.1 示例
只指定第一个参数(将会跑所有指定Component下的所有case+ NotePad项目本身的使用了Instrumentation的用例,具体意思请看下一节的分析)
~~~
dict = targetDevice.instrument('com.example.android.notepad.tryout/android.test.InstrumentationTestRunner')
print dict
~~~
指定只跑其中的一个Case:
~~~
dict = dict = targetDevice.instrument('com.example.android.notepad.tryout/android.test.InstrumentationTestRunner',
{'class':'com.example.android.notepad.tryout.TCCreateNote'})
print dict
~~~
### 9.2 分析
这里首先需要看下官方的描述
Runs the specifiedcomponent under Android instrumentation, and returns the results in adictionary whose exact format is dictated by the component being run. Thecomponent must already be present on this device
这里重点是第一句“Runs the specified component under Android instrumentation“,剩下的是说返回值根据模块不一样而有所差别。那么第一句翻译过来就是”运行使用了Anroid Instrumentation的指定模块“。那么究竟什么是使用了Android Instrumentation的指定模块呢?其实如果你有用过Robotium的话应该知道,脚本的每个case都是从Instrumentation相关的类中继承下来的。
以下是本人之前写的一个Robotium的测试case(具体请查看本人之前的一篇《[Robotium创建一个Note的实例](http://blog.csdn.net/zhubaitian/article/details/39502119)》,可以看到它是继承于“ActivityInstrumentationTestCase2”的,其实它就满足了刚才的描述“使用了Anroid Instrumentation的指定模块“
~~~
package com.example.android.notepad.tryout;
import com.robotium.solo.Solo;
import android.test.ActivityInstrumentationTestCase2;
import android.app.Activity;
@SuppressWarnings("rawtypes")
public class TCCreateNote extends ActivityInstrumentationTestCase2{
private static Solo solo = null;
public Activity activity;
private static final int NUMBER_TOTAL_CASES = 2;
private static int run = 0;
private static Class<?> launchActivityClass;
//对应re-sign.jar生成出来的信息框里的两个值
private static String mainActiviy = "com.example.android.notepad.NotesList";
private static String packageName = "com.example.android.notepad";
static {
try {
launchActivityClass = Class.forName(mainActiviy);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
@SuppressWarnings("unchecked")
public TCCreateNote() {
super(packageName, launchActivityClass);
}
@Override
public void setUp() throws Exception {
//setUp() is run before a test case is started.
//This is where the solo object is created.
super.setUp();
//The variable solo has to be static, since every time after a case's finished, this class TCCreateNote would be re-instantiated
// which would lead to soto to re-instantiated to be null if it's not set as static
if(solo == null) {
TCCreateNote.solo = new Solo(getInstrumentation(), getActivity());
}
}
@Override
public void tearDown() throws Exception {
//Check whether it's the last case executed.
run += countTestCases();
if(run >= NUMBER_TOTAL_CASES) {
solo.finishOpenedActivities();
}
}
public void testAddNoteCNTitle() throws Exception {
solo.clickOnMenuItem("Add note");
solo.enterText(0, "中文标签笔记");
solo.clickOnMenuItem("Save");
solo.clickInList(0);
solo.clearEditText(0);
solo.enterText(0, "Text 1");
solo.clickOnMenuItem("Save");
solo.assertCurrentActivity("Expected NotesList Activity", "NotesList");
solo.clickLongOnText("中文标签笔记");
solo.clickOnText("Delete");
}
public void testAddNoteEngTitle() throws Exception {
solo.clickOnMenuItem("Add note");
solo.enterText(0, "English Title Note");
solo.clickOnMenuItem("Save");
solo.clickInList(0);
solo.clearEditText(0);
solo.enterText(0, "Text 1");
solo.clickOnMenuItem("Save");
solo.assertCurrentActivity("Expected NotesList Activity", "NotesList");
solo.clickLongOnText("English Title Note");
solo.clickOnText("Delete");
}
}
~~~
那么我们先在目标机器上执行命令“pm list instrumentation”看是否能列出这个“Component”:
![](https://box.kancloud.cn/2016-08-15_57b17558eb89f.jpg)
这其中哪一个是我们想要的呢?这要看我们的Robotium测试项目中的AndroidManifest.xml的定义了,根据下图的packageName再对照上图的输出我们就定位到我们想要的Component了:
![](https://box.kancloud.cn/2016-08-15_57b175591fc76.jpg)
如果我们调用这个方法的时候只是填写了第一个参数的话,上图处在”com.example.andriod.notepad.tryout”这个Component下的所有三个方法都会执行。但在我的测试中,发现除了跑这个Case之外,它还跑多了一些步骤,就是额外的多创建了一个Note1。我查了半天,发现原来我之前除了编写了基于ActivityInstrumentationTestCase2的Robotium的这个项目之外,还在NoetePad这个项目上直接用InstrumentationTestCase写了一个基于Instrumentation的测试用例,做得事情就是增加一个Note1,具体请看本人另外一篇blog《[SDK Instrumentation创建一个Note的实例](http://blog.csdn.net/zhubaitian/article/details/39546371)》
![](https://box.kancloud.cn/2016-08-15_57b1755943887.jpg)
其实调用这个方法相当于在shell脚本上执行如下的命令:
*am instrument -w -r -e class com.example.android.notepad.tryout.TCCreateNote com.example.android.notepad.tryout/android.test.InstrumentationTestRunner*
最后提一下的是,我们的脚本在执行示例的时候大概5秒左右就会失败,但事实上在设备端所有的指定component的测试用例已经在执行的了。要解决这个问题需要重新编译源码,这里就免了,具体请查看:[http://stackoverflow.com/questions/4264057/android-cts-is-showing-shellcommandunresponsiveexception-on-emulator](http://stackoverflow.com/questions/4264057/android-cts-is-showing-shellcommandunresponsiveexception-on-emulator)
这里尝试做一个简单的总结
- 调用此方法之前先要找到第一个参数怎么写:执行命令“pm list instrumentation”
- 调用次方法如果不指定第一个参数会执行指定Component下面的所有测试脚本和目标应用包中所有用到Instrumentation的测试用例
- 调用此方法最终事实上是在目标机器上根据指定的参数执行“am instrument xxxx”
## 10 void press (string name, integer type)
### 10.1 示例
~~~
targetDevice.press('KEYCODE_BACK',MonkeyDevice.DOWN_AND_UP)
~~~
### 10.2 分析
这个方法的目的是发送一个指定的Key事件到Android设备以触发相应的动作,比如示例中发送“KEYCODE_BACK”这个key到设备端去触发”返回“键的按下和升起(也就是点击)的动作。
具体Key的Code请查看:[http://developer.android.com/reference/android/view/KeyEvent.html](http://developer.android.com/reference/android/view/KeyEvent.html)
第二个参数是指导该Key应该如何Behave,比如先按下去,休眠一秒再弹起来(其实就相当于一个长按的动作)。具体支持behavior在本MonkeyDevice这个类的成员变量里有定义好:
<table border="1" cellspacing="0" cellpadding="0"><tbody><tr><td valign="top" style="background-color:rgb(191,191,191)"><p align="center">Type</p></td><td valign="top" style="background-color:rgb(191,191,191)"><p align="center">Constants</p></td><td valign="top" style="background-color:rgb(191,191,191)"><p align="center">Notes</p></td><td valign="top" style="background-color:rgb(191,191,191)"><p align="center">Comment</p></td></tr><tr><td valign="top"><p align="center"><em><span style="color:rgb(34,34,34)">int</span><span style="color:rgb(34,34,34)">(</span><span style="color:red">官网是</span><span style="color:red">string,</span><span style="color:red">下同</span><span style="color:rgb(34,34,34)">)</span></em></p></td><td valign="top"><p align="center"><a target="_blank" href="http://developer.android.com/tools/help/MonkeyDevice.html#ACTION_DOWN"><span style="color:rgb(37,138,175)">DOWN</span></a></p></td><td valign="top"><p><span style="color:rgb(34,34,34)">Use this with the </span><span style="color:rgb(0,102,0)">type</span><span style="color:rgb(34,34,34)"> argument of </span><a target="_blank" href="http://developer.android.com/tools/help/MonkeyDevice.html#press"><span style="color:rgb(37,138,175)">press()</span></a><span style="color:rgb(34,34,34)"> or </span><a target="_blank" href="http://developer.android.com/tools/help/MonkeyDevice.html#touch"><span style="color:rgb(37,138,175)">touch()</span></a><span style="color:rgb(0,102,0)"> </span><span style="color:rgb(34,34,34)">to send a DOWN event.</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)"> </span></p></td></tr><tr><td valign="top"><p align="center"><em><span style="color:rgb(34,34,34)">int</span></em></p></td><td valign="top"><p align="center"><a target="_blank" href="http://developer.android.com/tools/help/MonkeyDevice.html#ACTION_UP"><span style="color:rgb(37,138,175)">UP</span></a></p></td><td valign="top"><p><span style="color:rgb(34,34,34)">Use this with the </span><span style="color:rgb(0,102,0)">type</span><span style="color:rgb(34,34,34)"> argument of </span><a target="_blank" href="http://developer.android.com/tools/help/MonkeyDevice.html#press"><span style="color:rgb(37,138,175)">press()</span></a><span style="color:rgb(34,34,34)"> or </span><a target="_blank" href="http://developer.android.com/tools/help/MonkeyDevice.html#touch"><span style="color:rgb(37,138,175)">touch()</span></a><span style="color:rgb(0,102,0)"> </span><span style="color:rgb(34,34,34)">to send an UP event.</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)"> </span></p></td></tr><tr><td valign="top"><p align="center"><em><span style="color:rgb(34,34,34)">int</span></em></p></td><td valign="top"><p align="center"><a target="_blank" href="http://developer.android.com/tools/help/MonkeyDevice.html#ACTION_DOWN_AND_UP"><span style="color:rgb(37,138,175)">DOWN_AND_UP</span></a></p></td><td valign="top"><p><span style="color:rgb(34,34,34)">Use this with the </span><span style="color:rgb(0,102,0)">type</span><span style="color:rgb(34,34,34)"> argument of </span><a target="_blank" href="http://developer.android.com/tools/help/MonkeyDevice.html#press"><span style="color:rgb(37,138,175)">press()</span></a><span style="color:rgb(34,34,34)"> or </span><a target="_blank" href="http://developer.android.com/tools/help/MonkeyDevice.html#touch"><span style="color:rgb(37,138,175)">touch()</span></a><span style="color:rgb(0,102,0)"> </span><span style="color:rgb(34,34,34)">to send a DOWN event immediately followed by an UP event.</span></p></td><td valign="top"><p><span style="color:rgb(34,34,34)"> </span></p></td></tr><tr><td valign="top"><p align="center"><em><span style="color:rgb(255,0,0)">int</span></em></p></td><td valign="top"><p align="center"><span style="color:rgb(255,0,0)">MOVE</span></p></td><td valign="top"><p><span style="color:rgb(255,0,0)"> <span style="background-color:rgb(255,255,51)">TBD</span></span></p></td><td valign="top"><p><span style="color:rgb(255,0,0)">官网没有列出</span><span style="color:red">来</span></p></td></tr></tbody></table>
## 11. void touch (integer x,integer y, integer type)
### 11.1 示例
~~~
viewer = targetDevice.getHierarchyViewer()
note = viewer.findViewById('id/text1')
point = viewer.getAbsoluteCenterOfView(note)
startX = point.x
startY = point.y
targetDevice.touch(startX,startY,MonkeyDevice.DOWN_AND_UP)
~~~
### 11.2 分析
这个和上面的press方法在结果上有点类似,但是本方法是接受坐标进行点击的,而上面方法接受的是keycode。
第二个参数同上。
## 12. void type (string message)
viewer =targetDevice.getHierarchyViewer()
note = viewer.findViewById(*'id/text1'*)
point = viewer.getAbsoluteCenterOfView(note)
startX = point.x
startY = point.y
targetDevice.touch(startX,startY,MonkeyDevice.DOWN_AND_UP)
MonkeyRunner.sleep(3)
targetDevice.type(*'NewContent'*)
### 12.1 示例
~~~
viewer = targetDevice.getHierarchyViewer()
note = viewer.findViewById('id/text1')
point = viewer.getAbsoluteCenterOfView(note)
startX = point.x
startY = point.y
targetDevice.touch(startX,startY,MonkeyDevice.DOWN_AND_UP)
MonkeyRunner.sleep(3)
targetDevice.type('NewContent')
~~~
### 12.2 分析
指定一串字符串进行模拟键盘输入,等同于调用press方法按照一个一个的keycode用MonkeyDevice的DOWN_AND_UP进行输入。
尝试时发现中文不支持,鉴于项目不需要用到这种手机键盘,所以节省时间暂不研究。
## 13. Wake()
### 13.1示例
~~~
targetDevice.wake()
~~~
### 13.2 分析
注意这里只是唤醒屏保,如果手机已经锁屏的话你是不能唤醒的。所以尝试这个API的时候要注意把锁屏功能先关闭掉。
## 14. MonkeyImange takeSnapshot()
### 14.1 示例
~~~
#Connect to the target targetDevice
targetDevice = MonkeyRunner.waitForConnection()
easy_device = EasyMonkeyDevice(targetDevice) #touch a button by id would need this
targetDevice.startActivity(component="com.example.android.notepad/com.example.android.notepad.NotesList")
#invoke the menu options
MonkeyRunner.sleep(6)
#targetDevice.press('KEYCODE_MENU', MonkeyDevice.DOWN_AND_UP);
'''
public ViewNode findViewById(String id)
* @param id id for the view.
* @return view with the specified ID, or {@code null} if no view found.
'''
#MonkeyRunner.alert("Continue?", "help", "Ok?")
pic = targetDevice.takeSnapshot()
pic = pic.getSubImage((0,38,480,762))
newPic = targetDevice.takeSnapshot()
newPic = newPic.getSubImage((0,38,480,762))
print (newPic.sameAs(pic,1.0))
newPic.writeToFile('./shot1.png','png')
~~~
## 14 object shell(string cmd)
### 14.1 示例
~~~
res = targetDevice.shell('ls /data/local/tmp|grep note')
print res
~~~
### 14.2 分析
这个命令等同于你直接在命令行上“adb shell $command”
##15 void reboot(string into)
其他参数没有用到所以也就没有尝试,仅仅尝试了不带参数的情况,结果就是直接reboot目标设备了
~~~
targetDevice.reboot()
~~~
这里有点需要提下的是,如果你是在MonkeyRunner命令行下执行这条命令的话,就算目标机器重启,整个MonkeyRunner的环境还是依然有效的。也就是说你如果继续打进一条"targetDevice.reboot()",你的设备就会再重启一次。
<table cellspacing="0" cellpadding="0" width="539" class=" " style="margin:0px 0px 10px; padding:0px; border-collapse:collapse; width:668px; max-width:100%; word-wrap:break-word!important"><tbody style="margin:0px; padding:0px; max-width:100%; word-wrap:break-word!important"><tr style="margin:0px; padding:0px; max-width:100%; word-wrap:break-word!important"><td valign="top" width="112" height="39" style="border-style:solid; border-color:rgb(0,0,0); margin:0px; padding:4px; word-break:break-all; max-width:100%; word-wrap:break-word!important"> </td></tr><tr style="margin:0px; padding:0px; max-width:100%; word-wrap:break-word!important"><td valign="top" width="111" height="13" style="border-style:solid; border-color:rgb(0,0,0); margin:0px; padding:4px; word-break:break-all; max-width:100%; word-wrap:break-word!important; background-color:rgb(190,192,191)"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; max-width:100%; clear:both; min-height:1em; white-space:pre-wrap; word-wrap:break-word!important"><span style="margin:0px; padding:0px; max-width:100%; word-wrap:break-word!important">作者</span></p></td><td valign="top" width="112" height="13" style="border-style:solid; border-color:rgb(0,0,0); margin:0px; padding:4px; word-break:break-all; max-width:100%; word-wrap:break-word!important; background-color:rgb(190,192,191)"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; max-width:100%; clear:both; min-height:1em; white-space:pre-wrap; word-wrap:break-word!important"><span style="margin:0px; padding:0px; max-width:100%; word-wrap:break-word!important">自主博客</span></p></td><td valign="top" width="111" height="13" style="border-style:solid; border-color:rgb(0,0,0); margin:0px; padding:4px; word-break:break-all; max-width:100%; word-wrap:break-word!important; background-color:rgb(190,192,191)"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; max-width:100%; clear:both; min-height:1em; white-space:pre-wrap; word-wrap:break-word!important"><span style="margin:0px; padding:0px; max-width:100%; word-wrap:break-word!important">微信</span></p></td><td valign="top" width="112" height="13" style="border-style:solid; border-color:rgb(0,0,0); margin:0px; padding:4px; word-break:break-all; max-width:100%; word-wrap:break-word!important; background-color:rgb(190,192,191)"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; max-width:100%; clear:both; min-height:1em; white-space:pre-wrap; word-wrap:break-word!important"><span style="margin:0px; padding:0px; max-width:100%; font-family:Helvetica; letter-spacing:0px; word-wrap:break-word!important">CSDN</span></p></td></tr><tr style="margin:0px; padding:0px; max-width:100%; word-wrap:break-word!important"><td valign="top" width="111" height="39" style="border-style:solid; border-color:rgb(0,0,0); margin:0px; padding:4px; word-break:break-all; max-width:100%; word-wrap:break-word!important; background-color:rgb(227,228,228)"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; max-width:100%; clear:both; min-height:1em; white-space:pre-wrap; word-wrap:break-word!important"><span style="margin:0px; padding:0px; max-width:100%; word-wrap:break-word!important">天地会珠海分舵</span></p></td><td valign="top" width="112" height="39" style="border-style:solid; border-color:rgb(0,0,0); margin:0px; padding:4px; word-break:break-all; max-width:100%; word-wrap:break-word!important"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; max-width:100%; clear:both; min-height:1em; white-space:pre-wrap; word-wrap:break-word!important"><span style="margin:0px; padding:0px; max-width:100%; font-size:11px; font-family:Helvetica; letter-spacing:0px; word-wrap:break-word!important"><a target="_blank" href="http://techgogogo.com/">http://techgogogo.com</a></span><span style="margin:0px; padding:0px; max-width:100%; font-family:Helvetica; font-size:11px; letter-spacing:0px; word-wrap:break-word!important"/></p><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; max-width:100%; clear:both; min-height:14px; white-space:pre-wrap; font-family:Helvetica; word-wrap:break-word!important"><br style="margin:0px; padding:0px; max-width:100%; word-wrap:break-word!important"/></p></td><td valign="top" width="111" height="39" style="border-style:solid; border-color:rgb(0,0,0); margin:0px; padding:4px; word-break:break-all; max-width:100%; word-wrap:break-word!important"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; max-width:100%; clear:both; min-height:1em; white-space:pre-wrap; word-wrap:break-word!important"><span style="margin:0px; padding:0px; max-width:100%; word-wrap:break-word!important">服务号</span><span style="margin:0px; padding:0px; max-width:100%; font-size:10px; font-family:Helvetica; letter-spacing:0px; word-wrap:break-word!important">:TechGoGoGo</span></p><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; max-width:100%; clear:both; min-height:1em; white-space:pre-wrap; word-wrap:break-word!important"><span style="margin:0px; padding:0px; max-width:100%; word-wrap:break-word!important">扫描码</span><span style="margin:0px; padding:0px; max-width:100%; font-size:10px; font-family:Helvetica; letter-spacing:0px; word-wrap:break-word!important">:</span></p><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; max-width:100%; clear:both; min-height:14px; white-space:pre-wrap; font-family:Helvetica; word-wrap:break-word!important"><img src="image/47cf4f9ec59b0ef1f807a6c33ab5ce5f.jpg" alt="" style="max-width:100%; margin:0px; padding:0px; height:auto!important; word-wrap:break-word!important; width:auto!important; visibility:visible!important"/></p></td><td valign="top" width="112" height="39" style="border-style:solid; border-color:rgb(0,0,0); margin:0px; padding:4px; word-break:break-all; max-width:100%; word-wrap:break-word!important"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; max-width:100%; clear:both; min-height:1em; white-space:pre-wrap; color:rgb(62,62,62); font-family:'Helvetica Neue',Helvetica,'Hiragino Sans GB','Microsoft YaHei',΢ÈíÑźÚ,Arial,sans-serif; font-size:18px; line-height:28.7999992370605px; word-wrap:break-word!important"><span style="margin:0px; padding:0px; max-width:100%; color:rgb(0,0,0); font-size:11px; font-family:Helvetica; letter-spacing:0px; word-wrap:break-word!important"><a target="_blank" href="http://blog.csdn.net/zhubaitian">http://blog.csdn.net/zhubaitian</a></span><span style="margin:0px; padding:0px; max-width:100%; color:rgb(0,0,0); font-family:Helvetica; font-size:11px; letter-spacing:0px; line-height:28.7999992370605px; word-wrap:break-word!important"/></p><div><span style="margin:0px; padding:0px; max-width:100%; color:rgb(0,0,0); font-family:Helvetica; font-size:11px; letter-spacing:0px; line-height:28.7999992370605px; word-wrap:break-word!important"><br/></span></div></td></tr></tbody></table>
- 前言
- MonkeyRunner创建一个Note的实例
- MonkeyRunner在Windows下的Eclipse开发环境搭建步骤(兼解决网上Jython配置出错的问题)
- MonkenRunner通过HierarchyViewer定位控件的方法和建议(Appium/UIAutomator/Robotium姊妹篇)
- MonkeyDevcie API 实践全记录
- MonkeyImage API 实践全记录
- EasyMonkeyDevice vs MonkeyDevice&amp;HierarchyViewer API Mapping Matrix
- adb概览及协议参考
- MonkeyRunner源码分析之-谁动了我的截图?
- MonkeyRunner源码分析之与Android设备通讯方式
- MonkeyRunner源码分析之启动
- Monkey源码分析之运行流程
- Monkey源码分析之事件源
- Monkey源码分析番外篇之WindowManager注入事件如何跳出进程间安全限制
- Monkey源码分析番外篇之Android注入事件的三种方法比较
- Monkey源码分析之事件注入
- monkey源码分析之事件注入方法变化
- MonkeyRunner源码分析之工作原理图
- Android自动化测试框架新书:&lt;&lt;MonnkeyRunner实现原理剖析&gt;&gt;交流