app 自动化工具uiautomator2 + app页面分析工具weditor的使用

一、踩坑经历

习惯性思维

这个确实菜踩了不少的坑,刚开始我是打算使用appium,和安卓的sdk的页面分析工具,uiautomatorviewer和monitor来做。

这个是受惯性思维吧,因为之前学习appium的使用,就是这样搞的,但是已经有将近俩年没有再碰了,不过windos端,我还是在把环境搞好了,但是公司办公使用是mac系统,导致我安装好安装的SDK也无法使用uiautomatorviewer和monitor,我把JDK也都卸载重装了好几遍。。。。
mac大概搞了一天,实在头大。。。
window前一天在家又搞到凌晨三点。。。吐血

转折–发现新大陆 weditor

就在我想放弃使用mac来搞这个的时候,突然在搜索monitor问题的时候,在一个论坛有个评论说建议使用weditor,顿时发现这个应该能代替我想弄的uiautomatorviewer和monitor。

然后开始搜索weditor

搜到项目地址
https://github.com/alibaba/web-editor
发现在阿里巴巴项目下,
然后搜到一篇文章,开启了学习weditor,放弃安卓SDK的uiautomatorviewer和monitor来定位分析页面。
https://www.cnblogs.com/RuguoCheng/p/10457637.html

二、学习weditor

1、安装和打开:

安装:
pip3 install -U weditor
使用:
python -m weditor
浏览器访问:
http://localhost:17310/

发现是真的好用呀,不用考虑系统。是mac还是window,直接浏览器打开分析。

简直爱的不行

2、简单使用

1)、链接手机调试

mac终端或者win cmd执行:

python -m weditor

一般默认会自动打开系统默认的浏览器,如果不打开,自己打开:
访问:

http://localhost:17310/

然后把手机打开usb调试:
点击连接connect并点击 Dump Hierarchy,就会显示手机页面。
如下图:
是不是很棒

在这里插入图片描述

2)、分析页面元素

点击一个你想点击的元素:
就会出现,如下图:
className 就和html页面的class属性一样。
resourceId 就和html页面的id属性一样。

d(resourceId=“com.xingin.xhs:id/bn_”) 就是选择器的用法。

由于之前学习了lua脚本,定位安卓的用法,所以这个看下我就懂了。

在这里插入图片描述

3)、引发思考–找到可以代替appium的模块uiautomator2

找到的灵感来自于俩个思路:
1、上一步页面显示的d(resourceId="com.xingin.xhs:id/bn_")中的d是什么东东?
当然,如果是我最初的方法,目前已经解决了,当时突然想知道d是什么
2、
进入weditor的项目页面:
https://github.com/alibaba/web-editor
看的有俩个依赖:uiautomator2和facebook-wda

在这里插入图片描述

然后进入uiautomator2页面看看
https://github.com/openatx/uiautomator2

看到了下面这段:
我的理解就是和appium差不多。

UiAutomator是Google提供的用来做安卓自动化测试的一个Java库,基于Accessibility服务。功能很强,可以对第三方App进行测试,获取屏幕上任意一个APP的任意一个控件属性,并对其进行任意操作,但有两个缺点:1. 测试脚本只能使用Java语言 2. 测试脚本要打包成jar或者apk包上传到设备上才能运行。

我们希望测试逻辑能够用Python编写,能够在电脑上运行的时候就控制手机。这里要非常感谢 Xiaocong He
(@xiaocong),他将这个想法实现了出来(见xiaocong/uiautomator),原理是在手机上运行了一个http
rpc服务,将uiautomator中的功能开放出来,然后再将这些http接口封装成Python库。
因为xiaocong/uiautomator这个库,已经很久不见更新。所以我们直接fork了一个版本,为了方便做区分我们就在后面加了个2
openatx/uiautomator2

往下在看看:
发现:
看到了d,原来页面的d就是使用这个项目。
在这里插入图片描述

开始学习下uiautomator2

三、学习uiautomator2的简单使用:

1、安装:

直接pip安装即可

pip install --upgrade --pre uiautomator2

2、连接手机:

有三种方式,一种是常用的usb,一种是wifiadb【可以借助软件】,还有一种直接局域网的ip地址。

Wi-Fiadb软件,下面是我自己收藏的软件,可以下载使用
app抓包小黄鸟、xposed、wifiadb、等工具软件
https://wwa.lanzoui.com/b00ullejg
密码:ackl

import json
import uiautomator2 as u2

# 使用文档:https://github.com/zhaojiafu/uiautomator2#installation
# 可以通过ip、wifiadb、USB devices链接
d = u2.connect('192.168.61.187:5555') # alias for u2.connect_wifi('10.0.0.1')
print(json.dumps(d.info,ensure_ascii=False))

# 设备信息
device_info = d.device_info
print("device_info",json.dumps(device_info,ensure_ascii=False))

d2 = u2.connect('192.168.61.148:5555') # 首次执行会往手机安装ATX软件
print(json.dumps(d2.info,ensure_ascii=False))

3、启动一个app–app_start函数

需要传入包名

可以通过weditor获取。
比如:随便进入一个软件,点击一个位置就可以拿到包名。
在这里插入图片描述

import json
import uiautomator2 as u2

# 使用文档:https://github.com/zhaojiafu/uiautomator2#installation
# 可以通过ip、wifiadb、USB devices链接
d = u2.connect('192.168.61.187:5555') # alias for u2.connect_wifi('10.0.0.1')
print(json.dumps(d.info,ensure_ascii=False))

result = d.app_start("com.xingin.xhs")
print("result",result)

4、停用一个app

app_stop 停用一个app,需要传入包名
app_clear 清理并退出一个app。【需要登录的app不要用,会把app登录状态退出】
app_stop_all 退出所有app。
d.app_stop_all(excludes=[‘com.examples.demo’]) 停用所有app除了包名com.examples.demo的。

import json
import uiautomator2 as u2
import time

# 使用文档:https://github.com/zhaojiafu/uiautomator2#installation
# 可以通过ip、wifiadb、USB devices链接
d = u2.connect('192.168.61.187:5555') # alias for u2.connect_wifi('10.0.0.1')
print(json.dumps(d.info,ensure_ascii=False))

result = d.app_start("com.xingin.xhs")

d.app_stop("com.xingin.xhs")
# 需要登录的app不要使用clear,会把数据都清空
d.app_clear('com.xingin.xhs')
time.sleep(10)
# stop all
d.app_stop_all()
# stop all app except for com.examples.demo
# d.app_stop_all(excludes=['com.examples.demo'])

5、获取一个app信息

app_info

import json
import uiautomator2 as u2
import time

# 使用文档:https://github.com/zhaojiafu/uiautomator2#installation
# 可以通过ip、wifiadb、USB devices链接
d = u2.connect('019b86d626a0bb08') # alias for u2.connect_wifi('10.0.0.1')
# print(json.dumps(d.info,ensure_ascii=False))

app_info = d.app_info("com.xingin.xhs")
print(json.dumps(app_info,ensure_ascii=False))

# save app icon
img = d.app_icon("com.xingin.xhs")
img.save("icon.png")

输出小红书app信息:

{
    "packageName": "com.xingin.xhs",
    "mainActivity": "com.xingin.xhs.activity.SplashActivity",
    "label": "小紅書",
    "versionName": "6.25.0",
    "versionCode": 6250099,
    "size": 63197480
}

6、等待app运行:

import json
import uiautomator2 as u2
import time

# 使用文档:https://github.com/zhaojiafu/uiautomator2#installation
# 可以通过ip、wifiadb、USB devices链接
d = u2.connect('192.168.61.187:5555') # alias for u2.connect_wifi('10.0.0.1')
print(json.dumps(d.info,ensure_ascii=False))


pid = d.app_wait("com.xingin.xhs") # 等待应用运行, return pid(int)
if not pid:
    print("com.xingin.xhs is not running")
else:
    print("com.xingin.xhs pid is %d" % pid)

pid2 = d.app_wait("com.xingin.xhs", front=True) # 等待应用前台运行
print("pid2",pid2)
pid3 = d.app_wait("com.xingin.xhs", timeout=20.0) # 最长等待时间20s(默认)
print("pid3",pid3)


7、 文件传输

和adb pull和push差不多的功能。

import json
import uiautomator2 as u2

# 使用文档:https://github.com/zhaojiafu/uiautomator2#installation
# 可以通过ip、wifiadb、USB devices链接
d = u2.connect('192.168.61.187:5555') # alias for u2.connect_wifi('10.0.0.1')
print(json.dumps(d.info,ensure_ascii=False))

# 外部往手机端推送
# 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)

# 从手机内部pull出来
d.pull("/sdcard/foo.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")

8、检测设备状态【测试感觉没有什么用,好像后期去掉了】

DeprecationWarning: Call to deprecated method healthcheck. (method: healthcheck is useless now) – Deprecated since version 3.0.0.

测试感觉没有什么用

import json
import uiautomator2 as u2

# 使用文档:https://github.com/zhaojiafu/uiautomator2#installation
# 可以通过ip、wifiadb、USB devices链接
# d = u2.connect('192.168.61.187:5555') # alias for u2.connect_wifi('10.0.0.1')
d = u2.connect('87d1294c') # alias for u2.connect_wifi('10.0.0.1')
print(json.dumps(d.info,ensure_ascii=False))
# healthcheck = d.healthcheck()
healthcheck = d.healthcheck()
print("healthcheck",healthcheck)


9、执行shell命令:

import json
import uiautomator2 as u2


# 使用文档:https://github.com/zhaojiafu/uiautomator2#installation
# 可以通过ip、wifiadb、USB devices链接
d = u2.connect('192.168.61.187:5555') # alias for u2.connect_wifi('10.0.0.1')
print(json.dumps(d.info,ensure_ascii=False))


# 1、简单使用
output, exit_code = d.shell("pwd", timeout=60) # timeout 60s (Default)
print("output, exit_code", output, exit_code)
# 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
print("output",output)
print("exit_code",exit_code)
# 第一个参数可以是列表
output, exit_code = d.shell(["ls", "-l"])
print("output, exit_code", output, exit_code)
# 2、运行长时间运行的 shell 命令

r = d.shell("logcat", stream=True)
# r: requests.models.Response
import time
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

10、各种设备信息

import json
import uiautomator2 as u2

# 使用文档:https://github.com/zhaojiafu/uiautomator2#installation
# 可以通过ip、wifiadb、USB devices链接
d = u2.connect('192.168.61.187:5555') # alias for u2.connect_wifi('10.0.0.1')

# 1、d.info
print(json.dumps(d.info,ensure_ascii=False))

# 2、device_info
print(json.dumps(d.device_info,ensure_ascii=False))

# 3、Get window size
print(json.dumps(d.window_size(),ensure_ascii=False))

# 4、print(d.app_current())
# 获取当前的应用信息。 对于某些 android 设备,输出可能为空(参见输出示例 3)
print(d.app_current())
# {'package': 'com.miui.home', 'activity': 'com.miui.home.launcher.Launcher'}

# 5、获取设备序列号
print(d.serial)

# 6、Get WLAN ip
print(d.wlan_ip)


11、滑动、点击等动作

import json
import uiautomator2 as u2
import time
import random

# 使用文档:https://github.com/zhaojiafu/uiautomator2#installation
# 可以通过ip、wifiadb、USB devices链接
d = u2.connect('192.168.61.187:5555') # alias for u2.connect_wifi('10.0.0.1')

# 1、粘贴板
d.set_clipboard('text', 'label')
print(d.clipboard)

# 2、开关屏幕
# d.screen_on() # turn on the screen
# d.screen_off() # turn off the screen

## 3、获取当前屏幕状态
screenOn = d.info.get('screenOn') # require Android >= 4.4
print("screenOn",screenOn)

## 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)
# d.press("enter") # 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


## 5、解锁屏幕、结合weditor来搞
# d.unlock()
# import time
# time.sleep(5)
# d(text="1").click()
# d(text="1").click()
# d(text="1").click()
# d(text="1").click()

## 5、点击:

# 按百分比x,y点击
# d.click(x, y)
# d.click(0.362, 0.41)

# 双击
# d.double_click(0.491, 0.125)
# d.double_click(0.491, 0.125, 0.1) # default duration between two click is 0.1s

# 长按着
# d.long_click(x, y)
# d.long_click(x, y, 0.5)

# 滑动
# d.swipe(sx, sy, ex, ey)
# d.swipe(sx, sy, ex, ey, 0.5) # swipe for 0.5s(default)

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

# # 实践发现上滑或下滑的时候,从中点开始滑动成功率会高一些
# d.swipe_ext("up", scale=0.8) # 代码会vkk
#
# # # 上翻、下翻、左翻、右翻
# # # 还可以使用Direction作为参数
# from uiautomator2 import Direction
#
# # d.swipe_ext(Direction.FORWARD) # 页面下翻, 等价于 d.swipe_ext("up"), 只是更好理解
# # d.swipe_ext(Direction.BACKWARD) # 页面上翻
# # d.swipe_ext(Direction.HORIZ_FORWARD) # 页面水平右翻
# d.swipe_ext(Direction.HORIZ_BACKWARD) # 页面水平左翻

# 俩点移动
# d.drag(sx, sy, ex, ey)
# d.drag(0.149, 0.553, 0.841, 0.56, 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
# points = [(0.1, 0.1), (0.3, 0.3), (0.7, 0.8)]
# 可以封装一个随机的上下翻页的函数,后续使用
# import random
# points = [(random.random(), 0.1), (random.random(), 0.3), (random.random(), 0.8)]
# points.reverse()
# d.swipe_points(points, 0.2)

# 按住并拖动
# 这个接口属于比较底层的原始接口,感觉并不完善,不过凑合能用。注:这个地方并不支持百分比
# 默认 [将日历软件挪动位置]
# d.touch.down(154, 1075) # 模拟按下
# time.sleep(random.random()) # down 和 move 之间的延迟,自己控制
# d.touch.move(667, 1077) # 模拟移动
# d.touch.up(667, 1077) # 模拟抬起

# 百分比支持
# 默认 [将日历软件挪动位置]
# window_x,window_y = d.window_size()
# print("window_x,window_y",window_x,window_y)
# def xy_int(x_lv,y_lv):
#     return int(window_x*x_lv),int(window_y*y_lv)
#
# d.touch.down(xy_int(0.149, 0.56)[0],xy_int(0.149, 0.56)[1]) # 模拟按下
# time.sleep(1 + random.random()) # down 和 move 之间的延迟,自己控制
# d.touch.move(xy_int(0.829, 0.568)[0],xy_int(0.829, 0.568)[1]) # 模拟移动
# d.touch.up(xy_int(0.829, 0.568)[0],xy_int(0.829, 0.568)[1]) # 模拟抬起


# 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.
# 把截图并保存到一个文件在电脑上,需要Android > = 4.2。
# d.screenshot("home.jpg")

# 手机截图到python image
# 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)


# 打开通知或快速设置
# d.open_notification()
# d.open_quick_settings()



12、选择器:

这里可以结合weditor。

import json
import uiautomator2 as u2
import time,random

# 使用文档:https://github.com/zhaojiafu/uiautomator2#installation
# 可以通过ip、wifiadb、USB devices链接
d = u2.connect('192.168.61.187:5555') # alias for u2.connect_wifi('10.0.0.1')
print(json.dumps(d.info,ensure_ascii=False))

# 1、启动app
result = d.app_start("com.xingin.xhs")
print("result",result)
time.sleep(random.uniform(3,10))
# Selector supports below parameters. Refer to UiSelector Java doc for detailed information.
# http://developer.android.com/tools/help/uiautomator/UiSelector.html
# 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

# 2、点击搜索
# Select the object with text 'Clock' and its className is 'android.widget.TextView'
d(resourceId="com.xingin.xhs:id/b4r").click()
time.sleep(random.uniform(1,5))

# 3、输入内容
d(resourceId="com.xingin.xhs:id/b67").clear_text()
uid = "chenger261"
d(resourceId="com.xingin.xhs:id/b67").send_keys(uid)
time.sleep(random.uniform(1,5))
d.press("enter")

# 4、选择用户
d(text="用户").click()
time.sleep(random.uniform(1,5))


# 5、选择对的用户
user = d(resourceId="com.xingin.xhs:id/b6w", textContains=uid)
if user:
    print("user",user.info)
    user.click()
    time.sleep(random.uniform(1, 5))
    # 循环滑动


else:
    print("没有获取到用户")


time.sleep(random.uniform(10))
# 跑完记得关闭app
d.app_stop_all()

13、录屏:

这个效果不是特别好,我用到的可能性不大,如果需要可以用下。

放在自动化控制app脚本前后录屏。

# pip3 install -U "uiautomator2[image]" -i https://pypi.doubanio.com/simple
import json
import uiautomator2 as u2
import time,random

# 使用文档:https://github.com/zhaojiafu/uiautomator2#installation
# 可以通过ip、wifiadb、USB devices链接
d = u2.connect('192.168.61.187:5555') # alias for u2.connect_wifi('10.0.0.1')
print(json.dumps(d.info,ensure_ascii=False))

d.screenrecord('output.mp4')
print("开始录屏")
time.sleep(10)
# or do something else

print("结束")
d.screenrecord.stop() # 停止录制后,output.mp4文件才能打开

14、获取页面的【类似于web的html】

d.dump_hierarchy()函数。

# 获取页面的html【安卓的】
# get the UI hierarchy dump content (unicoded).
# xml = d.dump_hierarchy()
# with open('ret.html','w',encoding='utf-8') as file:
#     file.write(xml)

15、判断是否有下一页:

对翻页前后的页面xml来对比是否一样,判断是否结束。

import uiautomator2 as u2
import time,random

d = u2.connect("192.168.61.187:5555")

while True:
    # 获取每次滑动前页面下半部分的所有元素
    page_content = d.dump_hierarchy()[(len(d.dump_hierarchy()) // 2):]
    d.swipe_ext("up")
    time.sleep(random.uniform(0.5,3))
    # 获取每次滑动后页面下半部分的所有元素,并与上一次滑动前的页面元素对比,页面元素没有变化时跳出循环
    new_page_content = d.dump_hierarchy()[(len(d.dump_hierarchy()) // 2):]
    if new_page_content == page_content:
        break

print("swipe end")

总结:

https://github.com/openatx/facebook-wda
这个好像是ios手机的模块,我没有苹果手机,暂时没有仔细看。感兴趣的自己研究试试吧。

经过学习下uiautomator2和weditor,发现uiautomator2可以代替appium,俩者可以达到一样的效果。

weditor的页面分析做的确实很棒,比安卓的SDK里面的uiautomatorviewer和monitor俩个功能来查看页面强很多,而且环境不用考虑mac和window各弄很久。

注意我mac弄了一天也没有弄好,用了这个就决定放弃安卓的SDK了。

参考:

https://www.cnblogs.com/RuguoCheng/p/10457637.html
https://github.com/alibaba/web-editor
https://github.com/openatx/uiautomator2
https://github.com/openatx/facebook-wda

  • 2
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhaojiafu666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值