自动化工具 (无需 Root) 基于 Android Monkey 二次开发,实现高速点击的 Android Monkey 自动化工具 fastmonkey - 代号 Maxim

zhangzhao_lenovo · 2018年01月19日 · 最后由 15220110112 回复于 2023年07月13日 · 26496 次阅读
本帖已被设为精华帖!

打造一款快速高效且高度可复用的 android 自动化测试工具 (qq 1 群 :608824162(已满) qq 2 群:745653339)

主页入口 请点我
https://github.com/zhangzhao4444/Maxim

优势

  1. 高速点击,每秒 10-15 action!
  2. 多平台兼容! 同时兼容 Android 5-9
  3. 轻量极简!

如何使用

  1. adb push  framework.jar  monkey.jar  文件到 /sdcard
  2. 执行 
    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 楼

参数说明

  1. tv.panda.test.monkey.Monkey 主调入口  无需修改
  2. -p com.panda.videoliveplatform  待测 appid
  3. 策略模式

    --uiautomatormix 混合模式(70% 控件解析随机点击,其余 30% 按原 Monkey 事件概率分布) 
    --pct-uiautomatormix n 可自定义混合模式中控件解析事件概率
    --uiautomatordfs DFS 深度遍历算法(优化版)(注 Android5 不支持 dfs)
    --uiautomatortroy Troy 模式 见(#74 楼
    非以上两种为原始 Monkey 策略

  4. 执行时长
    --running-minutes 60        执行 60 分钟 monkey

  5. 场景细粒度控制
    --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        同上

  6. 其他参数及用法同原始 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// ")}")
            ....
}    

todo

  1. 特殊事件序列 - 已完成
  2. 引入 GT 性能测试
  3. 控件黑名单 - 已完成
  4. xposed 模式 --见 xmonkey
  5. Ai 算法 模式

** 其他 **

扫盲贴: https://testerhome.com/topics/11884

常见问题排查

  1. 小米手机未开启 “开发者选项” -> "USB 调试(安全设置)允许通过 usb 调试修改权限或模拟点击"。
    开启后 ok 。报错 log 如下图

  2. accessibilityservice 被其他驱动占用 agent 未注销。如使用过 atx 未执行 unregister。
    执行 unregister 后 OK。报错 log 如下图,或无 log


  3. 厂商修改造成 dex 无法 load ,maxim 启动后就退出。实际什么都未执行。无 log 输出。 logcat 如下图。此问题暂时待查

4.运行 maxim 无任何 log,启动后就退出。需检查/sdcard/是否存在 monkey.jar ,framework.jar。部分机型发现 adb push 过去 monkey.jar 自动被更名成 monkey. 导致无法运行。

5.vivo7.1 运行 maxim 报错,需要关闭锁屏和开启 usb 模拟点击 ,然后就可以跑 monkey 了。报错如下:

update

#40 楼
支持特殊事件序列 max.xpath.actions
如何查看特殊事件 log #79 楼

#44 楼 #52 楼
支持屏蔽黑控件或黑区域 max.widget.black

#57 楼
支持截图,dump xml
崩溃回溯式截图 #92 楼

#74 楼
Troy 模式

#169 楼
Monkeyapi

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 213 条回复 时间 点赞

给力,用起来

4楼 已删除

学习一下,之前想改一直没真正找到点,没敢下手。

期待一下特殊事件序列

高速点击不应该是核心测试需求的诉求吧,实际的压测需要有页面缓冲、动效显示、图片加载的处理间隔,还应有等待回收逻辑处理完成,所以还是模拟用户行为间隔更重要。否则会引起研发不认可的 bug 及内存泄露压力不够的问题。

浮云 回复

高速是指解析界面算法。如果觉得 event 太快可以自行添加 Throttle。 速度不够何谈压力

思寒_seveniruby 将本帖设为了精华贴 01月23日 20:47

哦,原来指的是算法能力上能支持高速点击。实际压测还是要分压测场景和压测目的具体平衡事件比例,过快的操作更多考验的是未完成事件的中断,往往会发生用户正常操作不会遇到的 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 命令参数可能输错了。把你的 adb shell 那条命令发来看看

匿名 #14 · 2018年01月25日

很感谢分享,想问一下如何修改 monkey 源码进行二次开发?主要对这个过程感兴趣,网上这方面的资料很少,方便的话可以详细说一下过程吗?小白也想试试自己改一下

加 q 群说吧。这个简单一两句说不清楚

匿名 #16 · 2018年01月25日

额 不知道 Q 群是多少?方便告知一下吗

匿名 #17 · 2018年01月25日

看到了 谢谢

仅楼主可见
斯拉 回复

加 q 说吧

497703927

源码方便放到 github 上么?

spring-ssh 回复

后续会开源的,请关注

移动终端需要 root 权限吧

寒月守护 回复

不需要 root

仅楼主可见
寒月守护 回复

“开发者选项” -> "USB 调试(安全设置)允许通过 usb 调试修改权限或模拟点击" 这个可否打开了?

"USB 调试(安全设置)允许通过 usb 调试修改权限或模拟点击"这个打开后就可以了,给力!👍

老马 Maxim-高速 Android Monkey 工具使用记录 中提及了此贴 02月03日 11:04
zhangzhao_lenovo Android 的 Monkey Test 疑问 中提及了此贴 02月05日 20:04
zhangzhao_lenovo monkey 稳定性测试 中提及了此贴 02月05日 20:08
zhangzhao_lenovo Android 性能测试之 Monkey 中提及了此贴 02月05日 20:09

方便给下群号吗 我也想加群 了解下,自带的 monkey 太随机了

zhanglimin 回复

qq 群 :608824162

2018.02.23 update

  1. 增加支持 特殊事件序列(mix dfs troy 均支持)

需要配置 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 检查格式,注意” : , 非中文

将该文件 push 到 /sdcard/max.xpath.actions

如果要执行的一个事件序列,执行过程中会出现 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

老马 回复

帮助文档里有写这个,配置命名我规范了下 之前太随意了

zhangzhao_lenovo Monkey 测试基本操作介绍 (一) 中提及了此贴 02月26日 19:47

2018.02.28 update

  1. 支持黑控件 黑区域屏蔽(mix dfs troy 均支持)

配置 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 就停止了

东子 回复

monkey 停打印的 log 是什么? 加我 q 下 77227005 调试看下问题

楼主,这个不提供源码吗

chunyong 回复

还得过段时间。

按照楼主的操作文档执行了之后,为什么没有反应呢? 我是华为 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 麻烦楼主帮忙看下是什么原因

王华 回复

贴里 有三处 "常见问题排查"
可以先排查看看 或加我 q

先赞一个

关于黑控件 max.widget.black
-v -v -v -v 4 级 log 可以看到 blackWidget

生成:
每次刷新 activity 生成黑区域 会对控件 tree 按 xpath 进行 search,若找到则加入黑区域 或只配 bounds 则直接加入黑区域.

检测:
有 2 种:

  1. 获取控件 tree 时 如果一个控件在 黑区域内 会打印 inside black List 。该控件不会加入到后续点击队列
  2. 随机 point 时 如果 point 在 黑区域内 会打印 in pointer event:mblackwidgets 。会重新映射到黑区域外取 point。再执行点击 point

关于如何脱机运行(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 cmd 支持& 吗?

老马 回复

问这个脱机的人很多,我原来就不知道。

老马 回复

这个和 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 的一样么

thanksdanny 回复

嗯基本一致。只是将崩溃堆栈重定向输出到 log

😁 好的谢谢!今晚试用了下觉得很不错啊,想把他替换掉原生的 monkey 来用了

666,做的很棒。appium 底层的 uiautomate2 server 在解析 xpath 的时候有点 bug,我也在想着如何改进。你后续可以尝试支持下 webdriver 协议了。

thanksdanny 回复

多谢支持,有建议或问题 可随时 q 我

今年大会你可以这个开源项目提交个 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

hover 回复

你那里报错了吗? 加 q 群吧 看下 log

仅楼主可见
MJW 回复

qq 我下帮你看下原因 77227005

手机设置了不锁屏,发现跑的过程中会被锁屏,不知道大家遇到过这个情况没有?

你好,请问支持页面滑动吗

Caroline 回复

支持的

大神坐等源码,最近也在研究 monkey 源码,也想改造适合自己使用的 monkey

2018.03.22 update

  1. TROY 模式(支持特殊事件、黑控件等) 配置 max.xpath.selector troy 控件选择子来定制自有的控件选择优先级,例子如下
[
{
    "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

zhangzhao_lenovo 关于 monkey 的--throttle 参数 中提及了此贴 04月28日 17:57

用来压力测试很不错
楼主, 这个工具有开源的计划吗?

zsg5566 回复

github 上已有 dfs 算法 可以参考

关于特殊事件的 log 如何查看?

  1. Max 运行 开头会打印出 load 的 Special Event

  2. 解析生成 Tree 结构

分别表示
index|height|depth|childCount|descendantCount,className,contentDesc,text,xpath,clickable,rect

3.针对一个 xpath 进行查找
找到打印 Find it,已经对应执行的 event

匿名 #80 · 2018年05月22日

[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 端吗?

Smile 回复

你的参数传错了
正确的: --output-directory /sdcard/MonkeyLog

这个 output 目录 主要是保存 crash,anr traces,截图,pagesources xml

关于 max 标准输出流和异常流 可以重定向保存到 pc github 上有个 issue 有说明

谢谢~ 也可以通过 > 保存全部的 log 是吧~

再膜拜一下大神~~这个比原生的 monkey 要好用很多😊

Smile 回复

adb shell xxx >log.txt 2>err.txt

匿名 · #87 · 2018年05月29日
仅楼主可见

关于 crash-dump.log 及 崩溃捕获

一般如果 app 自己实现了 crash 上报的功能 就会去重写这个 defaultUncaughtHandler 接口,如果 app 没有捕获 crash, ActivityManagerProxy 会调 handleApplicationCrash 进入系统 crash 处理流程(如上图)

UIHandler.sendMessage 就是我们最常见的 app 弹了个 无响应的弹窗。我们主要关注 ams.crashApplication(下图红框)

monkey 里实现了 这个 IActivityController.appCrashed 回调,于是乎就把 crash 记录下来了。

源码参考
http://gityuan.com/2016/06/24/app-crash

针对这个,我这边的尝试是把截图藏在 PC 端,可以使用 minicap 工具

楼主,我问下,不同版本的 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。麻烦能讲解下吗?

轩天 回复

注入 event 时 point 选取范围去掉状态栏区域

Boxer 回复
  1. 可以拿到具体 view 元素, 最终 click 的也是对应元素的坐标
  2. DFS.kt 就对应 dfs 深度遍历算法

每分钟 100-200 截图,故因大量截图对手机空间要求较高,仅为复现崩溃时建议开启截图

想问下怎么做到仅在复现崩溃时开启截图?
是使用崩溃回溯式截图这个功能吗?

群主是狗 回复

是的,使用崩溃回溯式截图

monkey.jar 的是下发指令执行操作的,那这个 framework.jar 是做什么的用的,他跟原生的/system/framework.jar 有什么区别

仅楼主可见

膜拜大神,坐等开源

simple 专栏文章:[精华帖] 社区历年精华帖分类归总 中提及了此贴 12月13日 14:44

命令: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 被禁用了。

106楼 已删除

出现 crash 或者 anr 的后,还会继续执行 monkey 吗,直到达到设定时间才会停止么?

Leo 回复

嗯。

109楼 已删除
wenxiaomao MixMonkey 基于 Android Monkey 中提及了此贴 12月31日 21:49

支持出现 crash 或者 anr 后即停止 monkey 运行么?

如果运行多轮 monkey,那么每轮出现的 crash 信息或者 oom traces 是追加还是覆盖写入 sdcard/crash-dump.log 和/sdcard/oom-traces.log?

Leo 回复

追加写入

Leo 回复

--ignore-crashes 原 monkey 有个参数如果不设置就是你说的这个场景。 但是如果启用了--running-minutes 则 crash 后会继续执行

simple [精彩盘点] TesterHome 社区 2018 年 度精华帖 中提及了此贴 01月07日 12:08

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,附上测试机型:

  1. google nexus 6 Android 版本:7.1.1
  2. 魅族 15 Android 版本:7.1.1
  3. OPPO R17 Android 版本:8.1.0
Viking Den 回复

hello 加我 qq 77227005,看上去问题不大

simple 有没有啥定制 monkey 的方法? 中提及了此贴 01月16日 09:57
120楼 已删除

在 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 还有什么用?

foly2019 回复

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 请教一下吗

楼主,崩溃回溯截图的实现原理是什么呢,有没有相关资料

Bach 回复

每个 event 异步截图 bitmap 入栈,崩溃回调时做出栈本地回写

谢谢,还有一个问题,比如我跑一次出了 n 次崩溃,设置了 50 张的回溯区间,那么这些截图是怎么分配的呢。

Bach 回复

倒序 50 张,不满 50 的有多少存多少。 连续崩溃的主看第一次崩溃截图

max.xpath.actions 这里面的点击事件能不能根据 id 进行点击呢,我发现我们的 app 找不到 xpath 路径了

TD 回复

id 可以
"xpath": "//*[@resource-id='com.longzhu.tga:id/edit_phone_num']",

TD · #136 · 2019年03月07日
仅楼主可见
TD 回复

index 没错就没问题

谢谢,我想起来是没有选中 ADBKeyBoard,但是我在键盘管理选了这个之后,输入框能输入了,但是有几个问题还不明白还要请教一下:1、登录的按钮我用了 click,id,index 都是对的但是不点击,反而点了另外一个按钮;2、在其他页面也有输入框之前是可以随机输入的,现在我的 max.xpath.actions 只配置了输入用户名密码的,其他的输入框现在都不能输入了,这个是正常现象吗?

TD 回复

选择 ADBKeyBoard 之后,只有用户名密码的输入框可以输入,而且有时候也是输入不全的,比如我配置输入的是 autotest,输入的只有 auto

TD 回复

输入不全是因为 throttle 太小了

TD 回复

哦哦,那现在我的 max.xpath.actions 只配置了输入用户名密码的,其他的输入框现在都不能输入了,这个是正常现象吗?

TD 回复

max.config 里配置 max.randomPickFromStringList = true
并配置 max.strings 几条随机输入的 text。
其他输入框就按 strings 里的随机选中输入

好的,谢谢,我试一下

ovwane [该话题已被删除] 中提及了此贴 03月09日 22:49

请问下 api 适配中 findMethod 是怎么实现的呢?可以说下吗?因为有时候用 clazz.getDeclaredMethod(xx) 不生效,setAccessible(true) 也不行,所以想知道下怎么实现的呢

这个支持遍历 webview 吗?

Jiizukelee 回复

试一下?

匿名 #148 · 2019年04月12日

请教一下,执行 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

匿名 #150 · 2019年04月15日

找到原因了 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 增加这个延迟时间试试。 要么是这个设备性能太差了

你这个问题找到原因了没,老哥

foly2019 回复

我跟你遇到相同的问题,也是配置了 max.widget.black 不生效,但是配在 max.xpath.selector 的 blackList 里面是有效的,你后来有研究过怎么让 max.widget.black 生效吗?

思寒_seveniruby [该话题已被删除] 中提及了此贴 05月16日 20:48

请问老哥,你是采用什么方式在 Monkey.jar 里面截图的?
Surface ? screencap -p?

遇到和斯拉一样的问题,求解

isally 回复

更新下 新版 monkey.jar 再试试

158楼 已删除

log 上看没有 find it ,说明 xpath 没找到。检查下是不是 Index 配错了?

仅楼主可见

楼主你好,我想问下我使用了 appetizer 运行 Maxim,配置都设置好了,点击开始测试后,控制台输出为空,而且没有执行 adb 命令,这是为什么呢?如果不使用 appetizer 只使用 adb 命令就没问题

张荣 回复

我也发现了 appertizer 中的命令复制之后 缺少 adb shell 是不是这个原因

poison 回复

log 发一下看看

MBF 回复

可能是 apperitizer 出 bug 了

zhang 大大,10 系统可以支持了不~~~

楼主,修改 max.xpath.actions 后,push 到手机中,安装完 ADBKeyBoard.apk,执行命令登录页输入指定的用户名后不切换到密码输入栏,直接清除了用户名,在该栏输入密码。
请问是什么原因

请教一下能控制输入时间占比,让他快点结束吗?目前我们执行 monkey 用的 mix 模式,经常在一个输入框执行很久,也不出来,这有什么办法解决吗?

田雨 回复

检查下 xpath 配置是否正确,结合 log 看下

TD 回复

adbkeyboard 安装了吗? 或者使用随机填充字符串

2019.08.16 update
1.mix 增加 back event 默认事件占比 10%
--pct-back 5 (设置占比 5)

2.mix 增加 重启 app event 默认事件占比 0.3%
--pct-reset 0 (关闭重启 事件)

  1. mix 增加 null intent event 默认事件占比 0.2% 该事件探测 app 中 exported 组件,随机发 null intent --pct-nullintent 0 (关闭 null intent 事件)

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

终于有更次新了!

更新了吗,白嫖怪已就位

思寒_seveniruby [该话题已被删除] 中提及了此贴 09月04日 14:50

难受呀大佬,刚启动就结束了

测试zzZ 回复

logcat 中看下这个启动有什么报错?

请教下,比如我想点击屏幕指定一块区域,这个指定区域是要怎么计算的。

目前的执行结果里看到有一个 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% ?

178楼 已删除

app 无限启动退出,报错信息:

[Maxim] *** ERROR // : the top activity package com.miui.home is invalid.

如果是在 app 已经启动的状态下,就可以开始遍历

sampling 是采样没有对外开放,coverage 就是 activity 覆盖率,你这里是 20%

你的 app 没有 launch?

大神你好,想问问如何实现多台手机同时跑 monkey

apk 已经加固了,可以用吗,目前用的未加固的挺好用的

feifei123000 回复

adb -s xxdevice-id shell xxx

6dingdong6 回复

可以

好的,谢谢。感谢分享这么好的工具

仅楼主可见

怎么调整频率,不想跑的那么快

feifei123000 回复

正常 log,意思是当前 activity 非待测 app 的。

刘博琛 回复

--throttle xxx

大神,这个 Android9 支持吗?

阿卡测 回复

5-10 都支持

我这边可以正常开始跑, 但是跑的中途会因为
ERROR // : the top activity package com.bbk.launcher2 is invalid.
这个错误而导致 app 重启, 请问一般是什么原因引起的?

MannixZ 回复

命中防跳出机制,当前 activity 非待测 app 的,所以会立即执行切回原 app

我不是很明白为什么会突然跳到这个线程上,因为我看到在跑的设备前台一直在运行我需要测试的 app

能支持记录崩溃前的操作事件吗?光看截图看不出

Viking Den 回复


android 9 的 Oppo R17。已走到需要输入的地方就报错,adbkeyboard 已安装并且能够正常使用。请问是什么原因,如何解决?

想问下楼主,如何防止应用登出账号,因为我这边登出账号后就再也登陆不进去了,ps:应用只能微信登陆

lcmouse 回复

配置 widget 黑名单,屏蔽掉退出登录按钮

设置模块怎么跑呢 里面有很多其他的包名,怎么做到遍历呢


当设备不支持 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 上么。

6dingdong6 回复

max.config 是需要 push 到 /sdcard

6dingdong6 回复

我的也是空的 我的配置文件和你配置的一样 也把配置文件 push 到 sdcard 上了,。。。请问解决了吗😭 😭 😭 😭 😭

芋泥波波 回复

小写 true

还有个问题,,,为什么在 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.

芋泥波波 回复

json 格式有错误

为什么 com.tencent.qqmusic.activity.AppStarterActivity 已经加入黑名单了,还能 resume??
[Maxim] // activityResuming(com.tencent.qqmusic)
[Maxim] // : debug, currentActivity is com.tencent.qqmusic.activity.AppStarterActivity

liaili521 回复

log 开头会打印 blacklist 先确认下配置是否生效?

[Maxim] // DisallowActivity: com.tencent.qqmusic.activity.AppStarterActivity
开头日志里面是有生效的

这个 monkey 支持 Android10 的吗

@zhangzhao_lenovo 大神,能否适配一下 Android10 的手机呢,最近跑 Android10 的稳定性,跑不起来呢。

TD 回复

git 上最新版是支持的

好的,谢谢,新版本可以的👍

我想问下,就是当前测试的 activity 正是 我想要测试的 app,但是日志中却提示要 stop 我正在测试的 package,然后后台就把这个 app 进程杀掉了,然后又监测到当前 activity 是 huawei.launcher,就又重启应用。我想问下,明明一切正常并没有 crash,为什么会杀掉进程?是 maxim 代码有点问题么?感谢回复

6dingdong6 回复

红框上一步是命中了 RESET EVENT 就是重启 app,重启的过程就是把 app kill 掉然后再启动
top activity huawei xxx is isvalid 是指当前在桌面非待测 APP,下一步就启动 app

除了 crash 其他异常的 log 能捕获么

crash 目录生成了,但是目录里头没有图片是什么情况呢?

MannixZ 回复

同问。。。你有了解到为什么吗?

221楼 已删除

你好,一个模拟器指定了设备 id 能正常跑,再开启一个模拟器就立即停止了。

test258 回复

为什么要启动多个?我记得允许多台,adb -s xxdevice-id shell xxx

晓只 回复

图片在你指定输出位,比如我指定在/SDCARD/MKLOG,还有一种情况是,响应时间小于 200 毫秒是不截图的

这个问题是怎么解决的啊

TD 回复

@zhangzhao_lenovo 大神,Android11 的是不是也没适配,我看了一下和 Android10 一样的报错呢,麻烦更新一下哈,谢谢了

请问一下大佬,如何关闭 屏幕 180 度翻转啊? 发现每次跑 maxim 都会发生 180 度翻转,导致黑区域坐标有变化。

Viking Den 回复

请问这个解决了,我也是报了一样的错误

请问下楼主是怎么处理执行过程中把网络关了的情况

如果 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)

TD 回复

accessibilityservice 被其他进程占用中,可能是 appium\uiautomator\atx 等等,需要关闭后运行 max

这个进程可以用什么命令直接关掉吗?


请问这个 unregister 具体是怎么弄呀

经常跑着跑着整个手机卡住了,背景黑了,但是桌面 app 还能看到,就是点不了咋回事

大神,开源把

大神,该更新 sdk 了,现在 Android 9 已经明显不够用了

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册