之前做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(); }
很不幸,被我言中了。看来将uiautomator内置进来,还不是一件轻松的事情!