在 Android 開發中,不少時候,咱們可能想要修改第三方庫裏的某些類。那麼咱們有兩個主流的方式來實現:android
第一種方式,優勢是方法簡單不容易出錯,並且 Debug 的時候不會有什麼問題。缺點就是操做麻煩,升級的時候須要和上游進行 Rebase。並且當遇到 OkHttp 這種用 Maven 組織的項目,對慣用 Gradle 組織項目的 Android 工程師更是個災難。git
第二種方式,優勢是非侵入,不須要下載和引入第三方庫的源碼。而缺點的話,就是實現相對複雜(涉及到字節碼操做),並且由於字節碼已被修改,無法和源碼對應,因此 Debug 的時候也可能出問題。github
相信不少人在打包 Apk 的編譯期(Build Time)遇到過「Duplicate Class」的錯誤。緣由是 Dex 構建工具在把全部類打包進同一個 Dex 的時候,若是發現若是有重複的類要打包進 Dex 的話,就會報錯。bash
而在編輯期(Edit Time)的時候,若是咱們的全部源碼中有重複類的話,IDE 也會提示錯誤。可是若是咱們的源碼裏有一個和第三方 Jar 包裏重複的類,IDE 是不會提示錯誤的。爲何呢?app
由於重複類並不在同一個 Archive 裏。Archive 能夠看做類的容器,能夠是一個 Jar 包,也能夠是一個 Dex。固然你某個 Module 中的全部源碼,也能夠想像成是一個 Archive,因此源碼有重複類是會提示錯誤的。maven
總結如下,在源碼中的類和 Jar 包裏的類有重複的狀況下,在編輯期是不會提示錯誤的。只有當到了編譯期,構建工具將你源碼編譯出來的類,和第三方 Jar 裏的重複的類,混合到同一個 Archive 裏的時候纔會報錯。工具
既然,IDE 容許源碼中有和 Jar 裏的類重複的類。那麼,對於開頭提到的問題,咱們能夠提出一種新的解決方案:gradle
只把 Jar 裏想要修改的類的對應源碼拷貝到項目中修改,而後在最終編譯的時候把 Jar 包裏這些類給刪除掉。保證在打包進 Dex 的時候只有咱們拷貝的源碼編譯出來的類便可。ui
咱們可使用 JarFilterPlugin 來幫咱們在最後打包進 Dex 以前,把全部依賴的 Jar 包裏指定的 Class 文件所有過濾掉。url
咱們先把 Plugin 引入到咱們的項目中:
buildscript {
repositories {
maven { url "https://jitpack.io" }
}
dependencies {
classpath "com.github.nekocode:JarFilterPlugin:1.1"
}
}
複製代碼
而後咱們開始使用插件來過濾 Class 文件了。
假設咱們想要修改 Android Support V7 包裏的 AppCompatActivity 類。咱們只須要把 AppCompatActivity 類的源碼拷貝到咱們的項目中,而後在 App Module 的 budil.gradle 下添加以下配置:
apply plugin: 'jar-filter'
jarFilter {
skipFiles = [
'android/support/v7/app/AppCompatActivity.class',
'android/support/v7/app/AppCompatActivity\\$(.*).class'
]
}
複製代碼
這樣,在執行 Assemble 任務打包出的 Apk 中就只會有咱們拷貝的 AppCompatActivity 類。