Skip to content

Commit

Permalink
rename UIAutomatorServer to Device, add session.restart() method
Browse files Browse the repository at this point in the history
  • Loading branch information
codeskyblue committed Aug 21, 2019
1 parent b2c8509 commit 68f42d5
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 25 deletions.
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -336,13 +336,18 @@ d.app_list_running()

### Wait until app running
```python
if d.app_wait("com.example.android"): # 等待应用运行, return bool
print("com.example.android is running")
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(默认)
```

> Add in version 1.2.0

### Push and pull files
* push a file to the device

Expand Down Expand Up @@ -453,6 +458,7 @@ Session represent an app lifecycle. Can be used to start app, detect app crash.
```python
sess = d.session("com.netease.cloudmusic") # start 网易云音乐
sess.close() # 停止网易云音乐
sess.restart() # 冷启动网易云音乐
```
* Use python `with` to launch and close app
Expand Down
33 changes: 32 additions & 1 deletion examples/runyaml/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# coding: utf-8
#

import re
import os
import time
import argparse
Expand All @@ -21,6 +22,7 @@

SCREENSHOT = "screenshot"
EXIST = "assert_exist"
WAIT = "wait"


def split_step(text: str):
Expand All @@ -32,6 +34,7 @@ def split_step(text: str):
"下滑": SWIPE_DOWN,
"截图": SCREENSHOT,
"存在": EXIST,
"等待": WAIT,
}

for keyword in __alias.keys():
Expand Down Expand Up @@ -79,6 +82,15 @@ def run_step(cf: bunch.Bunch, app: u2.Session, step: str):
elif oper == EXIST:
assert app.xpath(body).wait(), body

elif oper == WAIT:
#if re.match("^[\d\.]+$")
if body.isdigit():
seconds = int(body)
logger.info("Sleep %d seconds", seconds)
time.sleep(seconds)
else:
app.xpath(body).wait()

else:
raise RuntimeError("Unhandled operation", oper)

Expand All @@ -91,16 +103,35 @@ def run_conf(d, conf_filename: str):
cf = yaml.load(read_file_content(conf_filename), Loader=yaml.SafeLoader)
default = {
"output_directory": "output",
"action_before_delay": 0,
"action_after_delay": 0,
"skip_cleanup": False,
}
cf.update(default)
for k, v in default.items():
cf.setdefault(k, v)
cf = bunch.Bunch(cf)

print("Author:", cf.author)
print("Description:", cf.description)
print("Package:", cf.package)
logger.debug("action_delay: %.1f / %.1f", cf.action_before_delay, cf.action_after_delay)

app = d.session(cf.package)
for step in cf.steps:
time.sleep(cf.action_before_delay)
run_step(cf, app, step)
time.sleep(cf.action_after_delay)

if not cf.skip_cleanup:
app.close()


device = None
conf_filename = None

def test_entry():
pass



if __name__ == "__main__":
Expand Down
10 changes: 7 additions & 3 deletions examples/runyaml/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@ author: shengxiang.ssx 圣翔
description: 扫一扫测试
package: com.taobao.taobao
link: https://aone.xxx.com/xxxx
output_directory: output # optional
output_directory: output # optional [default "output"]
action_before_delay: 0.5 # optional [default 0]
action_after_delay: 1 # optional [default 0]
skip_cleanup: false # optional [default true]
steps:
- 点击扫一扫
- 点击拍立淘
- 等待 我的淘宝
- 点击 扫一扫
- 点击 拍立淘
- 截图
- 存在 扫一扫
43 changes: 25 additions & 18 deletions uiautomator2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def connect(addr=None):
addr (str): uiautomator server address or serial number. default from env-var ANDROID_DEVICE_IP
Returns:
UIAutomatorServer
Device
Raises:
ConnectError
Expand Down Expand Up @@ -145,7 +145,7 @@ def connect_usb(serial=None, healthcheck=False):
healthcheck (bool): start uiautomator if not ready
Returns:
UIAutomatorServer
Device
Raises:
ConnectError
Expand Down Expand Up @@ -177,13 +177,13 @@ def connect_usb(serial=None, healthcheck=False):
d.healthcheck()
return d

def connect_wifi(addr:str) -> "UIAutomatorServer":
def connect_wifi(addr:str) -> "Device":
"""
Args:
addr (str) uiautomator server address.
Returns:
UIAutomatorServer
Device
Raises:
ConnectError
Expand All @@ -199,7 +199,7 @@ def connect_wifi(addr:str) -> "UIAutomatorServer":
u = urlparse.urlparse(addr)
host = u.hostname
port = u.port or 7912
return UIAutomatorServer(host, port)
return Device(host, port)


class TimeoutRequestsSession(requests.Session):
Expand Down Expand Up @@ -242,7 +242,7 @@ def request(self, method, url, **kwargs):

def plugin_register(name, plugin, *args, **kwargs):
"""
Add plugin into UIAutomatorServer
Add plugin into Device
Args:
name: string
Expand All @@ -260,14 +260,14 @@ def inner():
d = u2.connect()
d.ext_upload_screenshot()
"""
UIAutomatorServer.plugins()[name] = (plugin, args, kwargs)
Device.plugins()[name] = (plugin, args, kwargs)


def plugin_clear():
UIAutomatorServer.plugins().clear()
Device.plugins().clear()


class UIAutomatorServer(object):
class Device(object):
__isfrozen = False
__plugins = {}

Expand Down Expand Up @@ -304,7 +304,7 @@ def _freeze(self):

@staticmethod
def plugins():
return UIAutomatorServer.__plugins
return Device.__plugins

def __setattr__(self, key, value):
""" Prevent creating new attributes outside __init__ """
Expand Down Expand Up @@ -791,7 +791,7 @@ def app_start(self,
pkg_name,
activity=None,
extras={},
wait=True,
wait=False,
stop=False,
unlock=False, launch_timeout=None, use_monkey=False):
""" Launch application
Expand All @@ -800,7 +800,7 @@ def app_start(self,
activity (str): app activity
stop (bool): Stop app before starting the activity. (require activity)
use_monkey (bool): use monkey command to start app when activity is not given
wait (bool): wait until app started. default True
wait (bool): wait until app started. default False
Raises:
SessionBrokenError
Expand Down Expand Up @@ -921,26 +921,30 @@ def wait_activity(self, activity, timeout=10):
time.sleep(.5)
return False

def app_wait(self, package_name: str, timeout:float = 20.0, front=False) -> bool:
def app_wait(self, package_name: str, timeout:float = 20.0, front=False) -> int:
""" Wait until app launched
Args:
package_name (str): package name
timeout (float): maxium wait time
front (bool): wait until app is current app
Returns:
bool if app is running
pid (int) 0 if launch failed
"""
pid = None
deadline = time.time() + timeout
while time.time() < deadline:
if front:
if self.current_app()['package'] == package_name:
return True
pid = self._pidof_app(package_name)
break
else:
if package_name in self.app_list_running():
return True
pid = self._pidof_app(package_name)
break
time.sleep(1)
return False

return pid or 0

def app_list_running(self) -> list:
"""
Expand Down Expand Up @@ -1267,7 +1271,7 @@ def __getattr__(self, attr):
return getattr(self._default_session, attr)
except AttributeError:
raise AttributeError(
"'Session or UIAutomatorServer' object has no attribute '%s'" %
"'Session or Device' object has no attribute '%s'" %
attr)

def __call__(self, **kwargs) -> Session:
Expand Down Expand Up @@ -1319,3 +1323,6 @@ def swipe(self, x0, y0, x1, y1):
x0, y0 = self._adjust_pos(x0, y0, w, h)
x1, y1 = self._adjust_pos(x1, y1, w, h)
self.shell("input swipe %d %d %d %d" % (x0, y0, x1, y1))


UIAutomatorServer = Device # Deprecated UIAutomatorServer
14 changes: 14 additions & 0 deletions uiautomator2/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,20 @@ def close(self):
""" close app """
if self._pkg_name:
self.server.app_stop(self._pkg_name)

def restart(self):
"""
Stop app and start
Raises:
RuntimeError
"""
self.close()
self.server.app_start(self._pkg_name)
pid = self.server.app_wait(self._pkg_name, timeout=3)
if not pid:
raise RuntimeError("app start failed")
self._pid = pid

def running(self):
"""
Expand Down
5 changes: 4 additions & 1 deletion uiautomator2/xpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,17 @@ class XPathError(Exception):


class XPath(object):
def __init__(self, d):
def __init__(self, d: "uiautomator2.Device"):
"""
Args:
d (uiautomator2 instance)
"""
self._d = d
assert hasattr(d, "click")
assert hasattr(d, "swipe")
assert hasattr(d, "window_size")
assert hasattr(d, "dump_hierarchy")
assert hasattr(d, "screenshot")

self._watchers = [] # item: {"xpath": .., "callback": func}
self._timeout = 10.0
Expand Down

0 comments on commit 68f42d5

Please sign in to comment.