????實(shí)際項(xiàng)目開發(fā)過(guò)程中經(jīng)常會(huì)遇到和各種第三方app的對(duì)接邓嘹,實(shí)際產(chǎn)品中也開發(fā)了SDK便于與第三方二次開發(fā)险胰,但是這樣第三方還是會(huì)有不少開發(fā)成本汹押。件化的好處在于宿主和插件分開編譯,宿主和插件的可以并行開發(fā)起便、互不干涉棚贾,宿主可以按實(shí)際需求進(jìn)行相應(yīng)插件的下載、安裝及運(yùn)行榆综。網(wǎng)上開源的插件化框架也很多妙痹,都有各自的特點(diǎn)和不足,在項(xiàng)目中應(yīng)客戶的實(shí)際需求鼻疮,采用了360的replugin插件化框架怯伊。
? ??Replugin是360手機(jī)衛(wèi)士2017年開源的安卓插件化開發(fā)框架,屬于占坑類插件化開發(fā)框架陋守。相比于其他插件化方案震贵,replugin的hook點(diǎn)更少,經(jīng)過(guò)360手機(jī)衛(wèi)士眾多插件多年的驗(yàn)證水评,穩(wěn)定性值得信賴猩系。Replugin宿主無(wú)需升級(jí),即可支持新增的四大組件中燥,hook點(diǎn)只有Classloader一處寇甸,易于集成,插件管理穩(wěn)定成熟疗涉,支持插件安裝拿霉、升級(jí)、卸載咱扣、版本管理等绽淘。
1、replugin的接入
????對(duì)replugin插件的開發(fā)及集成進(jìn)行了些研究闹伪,從小demo試驗(yàn)到將app相關(guān)組件進(jìn)行插件化改造沪铭,并編寫demo進(jìn)行插件集成后的測(cè)試,將其中遇到的問(wèn)題進(jìn)行一些總結(jié)偏瓤。
① 插件的開發(fā)
插件的接入主要是一些gradle配置杀怠,首先需要在項(xiàng)目工程的build.gradle文件(不是module的build.gradle文件)中添加360 replugin的gradle依賴,包括host和plugin的依賴厅克。
然后在插件的build.gradle文件中添加相關(guān)配置赔退,需要引入replugin的gradle插件,在repluginPluginConfig中配置插件的名稱、包名及l(fā)auncher activity硕旗,然后在dependencies中引入'com.qihoo360.replugin:replugin-plugin-lib:2.2.4'庫(kù)。
????然后在插件的AndroidManifest.xml文件中進(jìn)行配置慧域,填寫插件名稱浪读,”com.qihoo360.plugin.version.ver”的value為100碘橘,不做改動(dòng)痘拆。????
????以上配置完成后纺蛆,插件的配置就算完成了桥氏,將插件打包成apk后將plugin1.apk后綴名改掉字支,改為plugin1.jar堕伪,插件的名稱自己取欠雌。
② 宿主的接入
????宿主的接入包括gradle配置疙筹、application的繼承以及插件的引入腌歉。
????在宿主module的build.gradle中引入replugin的host插件翘盖,在dependencies中引入庫(kù)” com.qihoo360.replugin:replugin-host-lib:2.2.4”
????然后在宿主的application中需要繼承RePluginApplication并實(shí)現(xiàn)相應(yīng)的接口馍驯,如果沒(méi)采用繼承方式的話玛痊,需要在application生命周期的方法中進(jìn)行相應(yīng)的一些初始化操作擂煞。這里采用繼承的方式对省。最后將插件放到宿主的assets/plugins目錄下蒿涎。
至此完成了宿主中插件的接入劳秋,而要在宿主中調(diào)起插件胖齐,只需啟動(dòng)插件的launcher activity呀伙。
2区匠、對(duì)接過(guò)程中遇到的問(wèn)題
? ? 宿主apk單獨(dú)運(yùn)行正常并不代表集成到宿主apk能運(yùn)行不出差錯(cuò)驰弄。
① 權(quán)限問(wèn)題
? ?????插件中在AndroidManifest.xml中聲明的權(quán)限戚篙,宿主中也相應(yīng)要聲明這些使用權(quán)限岔擂,或者動(dòng)態(tài)檢查申請(qǐng)權(quán)限。
② so庫(kù)目錄問(wèn)題
????集成后開始運(yùn)行塑崖,運(yùn)行時(shí)發(fā)現(xiàn)了so庫(kù)找不到的問(wèn)題规婆。
java.lang.UnsatisfiedLinkError: com.qihoo360.replugin.PluginDexClassLoader[DexPathList[[zip file "/data/data/hik.xxx/app_plugins_v3/xxx10-10-100.jar"],nativeLibraryDirectories=[/vendor/lib64, /system/lib64]]] couldn't find "libstlport_shared.so"
at java.lang.Runtime.loadLibrary(Runtime.java:366)
at java.lang.System.loadLibrary(System.java:988)
? ??so庫(kù)找不到的問(wèn)題抒蚜,一般是由于app中jniLibs下有多個(gè)so庫(kù)目錄嗡髓,但實(shí)際的so庫(kù)并沒(méi)有這些目錄中所有的cpu架構(gòu)的so庫(kù)饿这,導(dǎo)致so庫(kù)找不到蛹稍。把a(bǔ)pp依賴的幾個(gè)module都看了一遍后,發(fā)現(xiàn)確實(shí)有一個(gè)module中jniLibs目錄下有除了armeabi及armeabi-v7a以外的目錄,多了mips及x86目錄奉芦,將其刪了之后剧蹂,重新編譯插件宠叼,然后在宿主工程中運(yùn)行冒冬,發(fā)現(xiàn)仍然報(bào)這個(gè)錯(cuò)誤。最終查了些相關(guān)資料简烤,自己嘗試了多種方法后挥萌,發(fā)現(xiàn)要現(xiàn)在host的jniLibs目錄下先定好所采用的cpu架構(gòu)枉侧,并放上一個(gè)空so庫(kù)文件進(jìn)去榨馁。
????LibNativeTest.so無(wú)任何實(shí)際用途,純粹為了占坑黍特。但為何是這樣呢灭衷,這2天看了下replugin源碼翔曲,偶然間瞥到如下中文注釋瞳遍。代碼在PluginNativeLibsHelper.java中掠械。
③ 資源未找到引起崩潰
????插件內(nèi)部跳轉(zhuǎn)猾蒂,跳轉(zhuǎn)到一個(gè)activity時(shí)報(bào)資源文件abc_fade_out.xml未找到引起崩潰,找了一圈發(fā)現(xiàn)abc_fade_out.xml并不是插件apk中引入的資源罩缴,而是系統(tǒng)資源烙荷。
????然錯(cuò)誤提示指示系統(tǒng)的資源沒(méi)找到奢讨,但實(shí)際問(wèn)題肯定應(yīng)該是自身程序代碼問(wèn)題導(dǎo)致的焰薄。定位到出問(wèn)題的代碼片段塞茅,打日志野瘦,發(fā)現(xiàn)確實(shí)在調(diào)用AudioPlayUtil.getInstance()之后就沒(méi)往下執(zhí)行了飒泻。那這個(gè)方法中究竟為何會(huì)導(dǎo)致崩潰呢泞遗。跟蹤一下代碼史辙,看下整個(gè)的執(zhí)行流程聊倔。
????如上圖所示耙蔑,AudioPlayUtil單例初始化時(shí)傳入了application甸陌,在構(gòu)造函數(shù)中邀层,通過(guò)getApplicationContext獲取到Context并保存起來(lái),因?yàn)槭琴Y源找不到引起的問(wèn)題涛目,所以我們主要關(guān)注與資源相關(guān)的代碼霹肝。得到上下文Context后沫换,其中調(diào)用了context.getResources去拿資源讯赏,最終去res的raw目錄找資源冷尉。插件運(yùn)行沒(méi)問(wèn)題漱挎,但集成后運(yùn)行出現(xiàn)了問(wèn)題,而整個(gè)方法只有一個(gè)參數(shù)傳進(jìn)去雀哨。所以肯定是context出現(xiàn)了問(wèn)題磕谅。
? ??實(shí)際運(yùn)行中只是一個(gè)apk私爷,一個(gè)應(yīng)用绽昼,所以在activity中通過(guò)getApplication()獲取到的是宿主的application而不是插件的贷币。我們實(shí)際是想拿到插件中的資源,所以應(yīng)該使用插件的上下文來(lái)獲取啄糙。查找了RePlugin的相關(guān)api放刨,發(fā)現(xiàn)只有一個(gè)getPluginContext()方法來(lái)獲取插件的上下文工秩。所以對(duì)代碼進(jìn)行了下改造,傳入插件的上下文宏榕,資源獲取問(wèn)題得到解決拓诸。獲取資源的地方很多倍谜,像很多Activity中使用getResources().getText()都沒(méi)有報(bào)錯(cuò)褥民,所以需要通過(guò)Context獲取資源時(shí),如果傳入的是application上下文,則需要判斷是宿主還是插件的上下文逞刷。
3题篷、總結(jié)
? ?replugin的接入確實(shí)很方便葫笼,但是實(shí)際集成過(guò)程中還是會(huì)出現(xiàn)各種問(wèn)題。replugin插件可以以兩種方式進(jìn)行集成,內(nèi)置模式和外置模式,插件以內(nèi)置模式方式進(jìn)行集成時(shí)掷漱,需打包到宿主apk中。以外置方式插件可以下載后再安裝、運(yùn)行怀薛。插件化除了集成靈活外创倔,插件有獨(dú)立的版本號(hào)知押,升級(jí)時(shí)可以對(duì)插件獨(dú)立進(jìn)行升級(jí)而不需要整個(gè)app進(jìn)行升級(jí)良价。而且各插件可以獨(dú)立并行開發(fā)痊银,增強(qiáng)開發(fā)效率鬓照。但同時(shí)插件化也有不少問(wèn)題号显,插件化技術(shù)一般都使用了hook次屠,針對(duì)不同手機(jī)廠商的定制安卓系統(tǒng),兼容性需要經(jīng)過(guò)測(cè)試檢驗(yàn)怔昨,穩(wěn)定性也可能會(huì)是個(gè)問(wèn)題原叮,而且如果出現(xiàn)了問(wèn)題唯欣,排查問(wèn)題時(shí)對(duì)開發(fā)者的技術(shù)要求更高。這只是簡(jiǎn)單的集成挡鞍,集成后,插件宿主間通信等,還有很多細(xì)節(jié)還需繼續(xù)深入。