打造一款快速高效且高度可复用的 android 自动化测试工具 (qq 1 群 :608824162(已满) qq 2 群:745653339)
主页入口 请点我
https://github.com/zhangzhao4444/Maxim
执行
adb shell CLASSPATH=/sdcard/monkey.jar:/sdcard/framework.jar exec app_process /system/bin tv.panda.test.monkey.Monkey -p com.panda.videoliveplatform --uiautomatormix --running-minutes 60
脱机运行(#53 楼)
策略模式
--uiautomatormix 混合模式(70% 控件解析随机点击,其余 30% 按原 Monkey 事件概率分布)
--pct-uiautomatormix n 可自定义混合模式中控件解析事件概率
--uiautomatordfs DFS 深度遍历算法(优化版)(注 Android5 不支持 dfs)
--uiautomatortroy Troy 模式 见(#74 楼)
非以上两种为原始 Monkey 策略
执行时长
--running-minutes 60 执行 60 分钟 monkey
场景细粒度控制
--act-whitelist-file /sdcard/awl.strings 自定义 Activity 白名单
例:
com.panda.videoliveplatform.activity.WelcomeActivity
com.panda.videoliveplatform.activity.SplashWakeActivity
com.panda.videoliveplatform.activity.MainFragmentActivity
com.panda.videoliveplatform.activity.LiveRoomActivity
锁定跳转只可进入其中的某个 Activity
--act-blacklist-file 同上
其他参数及用法同原始 Monkey
a. 速度快 每秒 10-15 个 Action 事件
界面控件解析算法通过改造底层 framework,直接使用 AccessibilityNodeInfo 并优化减化其调度流程,解析速度控制在 50ms 内,可对界面变化做快速反应。
{
val clickable = ArrayList<AccessibilityNodeInfo>()
collectClickable(clickable, root) //递归算法生成node树结构
......
val node = clickable[random.nextInt(count)]
val nodeRect = Rect()
node.getBoundsInScreen(nodeRect) //选取其中某个node的 rect ,随机点击其中某point
generateClickEventAt(nodeRect, 0L)
}
b. Android 全平台兼容
兼容 Android5,6,7,8,p 各系列。通过反射原理动态解析各平台 Api 差异,使用一套逻辑兼容全系列。
{
Class<?> clazz = mAm.getClass();
String name = "setActivityController"; //存在差异的api
Method method = findMethod(clazz, name, android.app.IActivityController.class); //反射动态search api
if (method != null) {
......
}
method = findMethod(clazz, name, android.app.IActivityController.class, boolean.class);
if (method != null) {
......
}
c. 防跳出
控件解析时获取进程推栈 Top Activity,按非白即黑立即执行切回。各事件执行时按特有逻辑屏蔽掉状态栏,防止误操作。
{
......
cn = this.mDevice.mAm.getTasks(1, 0).get(0).topActivity //取top activity
if (cn != null) currentPackage = cn.getPackageName()
if (!MonkeyUtils.packageFilter.isPackageValid(currentPackage!!)) { //判断非白即黑
this.mQ.clear()
this.generateActivity()
......
}
d. 防休眠
休眠时自动检测并唤醒屏幕。
{
......
if (!this.mPM!!.isInteractive) { //判断处于休眠中
......
val i = Runtime.getRuntime().exec(arrayOf("input", "keyevent", "26")).waitFor() //唤醒设备
......
}
e. 熔断机制
当事件按某个特有模式固定执行一段时间时则自动触发熔断开始自拉活,防止假死。如重复点击同一位置 n 秒。
private fun isBlocked(): Boolean{
val jam = true
......
val last = actionsHistory.last()
for (i in 2..30){ //重复点击n次 触发熔断
if (mVerbose > 1) Logger.log("last action is ${actionsHistory.size-1} code = $last, action${actionsHistory.size-i} code = ${actionsHistory[actionsHistory.size-i]}")
if (last != actionsHistory[actionsHistory.size-i]){
return false
}
}
//其他熔断
.....
}
f. 场景细粒度
引入 Activity 黑白名单,可控制限定在某些场景内。如只测试某几个相关页面。
private inner class ActivityController : IActivityController.Stub() {
override fun activityStarting(intent: Intent, pkg: String): Boolean {
var allowActivity = true
if (MonkeyUtils.activityFilter.hasValidActivitys()){
val currentActivity: String? = try {intent.component.className} catch (e:Exception){null}
if (currentActivity != null){
allowActivity = MonkeyUtils.activityFilter.checkEnteringActivity(currentActivity) //通过filter的才允许跳转
}
Logger.log("// Activity : ${currentActivity} in Intent")
}
......
}
......
}
g. 随机自动输入
检测当遇到可输入模式时,按设定(ape.string)或随机输入键盘事件。如输入 666 或 2333 弹幕
随机输入 需要提前安装 adbkeyboard
https://github.com/senzhk/ADBKeyBoard
{
......
val inputMethodVisbleHight = this.mDevice.mIMM!!.getInputMethodWindowVisibleHeight() //存在键盘输入栏
if (inputMethodVisbleHight <= 0) return
//注入键盘事件
try { generateRandomKeyEvents() }catch (e : Exception){ }
......
}
h. 崩溃堆栈自动保存
当崩溃(crash、oom)发生时自动抓取,并存于/sdcard/crash-dump.log
{
override fun appCrashed(processName: String, pid: Int, shortMsg: String, longMsg: String, timeMillis: Long, stackTrace: String): Boolean {
......
writeDumpLog("// CRASH: $processName (pid $pid) (dump time: $dateStr)")
writeDumpLog("// Build Time: ${Build.TIME}")
writeDumpLog("// ${stackTrace.replace("\n", "\n// ")}")
....
}
扫盲贴: https://testerhome.com/topics/11884
小米手机未开启 “开发者选项” -> "USB 调试(安全设置)允许通过 usb 调试修改权限或模拟点击"。
开启后 ok 。报错 log 如下图
accessibilityservice 被其他驱动占用 agent 未注销。如使用过 atx 未执行 unregister。
执行 unregister 后 OK。报错 log 如下图,或无 log
或
厂商修改造成 dex 无法 load ,maxim 启动后就退出。实际什么都未执行。无 log 输出。 logcat 如下图。此问题暂时待查
4.运行 maxim 无任何 log,启动后就退出。需检查/sdcard/是否存在 monkey.jar ,framework.jar。部分机型发现 adb push 过去 monkey.jar 自动被更名成 monkey. 导致无法运行。
5.vivo7.1 运行 maxim 报错,需要关闭锁屏和开启 usb 模拟点击 ,然后就可以跑 monkey 了。报错如下:
#40 楼
支持特殊事件序列 max.xpath.actions
如何查看特殊事件 log #79 楼
#44 楼 #52 楼
支持屏蔽黑控件或黑区域 max.widget.black
#57 楼
支持截图,dump xml
崩溃回溯式截图 #92 楼
#74 楼
Troy 模式
#169 楼
Monkeyapi
先赞一个👍
给力,用起来
先赞一个
学习一下,之前想改一直没真正找到点,没敢下手。
期待一下特殊事件序列
高速点击不应该是核心测试需求的诉求吧,实际的压测需要有页面缓冲、动效显示、图片加载的处理间隔,还应有等待回收逻辑处理完成,所以还是模拟用户行为间隔更重要。否则会引起研发不认可的 bug 及内存泄露压力不够的问题。
高速是指解析界面算法。如果觉得 event 太快可以自行添加 Throttle。 速度不够何谈压力
哦,原来指的是算法能力上能支持高速点击。实际压测还是要分压测场景和压测目的具体平衡事件比例,过快的操作更多考验的是未完成事件的中断,往往会发生用户正常操作不会遇到的 bug。
而针对内存占用的压力还是需要图片加载,视频缓冲,合理节奏下的 GC 释放场景的正常测试。对 app 压测评估、对 app 压测 bug 补漏、通过 app 压测系统和底层服务等不同目的的方案设计还是有区别的。建议针对不同场景的使用可以做下建议性参数配置实例。
你好楼主使用你的工具 替换包名后 运行 提示
.. ..:.
..t.. Maxim .h..
..i.. . ....... . ..si
sandroidmonkeystreste
.sttoolMaxim.thistool.
.helpyoutofoundappcrash.thi
..stooluserandomordfsalgorithm:.
.smonkeyMaxim machine gunmonkey..
..monkey,..,monkeymonkeym,..,onkeym.
.onkeymon..keymon.keymonke..ymonkeym.
,onkeymonkeymonkeymonkeymonkeymon.key.
.monkeymonkeymonkeymonkeymonkeymonkeym.
.onkeymonkeymonkeythxforphdguxiaotian.:
.anythingUcancontactpanda_zzaqq77227005
. .
. .
[Maxim] *** ERROR // : No activities found to run, monkey aborted.
666,实践一下
很感谢分享,想问一下如何修改 monkey 源码进行二次开发?主要对这个过程感兴趣,网上这方面的资料很少,方便的话可以详细说一下过程吗?小白也想试试自己改一下
加 q 群说吧。这个简单一两句说不清楚
源码方便放到 github 上么?
移动终端需要 root 权限吧
“开发者选项” -> "USB 调试(安全设置)允许通过 usb 调试修改权限或模拟点击" 这个可否打开了?
方便给下群号吗 我也想加群 了解下,自带的 monkey 太随机了
2018.02.23 update
需要配置 max.xpath.action 文件
案例:
[
{
"prob": 1,
"activity":"tv.panda.account.activity.WebLoginActivity",
"actions": [
{
"xpath": "//*[@class='android.widget.EditText']",
"action": "INPUTTEXT",
"text": "13810751000",
"index": 0,
"throttle": 300
},
{
"xpath": "//*[@class='android.widget.EditText']",
"action": "INPUTTEXT",
"text": "123400",
"index": 1,
"throttle": 300
},
{
"xpath": "//*[@content-desc='登录' and @class='android.view.View']",
"index": 0,
"action": "CLICK",
"throttle": 1000
}]
},
{
"prob": 1,
"actions": [
{
"xpath": "//*[@class='android.view.View']",
"index": 0,
"action": "SWIPE",
"args": "10,1000,800,1000,100",
"throttle": 3000
}]
},
{
"prob": 1,
"actions": [
{
"xpath": "//*[@class='android.view.View']",
"index": 0,
"action": "TOUCH",
"args": "500,1000",
"throttle": 1000
}]
},
{
"prob": 1,
"actions": [
{
"xpath": "//*[@class='android.view.View']",
"index": 0,
"action": "KEYEVENT",
"keycode": 4,
"throttle": 1000
}]
}
]
上述包含 3 个特殊事件
发生概率 prob =1 为 100% 发生
仅当 当前 activity 为 tv.panda.account.activity.WebLoginActivity 时或无 activity 配置时做事件查找
xpath 为待查找控件的 xpath 支持复杂型 xpath,支持 index 索引选择
throttle 为该特殊步骤执行完后 sleep n 毫秒
Action 支持
1.Click 点击匹配到的 xpath 控件
2.INPUTTEXT 在匹配到的 xpath 控件中输入 text 指定字符,输入需要提前安装 adbkeyboard
3.TOUCH 点击指定坐标 args = (x,y)
4.SWIPE 按执行路径滑动 args = (x1,y1,x2,y2,step)
5.KEYEVENT 执行键盘事件 keycode
注 配置完成后请贴在 json.cn 检查格式,注意” : , 非中文
如果要执行的一个事件序列,执行过程中会出现 activity 跳转,则应该将该序列拆分成两个 actions 进行配置。
更新后 发现
是 ape.strings 对应现在的 max.strings
ape.xpath.actions 对应现在的 max.xpath.actions
还多了一个 max.config 是配置什么的
cmd@TR:~/workspace/git/Maxim$ cat max.config
max.startAfterNSecondsofsleep = 6000
max.wakeupAfterNSecondsofsleep = 4000
2018.02.28 update
配置 max.widget.black
案例
[
{
"activity":"com.panda.videoliveplatform.activity.MainFragmentActivity",
"xpath": "//*[@class='android.widget.TextView' and @text='我的校园' and @resource-id='com.panda.videoliveplatform:id/tv_title']"
},
{
"activity":"com.panda.videoliveplatform.activity.MainFragmentActivity",
"xpath": "//*[@class='android.widget.TextView' and @text='车队' and @resource-id='com.panda.videoliveplatform:id/tv_title']",
"index": 0,
"bounds": "[0,633][900,789]"
},
{
"activity":"com.panda.videoliveplatform.activity.MainFragmentActivity",
"bounds": "[0,1107][900,1263]"
}
]
当且仅当 当前 activity == 所配 activity 或未配 activity 时 做黑检查
三种方式:
1.仅配置 bounds
屏蔽某个区域,在该区域内的控件或坐标不会被点击。
2.配置 xpath
查找匹配的控件,屏蔽点击该控件。
3.xpath+bounds
查找匹配的控件,当控件存在时屏蔽指定的区域。
注 配置完成后请贴在 json.cn 检查格式,注意” : , 非中文
将该文件 push 到 /sdcard/max.widget.black
android5.1,加入特殊事件序列后,执行,一到特殊事件序列的 activity,monkey 就停止了
楼主,这个不提供源码吗
按照楼主的操作文档执行了之后,为什么没有反应呢? 我是华为 Mate9 下操作的,手机 USB 已经打开,已经把 framework.jar 和 monkey.jar push 到手机里,执行的命令是 adb shell CLASSPATH=/sdcard/monkey.jar:/sdcard/framework.jar exec app_process /system/bin tv.panda.test.monkey.Monkey -p xxxx(我要测试的进程名)—uiautomatormix —running-minutes 3 麻烦楼主帮忙看下是什么原因
先赞一个
关于黑控件 max.widget.black
-v -v -v -v 4 级 log 可以看到 blackWidget
生成:
每次刷新 activity 生成黑区域 会对控件 tree 按 xpath 进行 search,若找到则加入黑区域 或只配 bounds 则直接加入黑区域.
检测:
有 2 种:
关于如何脱机运行(adb 后拔掉 usb)
adb shell "CLASSPATH=/sdcard/monkey.jar:/sdcard/framework.jar exec app_process /system/bin tv.panda.test.monkey.Monkey -p com.panda.videoliveplatform --uiautomatormix --running-minutes 60 -v -v >/sdcard/monkeyout.txt 2>/sdcard/monkeyerr.txt &"
这个和 windows 没关系,""里面的都是丢给 adb shell 的,都是 linux,脱机可行,好像是自己会变成 daemon,测过
2018.03.09 update
1.(MIX 支持)高速截图 及 dump xml
配置
Max.config
max.takeScreenShot = true 开启截图
max.savePageSource = true 保存 xml
将该文件 push 到 /sdcard/max.config
截图的生效条件
throttle > 200 && max.takeScreenSho= true
1 默认保存在 /sdcard/
2 也可以自定义路径 --output-directory /sdcard/max1/
当自定义路径已存在 会自动mkdir max1.1 并将截图保存在max1.1中
案例:
adb shell CLASSPATH=/sdcard/monkey.jar:/sdcard/framework.jar exec app_process /system/bin tv.panda.test.monkey.Monkey -p com.panda.videoliveplatform --uiautomatormix --running-minutes 6 -v -v --throttle 400 --output-directory /sdcard/max1/
备注:每分钟 100-200 截图,故因大量截图对手机空间要求较高,仅为复现崩溃时建议开启截图
666,膜拜大神
请教一下,如果出现了 anr 跟 crash,日志的也是跟原生 monkey 的一样么
666,做的很棒。appium 底层的 uiautomate2 server 在解析 xpath 的时候有点 bug,我也在想着如何改进。你后续可以尝试支持下 webdriver 协议了。
今年大会你可以这个开源项目提交个 topic,挺实用的,百度和腾讯的都没开源,正好你的开源了。
执行白名单中的 activity, 请问这个命令有问题吗? adb shell CLASSPATH=/sdcard/monkey.jar:/sdcard/framework.jar exec app_process /system/bin tv.panda.test.monkey.Monkey -p packagename --uiautomatormix --pkg-whitelist-file /sdcard/awl.strings 200
手机设置了不锁屏,发现跑的过程中会被锁屏,不知道大家遇到过这个情况没有?
你好,请问支持页面滑动吗
大神坐等源码,最近也在研究 monkey 源码,也想改造适合自己使用的 monkey
2018.03.22 update
[
{
"firstList":
[
{ "xpath": "//*[contains(@text,'绝地求生')]" }
],
"selectList":
[
{ "xpath": "//*[@clickable='true']" },
{ "xpath": "//*[@clickable='true']//*[contains(name(),'Text')]" },
{ "xpath": "//*[@clickable='true']//*[contains(name(),'Button')]" },
{ "xpath": "//*[@clickable='true']//*[contains(name(),'Image')]" }
],
"lastList":
[
{ "xpath": "//*[../*[@selected='true']]" },
{ "xpath": "//*[../../*/*[@selected='true']]" },
{ "xpath": "//*[../../*/*[@selected='true'] and contains(@resource-id,'tab_')]" },
{ "xpath": "//*[contains(@resource-id,'HorizontalScrollView')]" }
],
"blackList":
[
{ "xpath": "//*[contains(@resource-id,'wrapper_in_custom_title_bar')]//*[contains(@resource-id,'right_button')]" },
{ "xpath": "//*[contains(@resource-id,'share')]" }
]
}
]
控件选择策略 会按 1first 2select 3last 并屏蔽 black 来执行遍历操作。
adb shell CLASSPATH=/sdcard/monkey.jar:/sdcard/framework.jar exec app_process /system/bin tv.panda.test.monkey.Monkey -p com.panda.videoliveplatform --uiautomatortroy --running-minutes 15 -v -v
另注 max.xpath.selector 需要 push 到/sdcard/
大神 666
用来压力测试很不错
楼主, 这个工具有开源的计划吗?
关于特殊事件的 log 如何查看?
Max 运行 开头会打印出 load 的 Special Event
解析生成 Tree 结构
分别表示
index|height|depth|childCount|descendantCount,className,contentDesc,text,xpath,clickable,rect
3.针对一个 xpath 进行查找
找到打印 Find it,已经对应执行的 event
[Maxim] // Rejecting start of Intent { act=android.content.pm.action.REQUEST_PERMISSIONS pkg=com.google.android.packageinstaller cmp=com.google.android.packageinstaller/com.android.packageinstaller.permission.ui.GrantPermissionsActivity } in package com.google.android.packageinstaller
如何能点到权限框?
问题没看明白,qq 加我说吧
--output-directory /sdcard/MonkeyLog/log.txt
输出的日志,只有文件夹,没有 log 啊....能像原生 monkey 那样把 log 定向到 PC 端吗?
你的参数传错了
正确的: --output-directory /sdcard/MonkeyLog
这个 output 目录 主要是保存 crash,anr traces,截图,pagesources xml
关于 max 标准输出流和异常流 可以重定向保存到 pc github 上有个 issue 有说明
再膜拜一下大神~~这个比原生的 monkey 要好用很多
关于 crash-dump.log 及 崩溃捕获
一般如果 app 自己实现了 crash 上报的功能 就会去重写这个 defaultUncaughtHandler 接口,如果 app 没有捕获 crash, ActivityManagerProxy 会调 handleApplicationCrash 进入系统 crash 处理流程(如上图)
UIHandler.sendMessage 就是我们最常见的 app 弹了个 无响应的弹窗。我们主要关注 ams.crashApplication(下图红框)
monkey 里实现了 这个 IActivityController.appCrashed 回调,于是乎就把 crash 记录下来了。
楼主,我问下,不同版本的 android 系统,照理 monkey.jar 和 framework.jar 是不一样的,你那只有一份这两个 jar 包,如何支持 android5~9 版本啊?
多平台兼容 可以参考下,道理差不多 https://testerhome.com/topics/15089
2018.07.25 update
1.崩溃回溯式截图
运行时 shell 增加 --imagepolling 参数 , 开启崩溃回溯截图、关闭原截图逻辑
当崩溃发生时 进行截图保存,实现可回溯崩溃场景,默认会在 /sdcard/crash_$timestamp/图
配置 max.config
max.takeScreenShot = true 开启截图
max.flushImagesThreshold =xx 回溯区间大小 xx 张
截图的生效条件: throttle > 200 && max.takeScreenShot = true && --imagepolling
请问下屏蔽掉状态栏是如何做到的?我目前想的方法是检测当前是否存在状态栏,但是不知道用啥方法?
你好,我有两个问题请教:
1.做 Monkey 的时候能够收集到点击事件实际触发的那个 view 的具体元素吗?我看楼主支持特殊事件序列 max.xpath.actions 不知道这个里面定义的 xpath 在定义后执行的时候应该是判断的,既然能判断应该也能 dump 出当前页面的所有元素的,是不是可以拿到点击的坐标元素?
2.src 下的 MonkeySourceUiAutomatorDFS.kt 文件对于执行有什么用?我看里面好多 api。麻烦能讲解下吗?
每分钟 100-200 截图,故因大量截图对手机空间要求较高,仅为复现崩溃时建议开启截图
想问下怎么做到仅在复现崩溃时开启截图?
是使用崩溃回溯式截图这个功能吗?
monkey.jar 的是下发指令执行操作的,那这个 framework.jar 是做什么的用的,他跟原生的/system/framework.jar 有什么区别
膜拜大神,坐等开源
命令:adb shell CLASSPATH=/sdcard/monkey.jar:/sdcard/framework.jar exec app_process /system/bin tv.panda.test.monkey.Monkey -p com.yangle.xiaoyuzhou --running-minutes 2 --uiautomatordfs --throttle 500 -v -v >/Users/wangshaoce/testlog/monkeylog/monkeyout.txt 2>/Users/wangshaoce/testlog/monkeylog/monkeyerr.txt &
monkeyerr 收集到到 error 为:
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(1 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(1 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(2 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(3 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(4 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(5 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(6 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(7 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(8 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(9 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(10 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(11 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(12 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(13 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(14 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(15 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(16 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(1 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(2 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(3 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(4 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(5 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(6 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(7 times), use default events generator.
未能准确收集到报错信息,请问 如何解决 已加楼主 q
这是什么厂设备? Android 版本多少的? 看上去像是 AccessibilityService 被禁用了。
出现 crash 或者 anr 的后,还会继续执行 monkey 吗,直到达到设定时间才会停止么?
如果运行多轮 monkey,那么每轮出现的 crash 信息或者 oom traces 是追加还是覆盖写入 sdcard/crash-dump.log 和/sdcard/oom-traces.log?
--ignore-crashes 原 monkey 有个参数如果不设置就是你说的这个场景。 但是如果启用了--running-minutes 则 crash 后会继续执行
Hi,作者:
我想问下这个 framework.jar 的作用是啥呢?为啥我 push framework.jar 和 monkey.jar 到手机后启动,然后同时抓取 logcat 的输出,发现系统在处理这个 framework.jar 时抛出了异常,这个应该没有起作用吧。下面是 logcat 中的输出:
01-14 16:43:21.256 E/System (31646): Unable to open zip file: /sdcard/framework.jar
01-14 16:43:21.258 E/System (31646): java.util.zip.ZipException: error in opening zip file
01-14 16:43:21.258 E/System (31646): at java.util.zip.ZipFile.open(Native Method)
01-14 16:43:21.258 E/System (31646): at java.util.zip.ZipFile.<init>(ZipFile.java:225)
01-14 16:43:21.258 E/System (31646): at java.util.zip.ZipFile.<init>(ZipFile.java:148)
01-14 16:43:21.258 E/System (31646): at java.util.jar.JarFile.<init>(JarFile.java:161)
01-14 16:43:21.258 E/System (31646): at java.util.jar.JarFile.<init>(JarFile.java:98)
01-14 16:43:21.258 E/System (31646): at libcore.io.ClassPathURLStreamHandler.<init>(ClassPathURLStreamHandler.java:47)
01-14 16:43:21.258 E/System (31646): at dalvik.system.DexPathList$Element.maybeInit(DexPathList.java:532)
01-14 16:43:21.258 E/System (31646): at dalvik.system.DexPathList$Element.findResource(DexPathList.java:568)
01-14 16:43:21.258 E/System (31646): at dalvik.system.DexPathList.findResource(DexPathList.java:440)
01-14 16:43:21.258 E/System (31646): at dalvik.system.BaseDexClassLoader.findResource(BaseDexClassLoader.java:74)
01-14 16:43:21.258 E/System (31646): at java.lang.ClassLoader.getResource(ClassLoader.java:793)
01-14 16:43:21.258 E/System (31646): at java.lang.ClassLoader.getResourceAsStream(ClassLoader.java:977)
01-14 16:43:21.258 E/System (31646): at java.util.ResourceBundle$RBClassLoader.getResourceAsStream(ResourceBundle.java:464)
01-14 16:43:21.258 E/System (31646): at java.util.ResourceBundle$Control$1.run(ResourceBundle.java:2603)
01-14 16:43:21.258 E/System (31646): at java.util.ResourceBundle$Control$1.run(ResourceBundle.java:2589)
01-14 16:43:21.258 E/System (31646): at java.security.AccessController.doPrivileged(AccessController.java:67)
01-14 16:43:21.258 E/System (31646): at java.util.ResourceBundle$Control.newBundle(ResourceBundle.java:2587)
01-14 16:43:21.258 E/System (31646): at java.util.ResourceBundle.loadBundle(ResourceBundle.java:1438)
01-14 16:43:21.258 E/System (31646): at java.util.ResourceBundle.findBundle(ResourceBundle.java:1402)
01-14 16:43:21.258 E/System (31646): at java.util.ResourceBundle.findBundle(ResourceBundle.java:1356)
01-14 16:43:21.258 E/System (31646): at java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1298)
01-14 16:43:21.258 E/System (31646): at java.util.ResourceBundle.getBundle(ResourceBundle.java:723)
01-14 16:43:21.258 E/System (31646): at java.util.logging.Level.<init>(Level.java:223)
01-14 16:43:21.258 E/System (31646): at java.util.logging.Level.<clinit>(Level.java:96)
01-14 16:43:21.258 E/System (31646): at java.util.logging.Logger.<clinit>(Logger.java:177)
01-14 16:43:21.258 E/System (31646): at java.util.logging.Logger.getLogger(Logger.java:393)
01-14 16:43:21.258 E/System (31646): at android.icu.util.TimeZone.<clinit>(TimeZone.java:92)
01-14 16:43:21.258 E/System (31646): at java.util.TimeZone.setDefault(TimeZone.java:712)
01-14 16:43:21.258 E/System (31646): at com.android.internal.os.RuntimeInit.commonInit(RuntimeInit.java:132)
01-14 16:43:21.258 E/System (31646): at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:256)
上面的 issue,附上测试机型:
在 max.widget.black 加了黑控件屏蔽,为什么没有生效?还是会点到
在 max.widget.black 加了以下控件的黑名单:
{
"activity": "com.netease.mobimail.activity.LoginActivity",
"xpath":"//*[@class='android.widget.TextView' and @resource-id='com.netease.mail:id/tv_forget_password']"
},
{
"activity": "com.netease.mobimail.activity.LoginActivity",
"xpath":"//*[@class='android.widget.Button' and @resource-id='com.netease.mail:id/button_register']"
},
{
"activity": "com.netease.mobimail.activity.TabActivity",
"xpath":"//*[@class='android.widget.ImageView' and @resource-id='com.netease.mail:id/iv_mail_list_filter']"
}
运行时还能点击到,log 输出:
但是如果配在 max.xpath.selector 的 blackList 里面是有效的,那 max.widget.black 还有什么用?
log: inside black list 是会把这些控件从 select 队列里删除掉
请问可以通过什么去获取 activity 页面呢。我用 weditor 只能获取到 xpath 但得不到 activity
大神,请教一个获取不到控件的问题。打开测试软件后,底部有 4 个按键用来切换不同的页面 (大多软件都这样),现在的情况是这样:刚进入软件时,默认打开的是第一个页面 (即首页),而且这 4 个页面都为同一个 activity,而我要点击的按钮在第 4 个页面'我的'里。我是这样做的,使用了 max.xpath.actions
但就是登入按钮无法 Find it。是不是因为默认打开的是首页,而 “我的” 页面虽然也是同一个 activity,但是被隐藏着的,所以无法 Find it 呢?
我要测试登入模块,针对这种情况如何去解决呢。
只保留对 com.yyt.module.user.LoginActivity 这个页面的登录 event。 前面两个事件 flow 全删掉
还发现一个问题。
明明已经找到了黑控件,可是后面跟着的 Click 事件恰好去根据 id 去点击了黑控件,可以加 Q 请教一下吗
楼主,崩溃回溯截图的实现原理是什么呢,有没有相关资料
max.xpath.actions 这里面的点击事件能不能根据 id 进行点击呢,我发现我们的 app 找不到 xpath 路径了
id 可以
"xpath": "//*[@resource-id='com.longzhu.tga:id/edit_phone_num']",
谢谢,我想起来是没有选中 ADBKeyBoard,但是我在键盘管理选了这个之后,输入框能输入了,但是有几个问题还不明白还要请教一下:1、登录的按钮我用了 click,id,index 都是对的但是不点击,反而点了另外一个按钮;2、在其他页面也有输入框之前是可以随机输入的,现在我的 max.xpath.actions 只配置了输入用户名密码的,其他的输入框现在都不能输入了,这个是正常现象吗?
选择 ADBKeyBoard 之后,只有用户名密码的输入框可以输入,而且有时候也是输入不全的,比如我配置输入的是 autotest,输入的只有 auto
max.config 里配置 max.randomPickFromStringList = true
并配置 max.strings 几条随机输入的 text。
其他输入框就按 strings 里的随机选中输入
请问下 api 适配中 findMethod 是怎么实现的呢?可以说下吗?因为有时候用 clazz.getDeclaredMethod(xx) 不生效,setAccessible(true) 也不行,所以想知道下怎么实现的呢
这个支持遍历 webview 吗?
请教一下,执行 max.xpath.actions 里面的 actions,日志有显示 Special Event,但是进入到这个页面后,里面的 action 没被执行,比如输入框,我想输入 123,结果输入框是随机输入字符,里面有告警信息:[Maxim] *** WARNING // Device has no this key KEYCODE_T,请问是啥原因?
日志信息:
[Maxim] // Selecting main activities from category android.intent.category.LAUNCHER
[Maxim] // + Using main activity com.pingan.anne.controller.WelcomeActivity (from package com.pingan.anne.rym)
[Maxim] // Selecting main activities from category android.intent.category.MONKEY
[Maxim] // Add Launcher To ActivityWhiteList : com.pingan.anne.controller.WelcomeActivity
[Maxim] // AllowPackage: com.pingan.anne.rym
[Maxim] // AllowActivity: com.pingan.anne.controller.HomeActivity
[Maxim] // AllowActivity: com.pingan.anydoor.rymlogin.ui.login.LoginActivity
[Maxim] // AllowActivity: com.pingan.anydoor.hybird.activity.CacheableWebViewActivity
[Maxim] // AllowActivity: com.pingan.anne.controller.WelcomeActivity
[Maxim] // IncludeCategory: android.intent.category.LAUNCHER
[Maxim] // IncludeCategory: android.intent.category.MONKEY
[Maxim] // Special Event:
[Maxim] // Event1:
[Maxim] // Prob: 1.0
[Maxim] // Actvity: com.pingan.anydoor.rymlogin.ui.login.LoginActivity
[Maxim] // Step0:
[Maxim] // XPath: //*[@resourceId='com.pingan.anne.rym:id/comm_input_txt']
[Maxim] // XPathExpression: org.apache.xpath.jaxp.XPathExpressionImpl@bbefac6
[Maxim] // Action: INPUTTEXT
[Maxim] // Text: 13188880000
[Maxim] // Throttle: 1000
[Maxim] // Step1:
[Maxim] // XPath: //*[@resourceId='com.pingan.anne.rym:id/comm_input_txt']
[Maxim] // XPathExpression: org.apache.xpath.jaxp.XPathExpressionImpl@bdd4a87
[Maxim] // Action: INPUTTEXT
[Maxim] // Text: qweqwe123
[Maxim] // Throttle: 1000
[Maxim] // Step2:
[Maxim] // XPath: //*[@resourceId='com.pingan.anne.rym:id/yzt_sdk_login_login_btn']
[Maxim] // XPathExpression: org.apache.xpath.jaxp.XPathExpressionImpl@5580db4
[Maxim] // Action: CLICK
[Maxim] // Text:
[Maxim] // Throttle: 1000
[Maxim] // Black Widget List:
[Maxim] // InputMethod ID: InputMethodInfo{com.baidu.input_mi/.ImeService, settings: com.baidu.input.ImeMainConfigActivity}.id
[Maxim] // InputMethod ID: InputMethodInfo{com.github.uiautomator/.FastInputIME, settings: null}.id
[Maxim] // InputMethod ID: InputMethodInfo{com.sohu.inputmethod.sogou.xiaomi/.SogouIME, settings: com.sohu.inputmethod.sogou.xiaomi.SogouIMESettingsLauncher}.id
[Maxim] // InputMethod ID: InputMethodInfo{com.netease.nie.yosemite/.ime.ImeService, settings: null}.id
[Maxim] // InputMethod ID: InputMethodInfo{com.android.adbkeyboard/.AdbIME, settings: null}.id
[Maxim] // Find ADBKeybaord.
[Maxim] // Device Info: Xiaomi-MI 8 UD, Android Version: 8.1.0
[Maxim] // activityResuming(com.pingan.anne.rym)
[Maxim] // activityResuming(com.pingan.anne.rym)
[Maxim] // activityResuming(com.pingan.anne.rym)
[Maxim] strategy : uiautomator-Troy.
--------------------------------------下面还有一段-----
[Maxim] // Activity : com.pingan.anydoor.rymlogin.ui.webview.LoginWebviewActivity in Intent
[Maxim] // Rejecting start of Intent { cmp=com.pingan.anne.rym/com.pingan.anydoor.rymlogin.ui.webview.LoginWebviewActivity } in package com.pingan.anne.rym
[Maxim] // Activity : com.pingan.anydoor.rymlogin.ui.webview.LoginWebviewActivity in Intent
[Maxim] // Rejecting start of Intent { cmp=com.pingan.anne.rym/com.pingan.anydoor.rymlogin.ui.webview.LoginWebviewActivity } in package com.pingan.anne.rym
[Maxim] // Special Event : XPath = //*[@resourceId='com.pingan.anne.rym:id/comm_input_txt'], Index = 0, Action = INPUTTEXT, Text = 13188880000
[Maxim] // InputMethodVisibleHeight: 53, lastInput=85, current=88
[Maxim] *** WARNING // Device has no this key KEYCODE_T
[Maxim] *** WARNING // Device has no this key KEYCODE_7
[Maxim] *** WARNING // Device has no this key KEYCODE_7
[Maxim] *** WARNING // Device has no this key KEYCODE_4
[Maxim] *** WARNING // Device has no this key KEYCODE_J
[Maxim] *** WARNING // Device has no this key KEYCODE_3
[Maxim] *** WARNING // Device has no this key KEYCODE_1
[Maxim] *** WARNING // Device has no this key KEYCODE_3
[Maxim] *** WARNING // Device has no this key KEYCODE_2
[Maxim] *** WARNING // Device has no this key KEYCODE_5
[Maxim] *** WARNING // Device has no this key KEYCODE_1
[Maxim] *** WARNING // Device has no this key KEYCODE_P
[Maxim] *** WARNING // Device has no this key KEYCODE_2
[Maxim] *** WARNING // Device has no this key KEYCODE_H
[Maxim] *** WARNING // Device has no this key KEYCODE_6
[Maxim] *** WARNING // Device has no this key KEYCODE_3
[Maxim] *** WARNING // Device has no this key KEYCODE_T
[Maxim] // Click: com.pingan.anne.rym:id/comm_input_txt, android.widget.EditText, Rect(174, 554 - 997, 678), 3ae219b787f9cfbe30cdb257e4dec4df
[Maxim] // event57, 2019-04-12 11:12:50.212
[Maxim] // Sleeping for 10 milliseconds
[Maxim] // event57, 2019-04-12 11:12:50.224
[Maxim] // Sleeping for 800 milliseconds
[Maxim] // event57, 2019-04-12 11:12:51.026
[Maxim] // Sleeping for 10 milliseconds
[Maxim] // event57, 2019-04-12 11:12:51.039
[Maxim] // Sleeping for 800 milliseconds
[Maxim] // event57, 2019-04-12 11:12:51.842
[Maxim] // Sleeping for 10 milliseconds
[Maxim] // event57, 2019-04-12 11:12:51.856
[Maxim] // Sleeping for 800 milliseconds
[Maxim] // event57, 2019-04-12 11:12:52.659
[Maxim] // Sleeping for 10 milliseconds
[Maxim] // event57, 2019-04-12 11:12:52.671
[Maxim] // Sleeping for 800 milliseconds
[Maxim] // event57, 2019-04-12 11:12:53.475
[Maxim] // Sleeping for 10 milliseconds
[Maxim] // event57, 2019-04-12 11:12:53.488
[Maxim] // Sleeping for 800 milliseconds
[Maxim] // event57, 2019-04-12 11:12:54.292
[Maxim] // Sleeping for 10 milliseconds
[Maxim] // event57, 2019-04-12 11:12:54.309
[Maxim] // Sleeping for 800 milliseconds
[Maxim] // event57, 2019-04-12 11:12:55.112
[Maxim] // Sending Key (ACTION_DOWN): 47 KEYCODE_S
[Maxim] // event58, 2019-04-12 11:12:55.120
[Maxim] // Sending Key (ACTION_UP): 47 KEYCODE_S
[Maxim] // event59, 2019-04-12 11:12:55.150
[Maxim] // Sleeping for 800 milliseconds
[Maxim] // event59, 2019-04-12 11:12:55.954
[Maxim] // Sleeping for 10 milliseconds
[Maxim] // event59, 2019-04-12 11:12:55.966
[Maxim] // Sleeping for 800 milliseconds
[Maxim] // event59, 2019-04-12 11:12:56.769
[Maxim] // Sleeping for 10 milliseconds
[Maxim] // event59, 2019-04-12 11:12:56.782
[Maxim] // Sleeping for 800 milliseconds
[Maxim] // event59, 2019-04-12 11:12:57.586
[Maxim] // Sleeping for 10 milliseconds
[Maxim] // event59, 2019-04-12 11:12:57.598
[Maxim] // Sleeping for 800 milliseconds
[Maxim] // event59, 2019-04-12 11:12:58.402
[Maxim] // Sleeping for 10 milliseconds
[Maxim] // event59, 2019-04-12 11:12:58.415
[Maxim] // Sleeping for 800 milliseconds
[Maxim] // event59, 2019-04-12 11:12:59.218
[Maxim] // Sleeping for 10 milliseconds
[Maxim] // event59, 2019-04-12 11:12:59.230
[Maxim] // Sleeping for 800 milliseconds
[Maxim] // event59, 2019-04-12 11:13:00.032
[Maxim] // Sleeping for 10 milliseconds
[Maxim] // event59, 2019-04-12 11:13:00.044
[Maxim] // Sleeping for 800 milliseconds
[Maxim] // event59, 2019-04-12 11:13:00.847
[Maxim] // Sleeping for 10 milliseconds
[Maxim] // event59, 2019-04-12 11:13:00.860
[Maxim] // Sleeping for 800 milliseconds
[Maxim] // event59, 2019-04-12 11:13:01.663
[Maxim] // Sleeping for 10 milliseconds
[Maxim] // event59, 2019-04-12 11:13:01.676
[Maxim] // Sleeping for 800 milliseconds
[Maxim] // event59, 2019-04-12 11:13:02.480
[Maxim] // Sleeping for 10 milliseconds
[Maxim] // event59, 2019-04-12 11:13:02.492
[Maxim] // Sleeping for 800 milliseconds
[Maxim] // event59, 2019-04-12 11:13:03.295
[Maxim] // Sleeping for 10 milliseconds
[Maxim] // event59, 2019-04-12 11:13:03.308
[Maxim] // Sleeping for 800 milliseconds
[Maxim] // event59, 2019-04-12 11:13:04.112
[Maxim] // Sleeping for 10 milliseconds
[Maxim] // event59, 2019-04-12 11:13:04.128
[Maxim] // Sleeping for 800 milliseconds
[Maxim] // event59, 2019-04-12 11:13:04.931
[Maxim] :Sending Touch (ACTION_DOWN): 0:(585.5,616.0)
[Maxim] // event60, 2019-04-12 11:13:04.944
[Maxim] :Sending Touch (ACTION_UP): 0:(585.5,616.0)
[Maxim] // event61, 2019-04-12 11:13:04.947
[Maxim] // Sleeping for 800 milliseconds
[Maxim] // Special Event : XPath = //*[@resourceId='com.pingan.anne.rym:id/comm_input_txt'], Index = 0, Action = INPUTTEXT, Text = 13188880000
[Maxim] // InputMethodVisibleHeight: 53, lastInput=88, current=128
[Maxim] // Click: com.pingan.anne.rym:id/comm_input_txt, android.widget.EditText, Rect(174, 716 - 997, 840), db6cf51b1433e580022c50e8954622e1
[Maxim] // Special Event : XPath = //[@resourceId='com.pingan.anne.rym:id/comm_input_txt'], Index = 0, Action = INPUTTEXT, Text = 13188880000
[Maxim] // InputMethodVisibleHeight: 53, lastInput=85, current=88
[Maxim] ** WARNING // Device has no this key KEYCODE_T
看 log 是 没有找到匹配 xpath 的控件。 如果找到 会打印 find it
找到原因了 resourceId 这个地方要用 resource-id,但是发现了一个新问题,输入框输入不全就执行了下一个步骤了。比如账号,我想输入 13188880000,但是实际执行时,只输入了 13,就不输入了,不知道这是什么原因
日志
[Maxim] // Special Event:
[Maxim] // Event1:
[Maxim] // Prob: 1.0
[Maxim] // Actvity: com.pingan.anydoor.rymlogin.ui.login.LoginActivity
[Maxim] // Step0:
[Maxim] // XPath: //*[@resource-id='com.pingan.anne.rym:id/comm_input_txt']
[Maxim] // XPathExpression: org.apache.xpath.jaxp.XPathExpressionImpl@dec9966
[Maxim] // Action: INPUTTEXT
[Maxim] // Text: 13188880000
[Maxim] // Throttle: 2000
[Maxim] // Step1:
[Maxim] // XPath: //*[@resource-id='com.pingan.anne.rym:id/comm_input_txt']
[Maxim] // XPathExpression: org.apache.xpath.jaxp.XPathExpressionImpl@f5e94a7
[Maxim] // Action: INPUTTEXT
[Maxim] // Text: qweqwe123
[Maxim] // Throttle: 1000
[Maxim] // Step2:
[Maxim] // XPath: //*[@resource-id='com.pingan.anne.rym:id/yzt_sdk_login_login_btn']
[Maxim] // XPathExpression: org.apache.xpath.jaxp.XPathExpressionImpl@cba5d54
[Maxim] // Action: CLICK
[Maxim] // Text:
[Maxim] // Throttle: 1000
------- 下面接一段-----
[Maxim] // Activity : com.pingan.anydoor.rymlogin.ui.login.LoginActivity in Intent
[Maxim] // Allowing start of Intent { cmp=com.pingan.anne.rym/com.pingan.anydoor.rymlogin.ui.login.LoginActivity } in package com.pingan.anne.rym
[Maxim] // Activity : com.pingan.anydoor.rymlogin.ui.login.LoginActivity in Intent
[Maxim] // Allowing start of Intent { cmp=com.pingan.anne.rym/com.pingan.anydoor.rymlogin.ui.login.LoginActivity } in package com.pingan.anne.rym
[Maxim] // : debug, currentActivity is com.pingan.anydoor.rymlogin.ui.login.LoginActivity
[Maxim] // Special Event : XPath = //*[@resource-id='com.pingan.anne.rym:id/comm_input_txt'], Index = 0, Action = INPUTTEXT, Text = 13188880000
[Maxim] // Find it : 1|1|4|0|1, android.widget.EditText, null, 13188880000, null, true, Rect(174, 554 - 914, 678)
[Maxim] // Special Event : XPath = //*[@resource-id='com.pingan.anne.rym:id/comm_input_txt'], Index = 1, Action = INPUTTEXT, Text = qweqwe123
[Maxim] // Find it : 3|1|4|0|1, android.widget.EditText, null, 登录密码, null, true, Rect(174, 716 - 997, 840)
[Maxim] // Special Event : XPath = //*[@resource-id='com.pingan.anne.rym:id/yzt_sdk_login_login_btn'], Index = 0, Action = CLICK, Text =
[Maxim] // Find it : 4|1|4|0|1, android.widget.TextView, null, 登录, null, true, Rect(83, 946 - 997, 1056)
[Maxim] // Click: com.pingan.anne.rym:id/rym_login_sdk_back_img, android.widget.ImageView, Rect(0, 110 - 110, 239), 8fc0405b6d8b908be727aa0e73466490
[Maxim] // event3, 2019-04-15 15:07:35.892
[Maxim] :Sending Touch (ACTION_DOWN): 0:(544.0,616.0)
[Maxim] // event4, 2019-04-15 15:07:35.894
[Maxim] :Sending Touch (ACTION_UP): 0:(544.0,616.0)
[Maxim] // event5, 2019-04-15 15:07:35.895
[Maxim] // Sleeping for 800 milliseconds
[Maxim] // event5, 2019-04-15 15:07:36.698
[Maxim] // debug, send text =13188880000
[Maxim] // event6, 2019-04-15 15:07:37.028
[Maxim] // Sleeping for 800 milliseconds
[Maxim] // event6, 2019-04-15 15:07:37.832
[Maxim] // Sleeping for 2000 milliseconds
[Maxim] // event6, 2019-04-15 15:07:39.836
[Maxim] // Sleeping for 800 milliseconds
[Maxim] // event6, 2019-04-15 15:07:40.640
[Maxim] :Sending Touch (ACTION_DOWN): 0:(585.5,778.0)
[Maxim] // event7, 2019-04-15 15:07:40.652
[Maxim] :Sending Touch (ACTION_UP): 0:(585.5,778.0)
[Maxim] // event8, 2019-04-15 15:07:40.656
[Maxim] // Sleeping for 800 milliseconds
[Maxim] // event8, 2019-04-15 15:07:41.459
[Maxim] // debug, send text =qweqwe123
[Maxim] // event9, 2019-04-15 15:07:41.791
[Maxim] // Sleeping for 800 milliseconds
[Maxim] // event9, 2019-04-15 15:07:42.594
[Maxim] // Sleeping for 1000 milliseconds
[Maxim] // event9, 2019-04-15 15:07:43.601
[Maxim] // Sleeping for 800 milliseconds
[Maxim] // event9, 2019-04-15 15:07:44.404
[Maxim] :Sending Touch (ACTION_DOWN): 0:(540.0,1001.0)
[Maxim] // event10, 2019-04-15 15:07:44.410
[Maxim] :Sending Touch (ACTION_UP): 0:(540.0,1001.0)
[Maxim] // event11, 2019-04-15 15:07:44.413
[Maxim] // Sleeping for 800 milliseconds
[Maxim] // event11, 2019-04-15 15:07:45.216
[Maxim] // Sleeping for 1000 milliseconds
[Maxim] // event11, 2019-04-15 15:07:46.222
[Maxim] // Sleeping for 800 milliseconds
[Maxim] // event11, 2019-04-15 15:07:47.025
[Maxim] :Sending Touch (ACTION_DOWN): 0:(55.0,174.5)
[Maxim] // event12, 2019-04-15 15:07:47.031
[Maxim] :Sending Touch (ACTION_UP): 0:(55.0,174.5)
[Maxim] // event13, 2019-04-15 15:07:47.036
[Maxim] // Sleeping for 800 milliseconds
Throttle: 2000 增加这个延迟时间试试。 要么是这个设备性能太差了
我跟你遇到相同的问题,也是配置了 max.widget.black 不生效,但是配在 max.xpath.selector 的 blackList 里面是有效的,你后来有研究过怎么让 max.widget.black 生效吗?
请问老哥,你是采用什么方式在 Monkey.jar 里面截图的?
Surface ? screencap -p?
遇到和斯拉一样的问题,求解
log 上看没有 find it ,说明 xpath 没找到。检查下是不是 Index 配错了?
楼主你好,我想问下我使用了 appetizer 运行 Maxim,配置都设置好了,点击开始测试后,控制台输出为空,而且没有执行 adb 命令,这是为什么呢?如果不使用 appetizer 只使用 adb 命令就没问题
zhang 大大,10 系统可以支持了不~~~
楼主,修改 max.xpath.actions 后,push 到手机中,安装完 ADBKeyBoard.apk,执行命令登录页输入指定的用户名后不切换到密码输入栏,直接清除了用户名,在该栏输入密码。
请问是什么原因
请教一下能控制输入时间占比,让他快点结束吗?目前我们执行 monkey 用的 mix 模式,经常在一个输入框执行很久,也不出来,这有什么办法解决吗?
2019.08.16 update
1.mix 增加 back event 默认事件占比 10%
--pct-back 5 (设置占比 5)
2.mix 增加 重启 app event 默认事件占比 0.3%
--pct-reset 0 (关闭重启 事件)
4.增加 monkey api
如何使用:
1)先启动 monkey
adb shell CLASSPATH=/sdcard/monkey.jar:/sdcard/framework.jar exec app_process /system/bin tv.panda.test.monkey.Monkey -p com.panda.videoliveplatform --uiautomatorapi --running-minutes 100 -v -v -v -v
2)adb shell netcfg 查看 ip
3) 结合 Monkeyapi.py 编写自己的 test.py
目前提供了如下接口
1)dumptree
getXml()
2) 点击
click(500,550)
3)back
back()
4) 截屏 base64
getScreenShotBase64()
demo
https://github.com/zhangzhao4444/Maxim/blob/master/MonkeyApi.py 无须修改
https://github.com/zhangzhao4444/Maxim/blob/master/test.py
终于有更次新了!
更新了吗,白嫖怪已就位
难受呀大佬,刚启动就结束了
请教下,比如我想点击屏幕指定一块区域,这个指定区域是要怎么计算的。
目前的执行结果里看到有一个 max.activity.statistics.log 文件。
内容类似这样——
"Sampling":Array[0],
"TestedActivity":Array[5],
"TotalActivity":Array[30],
"Coverage":20
这里的 Sampling、Coverage 分别是指什么?
TestedActivity 理解为测试走到的页面;TotalActivity 为总的 Activity 数。Coverage 这里的 20 表示覆盖的比例? 5/30 覆盖率为 16% ?
app 无限启动退出,报错信息:
[Maxim] *** ERROR // : the top activity package com.miui.home is invalid.
如果是在 app 已经启动的状态下,就可以开始遍历
sampling 是采样没有对外开放,coverage 就是 activity 覆盖率,你这里是 20%
大神你好,想问问如何实现多台手机同时跑 monkey
apk 已经加固了,可以用吗,目前用的未加固的挺好用的
怎么调整频率,不想跑的那么快
大神,这个 Android9 支持吗?
我这边可以正常开始跑, 但是跑的中途会因为
ERROR // : the top activity package com.bbk.launcher2 is invalid.
这个错误而导致 app 重启, 请问一般是什么原因引起的?
命中防跳出机制,当前 activity 非待测 app 的,所以会立即执行切回原 app
能支持记录崩溃前的操作事件吗?光看截图看不出
android 9 的 Oppo R17。已走到需要输入的地方就报错,adbkeyboard 已安装并且能够正常使用。请问是什么原因,如何解决?
设置模块怎么跑呢 里面有很多其他的包名,怎么做到遍历呢
当设备不支持 KEYCODE_BACK 时会导致注入失败从而重启 app,希望楼主看下
我的测试设备是华为荣耀 9
你好,我按如下配置的:配置电脑上的 max.config 文件
然后执行命令 adb shell CLASSPATH=/sdcard/monkey.jar:/sdcard/framework.jar exec app_process /system/bin tv.panda.test.monkey.Monkey -p com.xxx --uiautomatormix --running-minutes 3 -v -v --throttle 400 --output-directory /sdcard/testreport/ --imagepolling
结果跑出了 crash,但是 crash 截图文件夹是空的。求问这是为什么?
我试了下,日常测试截图(非崩溃时截图)也没有成功。感觉是 max.config 文件未生效,需要 push 到手机 sdcard 上么。
还有个问题,,,为什么在 max.xpath.selector 这个配置文件的 blacklist 里配置了一些控件 它还是能点击呢
adb shell CLASSPATH=/sdcard/monkey.jar:/sdcard/framework.jar exec app_process /system/bin tv.panda.test.monkey.Monkey -p com.fenbi.android.zenglish --uiautomatortroy --running-minutes 6 --imagepolling -v -v --throttle 500
org.json.JSONException: Unterminated object at character 142 of [
{
"firstList":
[
{ "xpath": "//[@class='android.widget.TextView' and @resource-id='com.fenbi.android.zenglish:id/name']" and @text='如何上课'}
],
"selectList":
[
{ "xpath": "//[@clickable='true'//[contains(name(),'android.widget.FrameLayout')]"}
],
"lastList":
[
{ "xpath": "//[@class='android.widget.LinearLayout' and @resource-id='com.fenbi.android.zenglish:id/tab_bar']" }
],
"blackList":
[
{ "xpath": "//[@class='android.widget.ImageButton' and @resource-id='com.fenbi.android.zenglish:id/sobot_btn_set_mode_rengong']" }
{ "xpath": "//[contains(@content-desc, '确认支付')]" }
{ "xpath": "//[@class='android.webkit.WebView' and @resource-id='com.fenbi.android.zenglish:id/web_view']" }
{ "xpath": "//[@class='android.widget.CheckedTextView' and @resource-id='com.fenbi.android.zenglish:id/ytknavibar_right']" }
{ "xpath": "//[@class='android.widget.TextView' and @resource-id='com.fenbi.android.zenglish:id/text_buy']" }
{ "xpath": "//[@class='android.widget.CheckedTextView' and @resource-id='com.fenbi.android.zenglish:id/mission']" }
{ "xpath": "//[contains(@resource-id, 'com.fenbi.android.zenglish:id/misc')]" }
]
}
]
at org.json.JSONTokener.syntaxError(JSONTokener.java:449)
at org.json.JSONTokener.readObject(JSONTokener.java:393)
at org.json.JSONTokener.nextValue(JSONTokener.java:100)
at org.json.JSONTokener.readArray(JSONTokener.java:429)
at org.json.JSONTokener.nextValue(JSONTokener.java:103)
at org.json.JSONTokener.readObject(JSONTokener.java:384)
at org.json.JSONTokener.nextValue(JSONTokener.java:100)
at org.json.JSONTokener.readArray(JSONTokener.java:429)
at org.json.JSONTokener.nextValue(JSONTokener.java:103)
at org.json.JSONArray.(JSONArray.java:92)
at org.json.JSONArray.(JSONArray.java:108)
at tv.panda.test.monkey.ape.model.XPathSelectorReader.read(XPathSelectorReader.kt:82)
at tv.panda.test.monkey.ape.model.XPathSelectorController.(XPathSelectorController.kt:70)
at tv.panda.test.monkey.MonkeySourceUiAutomatorTroy.(MonkeySourceUiAutomatorTroy.kt:67)
at tv.panda.test.monkey.Monkey.run(Monkey.kt:573)
at tv.panda.test.monkey.Monkey$Companion.main(Monkey.kt:1422)
at tv.panda.test.monkey.Monkey.main(Monkey.kt)
at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:251)
[Maxim] // Troy Selector:
[Maxim]
[Maxim]
[Maxim] *** ERROR // : the top activity package com.mumu.launcher is invalid.
为什么 com.tencent.qqmusic.activity.AppStarterActivity 已经加入黑名单了,还能 resume??
[Maxim] // activityResuming(com.tencent.qqmusic)
[Maxim] // : debug, currentActivity is com.tencent.qqmusic.activity.AppStarterActivity
[Maxim] // DisallowActivity: com.tencent.qqmusic.activity.AppStarterActivity
开头日志里面是有生效的
这个 monkey 支持 Android10 的吗
@zhangzhao_lenovo 大神,能否适配一下 Android10 的手机呢,最近跑 Android10 的稳定性,跑不起来呢。
我想问下,就是当前测试的 activity 正是 我想要测试的 app,但是日志中却提示要 stop 我正在测试的 package,然后后台就把这个 app 进程杀掉了,然后又监测到当前 activity 是 huawei.launcher,就又重启应用。我想问下,明明一切正常并没有 crash,为什么会杀掉进程?是 maxim 代码有点问题么?感谢回复
红框上一步是命中了 RESET EVENT 就是重启 app,重启的过程就是把 app kill 掉然后再启动
top activity huawei xxx is isvalid 是指当前在桌面非待测 APP,下一步就启动 app
除了 crash 其他异常的 log 能捕获么
你好,一个模拟器指定了设备 id 能正常跑,再开启一个模拟器就立即停止了。
这个问题是怎么解决的啊
@zhangzhao_lenovo 大神,Android11 的是不是也没适配,我看了一下和 Android10 一样的报错呢,麻烦更新一下哈,谢谢了
请问一下大佬,如何关闭 屏幕 180 度翻转啊? 发现每次跑 maxim 都会发生 180 度翻转,导致黑区域坐标有变化。
请问下楼主是怎么处理执行过程中把网络关了的情况
如果 app 使用 RN 导致了整个 app 只有 1 个 activity 的时候,该如何来用白名单和黑名单功能呢?
请教个问题,想用 shell 脚本自动化执行 maxim,有一步需要安装 apk,但是会有安装权限弹窗,怎么自动化点掉,有好的办法吗?
查了下资料,Android 自带的 UIAutomator 框架可以满足条件,但是提供的 api 得用 java。。用 java 写这么个操作感觉有点笨重,除了 java,还有其他法子不?
我也遇到了一样的问题,测试机型是 MEIZU MX5,android 5.1.想了解下后面你们是如何解决的呢
问题:
1、跑 app 的过程中重复退出 app,是什么原因导致的?
2、配置了 max.xpath.actions,但是第二次进入页面的时候不会执行 actions 里面的
求问:第一次用该工具,如何设置精准化 monkey 脚本,可以一直只跑登录退出操作?
@zhangzhao_lenovo 大神,这个错误是什么原因啊,一跑起来就停了,SM-G9600 的手机
java.lang.IllegalStateException: UiAutomationService android.accessibilityservice.IAccessibilityServiceClient$Stub$Proxy@2c0907falready registered!
at android.os.Parcel.createException(Parcel.java:1974)
at android.os.Parcel.readException(Parcel.java:1934)
at android.os.Parcel.readException(Parcel.java:1884)
at android.view.accessibility.IAccessibilityManager$Stub$Proxy.registerUiTestAutomationService(IAccessibilityManager.java:696)
at android.app.UiAutomationConnection.registerUiTestAutomationServiceLocked(UiAutomationConnection.java:399)
at android.app.UiAutomationConnection.connect(UiAutomationConnection.java:97)
at android.app.UiAutomation.connect(UiAutomation.java:234)
at android.app.UiAutomation.connect(UiAutomation.java:210)
at tv.panda.test.monkey.MonkeySourceRandomUiAutomatorMix.connect(MonkeySourceRandomUiAutomatorMix.kt:123)
at tv.panda.test.monkey.MonkeySourceRandomUiAutomatorMix.(MonkeySourceRandomUiAutomatorMix.kt:142)
at tv.panda.test.monkey.Monkey.run(Monkey.kt:558)
at tv.panda.test.monkey.Monkey$Companion.main(Monkey.kt:1422)
at tv.panda.test.monkey.Monkey.main(Unknown Source:2)
at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:341)
Caused by: android.os.RemoteException: Remote stack trace:
at com.android.server.accessibility.UiAutomationManager.registerUiTestAutomationServiceLocked(UiAutomationManager.java:88)
at com.android.server.accessibility.AccessibilityManagerService.registerUiTestAutomationService(AccessibilityManagerService.java:1354)
at android.view.accessibility.IAccessibilityManager$Stub.onTransact(IAccessibilityManager.java:159)
at android.os.Binder.execTransact(Binder.java:739)
java.lang.IllegalStateException: UiAutomation not connected!
at android.app.UiAutomation.throwIfNotConnectedLocked(UiAutomation.java:1112)
at android.app.UiAutomation.getWindows(UiAutomation.java:474)
at tv.panda.test.monkey.MonkeySourceRandomUiAutomatorMix.getWindowRoots$monkey_release(MonkeySourceRandomUiAutomatorMix.kt:685)
at tv.panda.test.monkey.MonkeySourceRandomUiAutomatorMix.collectClickable(MonkeySourceRandomUiAutomatorMix.kt:670)
at tv.panda.test.monkey.MonkeySourceRandomUiAutomatorMix.generatePointerEvent(MonkeySourceRandomUiAutomatorMix.kt:457)
at tv.panda.test.monkey.MonkeySourceRandomUiAutomatorMix.generateEvents(MonkeySourceRandomUiAutomatorMix.kt:850)
at tv.panda.test.monkey.MonkeySourceRandomUiAutomatorMix.getNextEvent(MonkeySourceRandomUiAutomatorMix.kt:92)
at tv.panda.test.monkey.Monkey.runMonkeyCycles(Monkey.kt:1155)
at tv.panda.test.monkey.Monkey.run(Monkey.kt:605)
at tv.panda.test.monkey.Monkey$Companion.main(Monkey.kt:1422)
at tv.panda.test.monkey.Monkey.main(Unknown Source:2)
at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:341)
java.util.NoSuchElementException
at java.util.LinkedList.getFirst(LinkedList.java:244)
at tv.panda.test.monkey.MonkeySourceRandomUiAutomatorMix.getNextEvent(MonkeySourceRandomUiAutomatorMix.kt:95)
at tv.panda.test.monkey.Monkey.runMonkeyCycles(Monkey.kt:1155)
at tv.panda.test.monkey.Monkey.run(Monkey.kt:605)
at tv.panda.test.monkey.Monkey$Companion.main(Monkey.kt:1422)
at tv.panda.test.monkey.Monkey.main(Unknown Source:2)
at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:341)
accessibilityservice 被其他进程占用中,可能是 appium\uiautomator\atx 等等,需要关闭后运行 max
请问这个 unregister 具体是怎么弄呀
经常跑着跑着整个手机卡住了,背景黑了,但是桌面 app 还能看到,就是点不了咋回事
大神,开源把
大神,该更新 sdk 了,现在 Android 9 已经明显不够用了
请叫大佬,没有报错,运行后直接停止什么情况?