有關(guān)Android插件化的一些總結(jié)思考
最近幾年移動(dòng)開發(fā)業(yè)界興起了「 插件化技術(shù) 」的旋風(fēng),各個(gè)大廠都推出了自己的插件化框架,各種開源框架都評(píng)價(jià)自身功能優(yōu)越性,令人目不暇接。隨著公司業(yè)務(wù)快速發(fā)展,項(xiàng)目增多,開發(fā)資源卻有限,如何能在有限資源內(nèi)滿足需求和項(xiàng)目的增長(zhǎng),同時(shí)又能快速響應(yīng)問(wèn)題和迭代新需求,這就是一個(gè)矛盾點(diǎn)。此時(shí),插件化技術(shù)正好風(fēng)生水起,去了解各個(gè)主流框架實(shí)現(xiàn)思路,看看能對(duì)目前工作是否有幫助,是很有必要的。
主要分為以下幾個(gè)部分
- 插件化介紹
- 入門知識(shí)
- 實(shí)現(xiàn)原理
- 主流框架
- 實(shí)戰(zhàn)
- 小結(jié)
插件化介紹
百度百科里是這么定義插件的:「 是一種遵循一定規(guī)范的應(yīng)用程序接口編寫出來(lái)的程序,只能運(yùn)行在程序規(guī)定的系統(tǒng)平臺(tái)下,而不能脫離指定的平臺(tái)單獨(dú)運(yùn)行。」,也就是說(shuō),插件可以提供一種動(dòng)態(tài)擴(kuò)展能力,使得應(yīng)用程序在運(yùn)行時(shí)加載原本不屬于該應(yīng)用的功能,并且做到動(dòng)態(tài)更新和替換。
那么在 Android 中,何為「 插件化 」,顧名思義,就是把一些核心復(fù)雜依賴度高的業(yè)務(wù)模塊封裝成獨(dú)立的插件,然后根據(jù)不同業(yè)務(wù)需求進(jìn)行不同組合,動(dòng)態(tài)進(jìn)行替換,可對(duì)插件進(jìn)行管理、更新,后期對(duì)插件也可進(jìn)行版本管理等操作。在插件化中有兩個(gè)概念需要講解下:
宿主
所謂宿主,就是需要能提供運(yùn)行環(huán)境,給資源調(diào)用提供上下文環(huán)境,一般也就是我們主 APK ,要運(yùn)行的應(yīng)用,它作為應(yīng)用的主工程所在,實(shí)現(xiàn)了一套插件的加載和管理的框架,插件都是依托于宿主的APK而存在的。
插件
插件可以想象成每個(gè)獨(dú)立的功能模塊封裝為一個(gè)小的 APK ,可以通過(guò)在線配置和更新實(shí)現(xiàn)插件 APK 在宿主 APK 中的上線和下線,以及動(dòng)態(tài)更新等功能。
那么為何要使用插件化技術(shù),它有何優(yōu)勢(shì),能給我們帶來(lái)什么樣好處,這里簡(jiǎn)單列舉了以下幾點(diǎn):
- 讓用戶不用重新安裝 APK 就能升級(jí)應(yīng)用功能,減少發(fā)版本頻率,增加用戶體驗(yàn)。
- 提供一種快速修復(fù)線上 BUG 和更新的能力。
- 按需加載不同的模塊,實(shí)現(xiàn)靈活的功能配置,減少服務(wù)器對(duì)舊版本接口兼容壓力。
- 模塊化、解耦合、并行開發(fā)、 65535 問(wèn)題。
入門知識(shí)
首先我們要知道插件化技術(shù)是屬于比較復(fù)雜一個(gè)領(lǐng)域,復(fù)雜點(diǎn)在于它涉及知識(shí)點(diǎn)廣泛,不僅僅是上層做應(yīng)用架構(gòu)能力,還要求我們對(duì) Android 系統(tǒng)底層知識(shí)需要有一定的認(rèn)知,這里簡(jiǎn)單羅列了其中會(huì)涉及的知識(shí)點(diǎn):

首先,要介紹的是 Binder ,我們都知道 Android 多進(jìn)程通信核心就是 Binder ,如果沒(méi)有它真的寸步難行。 Binder 涉及兩層技術(shù),你可以認(rèn)為它是一個(gè)中介者模式,在客戶端和服務(wù)器端之間, Binder 就起到中介的作用。如果要實(shí)現(xiàn)四大組件的插件化,就需要在 Binder 上做修改, Binder 服務(wù)端的內(nèi)容沒(méi)辦法修改,只能改客戶端的代碼,而且四大組件的每個(gè)組件的客戶端都不一樣,這個(gè)就需要深入研究了。學(xué)習(xí)Binder的最好方式是 AIDL ,這方面在網(wǎng)上有很多資料,最簡(jiǎn)單的方式就是自己寫個(gè) aidl 文件自動(dòng)生成一個(gè) Java 類,然后去查看這個(gè)Java類的每個(gè)方法和變量,然后再去看四大組件,其實(shí)都是跟 AIDL 差不多的實(shí)現(xiàn)方式。
其次,是 App 打包的流程。代碼寫完了,執(zhí)行一次打包操作,中途經(jīng)歷了資源打包、 Dex 生成、簽名等過(guò)程。其中最重要的就是資源的打包,即 AAPT 這一步,如果宿主和插件的資源id沖突,一種解決辦法就是在這里做修改。
第三, App 在手機(jī)上的安裝流程也很重要。熟悉安裝流程不僅對(duì)插件化有幫助,在遇到安裝 Bug 的時(shí)候也非常重要。手機(jī)安裝 App 的時(shí)候,經(jīng)常會(huì)有下載異常,提示資源包不能解析,這時(shí)需要知道安裝 App 的這段代碼在什么地方,這只是第一步。第二步需要知道, App 下載到本地后,具體要做哪些事情。手機(jī)有些目錄不能訪問(wèn), App 下載到本地之后,放到哪個(gè)目錄下,然后會(huì)生成哪些文件。插件化有個(gè)增量更新的概念,如何下載一個(gè)增量包,從本地具體哪個(gè)位置取出一個(gè)包,這個(gè)包的具體命名規(guī)則是什么,等等。這些細(xì)節(jié)都必須要清楚明白。
第四,是 App 的啟動(dòng)流程。 Activity 啟動(dòng)有幾種方式?一種是寫一個(gè) startActivity ,第二種是點(diǎn)擊手機(jī) App ,通過(guò)手機(jī)系統(tǒng)里的 Launcher 機(jī)制,啟動(dòng) App 里默認(rèn)的 Activity 。通常, App 開發(fā)人員喜聞樂(lè)見(jiàn)的方式是第二種。那么第一種方式的啟動(dòng)原理是什么呢?另外,啟動(dòng)的時(shí)候,Main 函數(shù)在哪里?這個(gè) Main 函數(shù)的位置很重要,我們可以對(duì)它所在的類做修改,從而實(shí)現(xiàn)插件化。
第五點(diǎn)更重要,做 Android 插件化需要控制兩個(gè)地方。首先是插件 Dex 的加載,如何把插件 Dex 中的類加載到內(nèi)存?另外是資源加載的問(wèn)題。插件可能是 Apk 也可能是 so 格式,不管哪一種,都不會(huì)生成 R.id ,從而沒(méi)辦法使用。這個(gè)問(wèn)題有好幾種解決方案。一種是是重寫 Context 的 getAsset 、 getResource 之類的方法,偷換概念,讓插件讀取插件里的資源,但缺點(diǎn)就是宿主和插件的資源 id 會(huì)沖突,需要重寫 AAPT 。另一種是重寫 AMS中保存的插件列表,從而讓宿主和插件分別去加載各自的資源而不會(huì)沖突。第三種方法,就是打包后,執(zhí)行一個(gè)腳本,修改生成包中資源id。
第六點(diǎn),在實(shí)施插件化后,如何解決不同插件的開發(fā)人員的工作區(qū)問(wèn)題。比如,插件1和插件2,需要分別下載哪些代碼,如何獨(dú)立運(yùn)行?就像機(jī)票和火車票,如何只運(yùn)行自己的插件,而不運(yùn)行別人的插件?這是協(xié)同工作的問(wèn)題。火車票和機(jī)票,這兩個(gè) Android 團(tuán)隊(duì)的各自工作區(qū)是不一樣的,這時(shí)候就要用到 Gradle 腳本了,每個(gè)項(xiàng)目分別有各自的倉(cāng)庫(kù),有各自不同的打包腳本,只需要把自己的插件跟宿主項(xiàng)目一起打包運(yùn)行起來(lái),而不用引入其他插件,還有更厲害的是,也可以把自己的插件當(dāng)作一個(gè) App 來(lái)打包并運(yùn)行。
上面介紹了插件化的入門知識(shí),一共六點(diǎn),每一點(diǎn)都需要花大量時(shí)間去理解。否則,在面對(duì)插件化項(xiàng)目的時(shí)候,很多地方你會(huì)一頭霧水。而只要理解了這六點(diǎn)核心,一切可迎刃而解。
實(shí)現(xiàn)原理
在Android中應(yīng)用插件化技術(shù),其實(shí)也就是動(dòng)態(tài)加載的過(guò)程,分為以下幾步:
- 把可執(zhí)行文件( .so/dex/jar/apk 等)拷貝到應(yīng)用 APP 內(nèi)部。
- 加載可執(zhí)行文件,更換靜態(tài)資源
- 調(diào)用具體的方法執(zhí)行業(yè)務(wù)邏輯
Android 項(xiàng)目中,動(dòng)態(tài)加載技術(shù)按照加載的可執(zhí)行文件的不同大致可以分為兩種:
- 動(dòng)態(tài)加載 .so 庫(kù)
- 動(dòng)態(tài)加載 dex/jar/apk文件(現(xiàn)在動(dòng)態(tài)加載普遍說(shuō)的是這種)
第一點(diǎn), Android 中 NDK 中其實(shí)就使用了動(dòng)態(tài)加載,動(dòng)態(tài)加載 .so 庫(kù)并通過(guò) JNI 調(diào)用其封裝好的方法。后者一般是由 C/C++ 編譯而成,運(yùn)行在 Native 層,效率會(huì)比執(zhí)行在虛擬機(jī)層的 Java 代碼高很多,所以 Android 中經(jīng)常通過(guò)動(dòng)態(tài)加載 .so 庫(kù)來(lái)完成一些對(duì)性能比較有需求的工作(比如 Bitmap 的解碼、圖片高斯模糊處理等)。此外,由于 .so 庫(kù)是由 C/C++ 編譯而來(lái)的,只能被反編譯成匯編代碼,相比中 dex 文件反編譯得到的 Smali 代碼更難被破解,因此 .so 庫(kù)也可以被用于安全領(lǐng)域。
其二,“基于 ClassLoader 的動(dòng)態(tài)加載 dex/jar/apk 文件”,就是我們指在 Android 中 動(dòng)態(tài)加載由 Java 代碼編譯而來(lái)的 dex 包并執(zhí)行其中的代碼邏輯,這是常規(guī) Android 開發(fā)比較少用到的一種技術(shù),目前說(shuō)的動(dòng)態(tài)加載指的就是這種。
Android 項(xiàng)目中,所有 Java 代碼都會(huì)被編譯成 dex 文件,Android 應(yīng)用運(yùn)行時(shí),就是通過(guò)執(zhí)行 dex 文件里的業(yè)務(wù)代碼邏輯來(lái)工作的。使用動(dòng)態(tài)加載技術(shù)可以在 Android 應(yīng)用運(yùn)行時(shí)加載外部的 dex 文件,而通過(guò)網(wǎng)絡(luò)下載新的 dex 文件并替換原有的 dex 文件就可以達(dá)到不安裝新 APK 文件就升級(jí)應(yīng)用(改變代碼邏輯)的目的。
所以說(shuō),在 Android 中的 ClassLoader 機(jī)制主要用來(lái)加載 dex 文件,系統(tǒng)提供了兩個(gè) API 可供選擇:
- PathClassLoader:只能加載已經(jīng)安裝到 Android 系統(tǒng)中的 APK 文件。因此不符合插件化的需求,不作考慮。
- DexClassLoader:支持加載外部的 APK、Jar 或者 dex 文件,正好符合文件化的需求,所有的插件化方案都是使用 DexClassloader 來(lái)加載插件 APK 中的 .class文件的。
主流框架
在 Android 中實(shí)現(xiàn)插件化框架,需要解決的問(wèn)題主要如下:
- 資源和代碼的加載
- Android 生命周期的管理和組件的注冊(cè)
- 宿主 APK 和插件 APK 資源引用的沖突解決
下面分析幾個(gè)目前主流的開源框架,看看每個(gè)框架具體實(shí)現(xiàn)思路和優(yōu)缺點(diǎn)。
DL 動(dòng)態(tài)加載框架( 2014 年底)
是基于代理的方式實(shí)現(xiàn)插件框架,對(duì) App 的表層做了處理,通過(guò)在 Manifest 中注冊(cè)代理組件,當(dāng)啟動(dòng)插件組件時(shí),首先啟動(dòng)一個(gè)代理組件,然后通過(guò)這個(gè)代理組件來(lái)構(gòu)建,啟動(dòng)插件組件。 需要按照一定的規(guī)則來(lái)開發(fā)插件 APK,插件中的組件需要實(shí)現(xiàn)經(jīng)過(guò)改造后的 Activity、FragmentActivity、Service 等的子類。
優(yōu)點(diǎn)如下:
- 插件需要遵循一定的規(guī)則,因此安全方面可控制。
- 方案簡(jiǎn)單,適用于自身少量代碼的插件化改造。
缺點(diǎn)如下:
- 不支持通過(guò) This 調(diào)用組件的方法,需要通過(guò) that 去調(diào)用。
- 由于 APK 中的 Activity 沒(méi)有注冊(cè),不支持隱式調(diào)用 APK 內(nèi)部的 Activity。
- 插件編寫和改造過(guò)程中,需要考慮兼容性問(wèn)題比較多,聯(lián)調(diào)起來(lái)會(huì)比較費(fèi)時(shí)費(fèi)力。
DroidPlugin( 2015 年 8 月)
DroidPlugin 是 360 手機(jī)助手實(shí)現(xiàn)的一種插件化框架,它可以直接運(yùn)行第三方的獨(dú)立 APK 文件,完全不需要對(duì) APK 進(jìn)行修改或安裝。一種新的插件機(jī)制,一種免安裝的運(yùn)行機(jī)制,是一個(gè)沙箱(但是不完全的沙箱。就是對(duì)于使用者來(lái)說(shuō),并不知道他會(huì)把 apk 怎么樣), 是模塊化的基礎(chǔ)。
實(shí)現(xiàn)原理:
- 共享進(jìn)程:為android提供一個(gè)進(jìn)程運(yùn)行多個(gè) apk 的機(jī)制,通過(guò) API 欺騙機(jī)制瞞過(guò)系統(tǒng)。
- 占坑:通過(guò)預(yù)先占坑的方式實(shí)現(xiàn)不用在 manifest 注冊(cè),通過(guò)一帶多的方式實(shí)現(xiàn)服務(wù)管理。
- Hook 機(jī)制:動(dòng)態(tài)代理實(shí)現(xiàn)函數(shù) hook ,Binder 代理繞過(guò)部分系統(tǒng)服務(wù)限制,IO 重定向(先獲取原始 Object –> Read ,然后動(dòng)態(tài)代理 Hook Object 后–> Write 回去,達(dá)到瞞天過(guò)海的目的)。
插件 Host 的程序架構(gòu):

優(yōu)點(diǎn)如下:
- 支持 Android 四大組件,而且插件中的組件不需要在宿主 APK 中注冊(cè)。
- 支持 Android 2.3 及以上系統(tǒng),支持所有的系統(tǒng) API。
- 插件與插件之間,插件與宿主之間的代碼和資源完全隔閡。
- 實(shí)現(xiàn)了進(jìn)程管理,插件的空進(jìn)程會(huì)被及時(shí)回收,占用內(nèi)存低。
缺點(diǎn)如下:
- 插件 APK 中不支持自定義資源的 Notification,通知欄限制。
- 插件 APK 中無(wú)法注冊(cè)具有特殊的 IntentFilter 的四大組件。
- 缺乏對(duì) Native 層的 Hook 操作,對(duì)于某些帶有 Native 代碼的插件 APK 支持不友好,可能無(wú)法正常運(yùn)行。
- 由于插件與插件,插件與宿主之間的代碼完全隔離,因此,插件與插件,插件與宿主之間的通信只能通過(guò) Android 系統(tǒng)級(jí)別的通信方式。
- 安全性擔(dān)憂(可以修改,hook一些重要信息)。
- 機(jī)型適配(不是所有機(jī)器上都能行,因?yàn)榇罅坑梅瓷湎嚓P(guān),如果rom廠商深度定制了framework層,反射的方法或者類不在,容易插件運(yùn)用失敗)
Small( 2015 年底)
Small 是一種實(shí)現(xiàn)輕巧的跨平臺(tái)插件化框架,基于“輕量、透明、極小化、跨平臺(tái)”的理念,實(shí)現(xiàn)原理有以下三點(diǎn)。
- 動(dòng)態(tài)加載類:我們知道插件化很多都從 DexClassLoader 類有個(gè) DexPathList 清單,支持 dex/jar/zip/apk 文件格式,卻沒(méi)有支持 .so 文件格式,因此 Small 框架則是把 .so 文件包裝成 zip 文件格式,插入到 DexPathList 集合中,改寫動(dòng)態(tài)加載的代碼。
- 資源分段:由于 Android 資源的格式是 0xPPTTNNNN ,PP 是包 ID ,00-02 是屬于系統(tǒng),7f 屬于應(yīng)用程序,03-7e 則保留,可以在這個(gè)范圍內(nèi)做文章 , TT 則是 Type 比如,attr 、layout 、string 等等,NNNN 則是資源全局 ID。那么這個(gè)框架則是對(duì)資源包進(jìn)行重新打包,每個(gè)插件重新分配資源 ID ,這樣就保證了宿主和插件的資源不沖突。
- 動(dòng)態(tài)代理注冊(cè):在 Android 中要使用四大組件,都是需要在 manifest 清單中注冊(cè),這樣才可以使用,那如何在不注冊(cè)情況也能使用呢,這里就是用到動(dòng)態(tài)代理機(jī)制進(jìn)行 Hook ,在發(fā)送 AMS 之前用占坑的組件來(lái)欺騙系統(tǒng),通過(guò)認(rèn)證后,再把真正要調(diào)用的組件還原回來(lái),達(dá)到瞞天過(guò)海目的。
架構(gòu)圖:

Picture
優(yōu)點(diǎn)如下:
- 所有插件支持內(nèi)置宿主包中。
- 插件的編碼和資源文件的使用與普通開發(fā)應(yīng)用沒(méi)有差別。
- 通過(guò)設(shè)定 URI ,宿主以及 Native 應(yīng)用插件,Web 插件,在線網(wǎng)頁(yè)等能夠方便進(jìn)行通信。
- 支持 Android 、 iOS 、和 Html5 ,三者可以通過(guò)同一套 Java 接口實(shí)現(xiàn)通信。
缺點(diǎn)如下:
- 暫不支持 Service 的動(dòng)態(tài)注冊(cè),不過(guò)這個(gè)可以通過(guò)將 Service 預(yù)先注冊(cè)在宿主的 AndroidManifest.xml 文件中進(jìn)行規(guī)避,因?yàn)? Service 的更新頻率通常非常低。
與其他主流框架的區(qū)別:
- DyLA : Dynamic-load-apk @singwhatiwanna
- DiLA : Direct-Load-apk @FinalLody
- APF : Android-Plugin-Framework @limpoxe
- ACDD : ACDD @bunnyblue
- DyAPK : DynamicAPK @TediWang
- DPG : DroidPlugin @cmzy, 360
功能
透明度
VirtualAPK (2017年 6 月 )
VirtualAPK 是滴滴開源的一套插件化框架,支持幾乎所有的 Android 特性,四大組件方面。
架構(gòu)圖:

實(shí)現(xiàn)思路:
VirtualAPK 對(duì)插件沒(méi)有額外的約束,原生的 apk 即可作為插件。插件工程編譯生成 apk后,即可通過(guò)宿主 App 加載,每個(gè)插件 apk 被加載后,都會(huì)在宿主中創(chuàng)建一個(gè)單獨(dú)的 LoadedPlugin 對(duì)象。如下圖所示,通過(guò)這些 LoadedPlugin 對(duì)象,VirtualAPK 就可以管理插件并賦予插件新的意義,使其可以像手機(jī)中安裝過(guò)的 App 一樣運(yùn)行。
- 合并宿主和插件的ClassLoader 需要注意的是,插件中的類不可以和宿主重復(fù)
- 合并插件和宿主的資源 重設(shè)插件資源的 packageId,將插件資源和宿主資源合并
- 去除插件包對(duì)宿主的引用 構(gòu)建時(shí)通過(guò) Gradle 插件去除插件對(duì)宿主的代碼以及資源的引用

特性如下:
四大組件均不需要在宿主manifest中預(yù)注冊(cè),每個(gè)組件都有完整的生命周期。
- Activity:支持顯示和隱式調(diào)用,支持Activity的theme和LaunchMode,支持透明主題;
- Service:支持顯示和隱式調(diào)用,支持Service的start、stop、bind和unbind,并支持跨進(jìn)程bind插件中的Service;
- Receiver:支持靜態(tài)注冊(cè)和動(dòng)態(tài)注冊(cè)的Receiver;
- ContentProvider:支持provider的所有操作,包括CRUD和call方法等,支持跨進(jìn)程訪問(wèn)插件中的Provider。
- 自定義View:支持自定義 View,支持自定義屬性和style,支持動(dòng)畫;
- PendingIntent:支持PendingIntent以及和其相關(guān)的Alarm、Notification和AppWidget;
- 支持插件Application以及插件manifest中的meta-data;
- 支持插件中的so。
優(yōu)秀的兼容性
- 兼容市面上幾乎所有的Android手機(jī),這一點(diǎn)已經(jīng)在滴滴出行客戶端中得到驗(yàn)證。
- 資源方面適配小米、Vivo、Nubia 等,對(duì)未知機(jī)型采用自適應(yīng)適配方案。
- 極少的 Binder Hook,目前僅僅 hook了兩個(gè)Binder:AMS和IContentProvider,hook 過(guò)程做了充分的兼容性適配。
- 插件運(yùn)行邏輯和宿主隔離,確保框架的任何問(wèn)題都不會(huì)影響宿主的正常運(yùn)行。
入侵性極低
- 插件開發(fā)等同于原生開發(fā),四大組件無(wú)需繼承特定的基類;
- 精簡(jiǎn)的插件包,插件可以依賴宿主中的代碼和資源,也可以不依賴;
- 插件的構(gòu)建過(guò)程簡(jiǎn)單,通過(guò) Gradle 插件來(lái)完成插件的構(gòu)建,整個(gè)過(guò)程對(duì)開發(fā)者透明。
如下是 VirtualAPK 和主流的插件化框架之間的對(duì)比。
RePlugin (2017 年 7 月)
RePlugin是一套完整的、穩(wěn)定的、適合全面使用的,占坑類插件化方案,由360手機(jī)衛(wèi)士的RePlugin Team研發(fā),也是業(yè)內(nèi)首個(gè)提出”全面插件化“(全面特性、全面兼容、全面使用)的方案。
框架圖:

主要優(yōu)勢(shì)有:
- 極其靈活:主程序無(wú)需升級(jí)(無(wú)需在Manifest中預(yù)埋組件),即可支持新增的四大組件,甚至全新的插件
- 非常穩(wěn)定:Hook 點(diǎn)僅有一處(ClassLoader),無(wú)任何 Binder Hook!如此可做到其崩潰率僅為“萬(wàn)分之一”,并完美兼容市面上近乎所有的 Android ROM。
- 特性豐富:支持近乎所有在“單品”開發(fā)時(shí)的特性。包括靜態(tài) Receiver、 Task-Affinity 坑位、自定義 Theme、進(jìn)程坑位、AppCompat、DataBinding等。
- 易于集成:無(wú)論插件還是主程序,只需“數(shù)行”就能完成接入。
- 管理成熟:擁有成熟穩(wěn)定的“插件管理方案”,支持插件安裝、升級(jí)、卸載、版本管理,甚至包括進(jìn)程通訊、協(xié)議版本、安全校驗(yàn)等。
- 數(shù)億支撐:有 360 手機(jī)衛(wèi)士龐大的數(shù)億用戶做支撐,三年多的殘酷驗(yàn)證,確保App用到的方案是最穩(wěn)定、最適合使用的。
實(shí)戰(zhàn)
主要是測(cè)試各個(gè)框架之間上手的容易度如何,并做不同對(duì)比,這邊寫了兩個(gè) Demo 例子,一個(gè)是基于 Small 框架,一個(gè)基于 VirtualAPK 框架,從中能看出不同。
Small 實(shí)踐
要引用官方最新的版本,不然在宿主和插件合并build.gradle 的時(shí)候會(huì)出現(xiàn)一個(gè) BUG,這是個(gè)坑位,注意行走。其次在模塊命名上要遵循一定的規(guī)則,比如業(yè)務(wù)模塊用 app.* ,公共庫(kù)模塊用 lib.* ,相當(dāng)于包名 .app.,.lib. 。每次在插件中添加一個(gè) activity 組件,都需要在宿主中配置路由,然后在重新編譯插件一遍,不然直接運(yùn)行的話,在宿主中是找到新添加的 activity 組件,會(huì)報(bào)該組件沒(méi)在系統(tǒng) manifest 中,所以每次新增或修改建議插件都重新編譯一遍。官方里說(shuō)了,對(duì)于 Service 支持不太友好,就沒(méi)去實(shí)踐了。
VirtualAPK 實(shí)踐
有個(gè)坑需要注意的是構(gòu)建環(huán)境,官方說(shuō)明是要以下版本環(huán)境,Gradle 2.14.1 和 com.android.tools.build 2.1.3, 之前編譯的是用最新的Gradle版本,導(dǎo)致一直有問(wèn)題,至于是否有其他問(wèn)題,可以看官方文檔。
具體代碼
- Small Demo :https://github.com/cr330326/MySmall
- VirtualAPK Demo :https://github.com/cr330326/MyVirtualAPKDemo
小結(jié)
正如開頭所說(shuō),要實(shí)現(xiàn)插件化的框架,無(wú)非就是解決那典型的三個(gè)問(wèn)題:插件代碼如何加載、插件中的組件生命周期如何管理、插件資源和宿主資源沖突怎么辦。每個(gè)框架針對(duì)這三個(gè)問(wèn)題,都有不同的解決方案,同時(shí)呢,根據(jù)時(shí)間順序,后出來(lái)的框架往往都會(huì)吸收已經(jīng)出的框架精髓,進(jìn)而修復(fù)那些比較有里程碑意義框架的不足。但這些框架的核心思想都是用到了代理模式,有的在表面層進(jìn)行代理,有的則在系統(tǒng)應(yīng)用層進(jìn)行代理,通過(guò)代理達(dá)到替換和瞞天過(guò)海,最終讓 Android 系統(tǒng)誤以為調(diào)用插件功能和調(diào)用原生開發(fā)的功能是一樣的,進(jìn)而達(dá)到插件化和原生兼容編程的目的。