1.什么是RePlugin?
在Android開發(fā)領(lǐng)域,有關(guān)插件化的討論一直熱度不減。目前市面上的插件化方案雖然很多,但多數(shù)只能實(shí)現(xiàn)某些功能的插件化,距離開發(fā)者的預(yù)期尚有相當(dāng)差距。對(duì)此,在近期GMTC全球移動(dòng)技術(shù)大會(huì)上,360手機(jī)衛(wèi)士主程序架構(gòu)負(fù)責(zé)人張炅軒宣布,360的插件化框架RePlugin已經(jīng)可以實(shí)現(xiàn)“全面插件化”,同時(shí)具有出色的穩(wěn)定性和靈活性,可適用于各種類型的應(yīng)用上。
“RePlugin預(yù)計(jì)7月份開源,這將是我們獻(xiàn)給安卓世界最好的禮物?!?60如是說。
2.RePlugin有什么用?
RePlugin是一套完整的、穩(wěn)定的、適合全面使用的,占坑類插件化方案,由360手機(jī)衛(wèi)士的RePlugin Team研發(fā),也是業(yè)內(nèi)首個(gè)提出”全面插件化“(全面特性、全面兼容、全面使用)的方案。
3.RePlugin官方介紹
其主要優(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)定、最適合使用的
截止2017年6月底,RePlugin的:
| 特性 | 描述 |
|---|---|
| 插件數(shù) | 103(核心57個(gè)) |
| 插件占應(yīng)用比 | 高達(dá)83% |
| 年發(fā)版次數(shù) | 高達(dá)596次(工作日均2次) |
| 崩潰率 | 萬(wàn)分之一(0.01%),極低 |
| 時(shí)間 | 2014年應(yīng)用,3年驗(yàn)證 |
目前360公司幾乎所有的億級(jí)用戶量的APP,以及多款主流第三方APP,都采用了RePlugin方案。
有關(guān)RePlugin的詳細(xì)介紹,請(qǐng)點(diǎn)擊這里閱讀《RePlugin 官方 WiKi》。
還支持以下特性
| 特性 | 描述 |
|---|---|
| 組件 | 四大組件(含靜態(tài)Receiver) |
| 升級(jí)無(wú)需改主程序Manifest | 完美支持 |
| Android特性 | 支持近乎所有(包括SO庫(kù)等) |
| TaskAffinity & 多進(jìn)程 | 支持(坑位方案)** |
| 插件類型 | 支持自帶插件(自識(shí)別)、外置插件** |
| 插件間耦合 | 支持Binder、Class Loader、資源等 |
| 進(jìn)程間通訊 | 支持同步、異步、Binder、廣播等 |
| 自定義Theme & AppComat | 支持 |
| DataBinding | 支持 |
| 安全校驗(yàn) | 支持 |
| 資源方案 | 獨(dú)立資源 + Context傳遞(相對(duì)穩(wěn)定) |
| Android 版本 | API Level 9+ (2.3及以上) |
愿景
讓插件化能飛入尋常應(yīng)用家,做到穩(wěn)定、靈活、自由,大小項(xiàng)目兼用。
RePlugin 架構(gòu)圖

4.SO?怎么用?
ok,看完了官方介紹給我們畫的大餅,現(xiàn)在看看怎么實(shí)現(xiàn)它,是的,坑來(lái)了。。
主程序的配置,這里就不多說了。。將RePlugin接入到您的主程序,官方文檔描述的很清楚,也沒有什么奇奇怪怪的錯(cuò)誤。
主要來(lái)說說如何開發(fā)新的 RePlugin 插件,從RePlugin的Wiki我們可以看到,好簡(jiǎn)單呀,就三步嘛,來(lái)吧。
然后我們碰到了.........
問題一:Gradle配置出錯(cuò)

EXCUSE ME?那里有問題?再看看文檔,沒啥特別的描述呀。
然后,我在Issues里找到了官方項(xiàng)目組說的這一句:“這個(gè)要自動(dòng)讀取前面build.gradle的配置內(nèi)容,如果放在前面,會(huì)讀為空。我們內(nèi)部討論過這個(gè)問題,如果要想自由放置就得傳參配置。當(dāng)時(shí)考慮到盡量減少傳參配置就約定俗成讓放在文件末尾。你可以看demo1?!?br> 好吧,既然如此能不能提一句只能放在文件末尾??!
你是360,你老大,我改!

??按你說的還不行??
然后,我在Issues里看到了吃瓜群眾說的這一句:“你試試把apply plugin: 'replugin-plugin-gradle'放在<apply plugin: 'com.android.application'之前就好了,我的就是這樣好使的,你試試?”
抱著試一試的心態(tài),然后我發(fā)現(xiàn)...成功了??說好的讀取配置內(nèi)容呢?說好的會(huì)讀為空呢?
OK,按照官方文檔,各項(xiàng)都配置完成,我們繼續(xù)進(jìn)行。。
插件界面很簡(jiǎn)單:

插件單獨(dú)運(yùn)行一下,ok,沒問題。
好的,接下來(lái)走一下內(nèi)置插件的流程,將插件項(xiàng)目build一個(gè)apk出來(lái),后綴改成jar,導(dǎo)入主程序assets的plugins內(nèi),
主程序界面也很簡(jiǎn)單,就一個(gè)HelloRePlugin的TextView,給TextView設(shè)置一個(gè)點(diǎn)擊事件
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
RePlugin.startActivity(MainActivity.this, RePlugin.createIntent("aap2", "com.zzcn77.replugindemo2.MainActivity"));
}
});
然后我們碰到了.........
問題二:主題出錯(cuò)
點(diǎn)擊HelloRePlugin,程序崩潰。

主題錯(cuò)了?繼承的是Activity啊,有主題啊,單獨(dú)運(yùn)行沒有錯(cuò)啊。。
自此,我開始多番嘗試之路,改了n個(gè)主題發(fā)現(xiàn)沒有用,氣的我,直接把
apply plugin: 'replugin-plugin-gradle'我把這句去掉了,運(yùn)行。。程序調(diào)起成功了。。。我的天哪
詭異的一幕出現(xiàn)了,吊起的插件Acitivity顯示界面:

???這個(gè)界面哪來(lái)的?,這不是我的插件界面啊。。
奇怪的是,插件的activity的onCreate也走了。那我的界面去哪了?
是不是因?yàn)槲覄h去了
apply plugin: 'replugin-plugin-gradle',所以出現(xiàn)問題了?,還是加上吧,再看看主題出錯(cuò)有沒有其他解決方法。------加上,buildApk,導(dǎo)入主程序,運(yùn)行主程序,點(diǎn)擊HelloRePlugin,調(diào)起,成功了?!,唉?你不是主題有問題的嗎?你不是主題有問題的嗎?你不是主題有問題的嗎?好吧,,雖然調(diào)起成功,可是還沒完,打開的activity界面依然如上。

然后我們發(fā)現(xiàn)了.........
問題三: Didn't find class "com.qihoo360.plugin.app2.Entry"
Didn't find class "com.qihoo360.plugin.app2.Entry" on path: DexPathList[[zip file "/data/user/0/com.replugindemo/app_plugins_v3/app2-10-10-101.jar"],nativeLibraryDirectories=[/data/user/0/com.replugindemo/app_plugins_v3_libs/app2-10-10-101, /vendor/lib, /system/lib]]
java.lang.ClassNotFoundException: Didn't find class "com.qihoo360.plugin.app2.Entry" on path: DexPathList[[zip file "/data/user/0/com.replugindemo/app_plugins_v3/app2-10-10-101.jar"],nativeLibraryDirectories=[/data/user/0/com.replugindemo/app_plugins_v3_libs/app2-10-10-101, /vendor/lib, /system/lib]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
at com.qihoo360.replugin.PluginDexClassLoader.loadClass(PluginDexClassLoader.java:76)
at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
at com.qihoo360.loader2.Loader.loadEntryMethod2(Loader.java:419)
at com.qihoo360.loader2.Plugin.loadEntryLocked(Plugin.java:857)
at com.qihoo360.loader2.Plugin.doLoad(Plugin.java:822)
at com.qihoo360.loader2.Plugin.loadLocked(Plugin.java:621)
at com.qihoo360.loader2.Plugin.load(Plugin.java:432)
at com.qihoo360.loader2.PmBase.loadPlugin(PmBase.java:1033)
at com.qihoo360.loader2.PmBase.loadAppPlugin(PmBase.java:1018)
at com.qihoo360.loader2.PmLocalImpl.getActivityInfo(PmLocalImpl.java:443)
at com.qihoo360.loader2.PmLocalImpl.loadPluginActivity(PmLocalImpl.java:319)
at com.qihoo360.loader2.PmInternalImpl.startActivity(PmInternalImpl.java:230)
at com.qihoo360.loader2.PmLocalImpl.startActivity(PmLocalImpl.java:307)
at com.qihoo360.i.Factory.startActivityWithNoInjectCN(Factory.java:324)
at com.qihoo360.replugin.RePlugin.startActivity(RePlugin.java:236)
at com.zzcn77.replugindemo.MainActivity$1.onClick(MainActivity.java:24)
at android.view.View.performClick(View.java:5198)
at android.view.View$PerformClick.run(View.java:21147)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Suppressed: java.lang.ClassNotFoundException: com.qihoo360.plugin.app2.Entry
at java.lang.Class.classForName(Native Method)
at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
... 25 more
Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack trace available
為什么?
再看看官方文檔,遺漏什么了?沒有啊。
再看看官方文檔,還有沒看到的?沒有啊。
為什么?
再回想一下整個(gè)流程,gradle出錯(cuò),主題樣式錯(cuò)誤,Didn't find class "com.qihoo360.plugin.app2.Entry
對(duì),主題樣式,這一環(huán)并沒有真正的解決。
找不到主題?application里面配置的有主題呀。
把a(bǔ)pplication的統(tǒng)一主題去掉,分別給每個(gè)activity配置主題。
再來(lái)一次,buildApk,導(dǎo)入主程序,運(yùn)行主程序,調(diào)起,成功了?。。⊥昝肋\(yùn)行?。?!
掌聲,掌聲,掌聲
總結(jié)
首次的整個(gè)集成過程,也算是踩坑無(wú)數(shù),樂趣多多啊。希望Replugin項(xiàng)目組在后續(xù)的版本中能夠提供更多的功能,以及更高的穩(wěn)定性,當(dāng)然也希望官方的Wiki再友好一點(diǎn),能對(duì)一些集成規(guī)范的描述更詳細(xì)點(diǎn)唄。不過好用是真的。
作為行業(yè)大哥360開源出來(lái)的全面化插件機(jī)制,以及在360眾多項(xiàng)目中的實(shí)踐,Replugin的功能性,肯定是毋庸置疑的,應(yīng)用場(chǎng)景也必將十分廣泛。相信在未來(lái)很多項(xiàng)目中,會(huì)見到它的身影。
