Qihoo360/RePlugin 插件的信息

本文主要讲述如何获取并使用插件的一些信息。这些信息大致包括:

插件命名

RePlugin的插件可以有两种名字,分别是:插件包名、插件别名。

  • 插件包名:顾名思义,就是插件的PackageName
  • 插件别名:为了“精简包名”而设计的别名,也是RePlugin推荐大家使用的

值得注意的是,在您调用插件逻辑时,您既可以使用插件包名,也可以使用插件别名,两者可以混用而不受影响(在RePlugin 2.2.0中支持

插件包名

插件包名可以任意起名,不受限制。

注意,若您的APK既作为单品,又作为插件,则建议分成两个包名,且Provider的Authority也建议改名,这样可针对不同的场景(插件还是单品)来做不同的处理。

插件别名

除了插件包名外,针对很多开发者的诉求(包名太长、有可能会改等),我们提出了“插件别名”的概念。

插件别名应做到尽可能的简短、易懂,并尽量为全小写。如:webview、push、protobuf等

要声明插件别名,需要在插件的AndroidManifest.xml中声明以下Meta-data:

 <meta-dataandroid:name="com.qihoo360.plugin.name"android:value="[你的插件别名]" />

注意

针对内置插件而言:

  • 若不填写插件别名,则RePlugin会将内置插件的“文件名”作为其插件名
  • 其优先级为:Meta-data声明的 > 文件名

而针对外置插件而言:

  • 若不填写插件别名,则RePlugin只能允许使用“插件包名”
  • P-n类型插件在生成“文件头”时就必须要设置别名,故不受影响

最佳实践

以下为360手机卫士或其它合作App采用的设计,可供您参考:

  • 建议给主要的、经常用到的插件,声明其“插件别名”(虽然不硬性要求),这样代码会更加简洁。

试想一下,是每次用“com.qihoo360.mobilesafe.plugin.webview”好呢?还是“webview”好呢?

  • 一些外部合作的插件(如360桌面等)可以只使用插件包名

插件的版本

RePlugin用到的版本可分为三种:插件版本号、“插件协议版本号”和“插件框架版本号”。

插件的VersionCode

插件版本号是很容易理解的,就是插件的VersionCode,可以自由发挥(当然了,毕竟是Integer类型,所以别超过32位最大值)。

插件的VersionName因其类型为String,故不作为我们的“插件版本”

最佳实践

为了更好的维护插件的版本,以360手机卫士的经验来看,建议可由“三位数”组成。

其中,第一位是大版本,第二位是功能版本,第三位是修复版本。

例如——101。其中第一位“1”为大版本,第二位“0”为功能版本,第三位“1”是修复版本

  • 大版本:当插件发生“极其重要的变化”时,可调整此版本
  • 功能版本:当插件增加了多个新功能,或优化了多个功能项时,可调整此版本
  • 修复版本:当插件出现一些Bug需要修复,或一些很小的改动项,或做A/B Test时,可调整此版本

这样做的好处是显而易见的——各插件能做到“并行开发”,而不受其影响。当然,五位数、七位数都可以,可根据您们的业务需要来定。

插件协议版本号

为了让插件和主程序、插件和插件之间,在针对“巨大接口调整”后仍能确保没有问题,故设立了“插件协议版本号”。

绝大多数开发者可无需关注此版本号,目前设定的默认值是“10”。

我们为什么要设立这个呢?

在开发应用的过程中,难免会遇到一种情况:插件之间,插件与宿主间的交互相对比较频繁。

如果某个插件或主程序的接口发生了极其重大的变化(例如彻底的重构和删除),首先面临的一个问题是——旧插件将无法再使用,其次还要考虑到新插件要做“各种兼容”,例如“逐一判断”接口等,非常费时费力。

为此,我们引入了“插件协议版本号”的概念。

要声明插件协议版本号,您需要在插件的AndroidManifest.xml中声明以下Meta-data:

 <meta-dataandroid:name="com.qihoo360.plugin.version.low"android:value="[你的插件协议版本号]" /> <meta-dataandroid:name="com.qihoo360.plugin.version.high"android:value="[你的插件协议版本号]" />

目前要求low和high应保持相等。

为什么会有low和high,而不是一个api_ver就搞定?

这个和我们之前RePlugin在2014年的更复杂的情形有关,时间关系不在此赘述。然而,随着目前框架的逐渐成熟,这个low和high其实完全可以“合二为一”(内部也是这么用的)。在未来版本,我们将做重构,确保只保留一个。

插件框架版本号

为了让插件兼容主程序的RePlugin框架,故设立了“插件框架版本号”。截止到2017年6月底,最新的版本号为“4”。

我们为什么要设立这个呢?

从2013年开始,RePlugin经历了数次非常大的改进,尤其以2017年的为甚。而仅以360手机卫士为例,截止到2017年6月底,我们已有102个插件,而有些插件仍需运行在早期的手机卫士上(例如杀毒、清理等),即便还在持续的更新。

若我们不设立这个版本号,则直接导致的结果是:旧插件在新、老手机卫士(或RePlugin架构)上的行为变得不可预测。

举个例子:有个插件是跑在早期手机卫士框架上,彼时还不支持“完全自定义Theme”方案。出于习惯,某Activity设置了一个特殊的,甚至是不正确的Theme。由于早期版本不生效,所以还一直相安无事。然而,如果没有“框架版本号”,则一旦框架突然支持了自定义Theme,则那个“有问题的”Theme就突然生效,导致行为不可预期的问题。

要声明插件框架版本号(绝大多数情况下不需要,默认为4),您需要在插件的AndroidManifest.xml中声明以下Meta-data:

 <meta-dataandroid:name="com.qihoo360.framework.ver"android:value="[你的框架版本号]" />

插件信息的获取

插件信息的类是 PluginInfo,无论是宿主还是插件均可使用。而要获取插件信息还是非常简单的:

  • 调用 RePlugin.getPlugin() 方法,可获取任意插件的信息,也可以借此判断插件是否安装(若为null则表示没有安装)
  • 调用 RePlugin.getPluginInfoList() 方法可获取所有已安装(包括内置插件)的信息
  • 调用 RePlugin.install() 方法,其返回值是“安装成功后”的PluginInfo。若返回Null则表示“安装失败”

获取“待更新插件信息”

PluginInfo中有一个“神奇的”方法:getPendingUpdate,很多人对此方法有一定的疑惑。然而一旦您遇到这种情况,就会发现这个方法变得非常有必要了。例如:

当前正在运行“卫士体检”插件,后在进程没有重启的情况下,对此插件作了升级。而我想获取这两个信息:

  • 当前正在运行的插件信息
  • 新版本(只不过还没生效)的插件信息

以上两种情况都会遇到,应该怎么办?

我们的做法是:

  • 当时调用了 RePlugin.install() 方法,其返回值就是“新版本插件信息”
  • 使用 RePlugin.getPlugin() 方法,得到的是“当前正在运行的”插件信息(而非新插件的)
  • 在这个“当前正在运行的”插件信息上,再调用 getPendingUpdate() 方法,则可以拿到这个“新版本插件信息”了。

代码说明一下:

// Fetch "Current Version" plugin.PluginInfo pi =RePlugin.getPluginInfo("exam"); if (pi !=null) { // Fetch "New Version" pluginPluginInfo newPi = pi.getPendingUpdate(); if (newPi !=null) { ... } else { // No update... } }