欢迎使用Poco (ポコ) UI自动化框架

A cross-engine UI automation framework. Unity3D/cocos2dx-*/Android native APP/iOS native APP/(Other engines SDK)/…

Fork Star 99+

快速预览

_images/logo-no-padding.png

Poco ポコ

Documentation Status chat on slack

A cross-engine UI automation framework. Unity3D/cocos2dx-*/Android native APP/iOS native APP/(Other engines SDK)/…

示例(Example)

首先请把usb线连上Android手机并打开 adb调试模式

_images/overview1.gif
# coding=utf-8

import time
from poco.drivers.unity3d import UnityPoco

poco = UnityPoco()

poco('btn_start').click()
time.sleep(1.5)

shell = poco('shell').focus('center')
for star in poco('star'):
    star.drag_to(shell)
time.sleep(1)

assert poco('scoreVal').get_text() == "100", "score correct."
poco('btn_back', type='Button').click()

更多的例子请移步 More examples. 网易自研引擎项目请参考 网易游戏项目测试脚本标准模板 来开始建立回归测试工程。

编写脚本专用工具(Tools)

获取界面中的UI元素和开始编写脚本,请使用我们专门为您打造的 AirtestIDE 或轻量级的检视器 PocoHierarchyViewer网易自研引擎 请直接使用 Hunter内嵌inspector .

_images/hunter-inspector.png

安装(Installation)

在电脑上安装poco,并把poco-sdk集成到游戏里

直接pip安装即可,名字叫 pocoui

pip install pocoui

SDK集成(Integration)

把sdk集成到游戏里请参考 Integration Guide网易自研引擎 无需嵌入sdk,请在hunter上直接配置,见 Integration Guide for NetEase

特性(Features)

  • 支持包括Unity3D, cocos2dx-*等主流引擎,也支持android/iOS原生应用
  • 在游戏运行时获取UI元素和层次结构(hierarchy)
  • 超快,不影响游戏性能
  • 5分钟完成就可以安装集成好
  • 提供了强大的引擎无关API
  • 支持多点触控 fling/pinch/…
  • 支持gps、加速度感应器等模拟输入
  • 可以很方便地扩找到私有引擎中使用
  • python 2/3兼容

文档(Documentation)

Online docs.

Use poco on platforms/engines

This section guide you how to start to use poco to write your test cases on different platforms/engines.

Poco drivers

如何使用(How to use Poco)

根据你所使用的引擎,按对应的方式初始化Poco实例。请先将Android手机连上电脑并启动好游戏/App,或者直接启动windows版并且不要让游戏后台运行。

下面例子列出几种常见引擎的初始化方式

  • Unity3D.
from poco.drivers.unity3d import UnityPoco

poco = UnityPoco()
# for unity editor on windows
# poco = UnityPoco(('localhost', 5001), unity_editor=True)

ui = poco('...')
ui.click()
  • Android native APP
from poco.drivers.android.uiautomation import AndroidUiautomationPoco

poco = AndroidUiautomationPoco()
poco.device.wake()
poco(text='Clock').click()

使用Poco选择UI对象

基本选择器(Basic Selector)

在poco实例后加一对括号就可以进行UI选择了。选择器会遍历所有UI,将满足给定条件的UI都选出来并返回。

括号里的参数就是所给定的条件,用属性名值对表示,其中第一个参数固定表示 节点名 其余可选参数均表示节点的属性及预期的属性值。下面的例子中可以感受一下选择表达式究竟是怎么样的。更详细的使用请参考 API Reference selecting UI

# select by node name
poco('bg_mission')

# select by name and other properties
poco('bg_mission', type='Button')
poco(textMatches='^据点.*$', type='Button', enable=True)
_images/hunter-poco-select-simple.png

相对选择器(Relative Selector)

直接用节点属性没法选出你所想要的UI时,还可以通过UI之间的渲染层级关系进行选择,例如父子关系、兄弟关系、祖先后代关系。

# select by direct child/offspring
poco('main_node').child('list_item').offspring('item')
_images/hunter-poco-select-relative.png

空间顺序选择器(Sequence Selector)

按照序号(顺序)进行选择总是按照空间排布顺序,先从左往右,再像之前那样一行一行从上到下,如下图中的数字标号,就是索引选择的序号。索引选择有个特例,一旦进行选择后,如果UI的位置发生了变化,那么下标序号仍然是按照选择的那一瞬间所确定的值。即,如果选择时1号UI现在去到了6号的位置,那么还是要用 poco(...)[1] 来访问,而不是6.如果选择了之后,某个UI消失了(从界面中移除或者隐藏了),那么如果再访问那个UI则可能会发生异常,其余的UI仍可继续访问。

items = poco('main_node').child('list_item').offspring('item')
print(items[0].child('material_name').get_text())
print(items[1].child('material_name').get_text())
_images/hunter-poco-select-sequence.png

迭代一组对象(Iterate over a collection of objects)

下面代码片段展示如何迭代遍历一组UI

# traverse through every item
items = poco('main_node').child('list_item').offspring('item')
for item in items:
    item.child('icn_item')
_images/hunter-poco-iteration.png

读取属性(Get object properties)

下面的例子展示如何通过代码获取UI的各种属性

mission_btn = poco('bg_mission')
print(mission_btn.attr('type'))  # 'Button'
print(mission_btn.get_text())  # '据点支援'
print(mission_btn.attr('text'))  # '据点支援' equivalent to .get_text()
print(mission_btn.exists())  # True/False, exists in the screen or not

全局操作(Global Operation)

在没有选定或指定UI的情况下也可以进行操作(模拟输入),也叫全局操作。

点击(click)
poco.click([0.5, 0.5])  # click the center of screen
poco.long_click([0.5, 0.5], duration=3)
滑动(swipe)
# swipe from A to B
point_a = [0.1, 0.1]
center = [0.5, 0.5]
poco.swipe(point_a, center)

# swipe from A by given direction
direction = [0.1, 0]
poco.swipe(point_a, direction=direction)
截屏(snapshot)

截屏幕并以base64编码返回。截图的格式(png, jpg, …)由对应的sdk实现决定,大多数情况下是png。详见 ScreenInterface.getScreen

Note: snapshot is not supported in some engine implementation of poco.

from base64 import b64decode

b64img, fmt = poco.snapshot(width=720)
open('screen.{}'.format(fmt), 'wb').write(b64decode(b64img))

异常处理(Exceptions)

本节说明如何处理异常

PocoTargetTimeout

from poco.exceptions import PocoTargetTimeout

try:
    poco('guide_panel', type='ImageView').wait_for_appearance()
except PocoTargetTimeout:
    # bugs here as the panel not shown
    raise

PocoNoSuchNodeException

from poco.exceptions import PocoNoSuchNodeException

img = poco('guide_panel', type='ImageView')
try:
    if not img.exists():
        img.click()
except PocoNoSuchNodeException:
    # If attempt to operate inexistent nodes, an exception will be thrown
    pass

单元测试(Unit Test)

Poco是自动化测试框架,不负责单元测试部分。如果想要进行系统地管理你的测试或编写更高级的测试代码,请参考我们的单元测试部分 PocoUnit. PocoUnit是一个提供了完善设施的专门为游戏和应用设计的单元测试框架,用法与python标准库 unittest 完全兼容。

Tutorial of PocoUnit.

术语解释(Some Concepts)

文档中可能会用到以下术语,在这里事先定义一下,避免误解和歧义。

  • Target device: test devices where the apps or games run on, it usually refers to mobile phone devices
  • UI proxy: proxy objects within Poco framework, they represent zero (none), one or multiple in-game UI elements
  • Node/UI element: UI element instances or nodes in app/game
  • 选择表达式 :除非你需要扩展或自定义更底层的Poco的行为,一般无需关心此。选择表达式是一种框架和sdk交互的底层数据结构,用在 Selector 类中。

下面的几个图形象地展示在Poco中层次结构(hierarchy)和UI属性的特征,从Inspector里也能很容易地预览当前界面的UI控件。

_images/hunter-inspector.png _images/hunter-inspector-text-attribute.png _images/hunter-inspector-hierarchy-relations.png

坐标系与度量空间定义

归一化坐标系(Normalized Coordinate System)

归一化坐标系就是将屏幕宽和高按照单位一来算,这样UI在poco中的宽和高其实就是相对于屏幕的百分比大小了,好处就是不同分辨率设备之间,同一个UI的归一化坐标系下的位置和尺寸是一样的,有助于编写跨设备测试用例。

归一化坐标系的空间是均匀的,屏幕正中央一定是(0.5, 0.5),其他标量和向量的计算方法同欧式空间。

_images/hunter-poco-coordinate-system.png
局部坐标系(Local Coordinate System (local positioning))

引入局部坐标系是为了表示相对于某UI的坐标。局部坐标系以UI包围盒左上角为原点,向右为x轴,向下为y轴,包围盒宽和高均为单位一。其余的定义和归一化坐标系类似。

局部坐标系可以更灵活地定位UI内或外的位置,例如(0.5, 0.5)就代表UI的正中央,超过1或小于0的坐标值则表示UI的外面。

Join to discuss!

chat on slack

Contributions

Any pull requests are welcomed! We will have the code checked carefully. Please make sure the codes are compatible with python 2/3 and have the same coding style.

安装Poco和PocoSDK

在电脑上安装poco,并把poco-sdk集成到游戏里

直接pip安装即可

pip install pocoui

把sdk集成到游戏里请参考 Integration Guide网易自研引擎 无需嵌入sdk,请在hunter上直接配置,见 Integration Guide for NetEase

如何使用

示例

下面Unity3D的例子展示了最简单的用法,更多的例子请移步 More examples. 网易自研引擎项目请参考 网易游戏项目测试脚本标准模板 来开始建立回归测试工程。

首先请把usb线连上Android手机并打开 adb调试模式

_images/overview.gif
# coding=utf-8

import time
from poco.drivers.unity3d import UnityPoco

poco = UnityPoco()

poco('btn_start').click()
time.sleep(1.5)

shell = poco('shell').focus('center')
for star in poco('star'):
    star.drag_to(shell)
time.sleep(1)

assert poco('scoreVal').get_text() == "100", "score correct."
poco('btn_back', type='Button').click()

编写脚本专用工具(Tools)

获取界面中的UI元素和开始编写脚本,请使用我们专门为您打造的 AirtestIDE 或轻量级的检视器 PocoHierarchyViewer网易自研引擎 请直接使用 Hunter内嵌inspector .

_images/hunter-inspector.png

Use poco on platforms/engines

This section guide you how to start to use poco to write your test cases on different platforms/engines.

API reference

Poco API

大部分用于编写测试脚本的函数和成员方法在下面的API文档里可以查找

poco.pocofw module

class Poco(agent, **options)[源代码]

基类:poco.acceleration.PocoAccelerationMixin

Poco standard initializer.

参数:
  • agent (PocoAgent) – an agent object for Poco to communicate with the target device. See PocoAgent definition for more details.
  • options
    • action_interval: time interval to wait for the action (such as touch or swipe) completion performed on device and for the UI to become still (stable). Default value is 0.8s.
    • poll_interval: the minimum time needed between each poll events (such as waiting for UI element to appear on the screen). Polling is done periodically.
    • pre_action_wait_for_appearance: time interval to wait before the action (such as click or swipe) is performed. If the target UI element does not appear on the screen after this time interval, the PocoNoSuchNodeException is raised
    • touch_down_duration: Touch down step duration of the click operation last for. If this argument is provided, this value will set to self.agent.input module. Note that not all implementation of poco support this parameter. If not support, you may see a warning.
    • reevaluate_volatile_attributes: Re-select target UI proxy when retrieving volatile attributes. Poco drivers that using hrpc connections should default to be False as hrpc always reevaluate the attributes remotely. This option is useful for StdPoco driver and should be handled by StdPoco.
__call__(name=None, **kw)[源代码]

Call Poco instance to select the UI element by query expression. Query expression can contain specific name and/or other attributes. Invisible UI elements will be skipped even if “visible=False” argument is set.

Selection process is not executed instantly, the query expression is stored in the UI proxy and the selection is executed only then when the UI element(s) info is required (such get the point coordinates where to click, and/or retrieve the specific attribute value).

实际案例

This example shows selecting a Button named ‘close’:

poco = Poco(...)
close_btn = poco('close', type='Button')
参数:

name (str) – name of the UI element to be selected

关键字参数:
  • xx – arbitrary key value pair that stands for selecting the UI matching the value of UI.xx
  • xxMatches (str) – arbitrary key value pair that stands for selecting the UI matching the regular expression pattern UI.xx

In keyword args, you can only use xx or xxMatches at the same time. Using both with the same attribute does not make sense. Besides, xx should not start with _ (underscore) as attributes start with _ are private attributes that used by sdk implementation.

# select the UI element(s) which text attribute matches the pattern '^close.*$'
poco = Poco(...)
arb_close_btn = poco(textMatches='^close.*$')
返回:UI proxy object representing the UI element matches the given query expression.
返回类型:UIObjectProxy
add_post_action_callback(cb)[源代码]

Register a callback function to be invoked after each action (such as touch or swipe).

The arguments to be passed are identical to the callback function in add_pre_action_callback.

参数:cb – the callback function
add_pre_action_callback(cb)[源代码]

Register a callback function to be invoked before each action (such as touch or swipe).

The callback function arguments are defined as follows:

  • action (str): name or tag of the action
  • proxy (UIObjectProxy or NoneType): related UI proxy which is involved in the action itself
  • args (tuple): all required arguments of the specific action function
参数:cb – the callback function
agent

Readonly property to access poco agent instance. See poco.agent.PocoAgent for more details.

返回:poco agent instance
返回类型:poco.agent.PocoAgent
apply_motion_tracks(tracks, accuracy=0.004)[源代码]

Similar to click but press the screen for the given time interval and then release

参数:
  • tracks (list) – list of poco.utils.track.MotionTrack object
  • accuracy (float) – motion accuracy for each motion steps in normalized coordinate metrics.
click(pos)[源代码]

Perform click (touch, tap, etc.) action on target device at given coordinates.

The coordinates (x, y) are either a 2-list or 2-tuple. The coordinates values for x and y must be in the interval between 0 ~ 1 to represent the percentage of the screen. For example, the coordinates [0.5, 0.5] represent the center of the screen and the coordinates [0, 0] represent the top left corner.

See CoordinateSystem for more details about coordinate system.

实际案例

Click the point of (100, 100) of screen which resolution is (1920, 1080):

poco.click([100.0 / 1920, 100.0 / 1080])
参数:pos (list(float, float) / tuple(float, float)) – coordinates (x, y) in range of 0 to 1
Raises:InvalidOperationException – when clicked outside of the screen
freeze()[源代码]

Snapshot current hierarchy and cache it into a new poco instance. This new poco instance is a copy from current poco instance (self). The hierarchy of the new poco instance is fixed and immutable. It will be super fast when calling dump function from frozen poco. See the example below.

实际案例

poco = Poco(...)
frozen_poco = poco.freeze()
hierarchy_dict = frozen_poco.agent.hierarchy.dump()  # will return the already cached hierarchy data
返回:new poco instance copy from current poco instance (self)
返回类型:Poco
get_screen_size()[源代码]

Get the real physical resolution of the screen of target device.

返回:float number indicating the screen physical resolution in pixels
返回类型:tuple
long_click(pos, duration=2.0)[源代码]

Similar to click but press the screen for the given time interval and then release

参数:
  • pos (2-list/2-tuple) – coordinates (x, y) in range from 0 to 1
  • duration – duration of press the screen
pinch(direction='in', percent=0.6, duration=2.0, dead_zone=0.1)[源代码]

Squeezing or expanding 2 fingers on the entire screen.

参数:
  • direction (str) – pinching direction, only “in” or “out”. “in” for squeezing, “out” for expanding
  • percent (float) – squeezing range from or expanding range to of the entire screen
  • duration (float) – time interval in which the action is performed
  • dead_zone (float) – pinching inner circle radius. should not be greater than percent
scroll(direction='vertical', percent=0.6, duration=2.0)[源代码]

Scroll from the lower part to the upper part of the entire screen.

参数:
  • direction (str) – scrolling direction. “vertical” or “horizontal”
  • percent (float) – scrolling distance percentage of the entire screen height or width according to direction
  • duration (float) – time interval in which the action is performed
sleep_for_polling_interval()[源代码]

Sleep for fixed number of seconds after each poll event. There is no need to call this method manually. It’s automatically invoked when required.

snapshot(width=720)[源代码]

Take the screenshot from the target device. The supported output format (png, jpg, etc.) depends on the agent implementation.

参数:
  • width (int) – an expected width of the screenshot. The real size depends on the agent implementation
  • might not be possible to obtain the expected width of the screenshot (and) –
返回:

  • screen_shot (str/bytes): base64 encoded screenshot data
  • format (str): output format ‘png’, ‘jpg’, etc.

返回类型:

2-tuple

start_gesture(pos)[源代码]

Start a gesture action. This method will return a PendingGestureAction object which is able to generate decomposed gesture steps. You can invoke .to and .hold any times in a chain. See the following example.

实际案例

poco = Poco(...)

# move from screen center to (0.6w, 0.6h) and hold for 1 second
# then return back to center
poco.start_gesture([0.5, 0.5]).to([0.6, 0.6]).hold(1).to([0.5, 0.5]).up()
参数:pos – starting coordinate of normalized coordinate system
返回:an object for building serialized gesture action.
返回类型:PendingGestureAction
swipe(p1, p2=None, direction=None, duration=2.0)[源代码]

Perform swipe action on target device from point to point given by start point and end point, or by the direction vector. At least one of the end point or direction must be provided.

The coordinates (x, y) definition for points is the same as for click event. The components of the direction vector (x, y) are also expressed in the range of the screen from 0 to 1.

See CoordinateSystem for more details about coordinate system.

实际案例

Following example shows how to perform a swipe action from (100, 100) to (100, 200) on screen with resolution 1920x1080:

poco.swipe([100.0 / 1920, 100.0 / 1080], [100.0 / 1920, 200.0 / 1080])

Or given by the specific direction instead of end point:

poco.swipe([100.0 / 1920, 100.0 / 1080], direction=[0, 100.0 / 1080])
参数:
  • p1 (2-list/2-tuple) – start point
  • p2 – end point
  • direction – swipe direction
  • duration (float) – time interval in which the swipe action is performed
Raises:

InvalidOperationException – when the start point of the swipe action lies outside the screen

use_render_resolution(use=True, resolution=None)[源代码]

Whether to use render resolution

参数:
  • use – True or false
  • resolution – render resolution in portrait mode, offset_x, offset_y, offset_width, offset_height, (0, 10, 1080, 1820)
wait_for_all(objects, timeout=120)[源代码]

Wait until all of given UI proxies show up before timeout. All UI proxies will be polled periodically. See option poll_interval in Poco’s initialization for more details.

参数:
  • objects (Iterable<UIObjectProxy>) – iterable object of the given UI proxies
  • timeout (float) – timeout in seconds, default is 120s
Raises:

PocoTargetTimeout – when not all of UI proxies appeared before timeout

wait_for_any(objects, timeout=120)[源代码]

Wait until any of given UI proxies show up before timeout and return the first appeared UI proxy. All UI proxies will be polled periodically. See options poll_interval in Poco’s initialization for more details.

参数:
  • objects (Iterable<UIObjectProxy>) – iterable object of the given UI proxies
  • timeout (float) – timeout in seconds, default is 120s
返回:

the first appeared UI proxy

返回类型:

UIObjectProxy

Raises:

PocoTargetTimeout – when none of UI proxies appeared before timeout

wait_stable()[源代码]

Sleep for fixed number of seconds in order to wait for the UI to become still (stable). There is no need to call this method manually. It’s automatically invoked when required.

poco.proxy module

class UIObjectProxy(poco, name=None, **attrs)[源代码]

基类:object

UI Proxy class that represents the UI element on target device.

Any action performing on this instance is handled by Poco. It is not necessary to initialize this object manually. See QueryCondition for more details about how to select the UI elements.

参数:
  • poco – the poco instance
  • name – query condition of “name” attribute, i.e. the UI element(s) with name name will be selected
  • attrs – other query expressions except for the name
__getitem__(item)[源代码]

Select the specific UI element by index. If this UI proxy represents a set of UI elements, then use this method to access the specific UI element. The new UI element will be wrapped by UIObjectProxy instance and therefore the returned value is also the UI proxy object.

The order of UI elements are determined by their position on the screen and not by the selection sequence. This rule is called “L2R U2D” (one by one from left to right, line by line from up to down), i.e. the most top left UI element is always the first one. See IterationOverUI for more details.

警告

This method may cause some performance issues depending on implementation of PocoAgent.

参数:item (int) – the index.
返回:a new UI proxy object representing the n-th of the current UI elements.
返回类型:UIObjectProxy
__iter__()[源代码]

Similar method to .__getitem__() with the difference that this method iterates over all UI elements. The order rules of UI elements is same as for .__getitem__(). See IterationOverUI for more details.

Yields:UIObjectProxy – a generator yielding new UI proxy represents the specific UI element iterated over
Raises:PocoTargetRemovedException – when hierarchy structure has changed and it is attempted to access to the nonexistent UI element over the iteration
__len__()[源代码]

Return the number of selected UI elements.

返回:returns 0 if none of the UI element matches the query expression otherwise returns the number of selected UI elements
返回类型:int
attr(name)[源代码]

Retrieve the attribute of UI element by given attribute name. Return None if attribute does not exist. If attribute type is str, it is encoded to utf-8 as str in Python2.7.

参数:name

attribute name, it can be one of the following or any other customized type implemented by SDK

  • visible: whether or not it is visible to user
  • text: string value of the UI element
  • type: the type name of UI element from remote runtime
  • pos: the position of the UI element
  • size: the percentage size [width, height] in range of 0~1 according to the screen
  • name: the name of UI element
  • …: other sdk implemented attributes
返回:None if no such attribute or its value is None/null/nil/etc. Otherwise the attribute value is returned. The returned value type is json serializable. In both py2 and py3, if the attribute value in remote is a text-like object, the return value type will be str.
Raises:PocoNoSuchNodeException – when the UI element does not exists

注解

Exception NodeHasBeenRemovedException is caught automatically.

child(name=None, **attrs)[源代码]

Select the direct child(ren) from the UI element(s) given by the query expression, see QueryCondition for more details about the selectors.

参数:
  • name – query expression of attribute “name”, i.e. the UI elements with name name will be selected
  • attrs – other query expression except for the name
返回:

a new UI proxy object representing the child(ren) of current UI element(s)

返回类型:

UIObjectProxy

children()[源代码]

The same as .child() but it selects all children from the UI element(s).

返回:a new UI proxy object
返回类型:UIObjectProxy
click(focus=None, sleep_interval=None)[源代码]

Perform the click action on the UI element(s) represented by the UI proxy. If this UI proxy represents a set of UI elements, the first one in the set is clicked and the anchor point of the UI element is used as the default one. It is also possible to click another point offset by providing focus argument.

See CoordinateSystem for more details.

参数:
  • focus (2-tuple/2-list/str) – an offset point (x, y) from the top left corner of the UI element(s), values must be in range of 0~1. This argument can be also specified by ‘anchor’ or ‘center’. ‘Center’ means to click the center of bounding box of UI element.
  • sleep_interval – number of seconds to wait after this action. Default is None which is the default sleep interval. This value can be configured by Poco initialization. See configuration at poco initialization for more details.
Raises:

PocoNoSuchNodeException – raised when the UI element does not exist

double_click(focus=None, sleep_interval=None)[源代码]

Perform the double click action on the UI element(s) represented by the UI proxy. If this UI proxy represents a set of UI elements, the first one in the set is clicked and the anchor point of the UI element is used as the default one. It is also possible to click another point offset by providing focus argument.

See CoordinateSystem for more details.

参数:
  • focus (2-tuple/2-list/str) – an offset point (x, y) from the top left corner of the UI element(s), values must be in range of 0~1. This argument can be also specified by ‘anchor’ or ‘center’. ‘Center’ means to double click the center of bounding box of UI element.
  • sleep_interval – number of seconds to wait after this action. Default is None which is the default sleep interval. This value can be configured by Poco initialization. See configuration at poco initialization for more details.
Raises:

PocoNoSuchNodeException – raised when the UI element does not exist

drag_to(target, duration=2.0)[源代码]

Similar to swipe action, but the end point is provide by a UI proxy or by fixed coordinates.

参数:
  • target (UIObjectProxy) – a UI proxy or 2-list/2-tuple coordinates (x, y) in NormalizedCoordinate system
  • duration (float) – time interval in which the action is performed
Raises:

PocoNoSuchNodeException – raised when the UI element does not exist

exists()[源代码]

Test whether the UI element is in the hierarchy. Similar to .attr('visible').

返回:True if exists otherwise False
返回类型:bool
focus(f)[源代码]

Get a new UI proxy copy with the given focus. Return a new UI proxy object as the UI proxy is immutable.

参数:f (2-tuple/2-list/str) – the focus point, it can be specified as 2-list/2-tuple coordinates (x, y) in NormalizedCoordinate system or as ‘center’ or ‘anchor’.
返回:a new UI proxy object (copy)
返回类型:UIObjectProxy
get_bounds()[源代码]

Get the parameters of bounding box of the UI element.

返回:4-list (top, right, bottom, left) coordinates related to the edge of screen in NormalizedCoordinate system
返回类型:list <float>
get_name()[源代码]

Get the UI element name attribute

返回:UI element name attribute
返回类型:str
get_position(focus=None)[源代码]

Get the position of the UI elements.

参数:focus – focus point of UI proxy, see .focus() for more details
返回:coordinates (x, y) in NormalizedCoordinate system
返回类型:2-list/2-tuple
Raises:TypeError – raised when unsupported focus type is specified
get_size()[源代码]

Get the UI element size in NormalizedCoordinate system.

返回:size [width, height] in range of 0 ~ 1.
返回类型:2-list
get_text()[源代码]

Get the text attribute of the UI element. Return None if no such attribute. Similar to .attr('text').

返回:None if the UI element does not have the text element, otherwise the utf-8 encoded text value. In both py2 and py3, the return value type will be str.
返回类型:str
invalidate()[源代码]

Clear the flag to indicate to re-query or re-select the UI element(s) from hierarchy.

alias is refresh()

Example

>>> a = poco(text="settings")
>>> print(a.exists())
>>> a.refresh()
>>> print(a.exists())
long_click(duration=2.0)[源代码]

Perform the long click action on the UI element(s) represented by the UI proxy. If this UI proxy represents a set of UI elements, the first one in the set is clicked and the anchor point of the UI element is used as the default one. Similar to click but press the screen for the given time interval and then release.

参数:duration (float) – whole action duration.
返回:the same as poco.pocofw.Poco.long_click(), depending on poco agent implementation.
nodes

Readonly property accessing the UI element(s) in the remote runtime.

offspring(name=None, **attrs)[源代码]

Select the offsprings including the direct child(ren) from the UI element(s) given by the query expression, see QueryCondition for more details about selectors.

参数:
  • name – query expression of attribute “name”, i.e. the UI elements with name name will be selected
  • attrs – other query expression except for the name
返回:

a new UI proxy object representing the child(ren) of current UI element(s)

返回类型:

UIObjectProxy

parent()[源代码]

Select the direct child(ren) from the UI element(s) given by the query expression, see QueryCondition for more details about the selectors.

警告

Experimental method, may not be available for all drivers.

返回:a new UI proxy object representing the direct parent of the first UI element.
返回类型:UIObjectProxy
pinch(direction='in', percent=0.6, duration=2.0, dead_zone=0.1)[源代码]

Squeezing or expanding 2 fingers on this UI with given motion range and duration.

参数:
  • direction (str) – pinching direction, only “in” or “out”. “in” for squeezing, “out” for expanding
  • percent (float) – squeezing range from or expanding range to of the bounds of the UI
  • duration (float) – time interval in which the action is performed
  • dead_zone (float) – pinching inner circle radius. should not be greater than percent
Raises:

PocoNoSuchNodeException – raised when the UI element does not exist

rclick(focus=None, sleep_interval=None)[源代码]

Perform the right click action on the UI element(s) represented by the UI proxy. If this UI proxy represents a set of UI elements, the first one in the set is clicked and the anchor point of the UI element is used as the default one. It is also possible to click another point offset by providing focus argument.

See CoordinateSystem for more details.

参数:
  • focus (2-tuple/2-list/str) – an offset point (x, y) from the top left corner of the UI element(s), values must be in range of 0~1. This argument can be also specified by ‘anchor’ or ‘center’. ‘Center’ means to click the center of bounding box of UI element.
  • sleep_interval – number of seconds to wait after this action. Default is None which is the default sleep interval. This value can be configured by Poco initialization. See configuration at poco initialization for more details.
Raises:

PocoNoSuchNodeException – raised when the UI element does not exist

refresh()

Clear the flag to indicate to re-query or re-select the UI element(s) from hierarchy.

alias is refresh()

Example

>>> a = poco(text="settings")
>>> print(a.exists())
>>> a.refresh()
>>> print(a.exists())
scroll(direction='vertical', percent=0.6, duration=2.0)[源代码]

Simply touch down from point A and move to point B then release up finally. This action is performed within specific motion range and duration.

参数:
  • direction (str) – scrolling direction. “vertical” or “horizontal”
  • percent (float) – scrolling distance percentage of selected UI height or width according to direction
  • duration (float) – time interval in which the action is performed
Raises:

PocoNoSuchNodeException – raised when the UI element does not exist

set_text(text)[源代码]

Set the text attribute of the UI element. If the UI element does not support mutation, an exception is raised

参数:text – the text value to be set
Raises:InvalidOperationException – when unable to mutate text value of the UI element
setattr(name, val)[源代码]

Change the attribute value of the UI element. Not all attributes can be casted to text. If changing the immutable attributes or attributes which do not exist, the InvalidOperationException exception is raised.

参数:
  • name – attribute name
  • val – new attribute value to cast
Raises:

InvalidOperationException – when it fails to set the attribute on UI element

sibling(name=None, **attrs)[源代码]

Select the sibling(s) from the UI element(s) given by the query expression, see QueryCondition for more details about the selectors.

参数:
  • name – query expression of attribute “name”, i.e. the UI elements with name name will be selected
  • attrs – other query expression except for the name
返回:

a new UI proxy object representing the child(ren) of current UI element(s)

返回类型:

UIObjectProxy

start_gesture()[源代码]

Start a gesture action. This method will return a PendingGestureAction object which is able to generate decomposed gesture steps. You can invoke .to and .hold any times in a chain. See the following example.

实际案例

poco = Poco(...)
ui1 = poco('xxx')
ui2 = poco('yyy')

# touch down on ui1 and hold for 1s
# then drag to ui2 and hold for 1s
# finally release(touch up)
ui1.start_gesture().hold(1).to(ui2).hold(1).up()

注解

always starts touching down at the position of current UI object.

返回:an object for building serialized gesture action.
返回类型:PendingGestureAction
swipe(direction, focus=None, duration=0.5)[源代码]

Perform a swipe action given by the direction from this UI element. For notices and limitations see .click().

参数:
  • direction (2-tuple/2-list/str) – coordinates (x, y) in NormalizedCoordinate system, it can be also specified as ‘up’, ‘down’, ‘left’, ‘right’. Swipe ‘up’ is equivalent to [0, -0.1], swipe ‘down’ is equivalent to [0, 0.1], swipe ‘left’ is equivalent to [-0.1, 0] and swipe ‘right’ is equivalent to [0.1, 0]
  • focus (2-tuple/2-list/str) – see .click() for more details
  • duration (float) – time interval in which the action is performed
Raises:

PocoNoSuchNodeException – raised when the UI element does not exist

wait(timeout=3)[源代码]

Block and wait for max given time before the UI element appears.

参数:timeout – maximum waiting time in seconds
返回:self
返回类型:UIObjectProxy
wait_for_appearance(timeout=120)[源代码]

Block and wait until the UI element appears within the given timeout. When timeout, the PocoTargetTimeout is raised.

参数:timeout – maximum waiting time in seconds
Raises:PocoTargetTimeout – when timeout
wait_for_disappearance(timeout=120)[源代码]

Block and wait until the UI element disappears within the given timeout.

参数:timeout – maximum waiting time in seconds
Raises:PocoTargetTimeout – when timeout

poco.exceptions module

exception InvalidOperationException(message=None)[源代码]

基类:poco.exceptions.PocoException

Raised when the operation performing on target device is foreseen, e.g. instruction to click outside the screen is definitely meaningless, then the InvalidOperationException is raised.

exception PocoException(message=None)[源代码]

基类:Exception

Base class for errors and exceptions of Poco. It is Python3 compatible.

exception PocoNoSuchNodeException(objproxy)[源代码]

基类:poco.exceptions.PocoException

Raised when the UI element specified by query expression cannot be found.

exception PocoTargetRemovedException(action, objproxy)[源代码]

基类:poco.exceptions.PocoException

Raised when the hierarchy structure changed over the selection or when accessing the UI element that is already recycled.

In most cases, there is no need to handle this exception manually. If this exception occurs, it usually means it is a bug in your code rather than application itself. Check your code first. The most of misuses comes from as follows.

实际案例

button1 = poco('button1')
time.sleep(10)   # waiting for long enough before the UI hierarchy changing
button1.click()  # PocoTargetRemovedException will raise at this line. Because the 'button1' is not on the screen.
exception PocoTargetTimeout(action, poco_obj_proxy)[源代码]

基类:poco.exceptions.PocoException

Raised when the timeout expired while waiting for some condition to be fulfilled, e.g. waiting for the specific UI element but it has not appeared on the screen.

Engine specific API

Poco drivers (engine specific poco implementation)

不同的游戏引擎或app平台需要使用对应的driver去实例化poco对象。对应的API参考如下。

For other engines and platforms, please refer to Integration guide for more details

For multiple devices cases, please refer to Multiple devices guide for more details.

Poco SDK API

poco.sdk package

Subpackages
poco.sdk.interfaces package

The brief introduction:

This package (poco.sdk.interfaces) defines the main standards for communication interfaces between poco and poco-sdk. If poco-sdk is integrated with an app running on another host or in different language, then poco-sdk is called remote runtime. The implementation of these interfaces can be done either remotely or locally depending on your own choice. If it is done locally, refer to poco.freezeui for more information.

Poco needs to communicate with the app runtime under the convention of interfaces described below and these interfaces must be properly implemented. Any object implementing the same interface is replaceable and the communication protocol or transport layer has no limitation. Furthermore, in many cases the communication can be customized that one part of interfaces can use HTTP protocol and other can use TCP.

Submodules
poco.sdk.interfaces.command module
class CommandInterface[源代码]

基类:object

This is one of the main communication interfaces. This interface defines command-level behaviours providing abilities to control remote runtime by sending self-defined command. The provided command can be various type - from string type to specific structure of a dict.

command(cmd, type)[源代码]

Emit a command to remote runtime (target device).

参数:
  • cmd – any json serializable data.
  • type (str) – a string value indicated the command type (command tag).
返回:

None (recommended).

poco.sdk.interfaces.hierarchy module
class HierarchyInterface[源代码]

基类:object

This is one of the main communication interfaces. This interface defines hierarchy-related behaviour assembling from IDumper, Attributor and Selector. The hierarchy mentioned is the real hierarchy on target app runtime, e.g. a game UI hierarchy in its runtime.

dump()[源代码]

Get the UI hierarchy with its origin structure and attributes, then store the structure and attributes into a json serializable dictionary.

返回:dict representing the hierarchy structure. Structure specification refers to IDumper.
返回类型:dict
getAttr(nodes, name)[源代码]

Get attribute of UI element.

参数:
  • nodes – UI element or list of UI elements, if there is a list of UI elements provided, then only the first UI element will be used
  • name (str) – attribute name
select(query, multiple)[源代码]

Select UI element(s) matching the given query expression and return the list of selected UI element(s)

参数:
  • query (tuple) – query expression, for the structure specification refer to Selector.
  • multiple (bool) – whether or not to select multiple elements, if False, the method terminates immediately once the node is found, otherwise the method travers through all nodes and then terminates
返回:

list of UI elements corresponding to the given query expression

返回类型:

list

setAttr(nodes, name, value)[源代码]

Set attribute of UI element.

参数:
  • nodes – UI element or list of UI elements, if there is a list of UI elements provided, then only the first UI element will be used
  • name (str) – attribute name
  • value – new value to be set.
Raises:

UnableToSetAttributeException – raised when:

  • fails to set attributes on given UI element
  • the engine does not support mutating attributes
  • developer does not allow to change the attribute value by implementation
poco.sdk.interfaces.input module
class InputInterface[源代码]

基类:object

This is one of the main communication interfaces. This interface ensures the ability for simulated input on target device. So far, the interface supports only some basic methods definitions. The motion event will be added in future to provide full support for mobile devices.

All coordinates are in NormalizedCoordinate system, see NormalizedCoordinate for more details.

applyMotionEvents(events)[源代码]

Apply a motion event on the device touch panel

参数:events (list) – list of events. each event is MotionEvent data (['u/d/m/s', (x, y), contact_id])
click(x, y)[源代码]

Perform click action as simulated input on target device. Coordinates arguments are all in range of 0~1.

参数:
  • y (float) – y-coordinate
  • x (float) – x-coordinate
getTouchDownDuration()[源代码]

Get touch down duration for each click operation. Each implementation should provide a default value.

返回:the touch down duration in seconds
返回类型:float
keyevent(keycode)[源代码]

Send a key event to target device.

参数:keycode (int or char) – Ascii key code
longClick(x, y, duration)[源代码]

Perform press action as simulated input on target device within given seconds. Coordinates arguments are all in range of 0~1.

参数:
  • x (float) – x-coordinate
  • y (float) – y-coordinate
  • duration (float) – time interval to perform the action
setTouchDownDuration(duration)[源代码]

Set touch down duration for each click operation.

参数:duration (float) – the duration in seconds
swipe(x1, y1, x2, y2, duration)[源代码]

Perform swipe action as simulated input on target device from point A to B within given time interval to perform the action. Coordinates arguments are all in range of 0~1.

参数:
  • x1 (float) – x-coordinate of the start point
  • y1 (float) – y-coordinate of the start point
  • x2 (float) – x-coordinate of the end point
  • y2 (float) – y-coordinate of the end point
  • duration (float) – time interval to perform the swipe action
poco.sdk.interfaces.screen module
class ScreenInterface[源代码]

基类:object

This is one of the main communication interfaces. This interface ensures the ability for accessing the rendering the results presented on screen of target device. Note that rendering results are very often not used in automated testing directly. Following methods definitions can assist to obtain the information about the app.

getPortSize()[源代码]

Get the real resolution of the screen in pixels.

返回:width and height in pixels
返回类型:2-list (float, float)
getScreen(width)[源代码]

Take the screenshot of the target device screen or target app’s window

参数:width (int) – expected width of the screenshot in pixels
返回:
  • b64img: base64 encoded screen data
  • format: screen data format (png/jpg/etc.)
返回类型:2-list (str, str)
poco.sdk.std package
Subpackages
poco.sdk.std.rpc package
Submodules
poco.sdk.std.rpc.controller module
exception RpcRemoteException[源代码]

基类:Exception

poco.sdk.std.rpc.reactor module
exception NoSuchMethod(name, available_methods)[源代码]

基类:Exception

poco.sdk.std.transport package
Submodules
poco.sdk.std.protocol module
class SimpleProtocolFilter[源代码]

基类:object

简单协议过滤器 协议按照 [有效数据字节数][有效数据] 这种协议包的格式进行打包和解包 [有效数据字节数]长度HEADER_SIZE字节 [有效数据]长度有效数据字节数字节 本类按照这种方式,顺序从数据流中取出数据进行拼接,一旦接收完一个完整的协议包,就会将协议包返回 [有效数据]字段接收到后会按照utf-8进行解码,因为在传输过程中是用utf-8进行编码的 所有编解码的操作在该类中完成

input(data)[源代码]

小数据片段拼接成完整数据包 如果内容足够则yield数据包

static pack(content)[源代码]

content should be str

static unpack(data)[源代码]

return length, content

Submodules
poco.sdk.AbstractDumper module
class IDumper[源代码]

基类:object

This interface defines the standard dumper behavior. Dumper class is introduced to get the hierarchy information and convert it into serializable data.

dumpHierarchy(onlyVisibleNode)[源代码]

Return the json serializable dictionary holding the hierarchy data. Refer to sample of returned structure object below.

Structure of the dict:

{
    # name can be duplicated from the original name or just left the default one
    # if it cannot be determined, however providing some meaningful name is preferred
    'name': '<a recognizable string>'

    # All available attributes of this node are in form of key-value pairs
    'payload': {
        'name': '',
        'pos': [0, 0],
        'size': [1, 1],
        ...
    },

    # If there is no child, this part can be omitted
    'children': [
        {...},  # Same structure as this dict.
    ],
}
返回:hierarchy data or None
返回类型:dict or NoneType
getRoot()[源代码]

Return the root node of the UI Hierarchy. The node information is wrapped by AbstractNode. See definition of AbstractNode for more details.

返回:instance that holds the hierarchy data
返回类型:inherit from AbstractNode
class AbstractDumper[源代码]

基类:poco.sdk.AbstractDumper.IDumper

This class partially implements IDumper using general traversal algorithm. In order to dump the hierarchy from the root node, this dumper first retrieves all available attributes of the root node and also the list all its children and then applies the same procedures as described on each child (i.e. treats each child as a root node) until the node that has no child(ren) is reached.

dumpHierarchy(onlyVisibleNode=True)[源代码]
返回:json serializable dict holding the whole hierarchy data
返回类型:dict
dumpHierarchyImpl(node, onlyVisibleNode=True)[源代码]

Crawl the hierarchy tree using the simple DFS algorithm. The dump procedure is the engine independent as the hierarchy structure is wrapped by AbstractNode and therefore the dump procedure can be algorithmized.

Following code demonstrates the simplest implementation. Feel free to implement your own algorithms to optimize the performance.

注解

Do not explicitly call this method as this is an internal function, call dumpHierarchy() function instead if you want to dump the hierarchy.

参数:
  • node (inherit from AbstractNode) – root node of the hierarchy to be dumped
  • onlyVisibleNode (bool) – dump only the visible nodes or all nodes, default to True
返回:

json serializable dict holding the whole hierarchy data

返回类型:

dict

poco.sdk.AbstractNode module
class AbstractNode[源代码]

基类:object

AbstractNode is a wrapper class that provides UI hierarchy and node info in game engine.

This class uniformly specifies node-related methods such as retrieving the attributes or accessing the parent nodes or their children.

enumerateAttrs()[源代码]

Enumerate all available attributes and yield the 2-tuple (name, value).

Yields:Iterable<str, ValueType>
getAttr(attrName)[源代码]

Return the attributes of the node. The list below shows the most used basic attributes used during while writing test code. The implementation class should return the corresponding value as soon as it retrieves its value. If the value cannot be determined, the default value is obtained from super class invocation and returned. See the example below for more detailed information. More attributes can be added in order to enhance the selection and displaying in Inspector.

The most used basic attributes are listed as follows:

  • name: name of the node, use the unique and meaningful name for each node is recommended
  • type: type of the name of the node, it can be either any string, e.g. “android.widget.Button” or just simple as “Button”
  • visible: True or False whether the node is rendered on screen. In case the return value is False, all children nodes are ignored in Poco selector
  • pos: position of the node in screen, return value should be 2-list coordinates (x, y) representing the percentage of the screen. e.g. if the node lies in the center of the screen, the attribute will be [0.5f, 0.5f]. If the returned value for position is negative, it means the node lies out of the screen
  • size: size of the node bounding box, similar to pos, value is also a 2-list of the percentage of the screen size, e.g. the screen size is always [1.0f, 1.0f], if the node lies in left half side of the screen, its size will be [0.5f, 1.0f], the returned value of size should be always positive value
  • scale: scale factor applied to the node itself, leave it [1.0f, 1.0f] by default
  • anchorPoint: 2-list coordinates (x, y) of the anchor expressed in the percentage related to the bounding box of the node, leave it [0.5f, 0.5f] by default.
  • zOrders: rendering order of this node, its value is a dictionary such as {"global": 0, "local": 0}, global zOrder value is compared with all nodes in the hierarchy, local zOrder value is compared with its parent and siblings. The most top nodes have the largest values.

实际案例

The following sample code demonstrates some ideas about the implementation of this method:

def getAttr(self, attrName):
    # basic attributes
    if attrName == 'name':
        return self.node.get_name() or '<no name>'

    elif attrName == 'pos':
        return self.node.get_position()

    # ...

    # extra engine-specific attributes
    elif attrName == 'rotation':
        return self.node.get_rotation()

    # call the super method by default
    else:
        return super().getAttr(attrName)
参数:attrName (str) – attribute name
返回:JsonSerializable attribute value or None if no such attribute.
getAvailableAttributeNames()[源代码]

Enumerate all available attribute names of this node. This method in base class returns the basic attribute name by default. It is possible to add other customized or engine-specific attributes. See the example below.

注解

It is recommended to always call the super method and return should contain the part from super method.

实际案例

This code demonstrates how to implement this method:

def getAvailableAttributeNames(self):
    return super().getAvailableAttributeNames() + (
        # add other engine-specific attribute names here if need.
        'rotation',
    )
返回:Iterable<str>
getChildren()[源代码]

Return an iterator over all children nodes of this node. This method is invoked by Selector or Dumper to retrieve the UI hierarchy.

返回:Iterable <AbstractNode>
getParent()[源代码]

Return the parent node of this node. Return None if there is no parent or parent is not accessible or this is the root node. This method is invoked by Selector or Dumper when traversing UI hierarchy.

返回:parent node of this node or None.
返回类型:AbstractNode or NoneType
setAttr(attrName, val)[源代码]

Apply changes of the attribute value to this node. Not all attributes can be modified. The most common attribute to be modified is the text. It is not recommended to modify attributes such as position, name, their modifications can lead to unexpected and false-positive errors.

参数:
  • attrName (str) – attribute name
  • val – attribute value
返回:

True if success else False or raise.

参见

setAttr in poco.sdk.interfaces.hierarchy

poco.sdk.Attributor module
class Attributor[源代码]

基类:object

This is a helper class to access the node attributes. In some cases it is not possible to explicitly invoke the node member functions thus the following two functions are introduced.

The instance of this class will be used in implementation of HierarchyInterface.

注解

Do not call these methods explicitly in the test codes.

poco.sdk.DefaultMatcher module
class DefaultMatcher[源代码]

基类:poco.sdk.DefaultMatcher.IMatcher

Default matcher implementation for poco hierarchy traversing. Including logical query condition and predicate expression. When traversing through the hierarchy tree, matcher will apply the match method on each node of the tree.

The formal definition of query condition as follows:

expr := (op0, (expr0, expr1, ...))
expr := (op1, (arg1, arg2))
  • op0str is logical operator (‘or’ or ‘and’) which has the same semantics as in python, e.g. ‘or’ means this expression/condition matches if any of the exprN matches

  • op1str is comparator, can be one of as follows:

    op1 := 'attr='
    op1 := 'attr.*='
    op1 := ... (other customized)
    

    The op1 must be a string. The Matcher will help to map to Comparator object.

match(cond, node)[源代码]

See Also: IMatcher.match

class EqualizationComparator[源代码]

基类:object

Compare two objects using the native equivalence (==) comparison operator

class RegexpComparator[源代码]

基类:object

Compare two objects using regular expression. Available only when the original value is string type. It always returns False if the original value or given pattern are not str type.

compare(origin, pattern)[源代码]
参数:
  • origin (str) – original string
  • pattern (str) – Regexp pattern string
返回:

True if matches otherwise False.

返回类型:

bool

poco.sdk.Selector module
class ISelector[源代码]

基类:object

This interface defines the standard selector behavior. Selector is used for selecting the specific UI element(s) by given query expression (formal definitions are in specific implementation classes).

select(cond, multiple=False)[源代码]
参数:
  • cond (tuple) – query expressiom
  • multiple (bool) – whether or not to select the multiple elements. If set to True, the method terminates immediately once the node is found, otherwise it traverses through all nodes and then exists
返回:

list <inherited from AbstractNode>

返回类型:

list

class Selector(dumper, matcher=None)[源代码]

基类:poco.sdk.Selector.ISelector

This class implements the standard Selector interface that uses DFS algorithm to travers through tree-like hierarchy structure. It supports flexible query expressions such as parental relationship, attribute predicate, etc. Any combinations of expressions mentioned above are also allowed as the query conditions.

The query expression can be defined as follows:

expr := (op0, (expr0, expr1))
expr := ('index', (expr, :obj:`int`))
expr := <other query condition> See implementation of Matcher.
  • op0 can be one of the following (‘>’, ‘/’, ‘-‘), each operator stands for as follows:

    '>': offsprings, select all offsprings matched expr1 from all roots matched expr0.
    '/': children, select all children matched expr1 from all roots matched expr0.
    '-': siblings, select all siblings matched expr1 from all roots matched expr0.
    '^': parent, select the parent of 1st UI element matched expr0. expr1 is always None.
    
  • 'index': select specific n-th UI element from the previous results

  • others: passes the expression to matcher

参数:
  • dumper (any implementation of IDumper) – dumper for the selector
  • matcher (any implementation of IMatcher) – DefaultMatcher instance by default.
getRoot()[源代码]

Get a default root node.

返回:default root node from the dumper.
select(cond, multiple=False)[源代码]

See Also: select method in ISelector.

selectImpl(cond, multiple, root, maxDepth, onlyVisibleNode, includeRoot)[源代码]

Selector internal implementation. TODO: add later.

注解

This doc shows only the outline of the algorithm. Do not call this method in your code as this is an internal method.

参数:
  • cond (tuple) – query expression
  • multiple (bool) – whether or not to select multiple nodes. If true, all nodes that matches the given condition will return, otherwise, only the first node matches will.
  • root (inherited from AbstractNode) – start traversing from the given root node
  • maxDepth (bool) – max traversing depth
  • onlyVisibleNode (bool) – If True, skip those node which visibility (the value of visible attribute) is False.
  • includeRoot (bool) – whether not not to include the root node if its child(ren) match(es) the node
返回:

The same as

select.

返回类型:

list <inherited from AbstractNode>

poco.sdk.exceptions module

This module provides several exceptions for poco-sdk. These exceptions are raised only in sdk corresponding runtime.

exception NoSuchTargetException[源代码]

基类:Exception

Raised when the index is out of range for selecting the UI element by given index.

exception NodeHasBeenRemovedException(attrName, node)[源代码]

基类:Exception

Raised when the node (UI element) is refreshed (updated, recycled or destroyed) while retrieving the attributes during traversing the hierarchy.

In some engines implementations, the UI hierarchy is refreshed in a stand-alone thread while poco is performing the traverse process, so the engine error might be triggered when poco is trying to retrieve the attribute of the UI element but the attribute is being updated at the same time. In this situation, poco sdk catches the engine error and raises this exception.

exception UnableToSetAttributeException(attrName, node)[源代码]

基类:Exception

Raised when settings the attribute of the given UI element failed. In most cases, the reason why it failed is that the UI element does not support mutation. From the point of view of SDK implementation, this exception can be raised proactively to indicate that the modification of the attribute is not allowed.

exception NoSuchComparatorException(matchingMethod, matcherName)[源代码]

基类:Exception

Raised when the matcher does not support the given comparison method.

exception NonuniqueSurfaceException(selector)[源代码]

基类:Exception

Raised when the device selector matches mutiple devices surface

exception InvalidSurfaceException(target, msg='None')[源代码]

基类:Exception

Raised when the device surface is invalid

Poco Examples and Tutorials

以下的所有示例大部分都是基于一个Unity3D写的小游戏,你可以下载这个小游戏并安装到你的手机上来测试一下例子里的代码。

Download the demo game

You can have a try most of the example scripts with the super simple demo game we provided.

More demo games for testing

The following files are standard apps with according poco-sdk integrated. You can download and install on your device to make sure it works for your environment.

如何嵌入PocoSDK(Integration Guide)

主流引擎直接将我们的sdk嵌入到游戏中即可,sdk总仓库 poco-sdk repo

嵌入sdk过程中遇到任何问题可以随时在github上提issue

Unity3D

PocoSDK 支持Unity3D 4以上版本,支持NGUI和UGUI,SDK目前只有c#版。如果你的Unity3D游戏使用了其他GUI框架,请参考 implementation guide 。接入步骤如下:

  1. poco-sdk repo clone或下载源码。
  2. 拷贝 Unity3D 文件夹到你的Unity3D项目脚本目录,任意路径都可以。
  3. 使用 NGUI 的话就把 Unity3D/ugui 目录删除。使用 UGUI 的话就把 Unity3D/ngui 目录删除。
  4. 场景中任意 GameObject 上 Add Component Unity3D/PocoManager.cs ,一般 GameObject 选root或者主camera.
Cocos2dx-lua

cocos2dx-lua版本 >= 3.1

  1. poco-sdk repo clone或下载源码。
  2. cocos2dx-lua/poco 文件夹复制到项目脚本文件夹中。你可以重命名该文件夹
  3. 将以下代码复制到您的游戏初始化脚本中,来初始化poco-sdk。
local poco = require('poco.poco_manager')
poco:init_server(15004)  -- default port number is 15004, change to another if you like

注解

您的cocos2dx-lua项目至少应该启用 socketsocket.core 模块。poco要求这个模块在运行时设置一个tcp服务器。

注解

如果cocos2dx-lua项目没有 mime 模块,它仍然可以工作,但是有点慢。

  1. (对于Android平台)最好检查一下adb logcat的输出(建议使用Android Studio里的logcat),选择你的应用看下是否有如下输出,如果有则表示接入成功。
_images/integration-guild-cocos2dxlua-sdk-started.png

整合之后,你可以开始 play with poco。如果你有任何问题,欢迎 open an issue here。标题格式: [cocos2dx-lua sdk 集成]xxx

Cocos2dx-js (beta)

PocoSDK 支持 3.1 <= Cocos2dx version <= 3.13.1 (理论上). 为了确保每个JavaScript引擎的兼容性, 这个JavaScript sdk是用ES5编写的

cocos2d-x 3.13.1 已经测试通过

  1. poco-sdk repo clone或下载源码。
  2. 拷贝 cocos2dx-js/Poco 文件夹到你的cocos2dx-js项目脚本目录,任意路径都可以。
  3. 由于sdk需要WebSocketServer,我们应该使用本机代码构建WebSocketServer模块和js绑定。 WebSocketServer是cocos2dx框架的一部分,但默认不包含,因此我们通过以下步骤手动构建它。 另请参阅WebSocketServer参考。 您最好在复制之前备份您的原始websockets文件夹。WebSocketServer的js绑定需要libwebsockets版本== 1.6。如果您的cocos2d-x引擎没有使用libwebsockets version == 1.6,那么在cocos2d-x本身中可能会有一些不兼容问题。
cp -r cocos2dx-js/3rd/websockets <your-cocos-project>/frameworks/cocos2d-x/external/websockets
cp cocos2dx-js/3rd/src/* <your-cocos-project>/frameworks/runtime-src/Classes
  1. 编辑 <your-cocos-project>/frameworks/runtime-src/Classes/AppDelegate.cpp. 在适当的位置添加下面2行代码
// include it at top
#include "jsb_websocketserver.h"

// register callbacks of websocketserver
sc->addRegisterCallback(register_jsb_websocketserver);
_images/integration-guild-cocos2dxjs-jsbwebsocketserver.png _images/integration-guild-cocos2dxjs-jsbwebsocketserver-2.png
  1. 编辑 <your-cocos-project>/frameworks/runtime-src/proj.android/jni/Android.mk. 在你自己的makefile适当位置添加下方的内容, 如果你正在使用AndroidStudio项目, 请编辑 proj.android-studio/jni/Android.mk 并保证路径正确
_images/integration-guild-cocos2dxjs-jsbwebsocketserver-3.png
...

$(call import-add-path, $(LOCAL_PATH)/../../../cocos2d-x/external)

LOCAL_SRC_FILES := hellojavascript/main.cpp \
                   ../../Classes/AppDelegate.cpp \
                   ../../Classes/WebSocketServer.cpp \
                   ../../Classes/jsb_websocketserver.cpp

LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../Classes \
                    $(LOCAL_PATH)/../../../cocos2d-x/external/websockets/include/android

LOCAL_STATIC_LIBRARIES := cocos2d_js_static websockets_static

include $(BUILD_SHARED_LIBRARY)
$(call import-module, websockets/prebuilt/android)
$(call import-module, scripting/js-bindings/proj.android)

...
  1. 编辑你的 project.json, 按下列顺序将sdk文件名添加到 jsList 中.
{
    // ...
    jsList: [
        // ...
        "src/lib/Poco/sdk/AbstractDumper.js",
        "src/lib/Poco/sdk/AbstractNode.js",
        "src/lib/Poco/sdk/Attributor.js",
        "src/lib/Poco/sdk/DefaultMatcher.js",
        "src/lib/Poco/sdk/IScreen.js",
        "src/lib/Poco/sdk/Selector.js",
        "src/lib/Poco/Cocos2dxNode.js",
        "src/lib/Poco/Cocos2dxDumper.js",
        "src/lib/Poco/POCO_SDK_VERSION.js",
        "src/lib/Poco/Poco.js"
    ]
}
  1. 重新编译你的项目
  2. require('Poco') 会在游戏的第一个初始化脚本中启动PocoSDK,并且不要在游戏的生命周期中销毁它
var PocoManager = window.PocoManager
var poco = new PocoManager()

// add poco on window object to persist
window.poco = poco

如果出现任何问题,请 open an issue here. 。 标题格式:[cocos2dx-js sdk 集成] xxx

Cocos-Creator

PocoSDK 支持 Cocos Creator 2.2.1 或更高的版本

已经在Cocos Creator 2.2.1上测试过。

  1. poco-sdk repo clone或下载源码。

  2. 复制 cocos-creator/Poco 文件夹到你的cocos-creator项目脚本目录,任意路径都可以。

  3. 因为SDK需要WebSocketServer的支持,我们需要开启WebSocketServer模块。

    WebSocketServer已经被cocos creator支持,但是默认没有开启,我们只需要按照如下步骤去开启他。

    1. 去到引擎目录
    2. 编辑 ccConfig.h 文件。文件路径在 your/path/to/CocosCreator_2.2.1/resources/cocos2d-x/cocos/base/ccConfig.h
    3. 编辑第62行。把 #define USE_WEBSOCKET_SERVER 0 改为 #define USE_WEBSOCKET_SERVER 1
  4. 重新编译你的项目

  5. require('Poco') 会在游戏的第一个初始化脚本中启动PocoSDK,并且不要在游戏的生命周期中销毁它

cc.Class({
    extends: cc.Component,

    .....

    //remember to put code in onLoad function
    onLoad: function () {
       .....

        var poco = require("./Poco") // use your own relative path
        window.poco = new poco(); // not destroy
        cc.log(window.poco);

    },

   .....
});

注解

当前的版本只支持Android和Windows平台。并且Poco只能在打包后使用,不支持预览模式中使用。

Unreal

(即将支持)

Android原生应用 (Native App)

什么都不需要做,直接使用即可。使用方法见 poco for Android Native App

网易自研引擎 (Netease Internal Engines)

Hunter 里直接配置即可,在 __init__ 指令最后面根据引擎加入下面代码片段。 要求safaia版本大于1.2.0. 有疑问请联系 lxn3032@corp.netease.com.

  • for NeoX
# core (add only if not present)
Safaia().install(require('safaia.init.core'))

# poco uiautomation
PocoUiautomation = require('support.poco.neox.uiautomation')
Safaia().install(PocoUiautomation)

# inspector extension
screen_handler = require('support.poco.neox.screen')()
InspectorExt = require('support.poco.safaia.inspector')
InspectorExt.screen = screen_handler
InspectorExt.dumper = require('support.poco.neox.Dumper')()
Safaia().install(InspectorExt)
  • for Messiah
# core (add only if not present)
Safaia().install(require('safaia.init.core'))

# poco uiautomation
PocoUiautomation = require('support.poco.messiah.uiautomation')
Safaia().install(PocoUiautomation)

# inspector extension
screen_handler = require('support.poco.messiah.screen')()
InspectorExt = require('support.poco.safaia.inspector')
InspectorExt.screen = screen_handler
InspectorExt.dumper = require('support.poco.cocos2dx.Dumper')()
Safaia().install(InspectorExt)
  • for cocos2dx-* and others: please contact lxn3032@corp.netease.com.
其他引擎 (Other Engines)

请见 implementation guide

如何用脚本抓取界面所有元素

Poco为不同的引擎定义了标准的界面层次结构(hierarchy)格式,在任何游戏上使用dump方法都可以获得相同的结构。示例代码和层次结构格式如下。

import json
from poco.drivers.unity3d import UnityPoco as Poco

poco = Poco()
ui = poco.agent.hierarchy.dump()
print(json.dumps(ui, indent=4))

下面就是层次结构(hierarchy)的数据表示,用 dict 存储并都是可json序列化的。

...
{
    "name": "OctopusArea",
    "payload": {
        "name": "OctopusArea",
        "type": "GameObject",
        "visible": true,
        "clickable": true,
        "zOrders": {
            "global": 0,
            "local": -10
        },
        "scale": [
            1,
            1
        ],
        "anchorPoint": [
            0.5,
            0.5
        ],
        "pos": [
            0.130729169,
            0.44907406
        ],
        "size": [
            0.0859375,
            0.125
        ]
    }
    "children": [
        {...},
        ...
    ],
}
...

Join to discuss!

join slack