插件化框架shadow的總結(jié)

1、插件框架有兩個(gè)作用:一是“自解耦”,二是“免安裝”。

目標(biāo):“像Web一樣開發(fā)App”則是一個(gè)我們后期達(dá)成的目標(biāo),這大概是“自解耦”和“免安裝”的組合形式

1.自解耦指的是:一個(gè)應(yīng)用原本由一份代碼編譯而成,希望改成將其中的一些功能單獨(dú)編譯,像插件一樣動態(tài)插在主應(yīng)用上。這樣一來可是使主應(yīng)用體積變小,下載安裝更方便。二來可以是比較獨(dú)立的功能可以單獨(dú)開發(fā)調(diào)試,甚至單獨(dú)更新版本。
2.免安裝指的是:一個(gè)應(yīng)用原本需要安裝過程才能啟動運(yùn)行,希望改為無需安裝即可從一個(gè)已經(jīng)安裝運(yùn)行的App中啟動起來。這一需求的主要目的是提高流量復(fù)用的能力。

還未具備的能力:1、下載一部分啟動一部分的能力。2、ContentProvider

2、宿主和插件使用同一個(gè)包名的好處

在執(zhí)行插件代碼的過程中,系統(tǒng)可能會調(diào)用一些(公有的或私有的)接口獲取應(yīng)用的applicationId,
然而插件從真正意義上來說并沒有安裝到設(shè)備上,如果插件的applicationId和宿主的applicationId不相同,系統(tǒng)獲取到插件的applicationId是一個(gè)沒有安裝過的包名,系統(tǒng)就因此crash。
為了避免出現(xiàn)上述情況,有兩種方法:

  1. hook系統(tǒng)接口,需要兼容各種OEM系統(tǒng)以及Android各版本
  2. 插件的applicationId和宿主的applicationId保持一致
3、Fragment調(diào)試很麻煩:

比如業(yè)務(wù)插件里有一個(gè)com.xx.GiftFragment類,實(shí)際運(yùn)行時(shí)這個(gè)類的名字就變成了com.xx.GiftFragment_。這就導(dǎo)致在com.xx.GiftFragment的源碼上打斷點(diǎn)是斷不下來的。必須在程序運(yùn)行起來之后,用IDE的重命名功能把它改名為com.xx.GiftFragment_,使得源碼和運(yùn)行時(shí)類名字一致才能斷點(diǎn)。

4、缺點(diǎn):

Shadow開源的代碼目前沒有包括插件下載和版本檢查實(shí)現(xiàn)的。
加固
卸載插件
ContentProvider
Fragment調(diào)試很麻煩
插件A同插件B有沖突so

插件化要解決的關(guān)鍵問題是:插件Activity能收到生命周期回調(diào)

舊框架使用反射的地方:attach初始化activity,super.onCreate()獲取私有變量傳遞給我們自己的new的activity

shdow的關(guān)鍵點(diǎn):使用AOP和字節(jié)碼編輯將插件activity繼承自activity的類替換為插件Activity繼承shadowActivity

Activity和Service最大的區(qū)別是Activity是有狀態(tài)的,Service是無狀態(tài)的。

對于插件框架來說,有兩點(diǎn)十分必要。

一是插件一般都是熱更新的,質(zhì)量上要求可能會降低一些,一旦出現(xiàn)Crash不會影響其他進(jìn)程的組件。
二是Android的JVM虛擬機(jī)不支持Native動態(tài)庫反加載,所以在同一個(gè)進(jìn)程中相同so庫的不同版本即不能同時(shí)加載,也不能換著加載,會造成插件和宿主存在so庫沖突。

動態(tài)化原理:

C語言需要編譯和連接兩個(gè)步驟,java則編譯成字節(jié)碼,在運(yùn)行時(shí)才會去查找用到的類,在用到的時(shí)候再去替換對應(yīng)真正要啟動的類

container代理殼子:

我們可以通過修改ClassLoader的parent,為ClassLoader新增一個(gè)parent。將原本的PathClassLoader->BootCalssLoader結(jié)構(gòu)變?yōu)镻athClassLoader ——> DexClassLoader ——> BootCalssLoader
Container的動態(tài)化是使用了唯一一次反射修改私有變量。ClassLoader的parent域不屬于非公開API,甚至不是Android的代碼,而是JDK的代碼

view同名問題:

插件和宿主存在同名的view會報(bào)錯,因?yàn)長ayoutInflater在inflated的時(shí)候做了一層緩存,以View的類名作為Key保存了Class對象。

一個(gè)自定義的Factory,然后復(fù)制了原本內(nèi)置構(gòu)造邏輯的代碼。在這段邏輯中,也有緩存機(jī)制。但是我們將緩存的Key添加了標(biāo)記插件apk的“partKey”作為一部分,這樣相同名字的View在緩存中就是不同的Key了

webview加載插件資源的問題:

替換ShadowWebView,攔截請求,將file:///android_asset/協(xié)議都修改成http://android.asset/協(xié)議

so加載的問題

插件A同插件B有沖突so,又需要在同一個(gè)進(jìn)程中工作,也需要so的設(shè)計(jì)方自行解決。
Android系統(tǒng)不允許在一個(gè)進(jìn)程中混用64位的so和32位的so,目前的解決方案是讓宿主先加載一個(gè)32位的so

看完shadow的分析文章,對于拿來主義的人是不適合的,因?yàn)樾枰芏喽伍_發(fā)或者完善的東西,至于在這些東西中存在了多少坑需要多長時(shí)間填就不知道了,對于快速驗(yàn)證可行性,產(chǎn)品解決方案快速落地的公司或者個(gè)人也是不適合的,需要做的東西太多了。

對于個(gè)人研究,完善shadow,讓這個(gè)框架快速成熟起來是可以的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容