stetho是Facebook推出的安卓APP网络诊断和数据监控的工具,接入方便,功能强大,是开发者必备的好工具。
主要功能包括:
- 查看App的布局
- 网络请求抓包
- 数据库、sp文件查看
- 自定义dumpapp插件
- 对于JavaScript的支持
无需root,只要能通过adb连接设备,操作方便。
接入方法
gradle配置
因为目前我们的项目中已经集成了okhttp,只需要在build.gradle添加如下两行配置
1 2 3 4 5 6
| dependencies { compile 'com.facebook.stetho:stetho-js-rhino:1.3.1' compile 'com.facebook.stetho:stetho-okhttp3:1.4.2' }
|
初始化
在Application类中完成初始化
1 2 3 4
| private void MyApplicationCreate() { Stetho.initializeWithDefaults(mContext); }
|
使用功能
- adb方式连接到设备
- 运行debug模式的app
- 在Chrome浏览器地址栏中输入chrome://inspect
- 选择需要inspect的应用进程
查看App的布局
网络诊断
给OkHttpClient添加拦截器。
1 2 3
| new OkHttpClient.Builder() .addNetworkInterceptor(new StethoInterceptor()) .build();
|
主要功能有包括下载图片的预览,JSON数据查看,网络请求内容和返回内容
数据库、sp文件查看
自定义dumpapp插件
1 2 3 4 5 6 7 8 9 10 11 12
| Stetho.initialize(Stetho.newInitializerBuilder(context) .enableDumpapp(new DumperPluginsProvider() { @Override public Iterable<DumperPlugin> get() { return new Stetho.DefaultDumperPluginsBuilder(context) .provide(new HelloWorldDumperPlugin()) .provide(new APODDumperPlugin(context.getContentResolver())) .finish(); } }) .enableWebKitInspector(new ExtInspectorModulesProvider(context)) .build());
|
其中HelloWorldDumperPlugin和APODDumperPlugin是自定义的插件,具体内容可以参考Stetho提供的sample程序
运行dumpapp脚本后以达到与app交互通信的效果。
1 2 3 4 5 6 7
| $ ./dumpapp -l apod crash files hello hprof prefs
|
原理简介
其中dumpapp是一个python脚本,通信的方式使用的是android提供的smartsocket接口
1 2 3 4 5 6 7 8 9 10 11
| --- smartsockets ------------------------------------------------------- Port 5037 is used for smart sockets which allow a client on the host side to request access to a service in the host adb daemon or in the remote (device) daemon. The service is requested by ascii name, preceeded by a 4 digit hex length. Upon successful connection an "OKAY" response is sent, otherwise a "FAIL" message is returned. Once connected the client is talking to that (remote or local) service. client: <hex4> <service-name> server: "OKAY" client: <hex4> <service-name> server: "FAIL" <hex4> <reason>
|
使用PyCharm对Python进行断点调试:
这段脚本的功能就是通过读取/proc/net/unix
文件去找app设置的socket
- 扫描android所有提供socket功能的设备,找到steho的devtools_remote
- 建立与第一步找到的进程socket,然后通过smartsocket进行通信。
- 设备上的app相当于一个服务器,脚本是客户端对它进行访问
后缀为_devtools_remote的socket是android留给chrome的后门。
详细内容可以看这篇官方文档
这篇文档提供的例子是在命令行中输入下面的命令,就能在电脑上看到手机chrome中的内容了:
adb forward tcp:9222 localabstract:chrome_devtools_remote
打开的chrome-devtool其实是一个websocket连接。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| private void handlePageList(LightHttpResponse response) throws JSONException { if (mPageListResponse == null) { JSONArray reply = new JSONArray(); JSONObject page = new JSONObject(); page.put("type", "app"); page.put("title", makeTitle()); page.put("id", PAGE_ID); page.put("description", ""); page.put("webSocketDebuggerUrl", "ws://" + mInspectorPath); Uri chromeFrontendUrl = new Uri.Builder() .scheme("http") .authority("chrome-devtools-frontend.appspot.com") .appendEncodedPath("serve_rev") .appendEncodedPath(WEBKIT_REV) .appendEncodedPath("devtools.html") .appendQueryParameter("ws", mInspectorPath) .build(); page.put("devtoolsFrontendUrl", chromeFrontendUrl.toString()); reply.put(page); mPageListResponse = LightHttpBody.create(reply.toString(), "application/json"); } setSuccessfulResponse(response, mPageListResponse); }
|
在android上的服务端socket写法,
详见LocalSocketServer类的listenOnAddress方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| private void listenOnAddress(String address) throws IOException { mServerSocket = bindToSocket(address); LogUtil.i("Listening on @" + address); while (!Thread.interrupted()) { try { LocalSocket socket = mServerSocket.accept(); Thread t = new WorkerThread(socket, mSocketHandler); t.setName( WORKER_THREAD_NAME_PREFIX + "-" + mFriendlyName + "-" + mThreadId.incrementAndGet()); t.setDaemon(true); t.start(); } catch (SocketException se) { if (Thread.interrupted()) { break; } LogUtil.w(se, "I/O error"); } catch (InterruptedIOException ex) { break; } catch (IOException e) { LogUtil.w(e, "I/O error initialising connection thread"); break; } } LogUtil.i("Server shutdown on @" + address); }
|
对于JavaScript的支持
Chrome开发者工具原生支持JavaScript,所以Stetho也提供了JavaScript的支持。
通过在console中输入如下代码可以让设备app弹出一个toast
1 2 3 4
| importPackage(android.widget); importPackage(android.os); var handler = new Handler(Looper.getMainLooper()); handler.post(function() { Toast.makeText(context, "Hello from JavaScript", Toast.LENGTH_LONG).show() });
|
更多玩法见Rhino on Stetho
相关链接
http://facebook.github.io/stetho/
https://github.com/facebook/stetho/tree/master/stetho-js-rhino
https://www.figotan.org/2016/04/18/using-stetho-to-diagnose-data-on-android/
https://developer.chrome.com/devtools/docs/remote-debugging-legacy
https://android.googlesource.com/platform/system/core/+/master/adb/protocol.txt