参考:https://www.cnblogs.com/findyou/p/3420936.html 基本方法
https://blog.csdn.net/qq_21406125/article/details/82732214(emmm,划重点,货多)
https://dup2.org/node/1538 开启真机的View Server服务
https://www.cnblogs.com/lynn-li/p/5947153.html 结果的比较,截图比较,或根据控件的有无及属性判断
#引入程序所用的模块
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice, MonkeyImage
获取设备要用到MonkeyRunner, MonkeyDevice
截图要用MonkeyImage
MonkeyRecord录制脚本(其实就是录(动作:坐标)),导入相应的模块,获取设备后,可以用MonkeyRecord.start(device)启动
MonkeyRecord。
device=MonkeyRunner.waitForConnection()
MonkeyRecord.start(device)
在MonkeyRecord上点击会同步到设备上,右侧会有坐标显示。
但只是为了获取坐标的话没必要用这个,开发者模式显示指针或者启动uiautomatorviewer会方便点。
导出录制完的脚本文件record.py,test_record.py record.py都放在monkeyrunner同级目录下
运行命令./monkeyrunner test_record.py record.py,这个test_record.py以也是参考资料里的,考虑到实际测试,设备可能会弹出一些消息提醒,第三方应用process_file方法可以增加条件判断来调用匿名函数,
test_record.py:
#coding=utf-8
import sys
from com.android.monkeyrunner import MonkeyRunner
#定义字典变量CMD_MAP,对应录制的脚本文件,(动作|坐标参数)
CMD_MAP = {
"TOUCH": lambda dev, arg: dev.touch(**arg),
"DRAG": lambda dev, arg: dev.drag(**arg),
"PRESS": lambda dev, arg: dev.press(**arg),
"TYPE": lambda dev, arg: dev.type(**arg),
"WAIT": lambda dev, arg: MonkeyRunner.sleep(**arg)
}
#分解从脚本文件 读取的字符串,并调用CMP_MAP中的对应的匿名函数lambda
def process_file(fp, device):
for line in fp:
#key对应动作类型,xy对应坐标元组或者其他参数
key, xy = line.split("|")
try:
xy = eval(xy)
except:
print ("参数坐标获取失败")
continue
if key not in CMD_MAP:
print ("未知的指令: " + key)
continue
#调用CMP_MAP中的对应的匿名函数lambda
CMD_MAP[key](device, xy)
def main():
file = sys.argv[1]
fp = open(file, "r")
device = MonkeyRunner.waitForConnection()
process_file(fp, device)
fp.close();
if __name__ == "__main__":
main()
一些基本方法
#连接到设备或模拟器
#参数1:超时时间,单位秒,浮点数。默认是无限期地等待。
#参数2:串deviceid,指定的设备名称。默认为当前设备(手机优先,比如手机通过USB线连接到PC、其次为模拟器)。
#默认连接:
device = MonkeyRunner.waitForConnection()
#参数连接:
device = MonkeyRunner.waitForConnection(1.0,'DSN号就够了')
#向设备或模拟器安装APK
#以下两种方式都是对的
device.installPackage('E:/JAVA/monkeyrunner/Test1/ThinkDrive_new.apk') Linux
device.installPackage('E:\\JAVA\\monkeyrunner\\Test1\\ThinkDrive_new.apk') windows
#参数可以为绝对路径,也可为相对路径
#卸载设备或模拟器中的APK
#参数为APK包名
device.removePackage('包名')
#启动任意的Activity
#device.startActivity(component="包名/启动Activity")
#以下两种都OK
device.startActivity(component="cn.richinfo.thinkdrive/cn.richinfo.thinkdrive.ui.activities.NavigateActivity")
device.startActivity(component="cn.richinfo.thinkdrive/.ui.activities.NavigateActivity")
#手机截图
#获取设备的屏蔽缓冲区,产生了整个显示器的屏蔽捕获。(截图)
result=device.takeSnapshot()
#返回一个MonkeyImage对象(点阵图包装),我们可以用以下命令将图保存到电脑上
result.writeToFile('电脑绝对路径')
#暂停 ,休眠
#暂停目前正在运行的程序指定的秒数
#MonkeyRunner.sleep(秒数,浮点数)
MonkeyRunner.sleep(5)
#字符串发送到键盘
#device.type('字符串')
device.type('54dr3asrgf')
#唤醒设备屏幕
#锁屏后,屏幕关闭,可以用下命令唤醒
device.wake()
#重起手机
device.reboot()
#模拟滑动
#device.drag((x1,y1),(x2,y2),t,s)
#(x1,y1)开始坐标
#(x2,y2)结束坐标
#t 拖动持续时间(以秒为单位),默认1.0秒
#s 插值点时要采取的步骤。默认值是10
device.drag((100,1053),(520,1053),0.1,10)
#在指定位置发送触摸事件
#device.touch(x,y,触摸事件类型)
#x,y的单位为像素
#触摸事件类型,
device.touch(520,520,'DOWN_AND_UP')
#发送指定类型指定键码的事件
#device.press(参数1:键码,参数2:触摸事件类型)
#参数1:见android.view.KeyEvent
#参数2,如有TouchPressType()返回的类型-触摸事件类型,有三种。
#1、DOWN 发送一个DOWN事件。指定DOWN事件类型发送到设备,对应的按一个键或触摸屏幕上。
#2、UP 发送一个UP事件。指定UP事件类型发送到设备,对应释放一个键或从屏幕上抬起。
#3、DOWN_AND_UP 发送一个DOWN事件,然后一个UP事件。对应于输入键或点击屏幕。
以上三种事件做为press()参数或touch()参数
#按下HOME键
device.press('KEYCODE_HOME',MonkeyDevice.DOWN_AND_UP)
#按下BACK键
device.press('KEYCODE_BACK',MonkeyDevice.DOWN_AND_UP)
#按下下导航键
device.press('KEYCODE_DPAD_DOWN',MonkeyDevice.DOWN_AND_UP)
#按下上导航键
device.press('KEYCODE_DPAD_UP',MonkeyDevice.DOWN_AND_UP)
#按下OK键
device.press('KEYCODE_DPAD_CENTER',MonkeyDevice.DOWN_AND_UP)
KeyCode:
home键 KEYCODE_HOME
back键 KEYCODE_BACK
send键 KEYCODE_CALL
end键 KEYCODE_ENDCALL
上导航键 KEYCODE_DPAD_UP
下导航键 KEYCODE_DPAD_DOWN
左导航 KEYCODE_DPAD_LEFT
右导航键 KEYCODE_DPAD_RIGHT
ok键 KEYCODE_DPAD_CENTER
上音量键 KEYCODE_VOLUME_UP
下音量键 KEYCODE_VOLUME_DOWN
power键 KEYCODE_POWER
camera键 KEYCODE_CAMERA
menu键 KEYCODE_MENU
根据控件ID获取控件
因为先学的Appium,uiautomator,By.id()方法很眼熟,使用要导入以下模块,还要手机设备提前开启View Server服务(但绝大多数商业手机是无法开启View Server的,模拟器和工程机不用这样)
#根据ID找到ViewNode,对viewnode的一些操作等
from com.android.chimpchat.hierarchyviewer import HierarchyViewer
#提供了根据ID进行访问方法touch、drag等
from com.android.monkeyrunner.easy import EasyMonkeyDevice
#根据ID返回PyObject的方法
from com.android.monkeyrunner.easy import By
#代表一个控件,可获取控件属性
from com.android.hierarchyviewerlib.models import ViewNode
device=MonkeyRunner.waitForConnection()
easy_device=EasyMonkeyDevice(device)
#试验前提:先打开酷狗音乐,点击“听”。模拟点击酷狗音乐“听”页面的“搜索”按钮,
easy_device.touch(By.id('id/
id/fve'),device.DOWN_AND_UP)
因为工作使用的工程机,试验比较简单,不用专门打开View server。
在控制台的实验结果:确实可以辨识并模拟操作控件。只是反应速度太慢,虽然资料显示MonkeyRunner这种分析控件ID是会慢一些,不知道是否是工程机的缘故,足足反应了10秒,我差点以为失败了,只是实现点击一下按钮而已(⊙v⊙)。
运行脚本文件
想要运行.py脚本,linux 控制台进入sdk/tools/bin目录下,py文件最好放在目录下,使用./monkeyrunner 文件名.py,可以运行。
简单试验./monkeyrunner MonkeyRunnerTest1.py
#coding=utf-8
from com.android.monkeyrunner import MonkeyRunner,MonkeyDevice
#连接设备,‘5’是等待时间,不设置的话永久等待?第二个参数是机台号,电脑连着复数设备的话,需要指定
device=MonkeyRunner.waitForConnection(5,'G0B0ME036482001L')
#打开酷狗App, 也可以component="包名/.Activity名"
device.startActivity("com.kugou.android/.app.splash.SplashActivity")
就不上图了,运行还是成功的,酷狗App打开。
运行结果截图的对比
image=device.takeSnapshot()
correct=MonkeyRunner.loadImageFromFile('要加载的正确图片文件路径')
image.sameAs(correct,0.9)返回ture 或 False
用控件的有无及属性值做判断依据
1.比如使用EasyMonkeyDevice模块的判断方法exist(),获取属性Text方法getText()
点击酷狗APP“听”页面“搜索”后是否跳转页面,根据有无这个页面唯一的Edittext控件的Id及内容判断(其实刚点进去是没有内容),我用控制台逐行运行语句,所以App上输入'123'后, 运行 text= easy_device.getText(''id/abj"),print打印查看,的确获取到了'123'。
if easy_device.exists(By.id(''id/abj"))==True:
text= easy_device.getText(''id/abj")
if text.encode('utf-8')=='123'
print('成功')
else
print('成功')
else
print('失败')
2.使用HierarchyViewer的findViewById获取控件,获取属性Text方法getText('控件')
导入HierarchyViewer模块,device=MonkeyRunner.waitForConnection()获取设备后,获取HierarchyViewer对象
hierarchyviewer=device.getHierarchyView()
#获取控件对象时就把相应属性一并打包获取了
search=hierarchyviewer.findViewById(''id/abj")
text=hierarchyviewer.getText(search)
3.判断当前Activity
获取的完整 包名/.Activity名,两个模块都有对应的方法
(1) easy_device.getFocusedWindowId()
(2 )hierarchyviewer.getFocusedWindowName()