Android 插件化开发(四):插件化实现方案

时间:2024-02-22 16:45:26

在经过上面铺垫后,我们可以尝试整体实现一下插件化了。这里我们先介绍一下最简单的实现插件化的方案。

一、最简单的插件化实现方案

最简单的插件化实现方案,对四大组件都是适用的,技术面涉及如下:

1). 合并所有插件的Dex,来解决插件的类的加载问题。

2). 预先在宿主的AndroidManifest.xml文件中声明插件的四大组件。(如果插件组件过多会很麻烦)

3). 把插件中的所有资源一次性的合并到宿主的资源中。(合并时可能会导致id冲突)

使用此组件化方案实现时,Service、ContentProvider 和 Receiver 只要合并 dex 就够了,因为这些没有资源访问的概念。

但是Activity插件化实现时就会比较麻烦,因为Activity严重依赖资源,想实现Activity的插件化就必须解决加载插件中资源的问题。

在 Android 插件化开发(三):资源插件化 中我们介绍过AssetsManager和Resource这两个类的关系,AssetManager有一个addAssetPath方法,可以一次性把插件的路径都导入,然后再生成一个含有全局资源的Resource,以后无论查找插件还是宿主的的资源都能找到了。

虽然此方案能实现插件化,但是此方案有很大的问题:

1. 插件的四大组件要事先声明,无法动态新增,这样对于Activity来说是无法兼容的问题(其他组件相对问题较少)。

2. 资源id会冲突。

3. 无法预料插件内Activity,对于插件内动态新增的Activity无法进行使用。

项目代码仓库地址:https://github.com/renhui/RHPluginProgramming/tree/master/ZeusStudy

了解如何实现一个最简单的插件化之后,我们再整理一下Activity如何实现插件化。这里单独再提一下 Activity 是因为 Activity 是 App 中使用频率最高的组件,所以这里我们先讲述一下Activity的插件化。

Activity 的插件化需要解决3方面的技术问题:

1). 宿主App可以加载App中的类。

2). 宿主App可以加载App中的资源。

3). 宿主App可以加载插件中的Activity。

前两个技术问题,我们已解决了,这里我们讲一下第3个的技术问题的解决方案。主要的解决方案有很多种,这里只简单以两个有标志性的框架:

a. 以DroidPlugin框架为代表的动态替换方案,提供对Android底层的各类进行Hook,以达到插件化中的四大组件的目的。

b. 以DynamicLoadApk框架为代表的静态代理方案,通过ProxyActivity统一加载插件中的所有Activity。

 

下面我们再讲一下DynamicLoadApk框架,此框架在《Android插件化开发指南》书中重点提及了,本人也比较感兴趣。

三、DynamicLoadApk 插件化框架

DynamicLoadApk 是一个开源的 Android 插件化框架。

插件化的优点包括:(1) 模块解耦,(2) 动态升级,(3) 高效并行开发(编译速度更快) (4) 按需加载,内存占用更低等等。

DynamicLoadApk 提供了 3 种开发方式,让开发者在无需理解其工作原理的情况下快速的集成插件化功能。

  1. 宿主程序与插件完全独立;
  2. 宿主程序开放部分接口供插件与之通信;
  3. 宿主程序耦合插件的部分业务逻辑。

1. DynamicLoadApk 框架核心概念

(1) 宿主:主 App,可以加载插件,也称 Host。

(2) 插件:插件 App,被宿主加载的 App,也称 Plugin,可以是跟普通 App 一样的 Apk 文件。

(3) 组件:指 Android 中的Activity、Service、BroadcastReceiver、ContentProvider,目前 DL 支持Activity、Service以及动态的BroadcastReceiver。

(4) 插件组件:插件中的组件。

(5) 代理组件:在宿主的 Manifest 中注册,启动插件组件时首先被启动的组件。目前包括 DLProxyActivity(代理 Activity)、DLProxyFragmentActivity(代理 FragmentActivity)、DLProxyService(代理 Service)。

(6) Base 组件:插件组件的基类,目前包括 DLBasePluginActivity(插件 Activity 的基类)、DLBasePluginFragmentActivity(插件 FragmentActivity 的基类)、DLBasePluginService(插件 Service 的基类)。

DynamicLoadApk 原理的核心思想可以总结为两个字:代理。通过在 Manifest 中注册代理组件,当启动插件组件时首先启动一个代理组件,然后通过这个代理组件来构建、启动插件组件。

2. DynamicLoadApk 框架设计思路

上面是 DynamicLoadApk 的总体设计图,DynamicLoadApk 主要分为四大模块:

(1) DLPluginManager

插件管理模块,负责插件的加载、管理以及启动插件组件。

(2) Proxy

代理组件模块,目前包括 DLProxyActivity(代理 Activity)、DLProxyFragmentActivity(代理 FragmentActivity)、DLProxyService(代理 Service)。

(3) Proxy Impl

代理组件公用逻辑模块,与(2)中的 Proxy 不同的是,这部分并不是一个组件,而是负责构建、加载插件组件的管理器。这些 Proxy Impl 通过反射得到插件组件,然后将插件与 Proxy 组件建立关联,最后调用插件组件的 onCreate 函数进行启动。

(4) Base Plugin

插件组件的基类模块,目前包括 DLBasePluginActivity(插件 Activity 的基类)、DLBasePluginFragmentActivity(插件 FragmentActivity 的基类)、DLBasePluginService(插件 Service 的基类)。

3. DynamicLoadApk 流程说明

上面是调用插件 Activity 的流程图,其他组件调用流程类似。

(1) 首先通过 DLPluginManager 的 loadApk 函数加载插件,这步每个插件只需调用一次。

(2) 通过 DLPluginManager 的 startPluginActivity 函数启动代理 Activity。

(3) 代理 Activity 启动过程中构建、启动插件 Activity。

四、其他的插件化解决方案

在介绍其他的插件化解决方案之前,我们先看一下插件化技术的演进图:

 以下是相关的项目地址:

7) Small:https://github.com/wequick/Small

 

虽然插件化的相关框架不少,但是核心技术还是不变的,那就是:反射 + 代理