Android-stetho
概述
本文是对Facebook开源的Android调试工具Stetho的全面学习总结。Stetho是一个功能强大的Android应用调试桥梁,它可以通过Chrome浏览器的开发者工具来调试Android应用,提供了包括视图层级检查、数据库查看、网络抓包、文件系统管理等多种调试功能。
文章主要内容包括:
- 基础集成指南 - 详细介绍了Stetho的下载、集成方法,以及与新版Chrome的兼容性问题解决方案
- 核心功能展示 - 通过截图演示了布局视图检查、SQLite数据库查看、网络抓包、DumpApp命令行工具等主要特性
- 源码深度解析 - 对Stetho的核心模块进行了详细的代码分析,包括:
- 初始化流程和配置系统
- DumpApp插件机制实现
- 数据库检查模块(inspector/database)
- 网络拦截模块(inspector/network)
- DumpApp实战开发 - 介绍了内置的四个DumpApp插件,并提供了自定义插件的实现思路,特别是MMKV数据管理插件的完整实现
- 通信机制深度剖析 - 详细分析了dumpapp脚本与Android应用之间的通信原理,包括ADB连接建立、Unix域套接字通信、自定义协议设计等底层实现
学习网站来源
下载
- 在gradle中添加依赖
1
2
3
4
5
6
7
8
9// Gradle dependency on Stetho
dependencies {
debugCompile 'com.facebook.stetho:stetho:1.5.1'
//下面依赖是非必须的,只有在需要监控网络的时候需要添加
debugCompile 'com.facebook.stetho:stetho-urlconnection:1.5.1'
debugCompile 'com.facebook.stetho:stetho-okhttp3:1.5.1'
//下面也非必须,在需要JS命令行的时候添加
debugCompile 'com.facebook.stetho:stetho-js-rhino:1.6.0'
}
上面是官网的做法,经本人测试,stetho与新版的chrome(130)联动有bug,官方仓库修复后并没有release,故建议导入模块或者使用MavenLocal
集成(来自官网)
在application中注册
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public class MyApplication extends Application {
public void onCreate() {
super.onCreate();
// 在调试模式下,启动stetho服务
if (BuildConfig.DEBUG) {
Stetho.initializeWithDefaults(this);
}
}
}
<application
android:name=".MyApplication" <!-- 注册自定义 Application 类 -->
<!-- 其他组件声明 -->
</application>启用网络检查
1
2
3
4
5OkHttpClient.Builder builder = new OkHttpClient.Builder();
if (BuildConfig.DEBUG) {
builder.addInterceptor(new StethoInterceptor());
}
instance = builder.build();自定义 dumpapp 插件
1
2
3
4
5
6
7
8
9
10
11Stetho.initialize(Stetho.newInitializerBuilder(context)
.enableDumpapp(new DumperPluginsProvider() {
public Iterable<DumperPlugin> get() {
return new Stetho.DefaultDumperPluginsBuilder(context)
.provide(new MyDumperPlugin())
.finish();
}
})
.enableWebKitInspector(Stetho.defaultInspectorModulesProvider(context))
.build());自定义插件是扩展 dumpapp 系统的首选方式,可以在配置过程中轻松添加。
stetho-sample
官方的示例Demo,可以供学习DumpApp的写法或者测试Chrome功能
git clone https://github.com/facebook/stetho.git- 记得使用低版本的JDK,比如1.8
- javaDoc报错,故注释掉这段代码即可暂时编译成功:
1
2
3
4
5source = android.sourceSets.main.java.srcDirs
classpath += files(android.bootClasspath)
if (JavaVersion.current().isJava8Compatible()) {
options.addStringOption('Xdoclint:none', '-quiet')
}若发现stetho-sample可以在chrome中展示,但是自己集成的项目不行,一种可能的原因是stetho-1.6.0与新版Chrome有兼容性问题,建议将github代码仓库中的stetho上传到MavenLocal或者当作模块导入(stetho已经停止维护,且其后续有更改并没有release到maven中)
特征
- 从chrome://inspect/#devices点击inspect进入chrome调试界面

- 布局视图,可以看view树,视图对应的style、properties

- 可以查看设备的数据存储,包括SQLite

- 可以抓包

- DumpApp的使用
- 使用自带的SharedPreferencesDumperPlugin,可以实现运行模式下SP的读写

- 自行拓展DumpPlugin,如:MmkvDumperPlugin,实现MMKV的增删改查

- 使用自带的SharedPreferencesDumperPlugin,可以实现运行模式下SP的读写
值得注意得是需要在github将script文件夹下载下来,里面包含了用python3实现的命令dumpapp
核心代码解析
com/facebook/stetho/Stetho.java
- initialize、InitializerBuilder初始化
- enableDumpapp、enableWebKitInspector添加配置
- PluginBuilder 配置 Dumper 插件和 Inspector 模块
- DefaultInspectorModulesBuilder、defaultInspectorModulesProvider,finish中会自动把SqliteDatabaseDriver加进来,也可以自己继承或者exclude
- DefaultDumperPluginsBuilder、defaultDumperPluginsProvider,finish中会自动添加内置的四个插件:
1
2
3
4provideIfDesired(new HprofDumperPlugin(mContext));
provideIfDesired(new SharedPreferencesDumperPlugin(mContext));
provideIfDesired(new CrashDumperPlugin());
provideIfDesired(new FilesDumperPlugin(mContext));
scripts
- dumpapp:主要脚本,负责解析命令行参数并连接到 Stetho 启用的应用程序
- main:这段代码是主入口,处理命令行参数并建立连接
- read_frames:这个函数处理从 Stetho 服务器返回的帧。每个帧有不同的代码表示不同类型的数据
- stetho_open.py:提供连接到 Android 设备上的 Stetho socket 的底层功能
- stetho_open:这个函数建立到 Stetho 启用应用的连接。它首先连接到 ADB 服务器,然后使用 ADB 转发到设备上的 socket
- _find_only_stetho_socket:这个函数在设备上查找运行 Stetho 的进程,通过检查 /proc/net/unix 的输出
- _connect_to_device:依托设备、端口以及 AdbSmartSocketClient 连接设备
- AdbSmartSocketClient:实现了 ADB 协议,用于与 Android Debug Bridge 服务器通信
- hprof_dump.sh:用于生成和转换 HPROF 内存分析文件的辅助脚本
com/facebook/stetho/dumpapp/
- Dumper.java
- Dumper 类是 Stetho 框架中的一个核心组件,主要负责处理来自命令行的转储请求并将其路由到相应的插件。它位于 Java 端,作为接收和执行命令的处理器。
- GlobalOptions.java
- 配置命令行的选项
- DumperContext.java
- Dumper上下文:mStdin、mStdout、mStderr、mParser、mArgs
- DumperPlugin.java
- Dumper的插件接口,需要实现getName、dump(DumperContext dumpContext)方法
- ArgsHelper.java
- nextOptionalArg、nextArg、drainToArray等处理命令行参数的工具类
- plugins/SharedPreferencesDumperPlugin.java
- 实现具读写SP功能的plugin,需要实现接口DumperPlugin
- DumpUsageException.class、DumpException.class等异常类
Stetho 的 Dumper 类与 Python 脚本形成了一个完整的客户端-服务器系统:
- Python 脚本作为客户端,负责解析命令行参数、建立连接并发送请求
- Java 端的 Dumper 类作为服务器端处理程序,接收请求并路由到适当的插件
- 通过一个自定义二进制协议,两者可以进行双向通信
com/facebook/stetho/inspector/database/
DatabaseConnectionProvider.java、DatabaseFilesProvider.java
- 提供数据库文件以及SQLite对象的接口
DefaultDatabaseFilesProvider.java
- 实现DatabaseFilesProvider接口
- 负责收集应用中的数据库文件,通过
mContext.databaseList()获得应用中的所有数据库文件
DefaultDatabaseConnectionProvider.java
- 实现DatabaseConnectionProvider接口
- 负责创建 SQLite 数据库连接
SqliteDatabaseDriver.java
- 数据库功能的核心实现类、处理SQLite数据库查询与展示
- getDatabaseNames获取数据库文件、排序、过滤临时文件,将每个文件包装为描述符返回
- getTableNames获得数据库中表和视图的名字
- executeSQL根据 SQL 类型分发到不同处理方法
SQLiteDatabaseCompat.java
- 兼容性层,用于在不同的 Android 版本中管理 SQLite 数据库的特性,如写前日志(WAL)和外键约束
- 这个文件和DefaultDatabaseConnectionProvider中处理打开数据库特性部分的设计挺好的,值得学习,也有一些我没见过的语法
Database.java
- 实现 Chrome DevTools 协议中数据库功能的核心类
- 处理来自 Chrome DevTools 的数据库相关请求
- 管理数据库驱动和连接,执行 SQL 查询并格式化结果
BaseDatabaseDriver.java、DatabaseDriver2
- 定义数据库驱动的核心接口
com/facebook/stetho/inspector/network
StethoInterceptor.java
- 核心作用: OkHttp3 的网络拦截器,是 Stetho 抓包功能的入口点和关键实现
- 拦截流程:
- intercept(): 主要拦截方法,完整的网络请求生命周期管理
- 生成唯一 requestId 用于追踪单个请求
- 创建 RequestBodyHelper 处理请求体数据
- 调用 chain.proceed() 执行实际网络请求
- 异常处理: 捕获 IOException 并通过 httpExchangeFailed() 报告
- 响应流拦截:
- 通过 interpretResponseStream() 拦截响应流
- 使用 ForwardingResponseBody 包装响应体,替换原始 InputStream
- 确保拦截后的流能正常传递给应用层
- Connection 验证: 检查是否使用了正确的 addNetworkInterceptor,而非 addInterceptor
NetworkEventReporter.java
- 网络事件报告的核心接口,定义了完整的网络监控生命周期
- requestWillBeSent(): 请求即将发送时调用
- responseHeadersReceived(): 接收到响应头时调用
- interpretResponseStream(): 关键方法 - 拦截响应流,实现数据捕获和流包装
- dataSent()/dataReceived(): 报告实际传输的数据量(压缩前后)
- httpExchangeFailed(): 处理网络异常情况
- 定义了 InspectorRequest、InspectorResponse、InspectorWebSocketFrame 等核心接口
NetworkEventReporterImpl.java
- 实现具体的网络事件报告逻辑,单例模式管理全局网络监控
- 将 Android 网络数据转换为 Chrome DevTools Protocol 格式
- 使用 NetworkPeerManager 管理调试客户端连接状态
- 通过 sendNotificationToPeers() 向所有连接的调试客户端发送事件
- 支持请求体的自动解压缩和格式化显示,处理 JSON 序列化
NetworkPeerManager.java
- 网络模块的核心管理器,继承自 ChromePeerManager
- 响应体文件管理: 持有 ResponseBodyFileManager 实例,负责临时文件的生命周期
- 美化打印器管理: 管理 AsyncPrettyPrinterRegistry,用于格式化不同类型的响应数据
- 连接状态监听: 通过 PeersRegisteredListener 监听调试客户端的连接状态
- 延迟初始化和自动清理机制
AsyncPrettyPrinter 系列
- AsyncPrettyPrinter.java: 异步美化打印器接口,支持不同数据格式
- AsyncPrettyPrinterRegistry.java: 管理不同类型数据的美化器注册表
- AsyncPrettyPrinterExecutorHolder.java: 线程池管理,避免阻塞主线程
- DownloadingAsyncPrettyPrinterFactory.java: 支持大文件的分块美化处理
Network.java (协议模块)
- 定义了 Chrome DevTools Network 协议的所有数据结构
- Request、Response、Initiator 等核心类型定义
- 支持 JSON 序列化注解,确保与调试客户端的协议兼容性
- 包含请求/响应的完整元数据:URL、方法、头部、时间戳等
ResponseBodyFileManager.java
- 管理网络响应的临时文件存储,使用应用私有目录
- 支持 Base64 编码标识和数据压缩
- 集成异步美化打印器,支持 JSON/XML 等格式的格式化显示
- 自动文件清理机制,避免存储空间泄漏
ResponseHandlingInputStream.java
- 抓包核心实现 - 装饰器模式包装原始 InputStream
- 实现数据的双写机制:流向应用的同时写入临时存储
- 支持数据解压缩计数和进度报告
- 透明处理,对应用代码完全无感知
RequestBodyHelper.java / DefaultResponseHandler.java
- RequestBodyHelper: 处理请求体的压缩、解压缩和数据统计
- DefaultResponseHandler: 响应数据读取的默认处理器,报告读取进度和完成状态
- 支持 gzip/deflate 等标准 HTTP 压缩格式
工具类组件
- CountingOutputStream.java: 统计输出流写入字节数的装饰器
- DecompressionHelper.java: HTTP 响应解压缩帮助类(gzip/deflate)
- GunzippingOutputStream.java: 专门的 gzip 解压缩输出流
- ResourceTypeHelper.java: 根据 Content-Type 判断资源类型
- MimeMatcher.java: MIME 类型匹配和识别
WebSocket 支持
- SimpleBinaryInspectorWebSocketFrame.java: 二进制 WebSocket 帧封装
- SimpleTextInspectorWebSocketFrame.java: 文本 WebSocket 帧封装
- 完整支持 WebSocket 握手、数据帧传输等生命周期监控
DumpApp
自带的四个DumpApp:
- HprofDumperPlugin:用于导出应用的 Heap Dump (HPROF 文件),即应用内存中的对象及其引用关系
- SharedPreferencesDumperPlugin:读写应用的 SharedPreferences 数据
- FilesDumperPlugin:导出应用的 文件系统 中的文件
- CrashDumperPlugin:用于导出 崩溃日志 (Crash logs)
自行实现几个DumpApp:
- 根据sample实现HelloWorldDumperPlugin
- 根据自己的Demo实现PosterMemoryDumperPlugin,实现内存海报数据的转储
- 完成MmkvDumperPlugin,实现MMKV数据的增删改查
实现DumpApp时需要实现DumperPlugin接口,只需改写getName、dump函数即可;可以使用DumperContext获得输入输出流、命令行传递来的参数等
MmkvDumperPlugin实现思路
综述
MmkvDumperPlugin 通过实现 DumperPlugin 接口来提供 MMKV 数据的增删改查操作。核心实现包括以下几点:
- 插件构建:
- 实现 getName 和 dump 方法。dump 方法根据命令行传入的操作命令(如 list、get、write 等)执行对应的 MMKV 操作。
- 获取 MMKV 实例:
- 根据命令行参数动态选择 MMKV 实例。如果指定了 -t mmkvId,则使用指定的实例;否则,使用默认实例。
- 支持以下命令:
- list:列出所有 MMKV 键值。
- get:获取指定键的值。
- write:写入数据到 MMKV。
- remove:删除指定键。
- clear:清空所有数据。
- 错误处理:
- 使用 DumpUsageException 处理错误,如参数缺失或 MMKV 实例获取失败。
主要代码:
1 |
|
Stetho 通信机制深度解析
dumpapp 与安卓应用的连接原理
架构概览

连接建立流程
PC端连接准备(dumpapp脚本)
1.1 参数解析
1 | # 从命令行参数或环境变量获取进程名 |
1.2 建立ADB连接
1 | # 通过stetho_open建立到设备的连接 |
2. stetho_open连接机制详解
2.1 ADB服务器连接
1 | def stetho_open(device=None, process=None, port=None): |
2.2 Socket名称格式化
1 | def _format_process_as_stetho_socket(process): |
2.3 自动发现Stetho进程
1 | def _find_only_stetho_socket(device, port): |
3. 协议握手与通信
3.1 协议握手
1 | # 发送DUMP协议标识和版本号 |
3.2 命令参数传输
1 | # 构造参数帧 |
3.3 数据帧解析
1 | def read_frames(sock): |
Android端实现分析
1. 服务器初始化
1.1 LocalSocketServer创建
1 | public class LocalSocketServer { |
1.2 套接字地址生成
1 | // 在Stetho初始化时生成 |
2. 协议处理
2.1 DumpappSocketLikeHandler
1 | public class DumpappSocketLikeHandler implements SocketLikeHandler { |
2.2 协议验证
1 | private void establishConversation(DataInputStream in) throws IOException { |
3. 命令执行框架
3.1 Dumper接口
1 | public interface Dumper { |
3.2 插件系统
Stetho支持多种内置插件、也可自行实现插件
总结
Stetho的连接机制巧妙地利用了:
- ADB的端口转发功能:将TCP连接转发到Unix域套接字
- Android的LocalSocket API:提供高效的进程间通信
- 自定义协议:支持双向数据流和命令执行
- 插件化架构:可扩展的调试功能
其他相关联源码,并未在这部分展示:
- Framer类: 负责协议帧的编码/解码
- 各种DumperPlugin: 具体功能实现
- ProtocolDetectingSocketHandler: 协议检测和路由
- Stetho初始化代码: 整个服务的启动过程
- 标题: Android-stetho
- 作者: rainbowYao
- 创建于 : 2025-09-02 17:20:06
- 更新于 : 2025-09-02 17:21:39
- 链接: https://redefine.ohevan.com/2025/09/02/Android-stetho/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。





