浅谈Android插件化

如今,插件化与组件化的开发越来越广泛的被我们所使用,尤其是许多大公司。

什么事插件化,什么是组件化呢?
组件化开发:就是将一个app分成多个模块,每个模块都是一个组件(Module),开发的过程中我们可以让这些组件相互依赖或者单独调试部分组件等,但是最终发布的时候是将这些组件合并统一成一个apk,这就是组件化开发。
插件化开发:和组件化开发略有不用,插件化开发时将整个app拆分成很多模块,这些模块包括一个宿主和多个插件,每个模块都是一个apk(组件化的每个模块是个lib),最终打包的时候将宿主apk和插件apk分开或者联合打包。

有了组件化,为什么还要用插件化呢?插件化开发总的来说有以下几点好处(不同插件框架不一样):
宿主和插件分开编译
并发开发
动态更新插件
按需下载模块
方法数或变量数爆棚

可参考:http://android.jobbole.com/82746/

一、简单了解

压缩包:
1、zip包:qq表情
2、dex包:代码
3、apk(未安装 安装)
安装:PathClassLoader
非安装:DexClassLoader

插件化的由来:
1、65535/64k
2、功能解耦,更有助于分工合作

插件化要解决的问题 :
1、动态加载apk
2、资源加载
3、代码加载

看一下我们平时在Android应用程序中使用的插件(以qq为例):
可以看到在assets--plugins文件中,许多功能是通过插件形式加载的。
例如微云plugin虽然我们使用不多,但在我们使用的时候点击微云,他会把微云插件下载下来。

qqapk-assetes-plugins.png
微信小程序&支付宝全部应用.png

无论是360、支付宝(全部应用)、微信(小程序虽然是用h5开发的,但是架构最终转化到微信里面,是转化成原生代码)等,平时我们使用的很多大型的应用程序要满足不同用户需求,程序都有插件化开发的身影。

二、插件化

1、判断插件是否存在
所需插件-->判断本地是否有插件-->本地没有则下载(请求服务获取文件名、包名等)

2、插件化原理
每次使用activity都会在mainifest.xml禽蛋文件中注册,那如何在宿主程序中加载外来的Activity(实现生命周期)呢?很多人会想到Hook技术,但我们还可以通过插桩技术来实现。

如果理解的类加载器、反射及动态代理概念,那么便很容易理解插件化开发。
本文简单以避开AndroidMainfest.xml限制,插件化方式让外来apk自由加载为例。

动态加载apk原理:
替身Activity注册 ----> 找到插件Activity进行替换

动态加载apk原理图.png

资源加载原理图:


插件化资源加载原理图.png

3、从framework层源码分析插件化

加载插件apk,因为需要获得DexClassLoader和一个代表插件apk的Resource,所以需要实例化Resource,而Resources不能直接通过new对象直接获得,下面带大家分析一下源码:

framework层Resources.java这个文件(下面代码仅是Resources构造方法):

 /**
     * Create a new Resources object on top of an existing set of assets in an
     * AssetManager.
     *
     * @deprecated Resources should not be constructed by apps.
     * See {@link android.content.Context#createConfigurationContext(Configuration)}.
     *
     * @param assets Previously created AssetManager.
     * @param metrics Current display metrics to consider when
     *                selecting/computing resource values.
     * @param config Desired device configuration to consider when
     *               selecting/computing resource values (optional).
     */
    @Deprecated
    public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config) {
        this(null);
        mResourcesImpl = new ResourcesImpl(assets, metrics, config, new DisplayAdjustments());
    }

    /**
     * Creates a new Resources object with CompatibilityInfo.
     *
     * @param classLoader class loader for the package used to load custom
     *                    resource classes, may be {@code null} to use system
     *                    class loader
     * @hide
     */
    public Resources(@Nullable ClassLoader classLoader) {
        mClassLoader = classLoader == null ? ClassLoader.getSystemClassLoader() : classLoader;
    }

    /**
     * Only for creating the System resources.
     */
    private Resources() {
        this(null);

        final DisplayMetrics metrics = new DisplayMetrics();
        metrics.setToDefaults();

        final Configuration config = new Configuration();
        config.setToDefaults();

        mResourcesImpl = new ResourcesImpl(AssetManager.getSystem(), metrics, config,
                new DisplayAdjustments());
    }

Resources中有三个构造函数,其中第二个是被系统隐藏的,第三个是只能创建系统Resources,那么我们只能通过第一个构造方法去实例化Resources(AssetManager assets,DisplayMetrics metrics,Configuration config){...}去实例化Resources。
AssetManager 资源管理类,metrics和config这两个参数和插件apk无关直接用系统的就可以,因此可通过context.getResources().getDisplayMetrics()和context.getResources().getConfiguration()获得。

那如何获取AssetManager呢,我们看AssetManager.java文件(仅AssetManager构造方法码):

   /**
     * Create a new AssetManager containing only the basic system assets.
     * Applications will not generally use this method, instead retrieving the
     * appropriate asset manager with {@link Resources#getAssets}.    Not for
     * use by applications.
     * {@hide}
     */
    public AssetManager() {
        synchronized (this) {
            if (DEBUG_REFS) {
                mNumRefs = 0;
                incRefsLocked(this.hashCode());
            }
            init(false);
            if (localLOGV) Log.v(TAG, "New asset manager: " + this);
            ensureSystemAssets();
        }
    }

AssetManager的构造方法是也被系统所隐藏的,那我们可以通过反射实例化AssetManager,因为空的AssetManager是没有任何作用的,因此要给它设置路径。

  /**
     * Add an additional set of assets to the asset manager.  This can be
     * either a directory or ZIP file.  Not for use by applications.  Returns
     * the cookie of the added asset, or 0 on failure.
     * {@hide}
     */
    public final int addAssetPath(String path) {
        return  addAssetPathInternal(path, false);
    }
通过反射实例化AssetManager.png

invoke(Object obj,Object...args)第一个参数为类的实例,第二个参数为相应函数中的参数。
那么我们便获得到了Resources实例。

4、替身PorxyActivity
未完,待续...

如有问题欢迎交流。

如转载请注明出处,谢谢!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,417评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,921评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,850评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,945评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,069评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,188评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,239评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,994评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,409评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,735评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,898评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,578评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,205评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,916评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,156评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,722评论 2 363
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,781评论 2 351

推荐阅读更多精彩内容