插件化知識(shí)梳理(7) - 類(lèi)的動(dòng)態(tài)加載入門(mén)


相關(guān)閱讀

插件化知識(shí)梳理(1) - Small 框架之如何引入應(yīng)用插件
插件化知識(shí)梳理(2) - Small 框架之如何引入公共庫(kù)插件
插件化知識(shí)梳理(3) - Small 框架之宿主分身
插件化知識(shí)梳理(4) - Small 框架之如何實(shí)現(xiàn)插件更新
插件化知識(shí)梳理(5) - Small 框架之如何不將插件打包到宿主中
插件化知識(shí)梳理(6) - Small 源碼分析之 Hook 原理
插件化知識(shí)梳理(7) - 類(lèi)的動(dòng)態(tài)加載入門(mén)
插件化知識(shí)梳理(8) - 類(lèi)的動(dòng)態(tài)加載源碼分析
插件化知識(shí)梳理(9) - 資源的動(dòng)態(tài)加載示例及源碼分析
插件化知識(shí)梳理(10) - Service 插件化實(shí)現(xiàn)及原理


一亏钩、前言

插件化知識(shí)梳理(6) - Small 源碼分析之 Hook 原理 這一章的學(xué)習(xí)完成之后漱挎,下一步我們將進(jìn)入插件化加載的精髓,動(dòng)態(tài)加載類(lèi)的學(xué)習(xí)亩歹,在此之前妒茬,我們需要先準(zhǔn)備一些關(guān)于類(lèi)加載的知識(shí)艺挪。

Android當(dāng)中胰伍,支持動(dòng)態(tài)加載的兩種方式為:DexClassLoaderPathClassLoader。這兩者之間的區(qū)別為:

  • DexClassLoader
    • 可以加載jar衡便、apk献起、dex
    • 支持從SD卡目錄加載。
  • PathClassLoader
    • 在許多文章中都有提到镣陕,在Dalvik虛擬機(jī)上谴餐,只能加載已經(jīng)安裝到系統(tǒng)中的Apk文件,也就是/data/app目錄下的apk文件呆抑。之所以有這個(gè)限制是因?yàn)?code>PathClassLoader會(huì)去讀取data/dalvik-cache目錄下經(jīng)過(guò)優(yōu)化后的dex文件岂嗓,如果文件不存在,那么就會(huì)報(bào)錯(cuò)鹊碍。由于手邊沒(méi)有機(jī)器厌殉,所以沒(méi)有版本驗(yàn)證。
    • 而在ART虛擬機(jī)上侈咕,通過(guò)源碼當(dāng)中的注釋公罕,可以發(fā)現(xiàn)是支持的。

二耀销、具體實(shí)例

實(shí)例的工程目錄結(jié)構(gòu)為:


  • app:宿主模塊
  • library:插件模塊
  • libraryinterface:插件接口模塊

其中楼眷,applibrary模塊分別依賴于libraryinterfacelibrarylibraryinterfaceAndroid Library類(lèi)型的Module,下面摩桶,我們開(kāi)始講解整個(gè)工程的構(gòu)建過(guò)程桥状。

2.1 接口模塊 libraryinterface

接口模塊相當(dāng)于是宿主模塊和插件模塊所定義的一套標(biāo)準(zhǔn)帽揪,宿主模塊遵循固定的業(yè)務(wù)邏輯硝清,而具體的實(shí)現(xiàn)則根據(jù)插件模塊的不同而不同。
在接口模塊中转晰,我們定義一個(gè)簡(jiǎn)單的接口IPlugin.java

public interface IPlugin {
    public int getVersion();
}

2.2 插件模塊 library

首先芦拿,我們?cè)诓寮K的build.gradle文件中,引入libraryinterface模塊

dependencies {
    //引入接口模塊
    compile project (':libraryinterface')
}

接著查邢,我們編寫(xiě)一個(gè)實(shí)現(xiàn)類(lèi):

public class PluginImpl implements IPlugin {

    @Override
    public int getVersion() {
        return 1;
    }
}

接下來(lái)需要做的就是將該插件模塊打包成一個(gè)jar文件蔗崎,同樣是在build.gradle文件中,創(chuàng)建一個(gè)Task任務(wù):

task makeJar(type: Copy) {
    delete 'build/libs/plugin.jar'
    from ('build/intermediates/bundles/release/')
    into ('../file/')
    include ('classes.jar')
    rename ('classes.jar','plugin.jar')
}

makeJar.dependsOn(build)

首先點(diǎn)擊make module


接下來(lái)扰藕,在項(xiàng)目的根目錄下執(zhí)行命令:

./gradlew makeJar

就會(huì)得到一個(gè)plugin.jar文件缓苛,但是這個(gè)jar文件是不能夠被動(dòng)態(tài)加載的,因?yàn)樗鼉?nèi)部其實(shí)是.class文件邓深,我們通過(guò)解壓可以看出:


那么我們就需要通過(guò)Android SDK自帶的dx工具進(jìn)行轉(zhuǎn)換未桥,把它轉(zhuǎn)換為.dex,轉(zhuǎn)換后的文件為plugin_dex.jar

/Users/lizejun/Library/Android/sdk/build-tools/25.0.3/dx --dex --output=file/plugin_dex.jar file/plugin.jar

plugin_dex.jar解壓之后芥备,可以看到它已經(jīng)被轉(zhuǎn)換成了.dex文件:


最后冬耿,將該jarpush到手機(jī)中的/sdcard/Plugin目錄下:

2.3 宿主模塊 app

首先,宿主模塊同樣需要依賴于接口模塊libraryinterface

dependencies {
    //引入接口模塊
    compile project (':libraryinterface')
}

在代碼當(dāng)中萌壳,我們通過(guò)DexClassLoader/PathClassLoader動(dòng)態(tài)外部的插件plugin_dex.jar亦镶,通過(guò)反射實(shí)例化PluginImpl類(lèi),并調(diào)用它的getVersion()方法進(jìn)行驗(yàn)證:

public class MainActivity extends AppCompatActivity {

    private TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTextView = (TextView) findViewById(R.id.tv_plug_result);
        getPluginA();
    }

    private void getPluginA() {
        File dexOutputDir = getDir("dex1", 0);
        String dexPath = Environment.getExternalStorageDirectory().toString() + "/Plugin/plugin_dex.jar";
        DexClassLoader loader = new DexClassLoader(dexPath, dexOutputDir.getAbsolutePath(), null, getClassLoader());
        try {
            Class clz = loader.loadClass("com.demo.lizejun.library.PluginImpl");
            IPlugin impl = (IPlugin) clz.newInstance();
            int version = impl.getVersion();
            mTextView.setText("Version=" + version);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void getPluginB() {
        String dexPath = Environment.getExternalStorageDirectory().toString() + "/Plugin/plugin_dex.jar";
        PathClassLoader loader = new PathClassLoader(dexPath, getClassLoader());
        try {
            Class clz = loader.loadClass("com.demo.lizejun.library.PluginImpl");
            IPlugin impl = (IPlugin) clz.newInstance();
            int version = impl.getVersion();
            mTextView.setText("Version=" + version);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

最終的結(jié)果為:



更多文章袱瓮,歡迎訪問(wèn)我的 Android 知識(shí)梳理系列:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末缤骨,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子尺借,更是在濱河造成了極大的恐慌荷憋,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,607評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件褐望,死亡現(xiàn)場(chǎng)離奇詭異勒庄,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)瘫里,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)实蔽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人谨读,你說(shuō)我怎么就攤上這事局装。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,960評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵铐尚,是天一觀的道長(zhǎng)拨脉。 經(jīng)常有香客問(wèn)我,道長(zhǎng)宣增,這世上最難降的妖魔是什么玫膀? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,750評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮爹脾,結(jié)果婚禮上帖旨,老公的妹妹穿的比我還像新娘。我一直安慰自己灵妨,他們只是感情好解阅,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著泌霍,像睡著了一般货抄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上朱转,一...
    開(kāi)封第一講書(shū)人閱讀 51,604評(píng)論 1 305
  • 那天蟹地,我揣著相機(jī)與錄音,去河邊找鬼肋拔。 笑死锈津,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的凉蜂。 我是一名探鬼主播琼梆,決...
    沈念sama閱讀 40,347評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼窿吩!你這毒婦竟也來(lái)了茎杂?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,253評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤纫雁,失蹤者是張志新(化名)和其女友劉穎煌往,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體轧邪,經(jīng)...
    沈念sama閱讀 45,702評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡刽脖,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了忌愚。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片曲管。...
    茶點(diǎn)故事閱讀 40,015評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖硕糊,靈堂內(nèi)的尸體忽然破棺而出院水,到底是詐尸還是另有隱情腊徙,我是刑警寧澤,帶...
    沈念sama閱讀 35,734評(píng)論 5 346
  • 正文 年R本政府宣布檬某,位于F島的核電站撬腾,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏恢恼。R本人自食惡果不足惜民傻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望厅瞎。 院中可真熱鬧饰潜,春花似錦初坠、人聲如沸和簸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,934評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)锁保。三九已至,卻和暖如春半沽,著一層夾襖步出監(jiān)牢的瞬間爽柒,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,052評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工者填, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留浩村,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,216評(píng)論 3 371
  • 正文 我出身青樓占哟,卻偏偏與公主長(zhǎng)得像心墅,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子榨乎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評(píng)論 2 355

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