以下是我這個系列的相關(guān)文章咸产,有興趣可以參考一下,可以給個喜歡或者關(guān)注我的文章疚漆。
[Android]如何做一個崩潰率少于千分之三噶應(yīng)用app--章節(jié)列表
記得我之前有介紹了一種非常適合于組件化后做插件化的框架,就是Small。
我在第九章節(jié)的時(shí)候就有介紹了Small的使用赡矢,還有深入分析Small的運(yùn)行原理。
近來使用Small研發(fā)插件中阅仔,遇到一些問題吹散,就在這里和大家討論一下。
這里說一下Small的的一些缺陷八酒,
(1)其不支持動態(tài)Service空民,Service都只能放在宿主里面了。
(2)Small暫時(shí)是只能通過冷更新(就是完全重啟App時(shí)才能加載羞迷,如果有更新界轩,當(dāng)你按home鍵或者返回鍵退出,其會將整個Process殺死重啟)衔瓮,源碼中木有在運(yùn)行途中增
這一篇的簡書,理解難度將會加大热鞍,因?yàn)楣敬a就不宜張貼啦葫慎,如果同學(xué)沒有項(xiàng)目木有實(shí)現(xiàn)過插件化的,理解起來會有一定的瓶頸薇宠。
1.關(guān)于插件化選型
可以參考以下文章
基礎(chǔ)看
Android客戶端插件化熱修復(fù)各種方案對比和最全總結(jié)
深入看這個
估計(jì)看完這些你就快可以瘋掉了偷办。^_^
選型基本需要考慮的問題
1.對四大組件的支持(hook點(diǎn)支持)
2.so庫支持
3.打包時(shí)資源沖突
4.更新方式和時(shí)機(jī)
2.插件間通信
每個插件都是基于base的module去開發(fā),那么通過這個base module那么我們就可以通過ModuleBus或者路由的機(jī)制完成傳輸了昼接。
Small本身定義的OpenUri來啟動對應(yīng)的模塊爽篷,并未有提供可以傳遞各種參數(shù)的方法。
而我們是通過自定義一個PluginManager封裝慢睡,類似之前介紹的分發(fā)機(jī)制去封裝一個方法標(biāo)志字符串標(biāo)志逐工,然后傳輸intent铡溪,context,viewgroup等對象泪喊,通過PluginManager遍歷過濾再傳輸?shù)綄?yīng)的插件模塊棕硫,其他需要傳輸?shù)男畔⒍伎梢苑庋b到intent里面。
3.資源冗余問題
你想像一下袒啼,如果你每個工程會依賴baseApi,那么編譯生成的base 的module哈扮,當(dāng)生成xxx.so文件的時(shí)候,不就會出現(xiàn)一份冗余的base module代碼和資源嗎蚓再?
這個問題其實(shí)Small有自定義的編譯代碼滑肉,其自己寫了一套編譯的groovy代碼,所以在編譯的時(shí)候重復(fù)依賴的module移除了摘仅。
Small的編譯代碼靶庙,如果沒點(diǎn)gradle構(gòu)建工程基礎(chǔ)和groovy編譯想法的確不容易找到
我這里簡單指明一下吧
之前說了使用DevSample查看Small的源碼,這里編譯的最終配使用的是AppPlugin
然后可以看到解決依賴的方法通過娃属,過濾掉D.txt里面的所要依賴的
通過app-D.txt ?compile.exclude掉這些依賴的庫
通過afterEvaluate最終加載這個過濾方法六荒。
AppPlugin這里也會有將每個module里面生成的R.txt重復(fù)的資源id過濾掉,還有保留public.txt的id
這里publicEntries是保存的public.txt里面的內(nèi)容,而bundle.Entries保存的是R.txt的內(nèi)容的
bundleEntries是過濾掉重復(fù)的R id的算法矾端。
如果不熟悉Gradle構(gòu)建流程掏击,也不打算深入了解的,就不需要深究了秩铆。
這里只要知道砚亭,每個module都編譯的時(shí)候都共有一份D.txt R.txt和public.txt,然后small的構(gòu)建會過濾掉相同的資源。然后編譯出來的so文件插件運(yùn)行的時(shí)候殴玛,還是通過一樣的資源id來索引到公用的base module的內(nèi)容钠惩。
那么為了增強(qiáng)每個功能模塊的獨(dú)立性,每個功能module都獨(dú)立成為一個工程(Small的這個工程模塊只是獨(dú)立成一個module)族阅,那么要怎么處理才能使工程都去除資源重復(fù)呢?
這里其實(shí)也很簡單膝捞,我們保證我們都依賴的自定義擴(kuò)展的Small庫坦刀,base的module是被宿主module引用的,那么需要保證其生產(chǎn)的D.txt和R.txt和public.txt蔬咬,其他的module都需要持有(手動或者配置下載到其他的module里面)鲤遥,然后編譯的時(shí)候修改加入遍歷這些txt的資源文件。
4.重復(fù)觸發(fā)
我在一個插件module里面發(fā)送一個信號林艘,然后多個module都需要接受這些信號盖奈,那么如何控制其它module接收順序,或者觸發(fā)順序調(diào)節(jié)呢狐援?給個選擇題吧
(1)插件提供判斷參數(shù)給觸發(fā)插件钢坦,將觸發(fā)順序的邏輯都寫在觸發(fā)插件里面究孕。(這里還需要考慮如果插件不存在的判空問題)
(2)將觸發(fā)的邏輯分發(fā)到其他插件,然后通過插件獲取其他插件的狀態(tài)(沒啟動或者不需要處理)而去判斷是否做相應(yīng)的操作
這里需要考慮到充分解耦的問題爹凹,因?yàn)榇a調(diào)整的觸發(fā)邏輯厨诸,控制不好我們很可能需要更替一個或者多個module,就因?yàn)橐粋€修改就更替module禾酱,這樣的設(shè)計(jì)是非常不好的微酬。估計(jì)有人肯定覺得這些方案都不適合吧。
那么我就提供第三種方案吧颤陶。
(3)PluginManager在發(fā)送信號到其他插件時(shí)候颗管,在發(fā)送前做過濾操作,需要過濾什么信號滓走,就需要讀取一個列表過濾列表(通過包名過濾或者信號名過濾)垦江,做成服務(wù)器可配置,那么隨時(shí)都可以轉(zhuǎn)換順序觸發(fā)邏輯了闲坎。
如果你看到這里有更好的解耦方案疫粥,也可以提出來,讓我們繼續(xù)學(xué)習(xí)腰懂。
5.全局彈框
有人是否有想過Android的彈框(自定義Dialog)是怎么彈出來的梗逮?
你想要在任意頁面里面可以彈出提示的彈框需要如何做?
我們彈出彈框需要依賴于window绣溜,并且我們創(chuàng)建dialog的時(shí)候需要頂層Activity的Content對象
那么我們需要如何可以獲取到頂層的Activity的Content對象呢慷彤?
這里面Application可以提供該頂層Activity時(shí)候的聲明周期,作出回調(diào)怖喻,然后我們可以通過做成base
Module保存底哗,其他插件獲取context實(shí)現(xiàn)或者直接獲取彈框?qū)ο蟆#ㄟ@里面需要api level 14)
6.最重要的提醒
我們最希望的是不能讓插件的任何調(diào)用會嵌入到宿主module或者其他插件的module锚沸,任何通信最好還是通過底層base module做的通信來協(xié)議來做跋选,因?yàn)橐坏┠居信锌眨寮瞥龑绊懙剿拗骰蛘咂渌寮罎ⅰ?/p>
這節(jié)就到這里哗蜈,希望對大家有一定的幫助前标。
如果你有更好的建議,請?jiān)谠u論中留言距潘,我會和各位繼續(xù)相互討論炼列,謝謝!
下一節(jié)將會更精彩R舯取<蠹狻!
我建立了一個關(guān)于Android架構(gòu)學(xué)習(xí)的群,里面可以進(jìn)一步進(jìn)行組件化學(xué)習(xí)和架構(gòu)思想的的交流稽犁。
群號是316556016焰望,也可以掃碼進(jìn)群。我在這里期待你們的加入g愿丁J凉馈!