一哄褒、RePlugin簡介
RePlugin是一套完整的、穩(wěn)定的煌张、適合全面使用的呐赡,占坑類插件化方案。我們“逐>詞”拆開來解釋這個定義:
完整的:讓插件運行起來“像單品那樣”骏融,支持大部分特性
穩(wěn)定的:如此靈活完整的情況下链嘀,其框架崩潰率僅為業(yè)內(nèi)很低的“萬分之一”
適合全面使用的:其目的是讓應用內(nèi)的“所有功能皆為插件”
占坑類:以穩(wěn)定為前提的Manifest占坑思路
插件化方案:基于Android原生API和語言來開發(fā),充分利用原生特性
RePlugin:<a >Github地址</a>
RePlugin使用簡易示例:<a >Github地址</a>僅作為學習交流使用档玻,歡迎star
二怀泊、RePlugin配置說明
RePlugin分宿主工程和插件工程,需要在工程下配置以下內(nèi)容
1误趴、宿主工程配置
A)在Project級別gradle的dependencies中添加
classpath 'com.qihoo360.replugin:replugin-host-gradle:2.1.3'
B)在Moudle級別gradle中添加
apply plugin: 'replugin-host-gradle'
compile 'com.qihoo360.replugin:replugin-host-lib:2.1.3'
2霹琼、插件工程配置
A)在Project級別gradle的dependencies中添加
classpath 'com.qihoo360.replugin:replugin-plugin-gradle:2.1.4'
B)在Moudle級別gradle中添加
apply plugin: 'replugin-plugin-gradle'
compile 'com.qihoo360.replugin:replugin-plugin-lib:2.1.3'
三、RePlugin內(nèi)置插件
1凉当、內(nèi)置插件安裝
內(nèi)置插件以jar文件的形式放置在assets->plugins目錄下(注:內(nèi)置插件只有放在此目錄下才能被RePlugin識別并自動安裝枣申,如plugins文件夾未自動創(chuàng)建,需要手動創(chuàng)建)
2看杭、內(nèi)置插件識別機制
插件的相關配置信息采用json的格式進行存儲忠藤,存儲在assets->plugins-builtin.json文件下,程序啟動時楼雹,由RePlugin識別并自動進行插件安裝
[{"high":null,
"frm":null,
"ver":100,
"low":null,
"pkg":"com.qihoo360.replugin.sample.demo1",
"path":"plugins/demo1.jar","name":"demo1"
}]
3模孩、內(nèi)置插件升級
A)主程序隨包升級
安裝包更新時,若插件版本更新時自動升級
B)通過install方法升級
同外置插件升級贮缅,RePlugin.install()方法進行插件升級
4榨咐、內(nèi)置插件刪除
直接移除jar文件即可,RePlugin會完成剩余操作
四谴供、RePlugin外置插件
1块茁、外置插件安裝
i. 外置插件安裝方式
采用加載apk的方式,使用RePlugin.install()方法進行安裝
ii. 外置插件安裝注意事項
如果處于debug模式憔鬼,需要在application中關閉簽名校驗龟劲,通過對RePluginConfig的處理,關閉簽名校驗轴或,(預計下個版本會默認關閉簽名校驗昌跌,不過官方建議在release中打開該校驗)
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
//--------------開發(fā)的時候不驗證簽名
RePluginConfig config = new RePluginConfig();
config.setVerifySign(!BuildConfig.DEBUG);
config.setPrintDetailLog(BuildConfig.DEBUG);
config.setUseHostClassIfNotFound(true);
RePlugin.App.attachBaseContext(this, config); }
iii. 插件的安裝
通過RePlugin.install()方法進行安裝,可以通過RePlugin.preload()方法對插件進行預加載照雁,提升用戶體驗
PluginInfo pluginInfo = RePlugin.install(absolutePath + "/aa.apk");
if (pluginInfo != null) {
Toast.makeText(MainActivity.this, "插件安裝成功",Toast.LENGTH_SHORT).show();
boolean preload = RePlugin.preload(pluginInfo);
if (preload){
Toast.makeText(MainActivity.this, "預加載完成", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this, "插件安裝失敗",Toast.LENGTH_SHORT).show();
}
iiii. 插件的版本
需要Plugin的AndroidManifest中對插件的別名和版本進行設置蚕愤,不設置的話以包名和version為默認值(注:暫不支持同版本覆蓋,升級插件必須修改版本號饺蚊,卸載重新安裝也需要進行版本修改)
<meta-data
android:name="com.qihoo360.plugin.name"
android:value="plugin01" />
<meta-data
android:name="com.qihoo360.plugin.version.ver"
android:value="114" />
2萍诱、插件的升級
通過RePlugin.install(pi)方法進行升級
3、插件的卸載
通過RePlugin.uninstall("demo01")卸載
五污呼、RePlugin宿主與插件交互
1裕坊、宿主打開插件中的四大組件
A)Activity
RePlugin.startActivity(MainActivity.this, RePlugin.createIntent("plugin01", "com.dg.replugindemo01.MainActivity"));
B)Service
PluginServiceClient.bindService(RePlugin.createIntent( "exam", "AbcService"), mServiceConn);
B)Service
PluginServiceClient.bindService(RePlugin.createIntent( "exam", "AbcService"), mServiceConn);
B)ContentProvider
PluginProviderClient.query(xxx);
。燕酷。籍凝。。
2苗缩、宿主調用插件方法
A)fetchComponentList(String pluginName);//獲取插件的組件列表
B)fetchPackageInfo(String pluginName);//獲取插件的包信息
C)fetchResources(String pluginName);//獲取插件的資源信息
D)fetchClassLoader(String pluginName);//獲取插件的ClassLoader對象
E)fetchContext(String pluginName);//獲取插件的Context對象
F)fetchBinder(String pluginName, String module, String process);
//通過插件里的Plugin類饵蒂,獲取插件定義的IBinder
示例:
//加載插件中的工具類
ClassLoader classLoader = RePlugin.fetchClassLoader("plugin01");
try {
Class<?> aClass = classLoader.loadClass("com.dgcredit.replugindemo01.DateHelper");
Method formatDate = aClass.getMethod("formatDate", Date.class);
String invoke = (String) formatDate.invoke(null, new Date());
tvShow.setText(invoke);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
///加載插件,并獲取插件的資源信息
Resources resources = RePlugin.fetchResources("plugin01");
int identifier = resources.getIdentifier("icon_app", "drawable", "com.dgcredit.replugindemo01");
ivShow.setImageResource(identifier);
3酱讶、插件調用宿主方法
//加載宿主中的工具類
ClassLoader classLoader = RePlugin.getHostClassLoader();
try {
Class<?> aClass = classLoader.loadClass("com.dgcredit.repluginhostdemo.DateHelper");
Method formatDate = aClass.getMethod("formatDate", Date.class);
String invoke = (String) formatDate.invoke(null, new Date());
viewById.setText(invoke);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
//加載宿主中圖片資源
ClassLoader classLoader = RePlugin.getHostClassLoader();
try{
Class clazz = classLoader.loadClass("com.dgcredit.repluginhostdemo.R$drawable");
Field field = clazz.getField("icon_app");
int identifier = (int)field.get(null);
ivShow.setImageResource(identifier);
}catch(Exception e){
Log.i("Loader", "error:"+Log.getStackTraceString(e));
}
4退盯、插件調用宿主組件
Intent intent = new Intent();
intent.setComponentName(new ComponentName("com.qihoo360.replugin.sample.host", "com.qihoo360.replugin.sample.host.MainActivity"));
context.startActivity(intent);
六、RePlugin接入錯誤集錦
1泻肯、Theme錯誤
Caused by: java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
解決方式
A)去除插件中對application的theme的引入渊迁,單獨對插件中的activity設置相關theme
android:theme="@style/AppTheme"
B)在宿主的build.gradle中加入
repluginHostConfig {
useAppCompat = true
}
2、ActivityNotFoundException錯誤
Unable to find explicit activity class{com.qihoo360.replugin.sample.host/con.qihoo360.replugin.sample.host.loader.a.ActivityN1NRNTS3};have you declared this activity in your AndroidManifest.xml?
解決方式:
關閉Setting中instand run功能灶挟。目前此Bug在官方2.1.4版本已修復宫纬,尚未驗證
3、Fail to apply plugin [id 'replugin-plugin-gradle']錯誤
解決方式:
這個plugin需要放在android配置之后膏萧,因為需要讀取android中的配置項
4漓骚、外置插件RePlugin.install()方法無反應
解決方式:
@override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
//-------------- 開發(fā)的時候不驗證簽名 -----------//
RePluginConfig config = new RePluginConfig();
config.setVerifySign(!BuildConfig.DEBUG);
RePlugin.App.attachBaseContext(this, config);
// =======================//
}