Android 插件化開發(fā)(動(dòng)態(tài)加載插件資源以及activity跳轉(zhuǎn))

相信很多人再開發(fā)過(guò)程會(huì)遇到方法數(shù)超過(guò)65535的問(wèn)題,通過(guò)學(xué)習(xí)我們通過(guò)一個(gè)簡(jiǎn)單的例子利用Android的插件化開發(fā)去解決這個(gè)問(wèn)題塌计。所謂插件化就是由宿主APP去加載以及運(yùn)行插件APP挺身。

下面是一些插件化的優(yōu)勢(shì):

1.模塊解耦

2.解除單個(gè)dex函數(shù)不能超過(guò)65535的限制

3.動(dòng)態(tài)升級(jí)

4.高效開發(fā)(編譯速度更快)

下面是插件化開發(fā)的缺點(diǎn):

1.插件化開發(fā)的APP不能在Google Play上線,也就是沒(méi)有海外市場(chǎng)锌仅。

2.技術(shù)有難度章钾,目前一些成熟的框架都是閉源的

下面開始通過(guò)一個(gè)簡(jiǎn)單的demo 實(shí)現(xiàn)Android插件化開發(fā)(類似支付寶中在未安裝滴滴軟件的情況下能夠跳轉(zhuǎn)到滴滴的頁(yè)面)

我們通過(guò)簡(jiǎn)單的圖片設(shè)置到頁(yè)面驗(yàn)證跳轉(zhuǎn)是否成功

1、首先我們創(chuàng)建一個(gè)宿主工程->MainActivity


用一個(gè)點(diǎn)擊事件做插件的Activity的跳轉(zhuǎn)技扼。

2伍玖、創(chuàng)建一個(gè)插件工程module->MainActivity(一定要是module不是Android library)

3、創(chuàng)建一個(gè)插件遵循的標(biāo)準(zhǔn)工程library(DidiInterface 和 BasePlugActivity)

例如 滴滴想要在支付寶上集成剿吻,那么就必須遵循這個(gè)標(biāo)準(zhǔn)做事


創(chuàng)建一個(gè) BasePlugActivity類 實(shí)現(xiàn)接口


緊接著插件的MainActivity去繼承這個(gè)BasePlugActivity窍箍。


看似以上代碼并沒(méi)有什么問(wèn)題,我們平常寫的最簡(jiǎn)單的代碼不就是這樣的嗎丽旅?? ?

其實(shí)坑馬上就來(lái)了椰棘。我們知道 setContenView以及 findViewById都是調(diào)用系統(tǒng)提供的上下文的,(包括BasePlugActivity中的類似onCreate都是調(diào)用系統(tǒng)的 super.Oncreate(saveInstanceState))然而插件apk我們是沒(méi)有安裝的榄笙,所以凡是調(diào)用系統(tǒng)上下文的方法都是不靠譜的邪狞,我們必須都要重寫他們。然后注入一個(gè)新的context.



好了茅撞,插件類也創(chuàng)建完了那么我們到底要怎么在宿主中去跳轉(zhuǎn)到這個(gè)沒(méi)有安裝的插件Activity呢帆卓?既然要跳轉(zhuǎn)那么第一步我們要做的可能是先去配置文件中注冊(cè)這個(gè)類。那么在宿主項(xiàng)目中并沒(méi)有這個(gè)Activity那么我們要怎么實(shí)現(xiàn)以上的需求呢米丘?

其實(shí)剑令,除了Hook我們還可以用插樁的方式,通過(guò)一個(gè)代理類專門做類的跳轉(zhuǎn)拄查。

我們?cè)谒拗黜?xiàng)目中創(chuàng)建一個(gè)ProxyActivity吁津,我們知道加載一個(gè)頁(yè)面除了要加載它的ClassLoader 還要重寫它的getResources。

所以首先我們創(chuàng)建一個(gè)管理單例類 ProxyManager專門去做這些東西


解釋下:DexclassLoader

在Java環(huán)境中,有個(gè)概念叫做”類裝載器(Class Loader)”,其作用是動(dòng)態(tài)加載Class文件.標(biāo)準(zhǔn)的Java SDK中有一個(gè)ClassLoader類,借助他可以裝載想要的Class文件,每個(gè)ClassLoader對(duì)象在初始化的時(shí)候必須指定Class文件的路徑.

但我們?cè)谑褂胘ava的時(shí)候,基本上沒(méi)有使用過(guò)ClassLoader,僅僅使用import就可以加載類文件了,簡(jiǎn)單的講,import中所引用的類文件有兩個(gè)特點(diǎn):

1:必須存在于本地,當(dāng)程序運(yùn)行需要該類的時(shí)候,內(nèi)部類裝載器會(huì)自動(dòng)裝載該類,這對(duì)程序員來(lái)說(shuō)是透明的,即程序員感知不到該過(guò)程

2:編譯時(shí)必須在現(xiàn)場(chǎng),否則編譯過(guò)程會(huì)因找不到引用文件而不能正常編譯.

但在有些情況下,所需要的類卻不能滿足以上兩個(gè)條件.比如當(dāng)該類是從遠(yuǎn)程下載并在本地執(zhí)行的時(shí)候,典型的例子就是通過(guò)瀏覽器中的AppletLet執(zhí)行的java程序,這些要執(zhí)行的程序是在服務(wù)器端.另一種情況是,要引用的Class文件不方便在編譯的時(shí)候直接參與,而只能在運(yùn)行時(shí)動(dòng)態(tài)調(diào)用.例如,在Android Framework中,所包含的Class文件是一些通用的類文件,但對(duì)于一些設(shè)備商而言,他們需要擴(kuò)充Framework,擴(kuò)充的具體工作包括兩點(diǎn):

1:需要增加一些額外的類文件,這些類文件提供廠商自定義的功能,這些文件一般以獨(dú)立的jar包存在

2:需要修改Framework中的已有的類文件,比如WindowManagerService類,在該類中添加使用自定義jar包中的代碼.使用自定義jar常用的方法是使用import關(guān)鍵字包含自定義的類,但為了保持和原生Framework的兼容性,對(duì)原聲Framework最少化修改,可以使類裝載器動(dòng)態(tài)裝載自定義jar包.

這就是使用ClassLoader的原因.

在一般情況下,應(yīng)用程序不需要?jiǎng)?chuàng)建一個(gè)全新的ClassLoader對(duì)象,而是使用當(dāng)前環(huán)境已經(jīng)存在的ClassLoader.因?yàn)閖ava的Runtime環(huán)境在初始化時(shí),其內(nèi)部會(huì)創(chuàng)建一個(gè)ClassLoader對(duì)象用于加載Runtime所需的各種java類.

每個(gè)ClassLoader必須有一個(gè)父ClasLoader,在裝載Class文件的時(shí)候,子ClassLoader會(huì)先請(qǐng)求其父ClassLoader加載該Class文件,只有當(dāng)其父ClassLoader找不到該Class的時(shí)候,子ClassLoader才會(huì)急促裝載該類,這是一種安全機(jī)制.

對(duì)于Android的應(yīng)用程序,本質(zhì)上雖然也是用Java開發(fā),并且使用標(biāo)準(zhǔn)的Java編譯器編譯出Class文件,但最終的APK文件中包含的確實(shí)dex類型的文件.dex文件是將所需的所有Class文件重新打包,打包的規(guī)則不是簡(jiǎn)單的壓縮,而是完全對(duì)Class文件內(nèi)部的各種函數(shù)表,變量表等進(jìn)行優(yōu)化,并產(chǎn)生一個(gè)新的文件,這就是dex文件.由于dex文件是一種經(jīng)過(guò)優(yōu)化的Class文件,因此要加載這樣特殊的Class文件就需要特殊的類裝載器,這就是DexClassLoader.Android SDK中提供了DexClassLoader類就是處于這個(gè)目的.

轉(zhuǎn)至?DexClassLoader的使用 - hongbochen1223的專欄 - CSDN博客

創(chuàng)建DexClassLoader 需要四個(gè)參數(shù)堕扶,分別代表的意義:

1:dexPath,指目標(biāo)類所在的APK或jar文件的路徑.類裝載器將從該路徑中尋找指定的目標(biāo)類,該類必須是APK或jar的全路徑.如果要包含多個(gè)路徑,路徑之間必須使用特定的分割符分隔,特定的分割符可以使用System.getProperty(“path.separtor”)獲得.

2:dexOutputDir,由于dex文件被包含在APK或者Jar文件中,因此在裝載目標(biāo)類之前需要先從APK或Jar文件中解壓出dex文件,該參數(shù)就是制定解壓出的dex 文件存放的路徑.在Android系統(tǒng)中,一個(gè)應(yīng)用程序一般對(duì)應(yīng)一個(gè)Linux用戶id,應(yīng)用程序僅對(duì)屬于自己的數(shù)據(jù)目錄路徑有寫的權(quán)限,因此,該參數(shù)可以使用該程序的數(shù)據(jù)路徑.

3:libPath,指目標(biāo)類中所使用的C/C++庫(kù)存放的路徑

4:最后一個(gè)參數(shù)是指該裝載器的父裝載器,一般為當(dāng)前執(zhí)行類的裝載器

這里我們可以把libPath置為null碍脏。

創(chuàng)建Resouces時(shí)我們需要AssetManager梭依。

通過(guò)源碼我們可以查看到addAssetPath這個(gè)方法和AssetManager的構(gòu)造方法注釋上面都有{@hide},這個(gè)表示我們不能在應(yīng)用層直接調(diào)用,如果我們還是要調(diào)用的話就需要用到反射:



寫完工具類,現(xiàn)在我們轉(zhuǎn)到宿主的MainActivity中典尾,我們需要跳轉(zhuǎn)到特定的activity中役拴,將ActivityName傳遞給proxyActivity。那么我們要怎么得到這個(gè)類名呢急黎?

我們?cè)赑roxyManager中通過(guò)context得到packmanager從而獲取


最后我們將插件apk導(dǎo)出來(lái)扎狱,然后放入宿主項(xiàng)目中的assert文件夾底下,寫入我們手機(jī)sd卡下勃教,這一步模擬的是插件apk的下載


好了淤击,結(jié)束了以上的步驟我們就可以運(yùn)行下看看到底跳是否成功?


然后點(diǎn)擊了宿主頁(yè)面后確實(shí)一片空白故源!不過(guò)索性沒(méi)有出現(xiàn)頁(yè)面崩潰和無(wú)法跳轉(zhuǎn)的現(xiàn)象污抬,這說(shuō)明我們的做法是沒(méi)有問(wèn)題。那么問(wèn)題到底出來(lái)哪里呢绳军?


我再來(lái)看下這個(gè)代理類印机。似乎沒(méi)什么問(wèn)題? 實(shí)際上我們界面顯示以及顯示后能夠交互是走了生命周期的onStart()以及onResume的方法门驾,換句話說(shuō)這個(gè)代理類實(shí)際上就是一個(gè)空殼 顯示不了界面射赛。

那么我們就得去執(zhí)行它的生命周期方法,至少要執(zhí)行 onCreate()奶是、onStart()以及onResume楣责。我們同樣的可以通過(guò)反射的方式得到這個(gè)Activity以及它的構(gòu)造方法。


我們可以看到object被強(qiáng)轉(zhuǎn)成了一開始的 interface,實(shí)際上這里的生命周期都可以通過(guò)反射的方式去執(zhí)行聂沙,但是一開始我們就制定了interface的規(guī)則秆麸,所以這個(gè)時(shí)候這個(gè)規(guī)則就派上了用場(chǎng)?

我們重新運(yùn)行下代碼看下情況。


以上就是插件化的一個(gè)小例子及汉,其實(shí)它的用到的無(wú)外乎是反射沮趣,DexClassLoader等機(jī)制。

動(dòng)態(tài)換膚:https://blog.csdn.net/MAGIC_JSS/article/details/52403778?utm_source=blogxgwz5

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末坷随,一起剝皮案震驚了整個(gè)濱河市房铭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌温眉,老刑警劉巖育叁,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異芍殖,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)谴蔑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門豌骏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)龟梦,“玉大人,你說(shuō)我怎么就攤上這事窃躲〖品。” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵蒂窒,是天一觀的道長(zhǎng)躁倒。 經(jīng)常有香客問(wèn)我,道長(zhǎng)洒琢,這世上最難降的妖魔是什么秧秉? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮衰抑,結(jié)果婚禮上象迎,老公的妹妹穿的比我還像新娘。我一直安慰自己呛踊,他們只是感情好砾淌,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著谭网,像睡著了一般汪厨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上愉择,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天劫乱,我揣著相機(jī)與錄音,去河邊找鬼薄辅。 笑死要拂,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的站楚。 我是一名探鬼主播脱惰,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼窿春!你這毒婦竟也來(lái)了拉一?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤旧乞,失蹤者是張志新(化名)和其女友劉穎蔚润,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體尺栖,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡嫡纠,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片除盏。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡叉橱,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出者蠕,到底是詐尸還是另有隱情窃祝,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布踱侣,位于F島的核電站粪小,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏抡句。R本人自食惡果不足惜探膊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望玉转。 院中可真熱鬧突想,春花似錦、人聲如沸究抓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)刺下。三九已至绑嘹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間橘茉,已是汗流浹背工腋。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留畅卓,地道東北人擅腰。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像翁潘,于是被迫代替她去往敵國(guó)和親趁冈。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

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