對於 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