前言

之前在论坛看到有同行在用 MonkeyRunner 测试一些 Android 的操作, 使用的是 Python 写的脚本, 就设想应该也是可以用 java 来写脚本的, 毕竟本身 MonkeyRunner 就是用 java 写的, 并调用了一些 Android 平台的 Api. 在网上上搜索了一下 确实也可以,只是网上的例子基本都是直接使用 Android 的 api, 相对来说看起来不是那么友好, 于是本着学习的态度,就自己尝试着学习下 MonkeyRunner 的源代码, 然后试着改下, 再稍微的封装下, 于是便有了这篇帖子. 本帖子中所描述并且给出的代码, 源于 Android 的基础 Api,二次进行的简单修改, 目的在于研究和学习之用. 同时用 java 编写类似 MonkeyRunner 的代码并不需要 MonkeyRunner.jar, 特此声明.

MonkeyRunner 基本结构

基本思路

简单说就是把 MonkeyRunner 的核心的几个类自己在写一遍, 因为本身并不复杂,所以写起来也用不了多少时间, 而且很多的方法基本都是删减点,然后直接拷贝过去就好了.

扩展对照

MonkeyRunner MteMonkeyRunner Description
MonkeyRunner MteMonkeyRunner 提供一些必要的操作入口,比如关键的连接设备等方法
MonkeyDevice MteMonkeyDevice 提供 Android 设备包括模拟器和真机的基本操作方法
MonkeyView MteMonkeyView 提供标准的界面 view object 的常规操作和封装
MonkeyImage MteMonkeyImage 提供截图的一些基本操作

举个栗子

MonkeyRunner

public static MonkeyDevice waitForConnection(PyObject[] args, String[] kws) {
    ArgParser ap = JythonUtils.createArgParser(args, kws);
    Preconditions.checkNotNull(ap);

    long timeoutMs;
    try {
        double timeoutInSecs = JythonUtils.getFloat(ap, 0);
        timeoutMs = (long) (timeoutInSecs * 1000.0);
    } catch (PyException e) {
        timeoutMs = Long.MAX_VALUE;
    }

    IChimpDevice device = chimpchat.waitForConnection(timeoutMs,
            ap.getString(1, ".*"));
    MonkeyDevice chimpDevice = new MonkeyDevice(device);
    return chimpDevice;
}

MteMonkeyRunner

public static MteMonkeyDevice waitForConnection(long timeoutMs, String deviceId) {
    setChimpChat();
    IChimpDevice device = chimpchat.waitForConnection(timeoutMs, deviceId);

    MteMonkeyDevice mmd = new MteMonkeyDevice(device);

    return mmd;
}

必要的了解

不管是 MonkeyRunner 还是我自己胡写的 MteMonkeyRunner 说穿了主要就是调用下面的几个个关键的 API:

MteMonkeyRunner 基本结构

就像前面提到的我只是把 MonkeyRunner 几个主要的类重写和拷贝了下, 在简单的进行了修改.只有四个主要的类文件.其实就是本人无耻的把对应方法中分析 python 参数的代码都删除掉了. 因为出发点为用 java 直接写代码, 所以并没有重新写个 UI 出来, 但是我分析过 MonkeyRunner 对应的界面代码, 真是挺对付的....

举个栗子

package test.example.testcase;

import java.util.Collection;

import com.mte.android.mmr.MteMonkeyDevice;
import com.mte.android.mmr.MteMonkeyImage;
import com.mte.android.mmr.MteMonkeyRunner;
import com.mte.util.DateTimeUtil;

public class MteMonkeyRunnerTest {

    public static void main(String args[]){

        String apppath="./app/android/oschina/osc-android-app-2.2.apk";
        String packageName="net.oschina.app";
        String startActivity="net.oschina.app/.AppStart";

        MteMonkeyDevice device=MteMonkeyRunner.waitForConnection(100000,"HC477WY00656");

        System.out.println("Device name is : " + device.getProperty("build.model"));

        for(String prop:device.getPropertyList()){

            System.out.println(prop +" : "+device.getProperty(prop));
        }

        device.installPackage(apppath);

        device.startActivity(startActivity);

        MteMonkeyRunner.sleep(30000);

        MteMonkeyImage image=new MteMonkeyImage(device.takeSnapshot());

        image.writeToFile("./screen/MteMonkeyRunnerTest"+DateTimeUtil.getCurrentDateTime()+".png", "png");

        MteMonkeyRunner.sleep(10000);


        Collection<String> viewLst=device.getViewIdList();

        System.out.println("device.getViewIdList() is : "+viewLst.size());

        if(viewLst.size()>=1){
            for(String prop:viewLst){
                System.out.println(prop);
            }
        }

        MteMonkeyRunner.sleep(20000);

        device.removePackage(packageName);

        device.dispose();

    }

}

可能出现的问题以及免责声明

本人在写完基本方法测试脚本的时候, 有时候发现 当我使用 device.shell() 或者是 device.getViewIdList() 等方法时候,会抛出异常, 而且在真机通过了,反而在模拟器上出现问题, 虽然花时间找了下解释, 但是基本上算是没解决, 我在见了自己的 MteMonkeyRunner 的类的时候,只是删除了对应的 python 的参数处理,而且关键的方法基本没变, 怀疑是本人的 Mac 环境问题,所以本人也很无奈, 大家如果有兴趣在使用的时候,请注意并请见谅.写的这些本身就是为了学习研究, 通过一些很具体的实践加深了解, 分析源代码是非常有效的学习方式.

参考

本帖子中的 MteMonkeyRunner 所有源代码都可以在 https://github.com/PandaSense/mtesense 中下载到,包名为 com.mte.android.mmr, 可以单独使用, 只要你把,帖子前面说明的五个 jar 添加到对应 project 的 java build path 就可以.

其他设想


↙↙↙阅读原文可查看相关链接,并与作者交流