前言
在Android应用开发过程中,我们经常需要看到网络请求的一些参数信息,包括但不限于get/post方案,返回结果数据,耗时时长等等。通常的做法是在项目的okhttp的build过程中,主动添加一个拦截器用于这些信息的捕捉。
但这种方案需要我们自己去在项目中编写拦截器;逻辑进行添加,且无法捕捉三方库或者其他module中的网络请求。在这个背景下,一个可以直接添加使用,并获取全局网络请求返回参数的工具库显得有必要。
下面就介绍一下应对上述场景开发的一款用于查看网络请求参数的工具:netviewer。辛苦点个star。
效果展示:
项目地址:https://github.com/LucasXu01/NetViewer
直接接入后,logcat可直接展示所有okhttp请求的详细信息:
若想在项目中实时获取所有的请求:
// 在主项目中获取NetworkViewer中的每次网络请求数据monitorData
NetViewerHelper.setMonitorDataInterface(object : MonitorDataInterface {
override fun getMonitorData(monitorData: MonitorData) {
Log.d("tag", "getMonitorData: ." + monitorData.host)
}
})
如何使用
1、netviewer接入
项目级的build.gradle添加:
buildscript {
dependencies {
......
//1、依赖抓包插件库
classpath 'io.github.lucasxu01:modular-netviewer-plugin:1.0.0'
}
}
app级别build.gradle:
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
//2、添加netviewer的插件
id 'netplugin'
}
app级别build.gradle继续添加:
//3、添加依赖
debugImplementation 'implementation 'io.github.lucasxu01:modular-netviewer:1.0.0
-备注: 使用debugImplementation是为了只在测试环境中引入
2、使用
-
接入netviewer后,所有经过okhttp的请求均会在控制台进行输出;
-
如果需要在项目中获取到网络请求具体参数信息,可:
// 在主项目中获取NetworkViewer中的每次网络请求数据monitorData NetViewerHelper.setMonitorDataInterface(object : MonitorDataInterface { override fun getMonitorData(monitorData: MonitorData) { Log.d("tag", "getMonitorData: ." + monitorData.host) } })
-
不展示log日志:
NetViewerHelper.isPrintNetLog = false
原理介绍
拦截APP的OKHTTP请求(添加拦截器处理抓包请求,使用ASM字节码插装技术实现)
- 写一个Interceptor拦截器,获取请求及响应的数据,转化为需要的数据结构
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
if (!MonitorHelper.isOpenMonitor) {
return chain.proceed(request)
}
val monitorData = MonitorData()
monitorData.method = request.method
val url = request.url.toString()
monitorData.url = url
if (url.isNotBlank()) {
val uri = Uri.parse(url)
monitorData.host = uri.host
monitorData.path = uri.path + if (uri.query != null) "?" + uri.query else ""
monitorData.scheme = uri.scheme
}
......
}
- 有了拦截器就可以通过字节码插桩技术在编译期自动为OKHTTP添加拦截器了,避免了使用者自己添加拦截器的操作
class OkHttpMethodAdapter(methodVisitor: MethodVisitor?, access: Int, name: String?, descriptor: String?) : AdviceAdapter(Opcodes.ASM7, methodVisitor, access, name, descriptor) {
override fun onMethodExit(opcode: Int) {
super.onMethodExit(opcode)
mv?.let {
it.visitVarInsn(ALOAD, 0)
it.visitFieldInsn(GETFIELD, "okhttp3/OkHttpClient\$Builder", "interceptors", "Ljava/util/List;")
it.visitFieldInsn(GETSTATIC, "com/lucas/netviewer/NetViewerHelper", "INSTANCE", "Lcom/lucas/netviewer/NetViewerHelper;")
it.visitMethodInsn(INVOKEVIRTUAL, "com/lucas/netviewer/NetViewerHelper", "getHookInterceptors", "()Ljava/util/List;", false)
it.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "addAll", "(Ljava/util/Collection;)Z", true)
it.visitInsn(POP)
}
}
}