对于 Android Developer 来讲,不少开源库都是属于开发必备的知识点,从使用方式到实现原理再到源码解析,这些都须要咱们有必定程度的了解和运用能力。因此我打算来写一系列关于开源库源码解析和实战演练的文章,初定的目标是 EventBus、ARouter、LeakCanary、Retrofit、Glide、OkHttp、Coil 等七个知名开源库,但愿对你有所帮助 😇😇java
公众号:字节数组git
系列文章导航:github
在使用 OkHttp 或者 Retrofit 的时候,我以为大部分开发者会作得最多的自定义实现就是拦截器了。由于 OkHttp 的拦截器真的是太有用了,咱们的不少需求:添加 Header、计算并添加签名信息、网络请求记录等均可以经过拦截器来自动完成,只要定义好规则,就能够覆盖到全局的 OkHttp 网络请求数据库
按照我写 [三方库源码笔记] 这系列文章的习惯,我是每写一篇关于源码讲解的文章,就会接着写一篇关于该三方库的自定义实现或者是扩展阅读。因此,承接上一篇文章:三方库源码笔记(11)-OkHttp 源码详解 本篇文章就来写关于 OkHttp 的实战内容,来实现一个在移动端的可视化抓包工具:Monitor数组
Monitor 适用于使用了 OkHttp/Retrofit 做为网络请求框架的项目,只要添加了 MonitorInterceptor 拦截器,Monitor 就会自动记录并保存全部的网络请求信息且自动弹窗展现markdown
最后实现的效果以下所示:网络
这里来简单地介绍下 Monitor 的实现思路app
其实 Monitor 是我蛮久前写的一个开源库了,恰好和我如今要写的文章主题相符,就趁着这机会作了一次总体重构,彻底使用 Kotlin 语言来实现,请放心食用。其核心思路就是经过 Interceptor 拿到 Request 和 Response,记录各项请求信息,存到数据库中进行持久化保存,在实现思路上相似于 squareup 官方的ogging-interceptor
,只是说 Monitor 会更加直接和方便😋😋框架
debug 版本的 MonitorInterceptor 的大致框架以下所示。HttpInformation 是对 request 和 response 的一个实体封装,也是最终会存到数据库中的实体类。经过 chain 拿到 request,先对本地数据库进行预先占位,在 proceed 后拿到 response,对本次请求结果进行解析,全部信息都存到 HttpInformation 中再来更新数据库,同时弹出 Notificationmaven
/** * 做者:leavesC * 时间:2020/10/20 18:26 * 描述: * GitHub:https://github.com/leavesC */
class MonitorInterceptor(context: Context) : Interceptor {
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
val httpInformation = HttpInformation()
processRequest(request, httpInformation)
httpInformation.id = insert(httpInformation)
val response: Response
try {
response = chain.proceed(request)
} catch (e: Throwable) {
httpInformation.error = e.toString()
throw e
} finally {
update(httpInformation)
}
processResponse(response, httpInformation)
update(httpInformation)
return response
}
private fun processRequest(request: Request, httpInformation: HttpInformation) {
···
}
private fun processResponse(response: Response, httpInformation: HttpInformation) {
···
}
private fun showNotification(httpInformation: HttpInformation) {
···
}
}
复制代码
release 版本的 MonitorInterceptor 则不会作任何操做,只是单纯将请求转发出去而已,不会形成多余的性能消耗和引用
class MonitorInterceptor(context: Context) : Interceptor {
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
return chain.proceed(request)
}
}
复制代码
HttpInformation 包含了单次网络请求下全部关于 request 和 response 的请求参数和返回值信息,responseBody 只会保存文本类型的返回值(例如 Json 和 XML),图片这类二进制文件则不会进行保存
class HttpInformation {
var url = ""
var host = ""
var path = ""
var scheme = ""
var protocol = ""
var method = ""
var requestHeaders = mutableListOf<HttpHeader>()
var responseHeaders = mutableListOf<HttpHeader>()
var requestBody = ""
var requestContentType = ""
var requestContentLength = 0L
var responseBody = ""
var responseContentType = ""
var responseContentLength = 0L
var requestDate = 0L
var responseDate = 0L
var responseTlsVersion = ""
var responseCipherSuite = ""
var responseCode = DEFAULT_RESPONSE_CODE
var responseMessage = ""
var error: String? = null
}
复制代码
HttpInformation 则是用 Room 数据库来持久化保存,不得不说的是,Jetpack 中的 Room 和 LiveData 来搭配使用仍是很爽的,将 LiveData 做为数据库的返回值,能够很方便地以观察者模式来实时监听数据库中的数据变化
/** * @Author: leavesC * @Date: 2020/11/14 16:14 * @Desc: */
@Dao
interface MonitorHttpInformationDao {
@Query("SELECT * FROM monitor_httpInformation WHERE id =:id")
fun queryRecordObservable(id: Long): LiveData<HttpInformation>
@Query("SELECT * FROM monitor_httpInformation order by id desc limit :limit")
fun queryAllRecordObservable(limit: Int): LiveData<List<HttpInformation>>
@Query("SELECT * FROM monitor_httpInformation order by id desc")
fun queryAllRecordObservable(): LiveData<List<HttpInformation>>
}
复制代码
UI 层则不用本身去考虑线程切换和内存泄露这类问题,直接进行 observe 便可
private val monitorViewModel by lazy {
ViewModelProvider(this).get(MonitorViewModel::class.java).apply {
allRecordLiveData.observe(this@MonitorActivity, Observer {
monitorAdapter.setData(it)
})
}
}
复制代码
代码我已经发布到了 jitpack,方便你们直接远程依赖使用。同时引入 debug 和 release 版本的依赖,release 版本的 MonitorInterceptor 不会作任何操做,避免了信息泄露,也不会增长 Apk 体积大小
allprojects {
repositories {
maven { url 'https://jitpack.io' }
}
}
dependencies {
debugImplementation 'com.github.leavesC.Monitor:monitor:1.1.3'
releaseImplementation 'com.github.leavesC.Monitor:monitor-no-op:1.1.3'
}
复制代码
只要向 OkHttpClient 添加了 MonitorInterceptor,以后的操做就都会自动完成
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(MonitorInterceptor(Context))
.build()
复制代码
GitHub 连接点击这里:Monitor