atx-server android集群 搭建
1.安装go环境
go下载地址:https://golang.org/dl/(验证go version)
2.下载go ide 推荐goland(破解:http://idea.lanyus.com/)
goland下载地址:自行解决
3.安装rethinkdb
下载地址:https://rethinkdb.com/docs/install/
4.安装atx-server
cmd 下 go get -v github.com/openatx/atx-server
5.启动rethinkdb
cmd下 rethinkdb --http-port 8090 #指定端口启动rethinkdb
如图:
6.build atx-server
如图:
go build 没有报错,说明构建成功
7.启动atx-server
在当前目录下 atx-server --port 8000(我的当前目录是C:\Users\hui\go\src\github.com\openatx\atx-server)
启动成功后如图:
8.安装安装uiautomator2(确保adb devices 能够识别到设备下,执行)
命令:pip install --pre --upgrade uiautomator2
9.将uiautomator安装到手机上 并自动运行
python -m uiautomator2 init 10.247.28.146(这里好像有问题,研究中)
先到这里哈~
使用
与设备建立连接
#1. 通过WiFi连接设备
如果手机和电脑处于同一个局域网, 可以使用如下方式通过手机ip建立连接
import uiautomator2 as u2
d = u2.connect('10.234.12.104')
print d.info
其中'10.234.12.104'是手机的IP地址, 可以通过adb指令获得: adb shell ifconfig | grep Mask
运行结果如下:
{u'displayRotation': 0, u'displaySizeDpY': 829, u'displaySizeDpX': 393, u'screenOn': True, u'displayWidth': 1080, u'productName': u'lotus', u'currentPackageName': u'com.miui.home', u'sdkInt': 27, u'displayHeight': 2150, u'naturalOrientation': True}
#2.通过USB连接设备
如果手机与电脑有通过USB连接, 可以使用如下方式建立连接
import uiautomator2 as u2
d = u2.connect('62ab58430211')
print d.info
其中'62ab58430211'是手机的SN, 可以使用adb指令获得: adb devices
运行结果如下:
{u'displayRotation': 0, u'displaySizeDpY': 829, u'displaySizeDpX': 393, u'screenOn': True, u'displayWidth': 1080, u'productName': u'lotus', u'currentPackageName': u'com.miui.home', u'sdkInt': 27, u'displayHeight': 2150, u'naturalOrientation': True}
#3.通过adb WiFi连接
如果配置了手机指定端口监听TCP/IP连接, 比如
adb tcpip 5555
可以通过指定端口建立连接
import uiautomator2 as u2
d = u2.connect('10.234.12.104:5555')
print d.info
这个方法在我的机器上python2.7会报错, 可能要在3.0以上
命令行指令
注: 下面的$device_ip代表手机IP
#1. init 为设备安装所需要的程序
python -m uiautomator2 init
#2. install: 安装apk, apk通过URL给出
python -m uiautomator2.cli install $device_ip https://example.org/some.apk
#3. clear-cache: 清空缓存
python -m uiautomator2 clear-cache
#4. app-stop-all: 停止所有应用
python -m uiautomator2 app-stop-all $device_ip
#5. screenshot: 截图
python -m uiautomator2 screenshot $device_ip screenshot.jpg
#6. healthcheck: 健康检查
python -m uiautomator2 healthcheck $device_ip
常用API
全局设置
#1. Debug HTTP Requests
import uiautomator2 as u2
d = u2.connect('10.234.12.104')
d.debug=True
print d.info
运行结果:
23:17:15.628 $ curl -X POST -d '{"params": {}, "jsonrpc": "2.0", "id": "eaacec696e5911b38ea35b652f5a0d54", "method": "deviceInfo"}' 'http://10.234.12.104:7912/jsonrpc/0'
23:17:15.856 Response (228 ms) >>>
{"jsonrpc":"2.0","id":"eaacec696e5911b38ea35b652f5a0d54","result":{"currentPackageName":"com.miui.home","displayHeight":2150,"displayRotation":0,"displaySizeDpX":393,"displaySizeDpY":829,"displayWidth":1080,"productName":"lotus","screenOn":true,"sdkInt":27,"naturalOrientation":true}}
<<< END
{u'displayRotation': 0, u'displaySizeDpY': 829, u'displaySizeDpX': 393, u'screenOn': True, u'displayWidth': 1080, u'productName': u'lotus', u'currentPackageName': u'com.miui.home', u'sdkInt': 27, u'displayHeight': 2150, u'naturalOrientation': True}
#2.Implicit wait
设置元素操作等待时间, 单位: 秒
d.implicitly_wait(10.0)
d(text="小米体检").click()
print("wait timeout", d.implicitly_wait())
第一步为设置全局元素操作等待时间, 第二步点击文本"小米体检", 如果10秒内"小米体检还没有出现则会 raise UiObjectNotFoundError
这是设置会影响的操作有: click, long_click, drag_to, get_text, set_text, clear_text等
APP管理
#1. 安装APP
只支持从网络链接安装
d.app_install('http://some-domain.com/some.apk')
#2. 运行APP
d.app_start("com.example.hello_world") # start with package name
#3. 停止运行
# 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')
#4. 停止所有运行的app
# stop all
d.app_stop_all()
# stop all app except for com.examples.demo
d.app_stop_all(excludes=['com.examples.demo'])
#5. 获取APP信息
print d.app_info("com.examples.demo")
#6. 保存app图标
# save app icon
img = d.app_icon("com.examples.demo")
img.save("icon.png")
#7. Push文件到设备
# 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)
#8. 从设备pull文件
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")
#9. 检查并维持设备端守护进程处于运行状态
d.healthcheck()
基本API使用
Shell Command
adb_shell已经废弃,现在使用shell.
short-lived shell command
默认的超时为60s, 我们试试用shell命令发送pwd指令
output, exit_code = d.shell("pwd", timeout=60)
print output
print exit_code
输出:
/
0
也可以这样写
output = d.shell('pwd').output
exit_code = d.shell('pwd').exit_code
参数可以以list的形式使用,我们试试
output, exit_code = d.shell(['ls', '-l'])
print output
print exit_code
long-running shell command
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
Session
#1. 使用session来操作APP的开启和关闭
sess = d.session("com.netease.cloudmusic") # start 网易云音乐
sess.close() # 停止网易云音乐
#2. 使用with来开启和关闭
with d.session("com.netease.cloudmusic") as sess:
sess(text="Play").click()
#3. 创建已经打开的APP的session
sess = d.session('com.ganji.android.haoche_c', attach=True)
time.sleep(5)
sess.close()
#4. 侦测APP Crash
# When app is still running
sess(text="Music").click() # operation goes normal
# If app crash or quit
sess(text="Music").click() # raise SessionBrokenError
# other function calls under session will raise SessionBrokenError too
#5. 检查session是否正常
# When app is still running
sess(text="Music").click() # operation goes normal
# If app crash or quit
sess(text="Music").click() # raise SessionBrokenError
# other function calls under session will raise SessionBrokenError too
检索设备信息
#1. base information
print d.info
结果:
{u'displayRotation': 0, u'displaySizeDpY': 829, u'displaySizeDpX': 393, u'screenOn': True, u'displayWidth': 1080, u'productName': u'lotus', u'currentPackageName': u'com.miui.home', u'sdkInt': 27, u'displayHeight': 2150, u'naturalOrientation': True}
Process finished with exit code 0
#2. windows size
print(d.window_size())
# device upright output example: (1080, 1920)
# device horizontal output example: (1920, 1080)
#3. Get current app info
print d.current_app()
运行结果:
{'activity': u'com.ganji.android.haoche_c.ui.main.MainActivity', 'package': u'com.ganji.android.haoche_c'}
Process finished with exit code 0
#4. Wait activity
sess = d.session('com.ganji.android.haoche_c')
time.sleep(5)
print d.wait_activity('com.ganji.android.haoche_c.ui.main.MainActivity')
#5. Get device serial number
print d.serial
#6. Get WLAN ip
print d.wlan_ip
#7. Get detailed device info
print d.device_info
Key Events
#1. Turn on/off screen
d.screen_on() # turn on the screen
d.screen_off() # turn off the screen
#2. Get current screen status
print d.info.get('screenOn')
#3. Press hard/soft key
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)
之前支持的key有以下这些:
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可以查看:
#4. Unlock screen
d.unlock()
# This is equivalent to
# 1. launch activity: com.github.uiautomator.ACTION_IDENTIFY
# 2. press the "home" key
Gesture interaction with the device
#1. Click on the screen
d.click(x, y)
#2. Double click
d.double_click(x, y)
d.double_click(x, y, 0.1) # default duration between two click is 0.1s
#3. Long click on the screen
d.long_click(x, y)
d.long_click(x, y, 0.5) # long click 0.5s (default)
#4. Swipe
d.swipe(sx, sy, ex, ey)
d.swipe(sx, sy, ex, ey, 0.5) # swipe for 0.5s(default)
#5. Drag
d.drag(sx, sy, ex, ey)
d.drag(sx, sy, ex, ey, 0.5) # swipe for 0.5s(default)
#6. Swipe points
# swipe from point(x0, y0) to point(x1, y1) then to point(x2, y2)
# time will speed 0.2s bwtween two points
d.swipe((x0, y0), (x1, y1), (x2, y2), 0.2)
多用于九宫格解锁,提前获取到每个点的相对坐标(这里支持百分比), 更详细的使用参考这个帖子
#7. Touch and drap (beta)
这个接口属于比较底层的原始接口,感觉并不完善,不过凑合能用。注:这个地方并不支持百分比
d.touch.down(10, 10) # 模拟按下
time.sleep(.01) # down 和 move 之间的延迟,自己控制
d.touch.move(15, 15) # 模拟移动
d.touch.up() # 模拟抬起
click, swipe, drag操作支持按比例操作, 比如
d.long_click(0.5, 0.5)
意思是长按屏幕中心
Screen-Related
#1. 获取当前设备方向
print d.orientation
可能的方向有
natural or n
left or l
right or r
upsidedown or u (can not be set)
#2. 设置设备方向
d.set_orientation('l') # or "left"
d.set_orientation("l") # or "left"
d.set_orientation("r") # or "right"
d.set_orientation("n") # or "natural"
#3. 禁止旋转和解除
# freeze rotation
d.freeze_rotation()
# un-freeze rotation
d.freeze_rotation(False)
#4. 截屏
# 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)
#5. 获取UI层级关系
# get the UI hierarchy dump content (unicoded).
xml = d.dump_hierarchy()
#6. 打开通知中心
d.open_notification()
#7. 快速设置
d.open_quick_settings()
Selector
选择当前窗口中的UI控件, 例如
# Select the object with text 'Clock' and its className is 'android.widget.TextView'
d(text='Clock', className='android.widget.TextView')
支持以下这些选择参数, 详细可以参考
text, textContains, textMatches, textStartsWith
className, classNameMatches
description, descriptionContains, descriptionMatches, descriptionStartsWith
checkable, checked, clickable, longClickable
scrollable, enabled,focusable, focused, selected
packageName, packageNameMatches
resourceId, resourceIdMatches
index, instance
#1. Children (子级控件)
# get the children or grandchildren
d(className="android.widget.ListView").child(text="Bluetooth")
#2. Siblings(同级控件)
# get siblings
d(text="Google").sibling(className="android.widget.ImageView")
#3. children by text or description or instance
# 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"
)
补充:mac config atx-server2
1.
node -v :v8.9.1
npm -v5.5.1
python:3.9.6
brew install rethinkdb【终端键入rethinkdb即可启动】
git clone https://github.com/openatx/atxserver2.git
安装:pip install -r requirements.txt
执行:python main.py
访问localhost:4000 或127.0.0.1:4000 列表是空的
需要安装atserver2-android-provider
2.
git clone https://github.com/openatx/atxserver2-android-provider
安装:pip install -r requirements.txt
执行:python main.py
3.
启动步骤:
先启动rethinkdb
再启动atx-server
再启动atxserver2-android-provider
再访问:http://127.0.0.1:4000
需要登陆用户名输入admin -点击使用即可
效果图: