溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

EasyMonkeyDevice vs MonkeyDevice&HierarchyViewer API Mapping Matrix

發(fā)布時(shí)間:2020-06-04 09:30:47 來源:網(wǎng)絡(luò) 閱讀:433 作者:zhukev 欄目:移動(dòng)開發(fā)

1. 前言

本來這次文章的title是寫成和前幾篇類似的《EasyMonkeyDevice API實(shí)踐全記錄》,內(nèi)容也打算把每個(gè)API的實(shí)踐和建議給記錄下來,但后來想了下覺得這樣子并不是最好的方法,鑒于EasyMonkeyDevice其實(shí)就是在前幾章描述的MonkeyDevice和HierarchyViewer的基礎(chǔ)上加了一層Wrapper,把原來的通過接受坐標(biāo)點(diǎn)或者ViewNode來操作控件的思想統(tǒng)一成通過控件ID來操作,其實(shí)最終它們都會(huì)轉(zhuǎn)換成坐標(biāo)點(diǎn)或ViewNode進(jìn)行操作。以touch和visible這兩個(gè)API為例子,大家看下以下的源碼就很清楚了。
MonkeyDevice里面的touch是用坐標(biāo)點(diǎn)作為參數(shù)的,而下面的EasyMonkeyDevice用得是id(By這個(gè)類里面就一個(gè)ID而已,有興趣查其源碼),最終還是轉(zhuǎn)成坐標(biāo)點(diǎn):
public void touch(By selector, TouchPressType type)     {         Point p = getElementCenter(selector);         mDevice.getImpl().touch(p.x, p.y, type);     }
HierarchyViewer里面的Visible用的是ViewNode,EasyMonkeyDevice用得是id,最終還是轉(zhuǎn)成ViewNode:
public boolean visible(By selector)     {         ViewNode node = selector.findView(mHierarchyViewer);         return mHierarchyViewer.visible(node);     }
所以本文應(yīng)該除了給出API的實(shí)踐之外還應(yīng)該把每個(gè)API和其與MonkeyDevice和HierarchyViewer的API所對(duì)應(yīng)的API給列出來做一個(gè)對(duì)應(yīng)的Map,方便我們參考。

實(shí)踐中我們還是用SDK自帶的NotePad APK,假設(shè)已經(jīng)有一個(gè)Note存在的情況下,通過以下步驟來走一遍EasyMonkeyDevice的所有API:
  • 使用MonkeyDevice對(duì)象實(shí)例化EasyMonkeyDevice
  • 通過ID Touch一個(gè)Note
  • 獲得進(jìn)入NoteEditor activity后的WindowId并驗(yàn)證是否正確
  • 通過ID檢查Note的內(nèi)容這個(gè)EditText是否存在和可見
  • 通過Note的ID獲得Text
  • 通過Note的ID Type進(jìn)新Text
  • 通過Note的ID獲得Location
以下是我們操作過程中會(huì)看到的兩個(gè)Activity的截圖,先貼上來給大家對(duì)以上步驟有一個(gè)感性認(rèn)識(shí),最后我會(huì)貼出實(shí)踐驗(yàn)證性代碼。
NotesList Activity截圖:
EasyMonkeyDevice vs MonkeyDevice&HierarchyViewer API Mapping Matrix
NoteEditor Activity截圖:
EasyMonkeyDevice vs MonkeyDevice&HierarchyViewer API Mapping Matrix

2. EaysyMonkeyDevice API List and Sample

EasyMonkeyDevice是在MonkeyDevice和HierarchyViewer的基礎(chǔ)上出來的一個(gè)類,按照本人的理解,主要增加的功能就是:

  • 在MonkeyDevice和HierarchyViewer的基礎(chǔ)上針對(duì)部分API增加了對(duì)控件ID的支持以操作控件
以下是個(gè)人整理的列表:嘗試對(duì)所有的API進(jìn)行一個(gè)描述和示例Demo

Return

EasyMonkeyDevice

Demo

Comment

 

 

EasyMonkeyDevice(

MonkeyDevice device)

Use Monkey device to construct

an EasyMonkeyDevice object,

note that it would instantiate a

HierarchyViewer member by

device within this constructor

 

device = MonkeyRunner.waitForConnection()

 

eDevice=EasyMonkeyDevice(device)

Constructor

Void

touch(By selector,

TouchPressType type)

Sends a touch event specified

by ‘type’ to the screen location

specified by ‘by’

 觸摸點(diǎn)擊主窗口:

#Step 1: try touching on the first note

eDevice.touch(By.id('id/text1'),

              MonkeyDevice.DOWN_AND_UP)

觸摸彈出框或Menu Options會(huì)失敗:

MonkeyRunner.sleep(2)

print 'Show Menu Options'

device.press('KEYCODE_MENU',

             MonkeyDevice.DOWN_AND_UP);

 

MonkeyRunner.sleep(3)

print 'Press on the menu entry of \

 \"Add note\"'

eDevice.touch(By.id('id/title'),

               MonkeyDevice.DOWN)

 

參數(shù)By實(shí)際上

只有By.ID,從

其源碼可以看

出來;

type參數(shù)跟

MonkeyDevice

一樣就那幾個(gè)

DOWN/UP之類的

 

根據(jù)個(gè)人實(shí)踐

和網(wǎng)上評(píng)論,

對(duì)系統(tǒng)菜單和

彈出框的支持

有問題

Void

type(By selector, String text)

Types a string into the specified

object

 

#Step 5: setText

eDevice.type(By.id(noteId), 'New')

 

Boolean

exists(By selector)

Checks if the specified object

exists.

 

#Step3: is note EditText exist?

noteId = 'id/note'

if True == eDevice.exists(By.id(noteId)):

    print 'Note exist'

else:

    print 'Note not found!'

    exit(2)

 

Boolean

visible(By selector)

Checks if the specified object is visible.

 

#Step4: is note EditText visible?

if True == eDevice.visible(By.id(noteId)):

    print 'Note is visible'

else:

    print 'Note is invisible'

    exit(3)

 

String

getText(By selector)

Obtain the text in the selected

input box.

 

#Step 4: getText

text = eDevice.getText(By.id(noteId))

print 'Note text:',text.encode('utf-8')

 

String

getFocusedWindowId()

Gets the id of the focused window.

returns = "The symbolic id of the

focused window or None."

 

#Step 2: Get the window ID

winId = 'com.example.android.notepad/\

    com.example.android.notepad.NoteEditor'

#Need to sleep a while till ready

MonkeyRunner.sleep(3)

winId = eDevice.getFocusedWindowId()

if(winId == winId):

    print "Edit Note WinId is:",\

        winId.encode('utf-8')

else:

    print "Failed"

    exit(1)



 結(jié)果跟

HierarchyViewer

getFocusedWin

dowName

返回值一模

一樣,所以

猜想WindowID

WindowName

是同一回事

PyTuple

locate(By selector)

Locates the coordinates of the

selected object

returns = "Tuple containing

(x,y,w,h) location and size.")

 

#Step 6: locate

locate = eDevice.locate(By.id(noteId))

print 'Location(x,y,w,h) is:',locate

 


3. EasyMonkeyDevice vs MonkeyDevice API Mapping Matrix

這里會(huì)列出MonkeyDevice的所有API已經(jīng)EasyMonkeyDevice與其對(duì)應(yīng)的API,沒有去掉冗余是因?yàn)榉奖憬窈驲eference的時(shí)候知道EasyMonkeyDevice并不是完全把所有MonkeyDevice的API都進(jìn)行Wrap的,只有以下兩個(gè)。下面一章理同。
  • touch:MonkeyDevice通過坐標(biāo)點(diǎn)touch;EasyMonkeyDevice通過控件ID去touch
  • type:MonkeyDevice往當(dāng)前focused地方輸入;EasyMonkeyDevice往由ID指定控件輸入

EasyMonkeyDevice API vs MonkeyDevice API

 

MonkeyDevice

EasyMonkeyDevice

Comment

 

Void broadcastIntent (string uri, string action,

 string data, string mimetype, 

iterable categories dictionary extras, 

component component, iterable flags)

Broadcasts an Intent to this device, as if the

Intent were coming from an application.

 

 

Void drag (tuple start, tuple end, float duration, 

integer steps)

Simulates a drag gesture (touch, hold, and

move) on this device's screen.

 

 

ObjectgetProperty (string key)

Given the name of a system environment

variable, returns its value for this device.

The available variable names are listed in

the detailed description of this method.

 

 

ObjectgetSystemProperty (string key)

The API equivalent of adb shell getprop

<key>. This is provided for

use by platform developers.

 

 

Void installPackage (string path)

Installs the Android application or test package

 contained in packageFile onto this device.

If the application or test package is already

installed, it is replaced.

 

 

Dictionaryinstrument (string className, dictionary args)

Runs the specified component under

Android instrumentation, and returns the results

 in a dictionary whose exact format is dictated

by the component being run.

 The component must already be present on

this device.

 

 

Void press (string name, dictionary type)

Sends the key event specified by type to the

key specified by keycode.

 

 

Void reboot (string into)

Reboots this device into the bootloader

specified by bootloadType.

 

 

Void removePackage (string package)

Deletes the specified package from this device,

 including its data and cache.

 

 

Objectshell (string cmd)

Executes an adb shell command and returns

the result, if any.

 

 

Void startActivity (string uri, string action, 

string data, string mimetype, iterable categories 

dictionary extras, component component, flags)

Starts an Activity on this device by sending an

Intent constructed from the supplied arguments.

 

 

MonkeyImagetakeSnapshot()

Captures the entire screen buffer of this device,

yielding a MonkeyImage object containing

a screen capture of the current display.

 

 

Void touch (integer x, integer y, integer type)

Sends a touch event specified by type to the

screen location specified by x and y.

Void touch(By selector, TouchPressType type)

Sends a touch event specified by

‘type’ to the screen location specified

 by ‘by’

MonkeyDevice通過坐標(biāo)點(diǎn)touch

EasyMonkeyDevice通過控件IDtouch

Void type (string message)

Sends the characters contained in message to

this device, as if they had been typed on

the device's keyboard. This is equivalent to

calling press() for each keycode in message 

using the key event type DOWN_AND_UP.

Void type(By selector, String text)

Types a string into the specified

object

MonkeyDevice往當(dāng)前focused地方輸入;

EasyMonkeyDevice往由ID指定控件輸入

Void wake ()

Wakes the screen of this device.

 

 

HierarchyViewer getHierarchyViewer()

Get the HierarchyViewer object for the device.

 

 

PyListgetPropertyList()

Retrieve the properties that can be queried

 

 

PyListgetViewIdList()

Retrieve the view ids for the current application

 

 

MonkeyViewgetViewById(String id)

doc = "Obtains the view with the specified id.",

args = {"id"},

argDocs = {"The id of the view to retrieve."},

returns = "The view object with the specified id."

 

 

MonkeyViewgetViewByAccessibilityIds(String WinId, String accessId)

args = {"windowId", "accessibility id"}

argDocs = {"The window id of the view to

retrieve.", "The accessibility id of the view to

retrieve."},

returns = "The view object with the specified id.")

 

 

MonkeyViewgetRootView()

Obtains current root view

 

 

PyListgetViewsByText(String text)

Obtains a list of views that contain the specified

text.",

args = {"text"},

returns = "A list of view objects that contain the specified text.")

 

 


4. EasyMonkeyDevice vs HierarchyViewer Mapping Matrix

EasyMonkeyDevice Wrap了HiearchyViewer 的相應(yīng)API而得到以下這些API
  • getFocusedWindowId:Wrap了hierarchyviewer的getFocusedWindowName,不再使用ViewNode而使用ID來的獲得Window id/Name,其實(shí)根據(jù)我的實(shí)踐id/name是同一回事
  • locate:其實(shí)就是把HierarchyViewer的getAbsolutePositionOfView和getAbsoluteCenterOfView整合在一起獲得起始坐標(biāo)和Width/Hight,前者獲得其實(shí)坐標(biāo),后者獲得中心位置,相減后乘以2就是EasyMonkeyDevice想要的Width/Hight了
  • visible: 同樣是把參數(shù)由ViewNode改成id
  • getText:同上

EasyMonkeyDevice API vs HierarchViewer API

 

HierarchyViewer

EasyMonkeyDevice

Comment

 

public ViewNode findViewById(String id)

/**

* Find a view by id.

* @param id id for the view.

* @return view with the specified ID, or {@code null} if no view found.

*/

 

 

 

public ViewNode findViewById(String id, ViewNode rootNode)

/**

* Find a view by ID, starting from the given root node

* @param id ID of the view you're looking for

* @param rootNode the ViewNode at which to begin the traversal

* @return view with the specified ID, or {@code null} if no view found.

*/

 

 

public String getFocusedWindowName()

/**

* Gets the window that currently receives the focus.

* @return name of the window that currently receives the focus.

*/

 

String getFocusedWindowId()

Gets the id of the focused window.

returns = "The symbolic id of the focused window or None."

 

public static Point getAbsolutePositionOfView(ViewNode node)/**

* Gets the absolute x/y position of the view node.

*

* @param node view node to find position of.

* @return point specifying the x/y position of the node.

*/

 

PyTuple locate(By selector)

Locates the coordinates of the selected object

returns = "Tuple containing (x,y,w,h) location and size.")

 

public static Point getAbsoluteCenterOfView(ViewNode node)

/**

* Gets the absolute x/y center of the specified view node.

*

* @param node view node to find position of.

* @return absolute x/y center of the specified view node.

*/

public boolean visible(ViewNode node)

/**

* Gets the visibility of a given element.

* @param selector selector for the view.

* @return True if the element is visible.

*/

 

boolean visible(By selector)

Checks if the specified object is visible.

 

public String getText(ViewNode node)

/**

* Gets the text of a given element.

*

* @param selector selector for the view.

* @return the text of the given element.

*/

 

String getText(By selector)

Obtain the text in the selected input box.

 


5. EasyMonkeyDevice Standalone API

剩下一個(gè)API是沒有跟以上的MonkeyDevice和HierarchyViewer有任何對(duì)應(yīng)關(guān)系的:
  • visible:通過id檢查該控件是否存在,猜想應(yīng)該是google在代碼重構(gòu)的時(shí)候增加的一個(gè)方法方便大家判斷而已

EasyMonkeyDevice Standalone API

 

EasyMonkeDevice

Comment

 

boolean exists(By selector)

Checks if the specified object exists.

 


6. 驗(yàn)證性代碼

from com.android.monkeyrunner import MonkeyRunner,MonkeyDevice,MonkeyImage from com.android.monkeyrunner.easy import EasyMonkeyDevice,By from com.android.chimpchat.hierarchyviewer import HierarchyViewer from com.android.hierarchyviewerlib.models import ViewNode, Window from java.awt import Point  #from com.android.hierarchyviewerlib.device import   #Connect to the target device  device = MonkeyRunner.waitForConnection()  eDevice=EasyMonkeyDevice(device)  device.startActivity(component="com.example.android.notepad/com.example.android.notepad.NotesList")  ''' MonkeyRunner.sleep(2) print 'Show Menu Options' device.press('KEYCODE_MENU',              MonkeyDevice.DOWN_AND_UP);  MonkeyRunner.sleep(3) print 'Press on the menu entry of \  \"Add note\"' eDevice.touch(By.id('id/title'),                MonkeyDevice.DOWN)  MonkeyRunner.sleep(2) device.press('KEYCODE_MENU',               MonkeyDevice.DOWN_AND_UP); '''  #Step 1: try touching on the first note eDevice.touch(By.id('id/text1'),               MonkeyDevice.DOWN_AND_UP)  #Step 2: Get the window ID  winId = 'com.example.android.notepad/\     com.example.android.notepad.NoteEditor' #Need to sleep a while till ready MonkeyRunner.sleep(3) winId = eDevice.getFocusedWindowId()  if(winId == winId):     print "Edit Note WinId is:",\         winId.encode('utf-8') else:     print "Failed"     exit(1)  #Step3: is note EditText exist? noteId = 'id/note' if True == eDevice.exists(By.id(noteId)):     print 'Note exist' else:     print 'Note not found!'     exit(2)  #Step4: is note EditText visible? if True == eDevice.visible(By.id(noteId)):     print 'Note is visible' else:     print 'Note is invisible'     exit(3)  #Step 4: getText text = eDevice.getText(By.id(noteId)) print 'Note text:',text.encode('utf-8')  #Step 5: setText eDevice.type(By.id(noteId), 'New')  #Step 6: locate locate = eDevice.locate(By.id(noteId)) print 'Location(x,y,w,h) is:',locate

7. EasyMonkeyDevice Source Code for Your Reference 

/*jadclipse*/// Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov.  package com.android.monkeyrunner.easy;  import com.android.chimpchat.hierarchyviewer.HierarchyViewer; import com.android.hierarchyviewerlib.models.ViewNode; import com.android.monkeyrunner.JythonUtils; import com.google.common.base.Preconditions; import org.python.core.*;  public class By extends PyObject     implements ClassDictInit {      public static void classDictInit(PyObject dict)     {         JythonUtils.convertDocAnnotationsForClass(com/android/monkeyrunner/easy/By, dict);     }      By(String id)     {         this.id = id;     }      public static By id(PyObject args[], String kws[])     {         ArgParser ap = JythonUtils.createArgParser(args, kws);         Preconditions.checkNotNull(ap);         String id = ap.getString(0);         return new By(id);     }      public static By id(String id)     {         return new By(id);     }      public ViewNode findView(HierarchyViewer viewer)     {         return viewer.findViewById(id);     }      private String id; }   /* 	DECOMPILATION REPORT  	Decompiled from: D:\Projects\Workspace\JarPackages\monkeyrunner.jar 	Total time: 69 ms 	Jad reported messages/errors: The class file version is 50.0 (only 45.3, 46.0 and 47.0 are supported) 	Exit status: 0 	Caught exceptions: */

8. By Class Source Code for Your Better Reference

/*jadclipse*/// Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov.  package com.android.monkeyrunner.easy;  import com.android.chimpchat.core.IChimpDevice; import com.android.chimpchat.core.TouchPressType; import com.android.chimpchat.hierarchyviewer.HierarchyViewer; import com.android.hierarchyviewerlib.models.ViewNode; import com.android.monkeyrunner.JythonUtils; import com.android.monkeyrunner.MonkeyDevice; import com.google.common.base.Preconditions; import java.util.Set; import org.eclipse.swt.graphics.Point; import org.python.core.*;  // Referenced classes of package com.android.monkeyrunner.easy: //            By  public class EasyMonkeyDevice extends PyObject     implements ClassDictInit {      public static void classDictInit(PyObject dict)     {         JythonUtils.convertDocAnnotationsForClass(com/android/monkeyrunner/easy/EasyMonkeyDevice, dict);     }      public EasyMonkeyDevice(MonkeyDevice device)     {         mDevice = device;         mHierarchyViewer = device.getImpl().getHierarchyViewer();     }      public void touch(PyObject args[], String kws[])     {         ArgParser ap = JythonUtils.createArgParser(args, kws);         Preconditions.checkNotNull(ap);         By selector = getSelector(ap, 0);         String tmpType = ap.getString(1);         TouchPressType type = TouchPressType.fromIdentifier(tmpType);         Preconditions.checkNotNull(type, (new StringBuilder()).append("Invalid touch type: ").append(tmpType).toString());         touch(selector, type);     }      public void touch(By selector, TouchPressType type)     {         Point p = getElementCenter(selector);         mDevice.getImpl().touch(p.x, p.y, type);     }      public void type(PyObject args[], String kws[])     {         ArgParser ap = JythonUtils.createArgParser(args, kws);         Preconditions.checkNotNull(ap);         By selector = getSelector(ap, 0);         String text = ap.getString(1);         type(selector, text);     }      public void type(By selector, String text)     {         Point p = getElementCenter(selector);         mDevice.getImpl().touch(p.x, p.y, TouchPressType.DOWN_AND_UP);         mDevice.getImpl().type(text);     }      public PyTuple locate(PyObject args[], String kws[])     {         ArgParser ap = JythonUtils.createArgParser(args, kws);         Preconditions.checkNotNull(ap);         By selector = getSelector(ap, 0);         ViewNode node = selector.findView(mHierarchyViewer);         Point p = HierarchyViewer.getAbsolutePositionOfView(node);         PyTuple tuple = new PyTuple(new PyObject[] {             new PyInteger(p.x), new PyInteger(p.y), new PyInteger(node.width), new PyInteger(node.height)         });         return tuple;     }      public boolean exists(PyObject args[], String kws[])     {         ArgParser ap = JythonUtils.createArgParser(args, kws);         Preconditions.checkNotNull(ap);         By selector = getSelector(ap, 0);         return exists(selector);     }      public boolean exists(By selector)     {         ViewNode node = selector.findView(mHierarchyViewer);         return node != null;     }      public boolean visible(PyObject args[], String kws[])     {         ArgParser ap = JythonUtils.createArgParser(args, kws);         Preconditions.checkNotNull(ap);         By selector = getSelector(ap, 0);         return visible(selector);     }      public boolean visible(By selector)     {         ViewNode node = selector.findView(mHierarchyViewer);         return mHierarchyViewer.visible(node);     }      public String getText(PyObject args[], String kws[])     {         ArgParser ap = JythonUtils.createArgParser(args, kws);         Preconditions.checkNotNull(ap);         By selector = getSelector(ap, 0);         return getText(selector);     }      public String getText(By selector)     {         ViewNode node = selector.findView(mHierarchyViewer);         return mHierarchyViewer.getText(node);     }      public String getFocusedWindowId(PyObject args[], String kws[])     {         return getFocusedWindowId();     }      public String getFocusedWindowId()     {         return mHierarchyViewer.getFocusedWindowName();     }      public PyObject __findattr_ex__(String name)     {         if(!EXPORTED_METHODS.contains(name))             return mDevice.__findattr_ex__(name);         else             return super.__findattr_ex__(name);     }      private By getSelector(ArgParser ap, int i)     {         return (By)ap.getPyObject(i).__tojava__(com/android/monkeyrunner/easy/By);     }      private Point getElementCenter(By selector)     {         ViewNode node = selector.findView(mHierarchyViewer);         if(node == null)         {             throw new PyException(Py.ValueError, String.format("View not found: %s", new Object[] {                 selector             }));         } else         {             Point p = HierarchyViewer.getAbsoluteCenterOfView(node);             return p;         }     }      private MonkeyDevice mDevice;     private HierarchyViewer mHierarchyViewer;     private static final Set EXPORTED_METHODS = JythonUtils.getMethodNames(com/android/monkeyrunner/easy/EasyMonkeyDevice);  }   /* 	DECOMPILATION REPORT  	Decompiled from: D:\Projects\Workspace\JarPackages\monkeyrunner.jar 	Total time: 920 ms 	Jad reported messages/errors: The class file version is 50.0 (only 45.3, 46.0 and 47.0 are supported) 	Exit status: 0 	Caught exceptions: */


  • <table id="fudyc"><div id="fudyc"></div></table>
  • <rp id="fudyc"></rp>
    1.  

      作者

      自主博客

      微信

      CSDN

      天地會(huì)珠海分舵

      http://techgogogo.com


      服務(wù)號(hào):TechGoGoGo

      掃描碼:

      EasyMonkeyDevice vs MonkeyDevice&HierarchyViewer API Mapping Matrix

      向AI問一下細(xì)節(jié)

      免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

      AI

      <kbd id="fudyc"><sup id="fudyc"></sup></kbd>