最近,我负责将Stetho集成到我们项目中。集成过程中,免不了出现一些坑,在此记录填坑之路。
Stetho 是一个功能强大的 Android 应用调试桥,起到桥梁的作用,连接 Android 应用和 Chrome,通过 Chrome 开发者工具调试 Android 应用,提供视图元素检查,网络监控,数据库动态交互,Dumpapp(可扩展的命令行交互接口),JavaScript Console 等功能。
仅开发期间集成使用
Stetho如果集成到项目中,必然是只在debug模式下使用
添加依赖
1
2
3
4dependencies {
//这个依赖是必须的
debugApi 'com.facebook.stetho:stetho:1.5.0'
}我们肯定还要支持网络监控功能,所以还需要添加一个网络助手依赖,因为我们项目使用的网络库是okhttp3,所以添加如下依赖
1
2
3dependencies {
debugApi 'com.facebook.stetho:stetho-okhttp3:1.5.0'
}如果项目使用的是HttpURLConnection,需要添加如下依赖
1
2
3dependencies {
debugApi 'com.facebook.stetho:stetho-urlconnection:1.5.0'
}如果还需要支持JavaScript console的功能(个人感觉这个我们不太用的上,所以没集成)需要添加如下依赖
1
2
3dependencies {
debugApi 'com.facebook.stetho:stetho-js-rhino:1.5.0'
}创建DebugApplication
在app/src/debug/java目录下,创建一个DebugApplication,并继承于我们之前的MainApplication。由于我们项目使用了Tinker,而Tinker使用了Application代理机制来对Applicaition实现热修复。所以,这里我们对DebugApplication也添加注解,生成项目真正的Application。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20"com.application.PatientDebugApplication", (application =
flags = ShareConstants.TINKER_ENABLE_ALL,
loadVerifyFlag = false)
public class DebugApplication extends MainApplication {
//省略构造方法..
public void onCreate() {
super.onCreate();
//每个进程都初始化Stetho
initStetho();
}
private void initStetho() {
//启用大多数默认配置 包括UI元素检查,SP及数据库的查看修改
Stetho.initializeWithDefaults(getApplication());
}
}同时还要在debug目录下创建一个
AndroidManifest.xml
,添加 debug 模式下需要的权限和修改 application 节点android:name
值为Tinker注解生成的真正的Application,其余的配置把项目的原先的Application抄过来就行。(使用tools:replace
覆盖android:name
字段)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!---->
<application
android:name="com.application.PatientDebugApplication"
android:hardwareAccelerated="false"
android:icon="@drawable/app_logo"
android:label="${APP_NAME}"
android:largeHeap="true"
android:persistent="true"
android:allowBackup="false"
android:theme="@style/Theme.Guahao.white" tools:replace="android:icon,android:theme,android:hardwareAccelerated,android:label,android:largeHeap,android:persistent,android:allowBackup,android:name">
<activity
//省略工厂activity
....
</application>
</manifest>目录结构图
我们还需要支持网络监控,方便我们查看页面产生的请求。按照官网,我们还需要添加如下的代码。
1
2
3OkHttpClient client = new OkHttpClient.Builder()
.addNetworkInterceptor(new StethoInterceptor())
.build()运行这段代码后,发现网络监控并没有作用。查看okhttp3源码及我们项目代码发现,1.拦截器要生效必须每次请求都要使用该Client。2.我们的网络库在这之前已经初始化了client并使用单例。也就是说,我们必须是要在已经生成的client中添加网络拦截器。
查看我们的网络库代码,可以获取该Client
1
OkHttpClient okHttpClient = OkHttpServerClientImpl.getInstance().getmClient();
查阅okhttp3源码,也发现这样一个方法。
1
2
3
4
5
6
7
8/**
* Returns an immutable list of interceptors that observe a single network request and response.
* These interceptors must call {@link Interceptor.Chain#proceed} exactly once: it is an error for
* a network interceptor to short-circuit or repeat a network request.
*/
public List<Interceptor> networkInterceptors() {
return networkInterceptors;
}看注释,这里返回的是一个不可变的List。所以如果直接在该List添加StethoInterceptor必然会报错。
那还有别的办法么?嗯..好像只能靠反射大法了。
1
2
3
4
5
6
7
8
9
10
11
12
13//支持网络监控
OkHttpClient okHttpClient = OkHttpServerClientImpl.getInstance().getmClient();
List<Interceptor> list = new ArrayList<>();
list.addAll(okHttpClient.networkInterceptors());
list.add(new StethoInterceptor());
Class<OkHttpClient> clz = OkHttpClient.class;
try {
Field field = clz.getDeclaredField("networkInterceptors");
field.setAccessible(true);
field.set(okHttpClient, list);
} catch (Exception e) {
e.printStackTrace();
}运行代码后,问题已解决。
使用步骤
打开Chrome浏览器,输入:chrome://inspect,找到自己的应用并点击inspect
View Hierarchy
在弹出的页面选择Elements,会出现当前页面的UI结构。点击某个元素节点,手机界面中对应的控件会高亮。点击左上角的搜索按钮,再点击app当前界面的控件,View Hierarchy 会显示该控件在层次中的位置。
从此,可以很方便地查看h5页面哪些元素是原生的,哪些元素是H5的,甩锅再也不是问题了
网络监控
在弹出的页面选择Network,会列出当前页面出现的所有请求的详细信息。包括请求方法,请求状态,请求大小,请求时间,请求头,响应头,响应体等等信息。
从此,再也不会出现response过长,AS显示不全的问题了,再也不需要额外使用HiJson这样的格式化工具了。
数据库的可视化查看及控制台修改
在弹出的页面选择Resources,数据库文件就放在Web SQL目录下,随意点击数据库,可以看到其下的表文件,点击表文件可以看到右边会显示里面的数据。
点击具体的数据库,可以使用SQL语句对其中的表直接进行操作。并且在使用SQL语句的时候,还会自动提示补全。
SP文件的可视化查看及直接修改
在弹出的页面选择Resources,SP文件就放在Local Storage目录里。点击任意SP文件,可以看到里面的值,并支持对key-value直接修改。
JavaScript Console
如果集成了JavaScript Console功能,可以在弹出的页面选择Console。JavaScript Console允许执行那些可以与应用或 Android SDK 交互的 JavaScript 代码。目前该功能比较鸡肋,因为自带的console只能关联到application的context,能进行的操作非常有限,且在控制台写js调用Java层的函数是没有自动补全的,容易写错不说,要换成Js的语法也是相当费劲
Stetho 使用 Rhino 实现使用脚本方式调用 Java。
关于 Rhino 相关语法可以参考下面的文档
Dump App
Dump App构造了一个命令行与Android App的交互通道,在命令行输入一行命令,App可以收到并且在命令行上进行反馈输出。并且支持自定义拓展命令行。
没用过,感觉不是有很大用处。