zoukankan      html  css  js  c++  java
  • ATX uiautomator2 README 学习

    连接设备

    有多种方式可以连接

    • wifi 首先要保证你的手机(10.0.0.1)和电脑在同一个局域网内
    import uiautomator2 as u2

    d = u2.connect('10.0.0.1') # alias for u2.connect_wifi('10.0.0.1')
    print(d.info)
    • usb
      usb通过设备号连接,可以通过adb devices 查看
    import uiautomator2 as u2

    d = u2.connect('123456f') # alias for u2.connect_usb('123456f')
    print(d.info)
    • adb wifi
    import uiautomator2 as u2

    d = u2.connect_adb_wifi("10.0.0.1:5555")

    # Equals to
    # + Shell: adb connect 10.0.0.1:5555
    # + Python: u2.connect_usb("10.0.0.1:5555")

    全局设置

    里面包含一些u2全局设置的属性

    • Http debug
    >>> d.debug = True
    >>> d.info
    12:32:47.182 $ curl -X POST -d '{"jsonrpc": "2.0", "id": "b80d3a488580be1f3e9cb3e926175310", "method": "deviceInfo", "params": {}}' 'http://127.0.0.1:54179/jsonrpc/0'
    12:32:47.225 Response >>>
    {"jsonrpc":"2.0","id":"b80d3a488580be1f3e9cb3e926175310","result":{"currentPackageName":"com.android.mms","displayHeight":1920,"displayRotation":0,"displaySizeDpX":360,"displaySizeDpY":640,"displayWidth":1080,"productName"
    :"odin","screenOn":true,"sdkInt":25,"naturalOrientation":true}}
    <<< END
    • 默认等待超时时间
    d.implicitly_wait(10.0)
    d(text="Settings").click() # if Settings button not show in 10s, UiObjectNotFoundError will raised

    print("wait timeout", d.implicitly_wait()) # get default implicit wait

    将会作用在这些方法中 clicklong_clickdrag_toget_text, set_textclear_text,等.

    app管理

    • 安装
    d.app_install('http://some-domain.com/some.apk')
    • 唤起app
    # 默认的这种方法是先通过atx-agent解析apk包的mainActivity,然后调用am start -n $package/$activity启动
    d.app_start("com.example.hello_world")

    # 使用 monkey -p com.example.hello_world -c android.intent.category.LAUNCHER 1 启动
    # 这种方法有个附带的问题,它自动会将手机的旋转锁定给关掉
    d.app_start("com.example.hello_world", use_monkey=True) # start with package name

    # 通过指定main activity的方式启动应用,等价于调用am start -n com.example.hello_world/.MainActivity
    d.app_start("com.example.hello_world", ".MainActivity")
    • 停止app
    # equivalent to `am force-stop`, thus you could lose data
    d.app_stop("com.example.hello_world")
    # equivalent to `pm clear`
    d.app_clear('com.example.hello_world')
    • 停止所有运行的app
    # stop all
    d.app_stop_all()
    # stop all app except for com.examples.demo
    d.app_stop_all(excludes=['com.examples.demo'])
    • 获取app信息
    d.app_info("com.examples.demo")
    # expect output
    #{
    # "mainActivity": "com.github.uiautomator.MainActivity",
    # "label": "ATX",
    # "versionName": "1.1.7",
    # "versionCode": 1001007,
    # "size":1760809
    #}

    # save app icon
    img = d.app_icon("com.examples.demo")
    img.save("icon.png")
    • 获取所有正在运行的app
    d.app_list_running()
    # expect output
    # ["com.xxxx.xxxx", "com.github.uiautomator", "xxxx"]
    • 等待app运行
    pid = d.app_wait("com.example.android") # 等待应用运行, return pid(int)
    if not pid:
    print("com.example.android is not running")
    else:
    print("com.example.android pid is %d" % pid)

    d.app_wait("com.example.android", front=True) # 等待应用前台运行
    d.app_wait("com.example.android", timeout=20.0) # 最长等待时间20s(默认)
    • 传文件到设备
    # push to a folder
    d.push("foo.txt", "/sdcard/")
    # push and rename
    d.push("foo.txt", "/sdcard/bar.txt")
    # push fileobj
    with open("foo.txt", 'rb') as f:
    d.push(f, "/sdcard/")
    # push and change file access mode
    d.push("foo.sh", "/data/local/tmp/", mode=0o755)
    • 从设备拉取一个文件到电脑
    d.pull("/sdcard/tmp.txt", "tmp.txt")

    # FileNotFoundError will raise if the file is not found on the device
    d.pull("/sdcard/some-file-not-exists.txt", "tmp.txt")
    • 设备健康检查
    d.healthcheck()

    常见api使用

    介绍如何操作设备

    shell命令

    • 具有超时保护的shell 命令(默认60s)
    output, exit_code = d.shell("pwd", timeout=60) # timeout 60s (Default)
    # output: "/ ", exit_code: 0
    # Similar to command: adb shell pwd

    # Since `shell` function return type is `namedtuple("ShellResponse", ("output", "exit_code"))`
    # so we can do some tricks
    output = d.shell("pwd").output
    exit_code = d.shell("pwd").exit_code

    # The first argument can be list. for example
    output, exit_code = d.shell(["ls", "-l"])
    # output: "/....", exit_code: 0

    该 adb shell会阻塞,直到有结果活超时,不适合长时间使用

    • 长期运行的shell
    r = d.shell("logcat", stream=True)
    # r: requests.models.Response
    deadline = time.time() + 10 # run maxium 10s
    try:
    for line in r.iter_lines(): # r.iter_lines(chunk_size=512, decode_unicode=None, delimiter=None)
    if time.time() > deadline:
    break
    print("Read:", line.decode('utf-8'))
    finally:
    r.close() # this method must be called

    r.close() 时,命令将会被终止

    会话

    会话代表应用程序生命周期。 可用于启动应用程序,检测应用程序崩溃。

    • 唤起和关闭app

      sess = d.session("com.netease.cloudmusic") # start 网易云音乐
      sess.close() # 停止网易云音乐
      sess.restart() # 冷启动网易云音乐
    • 使用pythonwith

    with d.session("com.netease.cloudmusic") as sess:
    sess(text="Play").click()
    • 连接运行的app
    # launch app if not running, skip launch if already running
    #如果app没有运行将会唤起,运行则会连接
    sess = d.session("com.netease.cloudmusic", attach=True)

    # raise SessionBrokenError if not running
    # 异常在app不在运行的时候
    sess = d.session("com.netease.cloudmusic", attach=True, strict=True)

    • 检测app崩溃
    # When app is still running
    sess(text="Music").click() # operation goes normal

    # If app crash or quit
    #异常在app不在运行的时候
    sess(text="Music").click() # raise SessionBrokenError
    # other function calls under session will raise SessionBrokenError too

    # check if session is ok.
    # Warning: function name may change in the future
    sess.running() # True or False

    获取设备信息

    • 基本信息 d.info
    { 
    u'displayRotation': 0,
    u'displaySizeDpY': 640,
    u'displaySizeDpX': 360,
    u'currentPackageName': u'com.android.launcher',
    u'productName': u'takju',
    u'displayWidth': 720,
    u'sdkInt': 18,
    u'displayHeight': 1184,
    u'naturalOrientation': True
    }
    • 设备的详细信息 d.device_info
    {'udid': '3578298f-b4:0b:44:e6:1f:90-OD103',
    'version': '7.1.1',
    'serial': '3578298f',
    'brand': 'SMARTISAN',
    'model': 'OD103',
    'hwaddr': 'b4:0b:44:e6:1f:90',
    'port': 7912,
    'sdk': 25,
    'agentVersion': 'dev',
    'display': {'width': 1080, 'height': 1920},
    'battery': {'acPowered': False,
    'usbPowered': False,
    'wirelessPowered': False,
    'status': 3,
    'health': 0,
    'present': True,
    'level': 99,
    'scale': 100,
    'voltage': 4316,
    'temperature': 272,
    'technology': 'Li-ion'},
    'memory': {'total': 3690280, 'around': '4 GB'},
    'cpu': {'cores': 8, 'hardware': 'Qualcomm Technologies, Inc MSM8953Pro'},
    'presenceChangedAt': '0001-01-01T00:00:00Z',
    'usingBeganAt': '0001-01-01T00:00:00Z'}
    • 屏幕大小

      print(d.window_size())
      # device upright output example: (1080, 1920)
      # device horizontal output example: (1920, 1080)
    • 运行的app

    print(d.app_current())
    # Output example 1: {'activity': '.Client', 'package': 'com.netease.example', 'pid': 23710}
    # Output example 2: {'activity': '.Client', 'package': 'com.netease.example'}
    # Output example 3: {'activity': None, 'package': None}
    • 等待activity
    d.wait_activity(".ApiDemos", timeout=10) # default timeout 10.0 seconds
    # Output: true of false
    • 获取设备号
    print(d.serial)
    # output example: 74aAEDR428Z9
    • 局域网ip
    print(d.wlan_ip)
    # output example: 10.0.0.1

    键盘事件

    • 打开/关闭屏幕
    d.screen_on() # turn on the screen
    d.screen_off() # turn off the screen
    • 获取屏幕状态
    d.info.get('screenOn') # require Android >= 4.4
    • 点击按键 d.press("home") # press the home key, with key name d.press("back") # press the back key, with key name d.press(0x07, 0x02) # press keycode 0x07('0') with META ALT(0x02)
    • 当前支持以下键名:
      • home
      • back
      • left
      • right
      • up
      • down
      • center
      • menu
      • search
      • enter
      • delete ( or del)
      • recent (recent apps)
      • volume_up
      • volume_down
      • volume_mute
      • camera
      • power

    更多key code定义参考Android KeyEvent

    • 解锁 python d.unlock() # This is equivalent to # 1. launch activity: com.github.uiautomator.ACTION_IDENTIFY # 2. press the "home" key

    与设备的手势交互

    • 单击

      d.click(x, y)
    • 双击

      d.double_click(x, y)
      d.double_click(x, y, 0.1) # default duration between two click is 0.1s
    • 长按

      d.long_click(x, y)
      d.long_click(x, y, 0.5) # long click 0.5s (default)
    • 滑动

      d.swipe(sx, sy, ex, ey)
      d.swipe(sx, sy, ex, ey, 0.5) # swipe for 0.5s(default)
    • 滑动扩展功能

      d.swipe_ext("right") # 屏幕右滑,41 "left", "right", "up", "bottom"
      d.swipe_ext("right", scale=0.9) # 默认0.9, 滑动距离为屏幕宽度的90%
      d.swipe_ext("right", box=(0, 0, 100, 100)) # (0,0) -> (100, 100) 这个区域做滑动

    * 拖拽

    ```python
    d.drag(sx, sy, ex, ey)
    d.drag(sx, sy, ex, ey, 0.5) # swipe for 0.5s(default)
    • 滑动解锁

      # swipe from point(x0, y0) to point(x1, y1) then to point(x2, y2)
      # time will speed 0.2s bwtween two points
      d.swipe_points([(x0, y0), (x1, y1), (x2, y2)], 0.2))

      多用于九宫格解锁,提前获取到每个点的相对坐标(这里支持百分比), 更详细的使用参考这个帖子 使用u2实现九宫图案解锁

    • 按着拖动

      这个接口属于比较底层的原始接口,感觉并不完善,不过凑合能用。注:这个地方并不支持百分比

    d.touch.down(10, 10) # 模拟按下
    time.sleep(.01) # down move 之间的延迟,自己控制
    d.touch.move(15, 15) # 模拟移动
    d.touch.up() # 模拟抬起

    注: clickswipedrag 这几个操作支持百分比

    屏幕相关

    • 设置屏幕方向
      • natural or n
      • left or l
      • right or r
      • upsidedown or u (can not be set)
    # retrieve orientation. the output could be "natural" or "left" or "right" or "upsidedown"
    orientation = d.orientation

    # WARNING: not pass testing in my TT-M1
    # set orientation and freeze rotation.
    # notes: setting "upsidedown" requires Android>=4.3.
    d.set_orientation('l') # or "left"
    d.set_orientation("l") # or "left"
    d.set_orientation("r") # or "right"
    d.set_orientation("n") # or "natural"
    • 屏幕旋转
    # freeze rotation
    d.freeze_rotation()
    # un-freeze rotation
    d.freeze_rotation(False)
    • 截屏
    # take screenshot and save to a file on the computer, require Android>=4.2.
    d.screenshot("home.jpg")

    # get PIL.Image formatted images. Naturally, you need pillow installed first
    image = d.screenshot() # default format="pillow"
    image.save("home.jpg") # or home.png. Currently, only png and jpg are supported

    # get opencv formatted images. Naturally, you need numpy and cv2 installed first
    import cv2
    image = d.screenshot(format='opencv')
    cv2.imwrite('home.jpg', image)

    # get raw jpeg data
    imagebin = d.screenshot(format='raw')
    open("some.jpg", "wb").write(imagebin)
    • dump 视图结构
    # get the UI hierarchy dump content (unicoded).
    xml = d.dump_hierarchy()
    • 打开通知和设置
    d.open_notification()
    d.open_quick_settings()

    选择器

    选择器是一种灵活的机制用户标识一个特殊的ui对象

    # Select the object with text 'Clock' and its className is 'android.widget.TextView'
    d(text='Clock', className='android.widget.TextView')

    注: 可以使用d.info输出定位的控件信息,来确认是否正确

    选择器支持以下参数,更多参考UiSelector java文档

    • texttextContainstextMatchestextStartsWith
    • classNameclassNameMatches
    • descriptiondescriptionContainsdescriptionMatchesdescriptionStartsWith
    • checkablecheckedclickablelongClickable
    • scrollableenabled,focusablefocusedselected
    • packageNamepackageNameMatches
    • resourceIdresourceIdMatches
    • indexinstance

    子和兄弟控件(Children and siblings)

    • children
    # get the children or grandchildren
    d(className="android.widget.ListView").child(text="Bluetooth")
    • siblings (兄弟)
    # get siblings
    d(text="Google").sibling(className="android.widget.ImageView")
    • text description instance 定位子view
    # get the child matching the condition className="android.widget.LinearLayout"
    # and also its children or grandchildren with text "Bluetooth"
    d(className="android.widget.ListView", resourceId="android:id/list")
    .child_by_text("Bluetooth", className="android.widget.LinearLayout")

    # get children by allowing scroll search
    d(className="android.widget.ListView", resourceId="android:id/list")
    .child_by_text(
    "Bluetooth",
    allow_scroll_search=True,
    className="android.widget.LinearLayout"
    )

    child_by_description child_by_instance 和 child_by_instance差不多,只是条件换了,但是都是查找屏幕内的view

    例子dom信息如下:

    <node index="0" text="" resource-id="android:id/list" class="android.widget.ListView" ...>
    <node index="0" text="WIRELESS & NETWORKS" resource-id="" class="android.widget.TextView" .../>
    <node index="1" text="" resource-id="" class="android.widget.LinearLayout" ...>
    <node index="1" text="" resource-id="" class="android.widget.RelativeLayout" ...>
    <node index="0" text="WiFi" resource-id="android:id/title" class="android.widget.TextView" .../>
    </node>
    <node index="2" text="ON" resource-id="com.android.settings:id/switchWidget" class="android.widget.Switch" .../>
    </node>
    ...
    </node>
     

    这里有一个例子来说明如何使用

    注: 不同版本的settings可能实现不一样,例如6.0的就不是ListView

    d(className="android.widget.ListView", resourceId="android:id/list") 
    .child_by_text("Wi‑Fi", className="android.widget.LinearLayout")
    .child(className="android.widget.Switch")
    .click()
    • 相对位置

      • d(A).left(B), selects B on the left side of A.
      • d(A).right(B), selects B on the right side of A.
      • d(A).up(B), selects B above A.
      • d(A).down(B), selects B under A.
    ## select "switch" on the right side of "Wi‑Fi"
    d(text="Wi‑Fi").right(className="android.widget.Switch").click()
    • 多个实例
      有时候界面上会有多个view具有相同的属性,例如 text,这时候你可以使用instance来选择你需要的实例
    d(text="Add new", instance=0)  # which means the first instance with text "Add new"

    更多api信息 list-like API (similar to jQuery):

    # get the count of views with text "Add new" on current screen
    d(text="Add new").count

    # same as count property
    len(d(text="Add new"))

    # get the instance via index
    d(text="Add new")[0]
    d(text="Add new")[1]
    ...

    # iterator
    for view in d(text="Add new"):
    view.info # ...

    注:在遍历list的时候要保证界面是不变化的,不然发生错误

    ui对象状态和信息

    • 检查ui是否存在
    d(text="Settings").exists # True if exists, else False
    d.exists(text="Settings") # alias of above property.

    # advanced usage
    d(text="Settings").exists(timeout=3) # wait Settings appear in 3s, same as .wait(3)

    • ui对象信息
    d(text="Settings").info

    # 输出
    { u'contentDescription': u'',
    u'checked': False,
    u'scrollable': False,
    u'text': u'Settings',
    u'packageName': u'com.android.launcher',
    u'selected': False,
    u'enabled': True,
    u'bounds': {u'top': 385,
    u'right': 360,
    u'bottom': 585,
    u'left': 200},
    u'className': u'android.widget.TextView',
    u'focused': False,
    u'focusable': True,
    u'clickable': True,
    u'chileCount': 0,
    u'longClickable': True,
    u'visibleBounds': {u'top': 385,
    u'right': 360,
    u'bottom': 585,
    u'left': 200},
    u'checkable': False
    }
    • 获取/设置/清空 输入框
    d(text="Settings").get_text()  # get widget text
    d(text="Settings").set_text("My text...") # set the text
    d(text="Settings").clear_text() # clear the text
    • 获取控件中心点
    x, y = d(text="Settings").center()
    # x, y = d(text="Settings").center(offset=(0, 0)) # left-top x, y

    点击选中的ui对象

    • 单击
    # click on the center of the specific ui object
    d(text="Settings").click()

    # wait element to appear for at most 10 seconds and then click
    d(text="Settings").click(timeout=10)

    # click with offset(x_offset, y_offset)
    # click_x = x_offset * width + x_left_top
    # click_y = y_offset * height + y_left_top
    d(text="Settings").click(offset=(0.5, 0.5)) # Default center
    d(text="Settings").click(offset=(0, 0)) # click left-top
    d(text="Settings").click(offset=(1, 1)) # click right-bottom

    # click when exists in 10s, default timeout 0s
    clicked = d(text='Skip').click_exists(timeout=10.0)

    # click until element gone, return bool
    is_gone = d(text="Skip").click_gone(maxretry=10, interval=1.0) # maxretry default 10, interval default 1.0

    • 长按
    # long click on the center of the specific UI object
    d(text="Settings").long_click()

    手势操作

    • 拖动
    # notes : drag can not be used for Android<4.3.
    # drag the UI object to a screen point (x, y), in 0.5 second
    d(text="Settings").drag_to(x, y, duration=0.5)
    # drag the UI object to (the center position of) another UI object, in 0.25 second
    d(text="Settings").drag_to(text="Clock", duration=0.25)
    • 滑动

      支持四个方向

      • left
      • right
      • top
      • bottom
      d(text="Settings").swipe("right")
      d(text="Settings").swipe("left", steps=10)
      d(text="Settings").swipe("up", steps=20) # 1 steps is about 5ms, so 20 steps is about 0.1s
      d(text="Settings").swipe("down", steps=20)
    • 双指滑动

    d(text="Settings").gesture((sx1, sy1), (sx2, sy2), (ex1, ey1), (ex2, ey2))
    • Two-point gesture on the specific UI object 不晓得怎么表达

    Supports two gestures:

    • In, from edge to center
    • Out, from center to edge
    # notes : pinch can not be set until Android 4.3.
    # from edge to center. here is "In" not "in"
    d(text="Settings").pinch_in(percent=100, steps=10)
    # from center to edge
    d(text="Settings").pinch_out()
    • 等待ui出现活消失

      # wait until the ui object appears
      d(text="Settings").wait(timeout=3.0) # return bool
      # wait until the ui object gone
      d(text="Settings").wait_gone(timeout=1.0)
    • fling指定的ui(scrollable)

      • horiz or vert(横竖)
      • forward or backward or toBeginning or toEnd (前后)
    # fling forward(default) vertically(default) 
    d(scrollable=True).fling()
    # fling forward horizontally
    d(scrollable=True).fling.horiz.forward()
    # fling backward vertically
    d(scrollable=True).fling.vert.backward()
    # fling to beginning horizontally
    d(scrollable=True).fling.horiz.toBeginning(max_swipes=1000)
    # fling to end vertically
    d(scrollable=True).fling.toEnd()
    • 滑动指定的ui对象(scrollable)

    Possible properties:

    • horiz or vert
    • forward or backward or toBeginning or toEnd, or to
    # scroll forward(default) vertically(default)
    d(scrollable=True).scroll(steps=10)
    # scroll forward horizontally
    d(scrollable=True).scroll.horiz.forward(steps=100)
    # scroll backward vertically
    d(scrollable=True).scroll.vert.backward()
    # scroll to beginning horizontally
    d(scrollable=True).scroll.horiz.toBeginning(steps=100, max_swipes=1000)
    # scroll to end vertically
    d(scrollable=True).scroll.toEnd()
    # scroll forward vertically until specific ui object appears
    d(scrollable=True).scroll.to(text="Security")

    观察者

    当选择器找不到指定对象的时候,你可以注册观察者来执行一些操作

    • 注册
    d.watcher("AUTO_FC_WHEN_ANR").when(text="ANR").when(text="Wait") 
    .click(text="Force Close")
    # d.watcher(name) ## creates a new named watcher.
    # .when(condition) ## the UiSelector condition of the watcher.
    # .click(target) ## perform click action on the target UiSelector.

    #
    d.watcher("ALERT").when(text="OK").click()
    # Same as
    d.watcher("ALERT").when(text="OK").click(text="OK")

    # 多条件
    d.watcher("AUTO_FC_WHEN_ANR").when(text="ANR").when(text="Wait")
    .press("back", "home")
    # d.watcher(name) ## creates a new named watcher.
    # .when(condition) ## the UiSelector condition of the watcher.
    # .press(<keyname>, ..., <keyname>.() ## press keys one by one in sequence.

    • 检查是否触发
    d.watcher("watcher_name").triggered
    # true in case of the specified watcher triggered, else false
    • 移除
    # remove the watcher
    d.watcher("watcher_name").remove()
    • 列出所有观察者
    d.watchers
    # a list of all registered watchers
    • 检查是否触发,任意一个
    d.watchers.triggered
    # true in case of any watcher triggered
    • 重置
    # reset all triggered watchers, after that, d.watchers.triggered will be false.
    d.watchers.reset()

    • 移除
    # remove all registered watchers
    d.watchers.remove()
    # remove the named watcher, same as d.watcher("watcher_name").remove()
    d.watchers.remove("watcher_name")
    • 强制运行所有
    # force to run all registered watchers
    d.watchers.run()

    另外文档还是有很多没有写,推荐直接去看源码init.py

    现在推荐使用这种观察者来处理弹窗等

    d.xpath.when(“服务条款%).when(“同意”).click() d.xpath.when(“立即体验”).click() d.xpath.when(“跳过”).click()
    d.xpath.run_watchers() # 运行一次弹窗检查 d.xpath.watch_background(2.0)

    全局设置

    # set delay 1.5s after each UI click and click, 点击延迟
    d.click_post_delay = 1.5 # default no delay

    # set default element wait timeout (seconds) 默认超时时间
    d.wait_timeout = 30.0 # default 20.0

    UiAutomator中的超时设置(隐藏方法)

    >> d.jsonrpc.getConfigurator() 
    {'actionAcknowledgmentTimeout': 500,
    'keyInjectionDelay': 0,
    'scrollAcknowledgmentTimeout': 200,
    'waitForIdleTimeout': 0,
    'waitForSelectorTimeout': 0}

    >> d.jsonrpc.setConfigurator({"waitForIdleTimeout": 100})
    {'actionAcknowledgmentTimeout': 500,
    'keyInjectionDelay': 0,
    'scrollAcknowledgmentTimeout': 200,
    'waitForIdleTimeout': 100,
    'waitForSelectorTimeout': 0}

    Input method

    这种方法通常用于不知道控件的情况下的输入。第一步需要切换输入法,然后发送adb广播命令,具体使用方法如下

    d.set_fastinput_ime(True) # 切换成FastInputIME输入法
    d.send_keys("你好123abcEFG") # adb广播输入
    d.clear_text() # 清除输入框所有内容(Require android-uiautomator.apk version >= 1.0.7)
    d.set_fastinput_ime(False) # 切换成正常的输入法
    d.send_action("search") # 模拟输入法的搜索

    send_action 说明

    该函数可以使用的参数有 go search send next done previous

    什么时候该使用这个函数呢?

    有些时候在EditText中输入完内容之后,调用press("search") or press("enter")发现并没有什么反应。
    这个时候就需要send_action函数了,这里用到了只有输入法才能用的IME_ACTION_CODE
    send_action先broadcast命令发送给输入法操作IME_ACTION_CODE,由输入法完成后续跟EditText的通信。(原理我不太清楚,有了解的,提issue告诉我)

    Toast

    Show Toast

    d.toast.show("Hello world")
    d.toast.show("Hello world", 1.0) # show for 1.0s, default 1.0s

    Get Toast

    # [Args]
    # 5.0: max wait timeout. Default 10.0
    # 10.0: cache time. return cache toast if already toast already show up in recent 10 seconds. Default 10.0 (Maybe change in the furture)
    # "default message": return if no toast finally get. Default None
    d.toast.get_message(5.0, 10.0, "default message")

    # common usage
    assert "Short message" in d.toast.get_message(5.0, default="")

    # clear cached toast
    d.toast.reset()
    # Now d.toast.get_message(0) is None

    XPath

    For example: 其中一个节点的内容

    <android.widget.TextView
    index="2"
    text="05:19"
    resource-id="com.netease.cloudmusic:id/qf"
    package="com.netease.cloudmusic"
    content-desc=""
    checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false"
    scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true"
    bounds="[957,1602][1020,1636]" />

    xpath定位和使用方法

    有些属性的名字有修改需要注意

    description -> content-desc
    resourceId -> resource-id

    常见用法

    # wait exists 10s
    d.xpath("//android.widget.TextView").wait(10.0)
    # find and click
    d.xpath("//*[@content-desc='分享']").click()
    # check exists
    if d.xpath("//android.widget.TextView[contains(@text, 'Se')]").exists:
    print("exists")
    # get all text-view text, attrib and center point
    for elem in d.xpath("//android.widget.TextView").all():
    print("Text:", elem.text)
    # Dictionary eg:
    # {'index': '1', 'text': '999+', 'resource-id': 'com.netease.cloudmusic:id/qb', 'package': 'com.netease.cloudmusic', 'content-desc': '', 'checkable': 'false', 'checked': 'false', 'clickable': 'false', 'enabled': 'true', 'focusable': 'false', 'focused': 'false','scrollable': 'false', 'long-clickable': 'false', 'password': 'false', 'selected': 'false', 'visible-to-user': 'true', 'bounds': '[661,1444][718,1478]'}
    print("Attrib:", elem.attrib)
    # Coordinate eg: (100, 200)
    print("Position:", elem.center())

    其他XPath常见用法

    See also: https://github.com/openatx/uiautomator2/blob/master/uiautomator2/ext/xpath/README.md

    uiautomator2 是一个超级好的项目,希望大家一起参与多提pr

  • 相关阅读:
    HDU 2433 Travel (最短路,BFS,变形)
    HDU 2544 最短路 (最短路,spfa)
    HDU 2063 过山车 (最大匹配,匈牙利算法)
    HDU 1150 Machine Schedule (最小覆盖,匈牙利算法)
    290 Word Pattern 单词模式
    289 Game of Life 生命的游戏
    287 Find the Duplicate Number 寻找重复数
    283 Move Zeroes 移动零
    282 Expression Add Operators 给表达式添加运算符
    279 Perfect Squares 完美平方数
  • 原文地址:https://www.cnblogs.com/hwllovelq/p/11648529.html
Copyright © 2011-2022 走看看