3.在插件Manifest下增进(否则不能打开插件),一方面是体系中从未专门需求插件化的供给

永利官方网站,前言:前一段时间新开源了一种周详插件化的方案–
RePlugin,从前向来都在关切 DroidPlugin
并且很早也在项目中间试验用了,但最后没有投入到确实的生育环节,一方面是项目中并未专门供给插件化的须要,另一方面也设想到
DroidPlugin 不是专门稳定,Android系统每更新1次 DroidPlugin
可能就会油然则生局地 Bug,究竟 Hook 了 Android
原生的太多东西,系统一旦更新引发 Bug 是免不了的。当然,这一个并不可能还是不可能认
DroidPlugin
的可观,它的原理和思路值得大家深入探索、学习,前一段时间更新过几篇插件化的法则分析的稿子(基于
DrodiPlugin
原理)学习进度中只好钦佩小编的思路和技能深度!前几篇小白也能看懂的插件化种类小说还是会不定期更新,但当下大家得以先来学习学习
RePlugin,究竟多学无毒,也能互相参考他们的思绪,相比优缺点。

android:value=”1″/>

RePlugin 是一套完整的、稳定的、适合周到使用的、占坑类插件化方案:

compile ‘com.qihoo360.replugin:replugin-plugin-lib:2.1.5’

三 、让工程的 Application 直接接轨自 RePluginApplication:

 1 public class MyApplication extends RePluginApplication { } 

当然,同时不要忘了在 AndroidManifest 对 MyApplication 的有关计划。

  • 证明:有时候是因为体系本来结构的急需,我们可能否一向动用持续
    RePluginApplication 的法子,这些题材看来 RePlugin
    开发者也想开了,所以还特意多了一种选取,上面是项指标 Application
    不继续 RePluginApplication 的主意:

    1 public class MyApplication extends Application {
    2
    3 @Override
    4 protected void attachBaseContext(Context base) {
    5 super.attachBaseContext(base);
    6 RePlugin.App.attachBaseContext(this);
    7 }
    8
    9 @Override
    10 public void onCreate() {
    11 super.onCreate();
    12 RePlugin.App.onCreate();
    13 }
    14
    15 @Override
    16 public void onLowMemory() {
    17 super.onLowMemory();
    18 RePlugin.App.onLowMemory();
    19 }
    20
    21 @Override
    22 public void onTrimMemory(int level) {
    23 super.onTrimMemory(level);
    24 RePlugin.App.onTrimMemory(level);
    25 }
    26
    27 @Override
    28 public void onConfigurationChanged(Configuration newConfig) {
    29 super.onConfigurationChanged(newConfig);
    30 RePlugin.App.onConfigurationChanged(newConfig);
    31 }
    32 }

3.在插件Manifest下拉长(不然不只怕打开插件)

(以上定义引自官方wiki)

android:name=”com.qihoo360.plugin.version.ver”

三 、管理插件

RePlugin 对插件定义两种办法一种是外置插件、一种是放到插件。

  • 外置插件:即从互联网下载或然从SD读取卡中得到的,以 .apk 结尾。
  • 内置插件:内置于 APP 之中,并随 APP 一并发版,要求将插件 apk 改成
    .jar 结尾放入主程序的assets/plugins目录。

① 、同集成主工程类似,在根目录的 build.gradle 添加 RePlugin Plugin Gradle 注重(假若单独创立插件工程,则不须要添加注释1底下的代码):

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.3'
        // 1、添加RePlugin Host Gradle依赖(主工程用)
        classpath 'com.qihoo360.replugin:replugin-host-gradle:2.2.1'
        // 2、添加RePlugin Plugin Gradle依赖(插件工程用)
        classpath 'com.qihoo360.replugin:replugin-plugin-gradle:2.2.1'
    }
}

2.在module下的build.gradle下添加

① 、集成主工程


2、在 app/build.gradle 中添加 replugin-plugin-gradle 插件和 replugin-plugin-lib 依赖:

apply plugin: 'com.android.application'

android {
    ...
}

apply plugin: 'replugin-plugin-gradle' // 集成 RePlugin 添加的配置

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:26.+'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    compile 'com.qihoo360.replugin:replugin-plugin-lib:2.2.1' // 集成 RePlugin 添加的配置
    testCompile 'junit:junit:4.12'
}

classpath‘com.android.tools.build:gradle:2.3.2’

  • 总体的:让插件运转起来“像单品这样”,协理超越半数表征。
  • 平安的:官方申明,其框架奔溃率“相当之一”。
  • 适合全面使用的:其目标是让使用内的“全部功能皆为插件”。
  • 占坑类:以平稳为前提的 Manifest 占坑思路。
  • 插件化方案:基于 Android 原生 API 和语言来支付,丰富利用原生天性。

(二)内置插件

累加停放插件非凡不难,首先在主工程的 assets 目录下创办一个 plugins
文件夹,然后就要作为插件的 apk 后缀名改成 .jar 并放入到新建的 plugins
文件夹下,剩下的工作就毫无管了,交给 RePlugin
即可,也就说,框架会自行加载插件。

  • 内置插件无需开发者安装,运行情势和外置插件一致,但不得删除。
  • 置于插件可通过 RePlugin.install()
    升级(需求先将升级包下载好),升级后同样外置插件。

4.插件中开辟宿主的activity

一 、在品种根目录的 build.gradle 下添加 RePlugin Host Gradle 信赖:

 1 buildscript {
 2     repositories {
 3         jcenter()
 4     }
 5     dependencies {
 6         classpath 'com.android.tools.build:gradle:2.3.3'
 7         // 1、添加RePlugin Host Gradle依赖
 8         classpath 'com.qihoo360.replugin:replugin-host-gradle:2.2.1'
 9     }
10 }

贰 、在 app/build.gradle 下添加 RePlugin Host Library 依赖(为了更清楚的代表出代码添加的职分,将原始代码也一并贴出):

 1 apply plugin: 'com.android.application'
 2 
 3 android {
 4     compileSdkVersion 26
 5     buildToolsVersion "26.0.1"
 6     defaultConfig {
 7         applicationId "cn.codingblock.repluginstudy"
 8         minSdkVersion 21
 9         targetSdkVersion 26
10         versionCode 1
11         versionName "1.0"
12         testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
13     }
14     buildTypes {
15         release {
16             minifyEnabled false
17             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18         }
19     }
20 }
21 
22 apply plugin: 'replugin-host-gradle'// 集成 RePlugin 添加的配置
23 
24 // 集成 RePlugin 添加的配置
25 repluginHostConfig {
26     useAppCompat = true // 如果项目需要支持 AppComat,则需要将此配置置为 true
27     // 如果应用需要个性化配置坑位数量,则需要添加以下代码进行配置
28 //    countNotTranslucentStandard = 6
29 //    countNotTranslucentSingleTop = 2
30 //    countNotTranslucentSingleTask = 3
31 //    countNotTranslucentSingleInstance = 2
32 }
33 
34 dependencies {
35     compile fileTree(dir: 'libs', include: ['*.jar'])
36     androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
37         exclude group: 'com.android.support', module: 'support-annotations'
38     })
39     compile 'com.android.support:appcompat-v7:26.+'
40     compile 'com.android.support.constraint:constraint-layout:1.0.2'
41     compile 'com.qihoo360.replugin:replugin-host-lib:2.2.1' // 集成 RePlugin 添加的配置
42     testCompile 'junit:junit:4.12'
43 }

上述代码有三点必要专注:

  • 需要将 apply plugin: ‘replugin-host-gradle’ 放在 android {…}
    之后。
  • 假定项目必要帮助 AppComat,则须要将 repluginHostConfig 的
    userAppCompat 置为 true。
  • 比方采纳须要天性化配置坑位数量,则必要在 repluginHostConfig
    中添加以下代码进行布局:

    countNotTranslucentStandard = 6
    countNotTranslucentSingleTop = 2
    countNotTranslucentSingleTask = 3
    countNotTranslucentSingleInstance = 2

android:value=”plugin1″/>

四、小结

起来体验了一下发觉,就算方今有大概会有那么一些坑须求踩一踩,在应用起来也不比
DroidPlugin
方便,要求在宿主和插件两端都要做集成工作。但全部明显发现,这一次的插件化框架显然比原先那多少个的插件化框架材质尤其的公事公办、足够,而且从
wiki 上发现 RePlugin
团队充满了一点都不小的心满意足在坚定不移维护、更新,并且布置分明,哪些效率在以往会助长、哪些成效在今后会被屏弃,一目精晓,让大家进一步看到了
RePlugin 美好的前途,作者信任在现在的插件化领域正是 RePlugin
无法一家独大,也必定处于三个13分重庆大学的身价!

classpath ‘com.qihoo360.replugin:replugin-plugin-gradle:2.1.5’

二 、集成插件

新建三个工程做为插件APP,那里为了有利于起见,直接在主工程中新建了叁个Module。

dependencies {

(一)外置插件的装置(升级)、运维、卸载

  • 设置插件:

    PluginInfo pluginInfo = RePlugin.install(Environment.getExternalStorageDirectory().getPath().toString() + “/plugin1.apk”);
    System.out.println(pluginInfo);

还要别忘了添加文件读写的权力。 输出日下:

10-30 16:10:23.769 20280-20280/cn.codingblock.repluginstudy I/System.out: PInfo { <cn.codingblock.plugin1:1(4)> [APK] [DEX_EXTRACTED] processes=[] js={"pkgname":"cn.codingblock.plugin1","name":"cn.codingblock.plugin1","low":10,"high":10,"ver":1,"verv":2814792716779521,"path":"\/data\/user\/0\/cn.codingblock.repluginstudy\/app_p_a\/-347346251.jar","type":11,"frm_ver":4} dex=/data/data/cn.codingblock.repluginstudy/app_p_od/-347346251.dex nlib=/data/data/cn.codingblock.repluginstudy/app_p_n/-347346251 }

设置成功了! (升级插件也是用 install()
方法,不可降级,同本版可覆盖安装)

  • 开发银行插件

先来看一下 RePlugin.java 中运转插件相关的源码:

 1 /**
 2  * 创建一个用来定向到插件组件的Intent <p>
 3  * <p>
 4  * 推荐用法: <p>
 5  * <code>
 6  * Intent in = RePlugin.createIntent("clean", "com.qihoo360.mobilesafe.clean.CleanActivity");
 7  * </code> <p>
 8  * 当然,也可以用标准的Android创建方法: <p>
 9  * <code>
10  * Intent in = new Intent(); <p>
11  * in.setComponent(new ComponentName("clean", "com.qihoo360.mobilesafe.clean.CleanActivity"));
12  * </code>
13  *
14  * @param pluginName 插件名
15  * @param cls        目标全名
16  * @return 可以被RePlugin识别的Intent
17  * @since 1.0.0
18  */
19 public static Intent createIntent(String pluginName, String cls) {
20     Intent in = new Intent();
21     in.setComponent(createComponentName(pluginName, cls));
22     return in;
23 }
24 
25 /**
26  * 开启一个插件的Activity <p>
27  * 其中Intent的ComponentName的Key应为插件名(而不是包名),可使用createIntent方法来创建Intent对象
28  *
29  * @param context Context对象
30  * @param intent  要打开Activity的Intent,其中ComponentName的Key必须为插件名
31  * @return 插件Activity是否被成功打开?
32  * FIXME 是否需要Exception来做?
33  * @see #createIntent(String, String)
34  * @since 1.0.0
35  */
36 public static boolean startActivity(Context context, Intent intent) {
37     // TODO 先用旧的开启Activity方案,以后再优化
38     ComponentName cn = intent.getComponent();
39     if (cn == null) {
40         // TODO 需要支持Action方案
41         return false;
42     }
43     String plugin = cn.getPackageName();
44     String cls = cn.getClassName();
45     return Factory.startActivityWithNoInjectCN(context, intent, plugin, cls, IPluginManager.PROCESS_AUTO);
46 }

听别人说 RePlugin 的 startActivity() 和 createIntent()
方法注释中的示例可知,运营插件须求先用插件的名字和指标Activity的全路径创制3个Intent,然后调用 RePlugin.startActviity() 运营即可:

Intent intent = RePlugin.createIntent("Plugin1", "cn.codingblock.plugin1.MainActivity");
if (!RePlugin.startActivity(MainActivity.this, intent)) {
    Toast.makeText(mContext, "启动失败", Toast.LENGTH_LONG).show();
}

点击按钮,输出如下:

10-30 16:21:02.464 20280-20280/cn.codingblock.repluginstudy D/RePlugin.ws001: start activity: intent=Intent { cmp=Plugin1/cn.codingblock.plugin1.MainActivity } plugin=Plugin1 activity=cn.codingblock.plugin1.MainActivity process=-2147483648
10-30 16:21:02.464 20280-20280/cn.codingblock.repluginstudy D/RePlugin.ws001: start activity: intent=Intent { cmp=Plugin1/cn.codingblock.plugin1.MainActivity } plugin=Plugin1 activity=cn.codingblock.plugin1.MainActivity process=-2147483648 download=true
10-30 16:21:02.464 20280-20280/cn.codingblock.repluginstudy D/RePlugin.ws001: plugin=Plugin1 not found, start download ...
10-30 16:21:02.469 20280-20280/cn.codingblock.repluginstudy D/RePlugin.ws001: isNeedToDownload(): V5 file not exists. Plugin = Plugin1

启航战败了!(插件名称确实是:Plugin1,而不是 plugin1 )

把 createIntent()
方法的率先参数换到插件的包名 cn.codingblock.plugin1
试一试,居然能够了。

不过,注释总不会如此赤裸裸的坑大家啊!

  • 卸载插件

    RePlugin.uninstall(“Plugin1”);

点击卸载,输入如下:

10-30 16:31:21.988 5006-5006/cn.codingblock.repluginstudy D/RePlugin.ws001: MP.pluginUninstall ... pluginName=Plugin1
10-30 16:31:21.988 5006-5006/cn.codingblock.repluginstudy D/RePlugin.ws001: Not installed. pluginName=Plugin1

没卸载成功?哈哈,这一个简单,原套路把参数换到包名,果然能够了:

10-30 16:41:46.179 10193-10193/cn.codingblock.repluginstudy D/RePlugin.ws001: MP.pluginUninstall ... pluginName=cn.codingblock.plugin1
10-30 16:41:46.202 10193-10193/cn.codingblock.repluginstudy D/RePlugin.ws001: sendIntent pr=cn.codingblock.repluginstudy intent=Intent { act=ACTION_UNINSTALL_PLUGIN (has extras) }
10-30 16:41:46.203 10193-10193/cn.codingblock.repluginstudy D/RePlugin.ws001: Clear plugin cache. pn=cn.codingblock.plugin1
10-30 16:41:46.204 10193-10193/cn.codingblock.repluginstudy D/RePlugin.ws001: removeInfo plugin table: info=PInfo { <cn.codingblock.plugin1:1(4)> [APK] processes=[] js={"pkgname":"cn.codingblock.plugin1","name":"cn.codingblock.plugin1","low":10,"high":10,"ver":1,"verv":2814792716779521,"path":"\/data\/user\/0\/cn.codingblock.repluginstudy\/app_p_a\/-347346251.jar","type":11,"frm_ver":4,"used":true} dex=/data/user/0/cn.codingblock.repluginstudy/app_p_od/-347346251.dex nlib=/data/user/0/cn.codingblock.repluginstudy/app_p_n/-347346251 } rc=true
10-30 16:41:46.204 10193-10193/cn.codingblock.repluginstudy D/RePlugin.ws001: cached filename: cn.codingblock.plugin1 -> null
10-30 16:41:46.275 10193-10263/cn.codingblock.repluginstudy V/RenderScript: 0xb34e8000 Launching thread(s), CPUs 4

运行插件那里毕竟在合法教程里面找不到,不过 Plugin.uninstall()
方法传入插件名即可那但是官方文书档案说的,此次不会是官方文书档案和源码注释合起伙来坑我们把? 经过反复试验后,有个有意思的意识:对于运营插件制造Intent 的createIntent() 方法和 卸载插件的 RePlugin.uninstall()
方法,如若项目是选择持续 RePluginApplication
方式的话,参数字传送包名才生效;假如不是延续的主意传插件名才生效!(本身是在一款BlackBerry3手提式有线电话机上试验的,由于并不曾广泛测试,所以不保障别的手提式有线电话机也是那一个套路)那不失为奇了葩了!

卸载插件时有一点索要专注:倘使插件正在运维,则不会立刻卸载插件,而是将卸载诉讼须要记录下来。直到全体“正在利用插件”的经过停止同等对待启后才会一蹴而就。(引自官方证实)

apply
plugin:’replugin-plugin-gradle’

android:name=”com.qihoo360.plugin.name”

}

Intent intent = new Intent();

_____________________插件端_________________________________

<–插件名称–>

<–插件版本–>

startActivity(intent);

intent.setComponent(new ComponentName(“com.redfinger.app”,
“com.redfinger.app.activity.LoginActivity”));

1.在项目根目录build.gradle下添加

_________________宿主________________________

1.在档次根目录build.gradle下添加

dependencies {

classpath ‘com.android.tools.build:gradle:2.3.2’

compile’com.qihoo360.replugin:replugin-host-lib:2.1.5′

}


2.在module下的build.gradle下添加

apply plugin: ‘replugin-host-gradle’//那几个放在Android前面

//假设插件中用到了AppCompactTheme那么还要在日前build.gradle中丰富

repluginHostConfig {

useAppCompat = true

}

compile ‘com.qihoo360.replugin:replugin-plugin-lib:2.1.5’


3.修改Application(注:添加的位于super后的首先行)

@Override

protected void attachBaseContext(Context base) {

super.attachBaseContext(base);

RePlugin.App.attachBaseContext(this);

}

@Override

public void onLowMemory() {

super.onLowMemory();

RePlugin.App.onLowMemory();

}

@Override

public void onTrimMemory(int level) {

super.onTrimMemory(level);

RePlugin.App.onTrimMemory(level);

}

@Override

public void onConfigurationChanged(Configuration config) {

super.onConfigurationChanged(config);

RePlugin.App.onConfigurationChanged(config);

}


4.设置更新插件都以同一个方式install

注:更新时的插件包要改版本号,否则就是覆盖(详见插件端的第叁条)更新插件后要重启APP生效

PluginInfopluginInfo = RePlugin.install(“/sdcard/replugin_new.apk”);


5.卸载插件

RePlugin.unInstall(“plugin01”)


6.论断插件是不是安装

PluginInfoinfo =
MP.getPlugin(“plugin01”,
true);


7.宿主打开插件中的第四次全国代表大会组件

RePlugin.startActivity(MainActivity.this,RePlugin.createIntent(“plugin01”,
“com.dg.replugindemo01.MainActivity”));

PluginServiceClient.bindService(RePlugin.createIntent( “exam”,
“AbcService”), mServiceConn);

PluginServiceClient.bindService(RePlugin.createIntent( “exam”,
“AbcService”), mServiceConn);

PluginProviderClient.query(xxx);


8.宿主调用插件方法

A)fetchComponentList(String pluginName);//获取插件的零部件列表

ComponentList cl = RePlugin.fetchComponentList(plugin);

B)fetchPackageInfo(String pluginName);//获取插件的包新闻

PluginInfo info=RePlugin.getPluginInfo(“”);

C)fetchResources(String pluginName);//获取插件的财富新闻

Resources resources=RePlugin.fetchResources(“”);

D)fetchClassLoader(String pluginName);//获取插件的ClassLoader对象

ClassLoader classLoader=RePlugin.fetchClassLoader(“”);

E)fetchContext(String pluginName);//获取插件的Context对象

Context context=RePlugin.fetchContext(“”);

F)fetchBinder(String pluginName, String module, String process);

//通过插件里的Plugin类,获取插件定义的IBinder

IBinder binder=RePlugin.fetchBinder(“”,””,””);


9.起步、绑定插件的Service

PluginServiceClient.bindService(RePlugin.createIntent(

“exam”, “AbcService”),mServiceConn);

10.调用RePlugin.install()方法,其重返值便是“新本子插件消息”使用RePlugin.getPlugin()方法,获得的是“当前正在运行的”插件新闻(而非新插件的)


11.在这些“当前正在运行的”插件音讯上,再调用getPendingUpdate()方法,则能够得到那一个“新本子插件音讯”了。

PluginInfo pi = RePlugin.getPluginInfo(“plugin01”);

if (pi != null) {

PluginInfo newPi = pi.getPendingUpdate();

if (newPi != null) {

//TODO

} else {

// No update

}

}

相关文章