前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >android插件化介绍

android插件化介绍

作者头像
李小白是一只喵
发布2020-11-24 12:32:26
8200
发布2020-11-24 12:32:26
举报
文章被收录于专栏:算法微时光算法微时光

image.png

转载:https://blog.csdn.net/suyimin2010/article/details/80958742

插件化介绍

image.png

插件化技术最初源于免安装运行apk的想法,这个免安装的apk可以理解为插件。

支持插件化的app可以在运行时加载和运行插件,这样便可以将app中一些不常用的功能模块做成插件,一方面减小了安装包的大小,另一方面可以实现app功能的动态扩展。

想要实现插件化,主要是解决下面三个问题:

  1. 插件中代码的加载和与主工程的互相调用
  2. 插件中资源的加载和与主工程的互相访问
  3. 四大组件生命周期的管理

插件化技术

技术的发展,根据实现原理可以将这几个框架划分成了三代。

image.png

第一代

dynamic-load-apk最早使用ProxyActivity这种静态代理技术,由ProxyActivity去控制插件中PluginActivity的生命周期。

该种方式缺点明显,插件中的activity必须继承PluginActivity,开发时要小心处理context。

而DroidPlugin通过Hook系统服务的方式启动插件中的Activity,使得开发插件的过程和开发普通的app没有什么区别,但是由于hook过多系统服务,异常复杂且不够稳定。

第二代

为了同时达到插件开发的低侵入性(像开发普通app一样开发插件)和框架的稳定性,在实现原理上都是趋近于选择尽量少的hook,并通过在manifest中预埋一些组件实现对四大组件的插件化。

另外各个框架根据其设计思想都做了不同程度的扩展,其中Small更是做成了一个跨平台,组件化的开发框架。

第三代

VirtualApp比较厉害,能够完全模拟app的运行环境,能够实现app的免安装运行和双开技术。

Atlas是阿里今年开源出来的一个结合组件化和热修复技术的一个app基础框架,其广泛的应用与阿里系的各个app,其号称是一个容器化框架。

插件化技术原理

类加载

Android中常用的有两种类加载器,DexClassLoader和PathClassLoader,它们都继承于BaseDexClassLoader。

代码语言:javascript
复制
// DexClassLoader
public class DexClassLoader extends BaseDexClassLoader {    
    public DexClassLoader(String dexPath, String optimizedDirectory,
            String libraryPath, ClassLoader parent) {        
        super(dexPath, new File(optimizedDirectory), libraryPath, parent);
    }
}
// PathClassLoader
public class PathClassLoader extends BaseDexClassLoader {    
    public PathClassLoader(String dexPath, ClassLoader parent) {     
       super(dexPath, null, null, parent);
    } 
 
    public PathClassLoader(String dexPath, String libraryPath,
            ClassLoader parent) {    
       super(dexPath, null, libraryPath, parent);
    }

}

DexClassLoader多传了一个optimizedDirectory参数,这个目录必须是内部存储路径,用来缓存系统创建的Dex文件。

而PathClassLoader该参数为null,只能加载内部存储目录的Dex文件。

Android对于外部的dex文件,主要通过 DexClassLoader 类加载。

代码语言:javascript
复制
//第一个参数为apk的文件目录
//第二个参数为内部存储目录
//第三个为库文件的存储目录
//第四个参数为父加载器
new DexClassLoader(apk.getAbsolutePath(), dexOutputPath, libsDir.getAbsolutePath(), parent)

类加载器的构造函数代码例子:

代码语言:javascript
复制
private DexClassLoader createDexClassLoader(String apkPath) {
    File dexOutputDir = mContext.getDir("dex", Context.MODE_PRIVATE);
    DexClassLoader loader = new DexClassLoader(apkPath, dexOutputDir.getAbsolutePath(),
            null, mContext.getClassLoader());
    return loader;
}
插件调用主工程

在构造插件的ClassLoader时会传入主工程的ClassLoader作为父加载器,所以插件是可以直接可以通过类名引用主工程的类。

主工程调用插件

若使用多ClassLoader机制,主工程引用插件中类需要先通过插件的ClassLoader加载该类再通过反射调用其方法。

插件化框架一般会通过统一的入口去管理对各个插件中类的访问,并且做一定的限制。

若使用单ClassLoader机制,主工程则可以直接通过类名去访问插件中的类。

注意:该方式有个弊病,若两个不同的插件工程引用了一个库的不同版本,则程序可能会出错,所以要通过一些规范去避免该情况发生。

资源加载

Android系统通过Resource对象加载资源。

因此,只要将插件apk的路径加入到AssetManager中,便能够实现对插件资源的访问。

代码语言:javascript
复制
//创建AssetManager对象 
AssetManager assets = new AssetManager();
 //将apk路径添加到AssetManager中
  if (assets.addAssetPath(resDir) == 0){              
    return null;  
}
 //创建Resource对象
 
r = new Resources(assets, metrics, getConfiguration(), compInfo);

由于AssetManager并不是一个public的类,需要通过反射去创建.

资源路径处理

和代码加载相似,插件和主工程的资源关系也有两种处理方式:

  • 合并式:addAssetPath时加入所有插件和主工程的路径;
  • 独立式:各个插件只添加自己apk路径

合并式

由于AssetManager中加入了所有插件和主工程的路径,因此生成的Resource可以同时访问插件和主工程的资源。

但是由于主工程和各个插件都是独立编译的,生成的资源id会存在相同的情况,在访问时会产生资源冲突。

独立式 各个插件的资源是互相隔离的,不过如果想要实现资源的共享,必须拿到对应的Resource对象。

Context处理

通常我们通过Context对象访问资源,光创建出Resource对象还不够,因此还需要一些额外的工作。

对资源访问的不同实现方式也需要不同的额外工作。

以VirtualAPK的处理方式为例。

创建Resource
代码语言:javascript
复制
if (Constants.COMBINE_RESOURCES) {
    //插件和主工程资源合并时需要hook住主工程的资源
    Resources resources = ResourcesManager.createResources(context, apk.getAbsolutePath());
    ResourcesManager.hookResources(context, resources);  
      return resources;
} else {  
      //插件资源独立,该resource只能访问插件自己的资源
    Resources hostResources = context.getResources();
    AssetManager assetManager = createAssetManager(context, apk);  
        return new Resources(assetManager, hostResources.getDisplayMetrics(), hostResources.getConfiguration());
}
关联resource和Activity
代码语言:javascript
复制
Activity activity = mBase.newActivity(plugin.getClassLoader(), targetClassName, intent);
activity.setIntent(intent);
//设置Activity的mResources属性,Activity中访问资源时都通过mResources
 
ReflectUtil.setField(ContextThemeWrapper.class, activity, "mResources", plugin.getResources())
四大组件支持

Android开发中有一些特殊的类,是由系统创建的,并且由系统管理生命周期。

如常用的四大组件,Activity,Service,BroadcastReceiver和ContentProvider。

仅仅构造出这些类的实例是没用的,还需要管理组件的生命周期。

其中以Activity最为复杂,不同框架采用的方法也不尽相同。下面以Activity为例详细介绍插件化如何支持组件生命周期的管理。

大致分为两种方式:

  1. ProxyActivity代理
  2. 预埋StubActivity,hook系统启动Activity的过程
ProxyActivity代理

ProxyActivity代理的方式最早是由dynamic-load-apk提出的,其思想很简单,在主工程中放一个ProxyActivy,启动插件中的Activity时会先启动ProxyActivity,在ProxyActivity中创建插件Activity,并同步生命周期。

下图展示了启动插件Activity的过程:

image.png

具体的过程如下:

首先需要通过统一的入口(如图中的PluginManager)启动插件Activity,其内部会将启动的插件Activity信息保存下来,并将intent替换为启动ProxyActivity的intent。

ProxyActivity根据插件的信息拿到该插件的ClassLoader和Resource,通过反射创建PluginActivity并调用其onCreate方法。

PluginActivty调用的setContentView被重写了,会去调用ProxyActivty的setContentView。由于ProxyActivity重写了getResource返回的是插件的Resource,所以setContentView能够访问到插件中的资源。同样findViewById也是调用ProxyActivity的。

hook方式

image.png

  1. Activity1调用startActivity,实际会调用Instrumentation类的execStartActivity方法,Instrumentation是系统用来监控Activity运行的一个类,Activity的整个生命周期都有它的影子。
  2. 通过跨进程的binder调用,进入到ActivityManagerService中,其内部会处理Activity栈。之后又通过跨进程调用进入到Activity2所在的进程中。
  3. ApplicationThread是一个binder对象,其运行在binder线程池中,内部包含一个H类,该类继承于类Handler。ApplicationThread将启动Activity2的信息通过H对象发送给主线程。
  4. 主线程拿到Activity2的信息后,调用Instrumentation类的newActivity方法,其内通过ClassLoader创建Activity2实例。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 插件化介绍
  • 插件化技术
  • 插件化技术原理
    • 类加载
      • 资源加载
        • 四大组件支持
        相关产品与服务
        容器服务
        腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档