之前在论坛看到有同行在用 MonkeyRunner 测试一些 Android 的操作, 使用的是 Python 写的脚本, 就设想应该也是可以用 java 来写脚本的, 毕竟本身 MonkeyRunner 就是用 java 写的, 并调用了一些 Android 平台的 Api. 在网上上搜索了一下 确实也可以,只是网上的例子基本都是直接使用 Android 的 api, 相对来说看起来不是那么友好, 于是本着学习的态度,就自己尝试着学习下 MonkeyRunner 的源代码, 然后试着改下, 再稍微的封装下, 于是便有了这篇帖子. 本帖子中所描述并且给出的代码, 源于 Android 的基础 Api,二次进行的简单修改, 目的在于研究和学习之用. 同时用 java 编写类似 MonkeyRunner 的代码并不需要 MonkeyRunner.jar, 特此声明.
简单说就是把 MonkeyRunner 的核心的几个类自己在写一遍, 因为本身并不复杂,所以写起来也用不了多少时间, 而且很多的方法基本都是删减点,然后直接拷贝过去就好了.
MonkeyRunner | MteMonkeyRunner | Description |
---|---|---|
MonkeyRunner | MteMonkeyRunner | 提供一些必要的操作入口,比如关键的连接设备等方法 |
MonkeyDevice | MteMonkeyDevice | 提供 Android 设备包括模拟器和真机的基本操作方法 |
MonkeyView | MteMonkeyView | 提供标准的界面 view object 的常规操作和封装 |
MonkeyImage | MteMonkeyImage | 提供截图的一些基本操作 |
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;
}
public static MteMonkeyDevice waitForConnection(long timeoutMs, String deviceId) {
setChimpChat();
IChimpDevice device = chimpchat.waitForConnection(timeoutMs, deviceId);
MteMonkeyDevice mmd = new MteMonkeyDevice(device);
return mmd;
}
java
static void setChimpChat() {
TreeMap<String, String> options = new TreeMap<String, String>();
options.put("backend", "adb");
chimpchat = ChimpChat.getInstance(options);
}
不管是 MonkeyRunner 还是我自己胡写的 MteMonkeyRunner 说穿了主要就是调用下面的几个个关键的 API:
就像前面提到的我只是把 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 就可以.