初識(shí)插件化開(kāi)發(fā)

最近要加入一個(gè)新的項(xiàng)目組齿风,使用的技術(shù)都是之前沒(méi)有接觸過(guò)的禾蚕,主要是利用Java的反射您朽,動(dòng)態(tài)加載技術(shù),實(shí)現(xiàn)插件化開(kāi)發(fā)换淆。

目前要解決的問(wèn)題是:實(shí)現(xiàn)框架與app之間的通訊哗总。
所以特別的來(lái)了解一下插件化開(kāi)發(fā)。

1.插件開(kāi)發(fā)的介紹

1. 定義:

? 所謂插件化倍试,就是讓我們的應(yīng)用不必再像原來(lái)一樣把所有的內(nèi)容都放在一個(gè)apk中讯屈,可以把一些功能和邏輯單獨(dú)抽出來(lái)放在插件apk中,然后主apk做到[按需調(diào)用]县习,這樣的好處是一來(lái)可以減少主apk的體積涮母,讓?xiě)?yīng)用更輕便,二來(lái)可以做到熱插拔躁愿,更加動(dòng)態(tài)化叛本。

2. 背景
image.png
3. 優(yōu)點(diǎn)
image.png

2.插件開(kāi)發(fā)需要解決的問(wèn)題

1.類(lèi)的動(dòng)態(tài)加載

類(lèi)的加載可以使用Java的ClassLoader機(jī)制,但是對(duì)于A(yíng)ndroid來(lái)說(shuō)彤钟,并不是說(shuō)類(lèi)加載進(jìn)來(lái)就可以用了来候,很多組件都是有“生命”的;因此對(duì)于這些有血有肉的類(lèi)逸雹,必須給它們注入活力营搅,也就是所謂的組件生命周期管理;

2. 資源的加載

資源加載方案大家使用的原理都差不多梆砸,都是用AssetManager的隱藏方法addAssetPath剧防。

3.插件開(kāi)發(fā)需要掌握的基礎(chǔ)知識(shí)

  • ClassLoader類(lèi)加載器

要想實(shí)現(xiàn)加載外部dex文件(即插件)來(lái)實(shí)現(xiàn)熱部署,那么必然要把其中的class文件加載到內(nèi)存中辫樱。

其中涉及到兩種ClassLoader:DexClassLoader和PathClassLoader。而DexClassLoader可以加載外部的jar,dex等文件俊庇,正是我們需要的狮暑。

關(guān)于ClassLoader詳解鸡挠,見(jiàn)ClassLoader完全解析

  • Java 反射

因?yàn)椴寮pk與宿主apk不在一個(gè)apk內(nèi)搬男,那么一些類(lèi)的訪(fǎng)問(wèn)必然要通過(guò)反射進(jìn)行獲取拣展。所以了解反射對(duì)插件化的學(xué)習(xí)是必須的。

關(guān)于Java反射缔逛,見(jiàn)Java反射詳解备埃。

  • 插件資源訪(fǎng)問(wèn)

res里的每一個(gè)資源都會(huì)在R.java里生成一個(gè)對(duì)應(yīng)的Integer類(lèi)型的id,APP啟動(dòng)時(shí)會(huì)先把R.java注冊(cè)到當(dāng)前的上下文環(huán)境褐奴,我們?cè)诖a里以R文件的方式使用資源時(shí)正是通過(guò)使用這些id訪(fǎng)問(wèn)res資源按脚,然而插件的R.java并沒(méi)有注冊(cè)到當(dāng)前的上下文環(huán)境,所以插件的res資源也就無(wú)法通過(guò)id使用了敦冬。

查看源碼辅搬,通過(guò)“addAssetPath”方法重新生成一個(gè)新的Resource對(duì)象來(lái)保存插件中的資源,避免沖突脖旱。

關(guān)于插件資源訪(fǎng)問(wèn)堪遂,見(jiàn)使用插件中的R資源

  • 代理模式

插件化實(shí)現(xiàn)的過(guò)程主要靠欺上瞞下萌庆,坑蒙拐騙來(lái)實(shí)現(xiàn)溶褪。想想雖然加載進(jìn)來(lái)了Activity等組件,但也僅僅是最為一個(gè)對(duì)象而存在践险,并沒(méi)有在A(yíng)ndroidManifest中注冊(cè)猿妈,沒(méi)有生命周期的回調(diào),并不能實(shí)現(xiàn)我們想要的效果捏境。因此無(wú)論是dynamic_load_apk通過(guò)代理activity來(lái)操控插件activity的方式于游,還是DroidPlugin通過(guò)hook activity啟動(dòng)過(guò)程來(lái)啟動(dòng)插件activity的方式,都是對(duì)代理模式的應(yīng)用垫言。

關(guān)于代理模式贰剥,見(jiàn)靜態(tài)代理與動(dòng)態(tài)代理

至此筷频,通過(guò)ClassLoader加載蚌成,然后通過(guò)代理模式讓Activity等組件具有生命周期實(shí)現(xiàn)真正的功能,并且解決了資源訪(fǎng)問(wèn)問(wèn)題凛捏〉S牵可能插件化已經(jīng)可以簡(jiǎn)單的實(shí)現(xiàn)一些初步的功能,然而插件化絕不止于此坯癣。更多的內(nèi)容仍需要進(jìn)一步探索瓶盛,不過(guò)以上知識(shí)是基礎(chǔ)中的基礎(chǔ),必備之必備。

比較重要的兩個(gè)插件開(kāi)發(fā)框架介紹惩猫,它們的實(shí)現(xiàn)原理不一樣
1. Dynamic_Load_apk (任玉剛)

Dynamic-Load-Apk簡(jiǎn)稱(chēng)DL這個(gè)開(kāi)源框架芝硬,他的實(shí)現(xiàn)方式是,在宿主中埋一個(gè)代理Activity轧房,更改ClassLoader后找到加載插件中的Activity拌阴,使用宿主中的Activity作為代理,回調(diào)給插件中Activity所以對(duì)應(yīng)的生命周期奶镶。

這個(gè)思路與AndroidDynamicLoader有點(diǎn)像迟赃,都是做一個(gè)代理,只不過(guò)Dynamic-load-apk加載的插件中的Activity厂镇。

項(xiàng)目地址:https://github.com/singwhatiwanna/dynamic-load-apk

Dynamic-load-apk詳解

2. DroidPlugin (張勇)

DroidPlugin它的原理是Hook客戶(hù)端一側(cè)的系統(tǒng)Api纤壁。
項(xiàng)目地址:https://github.com/DroidPluginTeam/DroidPlugin

DroidPlugin詳解

4.插件開(kāi)發(fā)的分類(lèi)

插件式編程,由易到難剪撬,分以下個(gè)類(lèi)型來(lái)說(shuō)吧:

  • 簡(jiǎn)單的單向接口插件構(gòu)架摄乒。
  • 雙向式接口插件構(gòu)架。
  • 界面式軟件的插件構(gòu)架残黑。
  • 進(jìn)程式插件構(gòu)架

1.單向接口插件構(gòu)架

框架不向插件開(kāi)放任何接口馍佑,框架決定了怎么加載插件,怎么調(diào)用插件梨水,怎么卸載插件拭荤,插件完全是被動(dòng)的,只能干自己的活疫诽,不能反過(guò)來(lái)要求框架舅世。

也就是說(shuō),框架老大奇徒,我說(shuō)怎么干就怎么干雏亚。這種一般用于算法式的框架,比如提供加密算法框架摩钙,主程序不做具體的加密罢低,由插件來(lái)完成加密,每完成一種合適的加密算法胖笛,就加入到插件目錄网持,主程序中就可以多出一種加密算法選擇,具體選擇哪個(gè)长踊,由用戶(hù)來(lái)選擇功舀。

2. 雙向式接口插件構(gòu)架

單向式插件構(gòu)架是最簡(jiǎn)單的一種,插件處于模塊化的地位身弊,沒(méi)有任何的話(huà)語(yǔ)權(quán)辟汰,一般的介紹插件機(jī)制的文章列敲,講的都是這種,比較容易說(shuō)清楚莉擒,但這種情況在真實(shí)項(xiàng)目中酿炸,一般是很少存在的,充其量是個(gè)模塊化編程涨冀,根本算不上插件式構(gòu)架。

框架調(diào)用插件的功能麦萤,天經(jīng)地義鹿鳖,插件反過(guò)來(lái)調(diào)用框架,也是天經(jīng)地義的壮莹。雙方只有交互的情況下翅帜,才能更智能,更符合用戶(hù)習(xí)慣命满,這才能算是一個(gè)標(biāo)準(zhǔn)的插件式構(gòu)架涝滴。

交互就是一個(gè)互相調(diào)用的過(guò)程而已,因此胶台,實(shí)現(xiàn)過(guò)程也不難歼疮,主框架也提供幾個(gè)頭文件,定義好一些接口诈唬,插件在運(yùn)行過(guò)程中韩脏,可以調(diào)用主框架的功能,實(shí)現(xiàn)一些環(huán)境變量的獲取與交互等功能铸磅。在實(shí)際項(xiàng)目中赡矢,插件和框架的頭文件通常都放在一個(gè)目錄即可,雙方各負(fù)責(zé)實(shí)現(xiàn)自己定義好的頭文件阅仔。這點(diǎn)在前面的例子中吹散,已經(jīng)演示過(guò)了,這里說(shuō)說(shuō)運(yùn)行過(guò)程中的加載過(guò)程八酒。

3. 界面式軟件的插件構(gòu)架

這個(gè)分類(lèi)和前面說(shuō)的構(gòu)架空民,是一樣的,唯獨(dú)不一樣的地方在于丘跌,界面袭景。我們現(xiàn)在的客戶(hù)端軟件,如果不提供一個(gè)好看的闭树,易用的界面耸棒,基本上很難擴(kuò)大使用人群,而這點(diǎn)也制約了個(gè)人共享軟件的發(fā)展报辱,現(xiàn)在很難再出現(xiàn)以前那樣有影響力的個(gè)人版本共享軟件了与殃,精力有限。

一個(gè)桌面軟件框架,肯定有一部分的界面幅疼,需要插件來(lái)提供米奸,比如提供工具欄,菜單爽篷,主客戶(hù)端區(qū)域等等悴晰,而主框架也需要開(kāi)放很多接口,供插件操作各種界面元素逐工。這涉及到了大量的界面交互內(nèi)容铡溪,這么一來(lái),整個(gè)框架的復(fù)雜度將會(huì)提高很多泪喊,而框架的接口定義棕硫,也將增加很多,導(dǎo)致整個(gè)接口閱讀和理解的難度增加袒啼。

在界面框架這塊哈扮,事先的預(yù)定義很重要,要根據(jù)項(xiàng)目的內(nèi)容進(jìn)行規(guī)劃蚓再,比如Word這樣的滑肉,一個(gè)或者多個(gè)文檔,各個(gè)插件都可以操作這個(gè)文檔对途,還不需要提供客戶(hù)區(qū)窗口赦邻。還比如winamp那樣的,各個(gè)插件互相不干擾实檀,也不使用主界面惶洲,都提供自己的界面,還比如QQ界面那樣的膳犹,多個(gè)tab頁(yè)恬吕,每個(gè)tab頁(yè)面算一個(gè)插件,點(diǎn)擊不同的tab按鈕须床,出來(lái)自己的界面铐料。這個(gè)界面需求定下來(lái),接口設(shè)計(jì)也就不一樣了豺旬。因此钠惩,構(gòu)架需要按照你的界面要求而開(kāi)發(fā)。

4. 進(jìn)程式界面插件構(gòu)架

最典型的例子族阅,就是早期的某些瀏覽器篓跛,具備多tab頁(yè)面功能,但如果某個(gè)頁(yè)面卡死坦刀,整個(gè)瀏覽器都將無(wú)法使用愧沟,導(dǎo)致其他已經(jīng)打開(kāi)的網(wǎng)頁(yè)也無(wú)法查看了蔬咬。這促使后來(lái)的瀏覽器全部采用了多進(jìn)程方式,也就是說(shuō)沐寺,每個(gè)tab頁(yè)面林艘,實(shí)際上都是一個(gè)新的進(jìn)程,某一個(gè)進(jìn)程卡死混坞,將不會(huì)對(duì)其他進(jìn)程產(chǎn)生影響狐援。

進(jìn)程式插件構(gòu)架實(shí)際上只是把多個(gè)窗口疊加在一起,看起來(lái)像一個(gè)程序拔第,底層則是各走各的路咕村,互不干擾。最基本的原理蚊俺,就是基于WINDOWS的窗口HWND可以互相嵌套的原理。

Windows上面的各個(gè)進(jìn)程逛万,進(jìn)程空間都是互不干擾泳猬,本進(jìn)程要訪(fǎng)問(wèn)其他進(jìn)程的東西,并在它的進(jìn)程中加入自己的代碼宇植,都需要非常麻煩或者說(shuō)高深的技術(shù)得封,但有一樣除外,窗口指郁。只需要使用FindWindow忙上,就可以找到其他進(jìn)程的窗口,窗口時(shí)windows的資源闲坎,所有的進(jìn)程公用這些資源疫粥,當(dāng)窗口所有資源耗盡的時(shí)候,就再也創(chuàng)建不了新的窗口了腰懂。這個(gè)限制梗逮,我得觀(guān)察是6萬(wàn)多個(gè),不知道對(duì)不對(duì)绣溜。自己的窗口在創(chuàng)建的時(shí)候慷彤,需要傳入一個(gè)父窗口句柄,而這個(gè)父窗口句柄怖喻,是沒(méi)有進(jìn)程限制的底哗。

進(jìn)程式插件在解決了窗口問(wèn)題之后,另外面臨的問(wèn)題锚沸,就是通訊問(wèn)題跋选,原來(lái)的接口指針,直接調(diào)用即可咒吐,現(xiàn)在這些指針野建,全部不能使用了属划。這里,我們可以采用如下圖所示方案候生。

  • 主框架接口
  • 通訊模塊
  • 加封/解封裝模塊
  • 插件模塊接口
  • 加封/解封模塊
  • 通訊模塊

如果把上面的通訊模塊同眯,換成http通訊,把加封/解封換成xml封裝方式唯鸭,是不是和“soap”協(xié)議一模一樣了须蜗?沒(méi)錯(cuò),標(biāo)準(zhǔn)的SOAP協(xié)議就是這么做的目溉。我們可以不用HTTP明肮,簡(jiǎn)單的TCP或者管道通訊即可,把接口用xml方式封裝缭付,然后傳遞到對(duì)端柿估,即可形成插件調(diào)用機(jī)制。

作為構(gòu)架陷猫,主要是把接口開(kāi)放給插件秫舌,但要屏蔽掉進(jìn)程通訊相關(guān)的細(xì)節(jié),因此把以上的通訊機(jī)制绣檬,封裝成一個(gè)lib或者dll足陨,在插件中,調(diào)用這些函數(shù)的時(shí)候娇未,通過(guò)通訊墨缘,會(huì)調(diào)用到主框架程序中。只要這個(gè)封裝庫(kù)做的夠好零抬,插件幾乎完全不知道自己是進(jìn)程式插件镊讼,還是單進(jìn)程式插件。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末媚值,一起剝皮案震驚了整個(gè)濱河市狠毯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌褥芒,老刑警劉巖嚼松,帶你破解...
    沈念sama閱讀 222,729評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異锰扶,居然都是意外死亡献酗,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)坷牛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)罕偎,“玉大人,你說(shuō)我怎么就攤上這事京闰⊙占埃” “怎么了甩苛?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,461評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)俏站。 經(jīng)常有香客問(wèn)我讯蒲,道長(zhǎng),這世上最難降的妖魔是什么肄扎? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,135評(píng)論 1 300
  • 正文 為了忘掉前任墨林,我火速辦了婚禮,結(jié)果婚禮上犯祠,老公的妹妹穿的比我還像新娘旭等。我一直安慰自己,他們只是感情好衡载,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布搔耕。 她就那樣靜靜地躺著,像睡著了一般痰娱。 火紅的嫁衣襯著肌膚如雪度迂。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,736評(píng)論 1 312
  • 那天猜揪,我揣著相機(jī)與錄音,去河邊找鬼坛梁。 笑死而姐,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的划咐。 我是一名探鬼主播拴念,決...
    沈念sama閱讀 41,179評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼褐缠!你這毒婦竟也來(lái)了政鼠?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 40,124評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤队魏,失蹤者是張志新(化名)和其女友劉穎公般,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體胡桨,經(jīng)...
    沈念sama閱讀 46,657評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡官帘,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了昧谊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片刽虹。...
    茶點(diǎn)故事閱讀 40,872評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖呢诬,靈堂內(nèi)的尸體忽然破棺而出涌哲,到底是詐尸還是另有隱情胖缤,我是刑警寧澤,帶...
    沈念sama閱讀 36,533評(píng)論 5 351
  • 正文 年R本政府宣布阀圾,位于F島的核電站哪廓,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏稍刀。R本人自食惡果不足惜撩独,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望账月。 院中可真熱鬧综膀,春花似錦、人聲如沸局齿。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,700評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)抓歼。三九已至讥此,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間谣妻,已是汗流浹背萄喳。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,819評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蹋半,地道東北人他巨。 一個(gè)月前我還...
    沈念sama閱讀 49,304評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像减江,于是被迫代替她去往敵國(guó)和親染突。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評(píng)論 2 361

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