Overview

假设我手上现在有猫眼、外卖、打车、买菜等好几个垂直领域的 APP,现在呢要开发一个集所有功能于一身的超级 APP 叫做美团,用 Shadow 该如何改造已有的垂直 APP 并集成到 meituan-app 这个新的 APP 内呢?

将猫眼 app 拆分为 library module 和 app module 两个模块

- maoyan-lib
- maoyan-app

为了将猫眼 APP 集成到 meituan-app 里,需要将猫眼打包为一个 Shadow 插件,相关的项目有三个:

- maoyan-lib
- maoyan-app

- maoyan-runtime
- maoyan-loader
- maoyan-plugin

plugin 打包后是一个 zip 文件,不能直接使用,需要解压、加载、初始化等各种前置操作,为了将这些 plugin 相关的业务与 meituan-app 业务代码隔离,以便 meituan-app 能透明地使用 plugin,还需要添加一个项目 meituan-manager;它作为桥梁连接主 APP 和各个 plugin,承担 plugin 的管理工作,虽然它是一个 com.android.application 但不会也不能作为 APP 独立运行

其实我们能够很容易地想到,meituan-manager 不应该就是 Shadow Library 吗?它不是应该作为 dependency 打包进主 APP 吗?

对!Shadow 作为一个普通的 dependency 确实是可以这样做,但这样的话 Shadow 一旦需要升级只能升级同时主 APP;那能不能把框架本身也像 plugin 那样动态加载随时升级呢?真是个大胆的想法,不过确实可以做到,就是把框架代码 meituan-manager 独立在主 APP 之外,单独打包并动态加载

一次性实现完美的插件框架很难,但 Shadow 将这些实现全部动态化起来,使插件框架的代码成为了插件的一部分。插件的迭代不再受宿主打包了旧版本插件框架所限制

- maoyan-lib
- maoyan-app

- maoyan-runtime
- maoyan-loader
- maoyan-plugin

- meituan-manager

最后就是构建主 APP:meituan-app,它是一个普通的 com.android.application,可以有自己的源码依赖、第三方依赖、业务代码(比如 Slash Page、主页)以及自定义构建脚本,assemble 打包出来的安装包即使没有 plugins 也是可以正常运行的,只不过 plugins 提供的功能就无法使用了

meituan-app 与各个 plugins 之间通过一个方法进行通讯:

public interface PluginManager {
    void enter(Context context, long formId, Bundle bundle, EnterCallback callback);
}

meituan-app 除了业务代码之外需要添加的改动有几处:

  1. meituan-manager 和 plugin 的下载/更新逻辑(plugin 是个 zip 文件,manager 是个 apk 文件)