之前做app功能遍历的项目中使用的是monkeyrunner+hierarchyviewer的方式,但是hierarchyviewer提供的信息太多而且无用的信息居多,所以想换成monkeyrunner+uiautomatorviewer的方式来做。但是在集合的时候调用monkeyrunner和uiautomator时出错:
public void test_Exception() {
System.setProperty("com.android.uiautomator.bindir", "D:/sdk/tools");
DebugBridge.init();
MyDeviceManager manager = null;
IDevice idevice = null;
try {
Thread.sleep(3000);
List<IDevice> devices = DebugBridge.getDevices();
idevice = devices.get(0);
manager = new MyDeviceManager(idevice);
getUIHierarchy(idevice);
} catch (Exception e) {
e.printStackTrace();
} finally {
manager.dispose();
DebugBridge.terminate();
}
}
private void getUIHierarchy(IDevice idevice) {
String path = System.getProperty("user.dir") + File.separator + "xml" + File.separator + "uidump.xml";
String command = String.format("%s %s %s", new Object[] { "/system/bin/uiautomator", "dump",
"/data/local/tmp/qianhui.xml" });
CountDownLatch commandCompleteLatch = new CountDownLatch(1);
try {
idevice.executeShellCommand(command, new CollectingOutputReceiver(commandCompleteLatch), 40000);
commandCompleteLatch.await(40L, TimeUnit.SECONDS);
System.out.println("Pull UI XML snapshot from device...1212");
idevice.getSyncService().pullFile("/data/local/tmp/qianhui.xml", path, SyncService.getNullProgressMonitor());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
在MyDeviceManager构造方法中执行的是创建monkey对象:
public MyDeviceManager(IDevice iDevice) {
this.mIDevice = iDevice;
this.mAdbChimpDevice = new AdbChimpDevice(iDevice);
/*String width = mAdbChimpDevice.getProperty("display.width");
System.out.println(width);
String height = mAdbChimpDevice.getProperty("display.height");
System.out.println(height);
sWidth = Integer.parseInt(width);
sHeight = Integer.parseInt(height);*/
}
当我执行上面的代码时报错:
06-01 17:06:47.897: E/AndroidRuntime(3007): *** FATAL EXCEPTION IN SYSTEM PROCESS: main
06-01 17:06:47.897: E/AndroidRuntime(3007): java.lang.IllegalStateException: UiAutomationService android.accessibilityservice.IAccessibilityServiceClient$Stub$Proxy@421baa38already registered!
06-01 17:06:47.897: E/AndroidRuntime(3007): at android.os.Parcel.readException(Parcel.java:1473)
06-01 17:06:47.897: E/AndroidRuntime(3007): at android.os.Parcel.readException(Parcel.java:1419)
06-01 17:06:47.897: E/AndroidRuntime(3007): at android.view.accessibility.IAccessibilityManager$Stub$Proxy.registerUiTestAutomationService(IAccessibilityManager.java:342)
06-01 17:06:47.897: E/AndroidRuntime(3007): at android.app.UiAutomationConnection.registerUiTestAutomationServiceLocked(UiAutomationConnection.java:175)
06-01 17:06:47.897: E/AndroidRuntime(3007): at android.app.UiAutomationConnection.connect(UiAutomationConnection.java:72)
06-01 17:06:47.897: E/AndroidRuntime(3007): at android.app.UiAutomation.connect(UiAutomation.java:188)
06-01 17:06:47.897: E/AndroidRuntime(3007): at com.android.uiautomator.core.UiAutomationShellWrapper.connect(UiAutomationShellWrapper.java:32)
06-01 17:06:47.897: E/AndroidRuntime(3007): at com.android.commands.uiautomator.DumpCommand.run(DumpCommand.java:74)
06-01 17:06:47.897: E/AndroidRuntime(3007): at com.android.commands.uiautomator.Launcher.main(Launcher.java:83)
06-01 17:06:47.897: E/AndroidRuntime(3007): at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
06-01 17:06:47.897: E/AndroidRuntime(3007): at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:271)
06-01 17:06:47.897: E/AndroidRuntime(3007): at dalvik.system.NativeStart.main(Native Method)
06-01 17:06:47.907: E/ServiceManager(3007): error in getService
06-01 17:06:47.907: E/ServiceManager(3007): android.os.RemoteException: Unknown binder error code. 0xfffffff7
06-01 17:06:47.907: E/ServiceManager(3007): at android.os.BinderProxy.transact(Native Method)
06-01 17:06:47.907: E/ServiceManager(3007): at android.os.ServiceManagerProxy.getService(ServiceManagerNative.java:123)
06-01 17:06:47.907: E/ServiceManager(3007): at android.os.ServiceManager.getService(ServiceManager.java:55)
06-01 17:06:47.907: E/ServiceManager(3007): at android.app.ActivityManagerNative$1.create(ActivityManagerNative.java:2152)
06-01 17:06:47.907: E/ServiceManager(3007): at android.app.ActivityManagerNative$1.create(ActivityManagerNative.java:2150)
06-01 17:06:47.907: E/ServiceManager(3007): at android.util.Singleton.get(Singleton.java:34)
06-01 17:06:47.907: E/ServiceManager(3007): at android.app.ActivityManagerNative.getDefault(ActivityManagerNative.java:76)
06-01 17:06:47.907: E/ServiceManager(3007): at com.android.internal.os.RuntimeInit$UncaughtHandler.uncaughtException(RuntimeInit.java:86)
06-01 17:06:47.907: E/ServiceManager(3007): at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:693)
06-01 17:06:47.907: E/ServiceManager(3007): at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:690)
06-01 17:06:47.907: E/ServiceManager(3007): at dalvik.system.NativeStart.main(Native Method)
06-01 17:06:47.917: I/Process(3007): Sending signal. PID: 3007 SIG: 9
06-01 17:06:47.917: E/AndroidRuntime(3007): Error reporting crash
06-01 17:06:47.917: E/AndroidRuntime(3007): java.lang.NullPointerException
06-01 17:06:47.917: E/AndroidRuntime(3007): at com.android.internal.os.RuntimeInit$UncaughtHandler.uncaughtException(RuntimeInit.java:86)
06-01 17:06:47.917: E/AndroidRuntime(3007): at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:693)
06-01 17:06:47.917: E/AndroidRuntime(3007): at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:690)
06-01 17:06:47.917: E/AndroidRuntime(3007): at dalvik.system.NativeStart.main(Native Method)
而当我把
manager = new MyDeviceManager(idevice);
getUIHierarchy(idevice);
的位置调换一下,执行成功。所以我怀疑monkeyrunner在启动的时候已经创建了uiautomator的对象,才会造成上面的提示错误,所以我试图去查看一下monkeyrunner到底有没有做这件事。
查看AdbChimpDevice创建的源码,发现
String command = new StringBuilder().append("monkey --port ").append(port).toString();
executeAsyncCommand(command, new LoggingOutputReceiver(LOG, Level.FINE));
这一步是打开monkey,在cmd下执行该命令就能知道:
通过这条命令我找到了system/bin下的monkey脚本:
# Script to start "monkey" on the device, which has a very rudimentary
# shell.
#
base=/system
export CLASSPATH=$base/framework/monkey.jar
trap "" HUP
exec app_process $base/bin com.android.commands.monkey.Monkey $*
然后用dex2jar工具将其编译成classes_dex2jar.jar,然后用JD-GUI打开。
找到了执行的方法,但是没发现执行uiautomator的函数。继续看AdbChimpDevice里方法一路跟踪到ChimpManager这个类,在AdbChimpDevice执行力该类的wake()方法:
public void wake()
throws IOException
{
sendMonkeyEvent("wake");
}
private String sendMonkeyEventAndGetResponse(String command)
throws IOException
{
command = command.trim();
LOG.info(new StringBuilder().append("Monkey Command: ").append(command).append(".").toString());
this.monkeyWriter.write(new StringBuilder().append(command).append("\n").toString());
this.monkeyWriter.flush();
return this.monkeyReader.readLine();
}
最终向12345端口的socket发送了一条wake的命令。
很不幸,被我言中了。看来将uiautomator内置进来,还不是一件轻松的事情!