QigsawBundle資源注入新方案(打包效率超高)

這個方案已經(jīng)棄用了智亮,雖然效率高,但是太麻煩,最后還是修改為編譯期間ASM愉豺。

研究Qigsaw獨立打包 QigsawBundle,開始發(fā)現(xiàn)可以在ActivityLifecycleCallbacks.onActivityPreCreated中注入Resources茫因,后來發(fā)現(xiàn)只有Android10+才行蚪拦,以前的沒有,IDE沒提示所以一直沒發(fā)現(xiàn)冻押。

不想在編譯期間織入代碼驰贷,想要做到獨立打包,所以想找個兼容所有版本的方法洛巢。
如果定義一個基類并在其中重寫 getResources 方法是最簡單且最高效的辦法括袒。但是引用三方庫時,沒法解決了稿茉。
后來想到一個辦法:絕大部分的三方庫的基類都是AppCompatActivity箱熬,如果在公認的基類中增加代碼來實現(xiàn)資源注入,那就太方便了狈邑。

研究發(fā)現(xiàn)這個辦法是確實可行的城须,于是就寫代碼了。
最后原理是這樣的:

絕大部分的項目都引用了appcompat米苹,現(xiàn)在把appcompat庫中的AppCompatActivity類通過ASM修改增加一個注入資源的方法糕伐。然后把修改后的庫打包為 appcompat.qb ,其它保持不變蘸嘶。再把庫發(fā)布到本地或公司倉庫良瞧。最后在項目中替換為新的依賴陪汽。

    implementation 'androidx.appcompat:appcompat:1.2.0'//大部分的項目用這個
    implementation 'androidx.appcompat:appcompat.qb:1.2.0'//替換為這個

全部手動去替換太麻煩,以下是全局自動替換的方式褥蚯。還可以寫在Root中挚冤,所有子項目都適用,具體方法請參考DEMO 的 ext.injectActivityResource

    configurations.all {
        resolutionStrategy.eachDependency { DependencyResolveDetails details ->
            if (details.requested.name == 'appcompat') {
                //只修改了name赞庶,其它都沒動训挡。
                details.useTarget group: details.requested.group, version: details.requested.version, name: 'appcompat.qb'
            }
        }
    }    

AppCompatActivity通過反射獲取用戶Application中的injectActivityResource變量。因為AppCompatActivity中的injectActivityResource變量是靜態(tài)的歧强,所以反射代碼基本上只會執(zhí)行一次澜薄,效率不用擔(dān)心。然后在每次返回Resources前摊册,都會先調(diào)用Handler.handleMessage()方法肤京,這個對象是注入進來的相當(dāng)于App.injectActivityResource.handleMessage()

用戶自己實現(xiàn)一個InjectActivityResource類,在其中實現(xiàn)注入Resources就行了茅特。
說起來比較麻煩忘分,看代碼就明白了。

//只列出了改動的代碼白修,其它方法還在
public class AppCompatActivity extends FragmentActivity {

    private static Handler injectActivityResource;
    private Message msg;

    private void initInjectActivityResource() {
        if (injectActivityResource != null) return;
        Context application = this.getApplicationContext();
        try {
            Field injectActivityResourceField = application.getClass().getDeclaredField("injectActivityResource");
            injectActivityResourceField.setAccessible(true);
            injectActivityResource = (Handler) injectActivityResourceField.get(application);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        initInjectActivityResource();
        super.onCreate(savedInstanceState);
    }

    @Override
    public Resources getResources() {
        if (injectActivityResource != null) {
            Resources resources = super.getResources();
            if (msg == null) msg = new Message();
            msg.obj = resources;
            injectActivityResource.handleMessage(msg);
            return resources;
        }
        return super.getResources();
    }
}

public class InjectActivityResource extends Handler {
    /**
     * 這個方法調(diào)用非常頻繁饭庞,所以建議用JAVA寫,以保證沒有多余的代碼熬荆。
     */
    @Override
    public void handleMessage(@NonNull Message msg) {
        Resources resources = (Resources) msg.obj;
        Qigsaw.onApplicationGetResources(resources);
        System.out.println("injectActivityResource " + resources.hashCode());
    }
}

class App : Application() {
    @Keep
    private val injectActivityResource: Handler = InjectActivityResource()
}

上面也說了絕大部分項目都是用AppCompatActivity作基類的舟山,但也有例外啊卤恳!怎么辦呢累盗?

所有例外的處理方法都是:注入Handler injectActivityResource,然后替換舊依賴突琳。

如果手動去替換也太麻煩了若债,所以寫了個工具(點擊查看項目),把依賴和類名寫進去拆融,點兩下就能發(fā)布到本地或公司庫蠢琳。

特別說明1:要求所有(需要替換的)依賴都保存到庫中勾拉,當(dāng)前項目本地(libs目錄中)的AAR和JAR中不能有需要替換的類扣甲,如果有則需發(fā)布到庫中玉吁。也能做到兼容朵你,但太麻煩,沒寫代碼纷闺。

特別說明2:請用戶自行發(fā)現(xiàn)需要替換的類甜紫,暫時沒工具薪贫,后面會補上。不準備在編譯期間發(fā)現(xiàn)(拖慢編譯速度)已卸,而是在運行期間發(fā)現(xiàn)佛玄。工具原理方案1:通過一個Debug模式注入的Provider讀取manifest的Activity,然后判斷類是否存在累澡,如果存在則先判斷是否為AppCompatActivity的子類梦抢,如果不是則通過反射判斷是否有注入的Handler injectActivityResource變量。
方案2:可以通過一個手動的Gradle任務(wù)來發(fā)現(xiàn)愧哟,檢測方法則用方案1的奥吩,當(dāng)依賴變更時手動執(zhí)行一次就好。

操作流程如下:

  1. 填寫所有需要修改的依賴和類
  2. 運行一次InjectorTest.inject()翅雏,會把所有依賴注入代碼然后復(fù)制到當(dāng)前工具項目中。
  3. 運行publishToMavenLocal(發(fā)布到本地)或publish(發(fā)布到公司庫)
    發(fā)布到Nexus的快捷方法:點擊查看
    注意事項:
  • 同一個依賴中的類寫在一個列表中人芽,比如AppCompatActivity1望几,AppCompatActivity2都寫在appcompat:1.2.0就好,不用每個寫一行萤厅。
  • 不用每個版本都寫出來橄抹,只寫當(dāng)前用的,最新的就行惕味。比如appcompat:1.1.0就不用寫出來楼誓。下面只是一個示例。
  • 所有新庫名加'.qb'(QigsawBundle的簡寫)
    "androidx.appcompat:appcompat:1.2.0"->"androidx.appcompat:appcompat.qb:1.2.0"
    @Test
    fun InjectorTest.inject() {
        val injected = inject(
            listOf(
                InjectDep("androidx.appcompat:appcompat:1.2.0", listOf(AppCompatActivity::class.java名挥,AppCompatActivity2::class.java)),
                InjectDep("androidx.appcompat:appcompatXYZ:1.1.0", listOf(AppCompatActivityXYZ::class.java))
            )
        )
        val folder = File(projectRootDir, "injected")
        folder.deleteAll()
        injected.forEach {
            val single = File(folder, it.pom.name.trimInjectedPom())
            it.depFile.moveTo(single)
            it.pom.moveTo(single)
        }
    }

最后

如果本文幫助到了你疟羹,也幫我點個贊吧!

如果你愿意禀倔,還可以贊賞一杯咖啡或一瓶水榄融,非常感覺你的慷慨!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末救湖,一起剝皮案震驚了整個濱河市愧杯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鞋既,老刑警劉巖力九,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異邑闺,居然都是意外死亡跌前,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門陡舅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來舒萎,“玉大人,你說我怎么就攤上這事”矍蓿” “怎么了章鲤?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長咆贬。 經(jīng)常有香客問我败徊,道長,這世上最難降的妖魔是什么掏缎? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任皱蹦,我火速辦了婚禮,結(jié)果婚禮上眷蜈,老公的妹妹穿的比我還像新娘沪哺。我一直安慰自己,他們只是感情好酌儒,可當(dāng)我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布辜妓。 她就那樣靜靜地躺著,像睡著了一般忌怎。 火紅的嫁衣襯著肌膚如雪籍滴。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天榴啸,我揣著相機與錄音孽惰,去河邊找鬼。 笑死鸥印,一個胖子當(dāng)著我的面吹牛勋功,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播库说,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼酝润,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了璃弄?” 一聲冷哼從身側(cè)響起要销,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎夏块,沒想到半個月后疏咐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡脐供,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年浑塞,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片政己。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡酌壕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情卵牍,我是刑警寧澤果港,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站糊昙,受9級特大地震影響辛掠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜释牺,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一萝衩、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧没咙,春花似錦猩谊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至袁梗,卻和暖如春宜鸯,著一層夾襖步出監(jiān)牢的瞬間憔古,已是汗流浹背遮怜。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留鸿市,地道東北人锯梁。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像焰情,于是被迫代替她去往敵國和親陌凳。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,486評論 2 348

推薦閱讀更多精彩內(nèi)容