1.准备工作
登录ApkPlug官网注册账号console.apkplug.com/ ,开通相关业务。
选择插件托管——>应用列表——>创建新应用(即主程序、宿主应用)。
然后进入应用详情,创建容器。容器即为保存一个或多个插件的集合。
再到插件列表中创建一个插件,将插件与应用绑定。
2.主应用开发
2.1宿主配置
a、下载jar包及so文件 github.com/apkplug/apkplug_jar/3.8.0
导入BundleCloud(x.x.x)-Release.jar并在jni/armeabi下加入libApkPlugPatchLibrary.so (其他架构自行添加,各种so已经提供)
*注:如果出现加载64位或32位so文件出错,请根据需求只保留32或64中一种so文件
github.com/apkplug/apkplug_jar/v_old 下为老版本apkplug兼容版,不便升级可以先使用此包
b、主应用权限配置
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.BIND_MIDI_DEVICE_SERVICE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
android 6.0需要自己动态申请如下权限,不申请可能有不可预测的错误:
Manifest.permission.WRITE_EXTERNAL_STORAGE
Manifest.permission.READ_EXTERNAL_STORAGE
Manifest.permission.READ_PHONE_STATE
Manifest.permission.ACCESS_NETWORK_STATE
c、主应用清单文件配置
<meta-data android:name="apkplug_appid" android:value="your appid" />
<meta-data android:name="apkplug_containerid" android:value="your containerid"/>
<activity android:name="org.apkplug.app.apkplugActivity"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:configChanges="orientation|keyboardHidden"/>
<intent-filter>
<action android:name="android.intent.action.MAIN"></action>
</activity>
<service android:name="com.apkplug.libmerge.common.MergeServeice" android:process=":merge" />
<service android:name="org.apkplug.app.apkplugService" />
<provider android:name="org.apkplug.app.apkplugProvider" android:authorities="xxx.apkplugprovider" />
xxx为宿主应用包名,不能用'.'代替
apkplug_appid在应用详情查询,apkplug_containerid在容器详情查询。
d、代码混淆
-keep class com.apkplug.** { *;}
-keep class org.apkplug.** { *;}
-keep class org.osgi.** { *;}
-keep class extends org.osgi.**
-keep class tengxin.sv.** { *;}
2.2主应用框架启动
主应用启动Apkplug最简只需要一段代码即可,建议在Application中启动框架。
FrameworkInstance frame=FrameworkFactory.getInstance().start(List,Context);
得到System插件上下文BundleContext
BundleContext bundleContext = FrameworkFactory.getInstance().getFrame().getSystemBundleContext();
BundleContext 可以用于宿主管理插件,与插件通信等
2.3初始化
插件托管能帮你使用后台上传的插件,所有功能在PlugManager统一获取,PlugManager获取方法:
PlugManager.getInstance()
在使用任何插件托管相关接口之前,需要提前调用init方法
PlugManager.getInstance().init(Context context,BundleContext bundleContext,String publickey,boolean isDebug)
参数说明:
publickey为后台为应用生成的key,到后台应用详情里可以找到。
isDebug: 是否debug模式,true:后台数据实时响应 false:后台数据1分钟后更新,1分钟内请求为缓存信息
如果是android 6.0系统,还需要调用requestPermission
PlugManager.getInstance().requestPermission(Activity activity)
来申请权限,并在onRequestPermissionsResult中调用回调来处理请求权限结果。
PlugManager.getInstance().onRequestPermissionsResult(int requestId, Activity activity,String[] permissions, int[] grantResults)
2.4注销SDK
当不再使用功能后,调用onDestroy,注销上下文
@Override
protected void onDestroy() {
super.onDestroy();
plugManager.onDestroy();
}
3.插件的管理
3.1SystemBundle
apkplug初始化以后默认有一个系统插件叫SystemBundle,它永远在插件列表的第一个位置,利用该插件您可以实现管理插件,与插件通信等功能
获取系统插件上下文
BundleContext bundleContext = FrameworkFactory.getInstance().getFrame().getSystemBundleContext();
3.2使用短连接管理插件
在插件详情中,我们自动为您生成短链,可以直接拷贝用于安装插件
使用短链安装的插件,必须在插件的plugin.xml中配置Short-Links=“短链”,否则查询不到
PlugManager manager = PlugManager.getInstance();
Bundle bundle = manager.checkLocalShortLinkPlug("http://xxxx");
if(bundle != null){
System.out.println("找到了插件");
}else{
System.out.println("插件没找到");
}
3.3使用短链接安装插件
此接口会先查找本地是否已经安装了这个短链指向的插件,如果已经安装则不管有没有更新版的插件都不会再次下载安装。如果没有安装,则下载安装。
PlugManager.getInstance().installPlugFromShortLink("http://yyfr.net/q0Y", new OnInstallSLPlugListener() {
@Override
public void onDownloadProgress(String s, String s1, long l, long l1) {
System.out.println("正在下载 百分比:"+l/l1);
}
@Override
public void onInstallSuccess(org.osgi.framework.Bundle bundle) {
System.out.println("安装成功了");
}
@Override
public void onInstallFailuer(int i, String s) {
System.out.println("安装失败了");
}
@Override
public void onDownloadFailure(String s) {
System.out.println("下载失败了");
}
});
3.4使用短链接更新插件
此接口会先检查本地是否已经安装此短链指向的插件,如果没安装则直接下载当前最新版安装。如果安装了,则先检测已安装插件的版本,如果不是最新的则下载最新的覆盖安装。如果检测本地已经是最新版本则不做处理。
注意在短链插件开发时在plugin.xml中配置Short-Links=“短链”,否则即使已经安装也找不到这个插件
PlugManager.getInstance().updatePlugByShortLink("http://yyfr.net/q0Y", new OnUpdateSLListener() {
.......
3.5安装插件
apkplug支持两种安装方式: 1.安装云端托管的插件 2.安装Assets目录下的插件
a.安装云端托管插件.此接口可以根据从云端获取的PlugInfo把对应的插件安装到本地
安装云端插件接口为:
PlugManager.getInstance().installPlug(Context context, PlugInfo plugInfo, OnInstallListener listener);
或者
PlugManager.getInstance().installPlug(Context context, PlugInfo plugInfo, InstallProperties properties,OnInstallListener listener);
b.安装本地Assets目录下的插件
安装本地插件接口为:
PlugManager.getInstance().installAssets(Context context,String apkName,String version,OnInstallListener listener);
或者
PlugManager.getInstance().installAssets(Context context,String apkName,String plugVersion,InstallProperties properties, final OnInstallListener listener);
后者可以通过InstallProperties 传入一些安装检测条件,其他相同'
apkName:assets下插件apk的文件名
plugVersion:assets下插件apk的版本号
4.插件开发
4.1插件相关配置
osgi包导入:下载地址github.com/apkplug/apkplug_jar/tree/master/OSGI.jar 下载最新版本即可
拷贝osgi.jar到项目的libs目录下在module的build.gradle中加入以下代码片段
dependencies {
provided files('libs/osgi.jar')
}
4.2配置文件plugin.xml
plugin.xml 与AndroidManifest.xml功能相似提供插件的系统属性。
将plugin.xml放在插件的assets目录下即可
一 plugin.xml有以下几个属性比较重要
1 plug_id --插件id,用于标识这个插件,在后台插件详情获取
2 Short-Links --使用短链操作插件的话,必须将短链配置到此项
3.Bundle-Name --插件名称
4.Bundle-SymbolicName --插件唯一标识类似安卓程序应用标识
5.Bundle-Version --插件版本号 如100
6.Bundle-Activator --插件入口类 ,通过它框架可在启动插件的时候找到并调用start()函数
7.Bundle-Activity --插件的 Lanucher Activity路径(多个包以 ‘,‘ 分割)
8.Export-Package --提供给其他插件使用的java类需要导出对应包路径(多个包以 ‘,‘ 分割)
9.Import-Package --插件内部没有这样的java类需要从其他插件导入(多个包以 ‘,‘ 分开)10.Bundle-Service --插件的Service类路径 (多个包以 ‘,‘ 分割) 【v2.0.0新增】
11.Bundle-Receiver --插件接收系统广播类路径 (多个包以 ‘,‘ 分割) 【v2.0.0新增】
示例: console.apkplug.com/documents/plug/prepare/configure/sample
4.3插件入口类BundleActivator
BundleActivator就两个函数
public void start(BundleContext context) 插件启动时被调用
public void stop(BundleContext context) 插件停止时被调用
我们可以在start函数中获取插件上下文BundleContext 并且初始化或注册一些插件提供的OSGI服务
我们可以在stop函数中注销OSGI服务,释放插件开辟的相关内存等。
示例:console.apkplug.com/documents/plug/prepare/BundleActivator/sample
4.4其他关于插件的
附录:console.apkplug.com/documents/plug/appendix/Bundle
5.宿主和插件的通信
官方文档共提供了三种,目前只简单介绍推荐的第一种RPC通信.
bundlerpc支持的功能:
1. 支持代码注册和静态注册两种方式
2. 插件间通信需要提前约定接口(interface)但:
2.1 插件与宿主可以同时存在约定的接口
2.2 同时bundlerpc提供一套通用的回调接口,尽量简化约定接口数
2.3 bundlerpc提供一个可序列化java对象池ObjectPool
2.3.1 利用ObjectPool可以将任意对象通过Intent和其他序列化方式传输
2.3.2.该功能对应的是Dispatch延时回复功能
3. 支持URL方式查询服务