当前位置:首页 > 科技  > 软件

面试官:你对插件化有什么了解?

来源: 责编: 时间:2024-09-10 09:47:30 18观看
导读背景插件化的诞生是为了解决什么问题?我们不妨好好思考一下,作为客户端开发,平时工作中是否为这样的情况发愁:核心业务功能迭代的时候,千小心,万小心,又是做AB,又是做灰度,最后线上还是出问题了,这个时候只能靠发版解决问题,奈何

背景

插件化的诞生是为了解决什么问题?A4o28资讯网——每日最新资讯28at.com

我们不妨好好思考一下,作为客户端开发,平时工作中是否为这样的情况发愁:A4o28资讯网——每日最新资讯28at.com

  • 核心业务功能迭代的时候,千小心,万小心,又是做AB,又是做灰度,最后线上还是出问题了,这个时候只能靠发版解决问题,奈何客户端的发版周期长,并且只有用户升级以后才能解决问题
  • 有些业务上线以来,用的人不多,占用的包体积还不小,这些功能是否可以动态加载
  • 开发一个功能,必须提交到应用商店以后,用户才能更新(涉及到监管)

所以说,插件化设计之初就是为了不安装新Apk,从而完成应用的更新迭代。A4o28资讯网——每日最新资讯28at.com

我之前所在的团队也做了插件化,主要的原因还是包体积的诉求,原因有两个:A4o28资讯网——每日最新资讯28at.com

  • 厂商预装的时候包体积的强制诉求:如果不做插件化,就需要每年预装阶段持续投入人力优化包体积,成本比较高
  • 对外投放的时候,小包有利于提高用户的转化

转换率转换率A4o28资讯网——每日最新资讯28at.com

上图是2018年谷歌IO披露的包体积与下载转化率之间的关系,时至今日,即使我们的网络状况已经有了很好的提升,但是优化包体积仍然是我们的目标,比如说:A4o28资讯网——每日最新资讯28at.com

  • 线下推广的时候用户的网络是不稳定的
  • 对于线上广告投放,用户不可能一直在wifi下,小的包体积可以让用户更快的进入应用内,避免劝退用户

所以我们可以看到,pdd这一方面做的很出色,仅有25m。A4o28资讯网——每日最新资讯28at.com

一、插件化难点

讲插件化之前,我们先科普一下其中的概念。A4o28资讯网——每日最新资讯28at.com

对于一个完整功能的App,我们可以将其划分成为很多模块,每个模块都可以将其划分成为一个Apk。然后将基础功能的Apk提交给应用市场上架,后续我们可以通过基础的Apk,下载其他模块的Apk,从而完成功能的扩展。A4o28资讯网——每日最新资讯28at.com

基础分包基础分包A4o28资讯网——每日最新资讯28at.com

在整个过程中,我们称提交给应用市场的Apk为宿主,其他模块的Apk称之为插件。A4o28资讯网——每日最新资讯28at.com

相信没接触过插件化的同学可能会有一些疑问,我们平时打包的时候不是都是一个完整的Apk,为什么可以加载一个单独的Apk?好了,这就是插件化的第一个难点。A4o28资讯网——每日最新资讯28at.com

二、加载插件Apk

作为一个Android开发,我们都知道Android里面的Davilk和Art虚拟机和Java虚拟机不是同一套,所以他们也有着不同的类加载结构。A4o28资讯网——每日最新资讯28at.com

我们先回顾一下。A4o28资讯网——每日最新资讯28at.com

1. Java类加载

Jvm中加载的文件是class文件,再由Jvm翻译成特定平台的机器码。使用的类加载器如下:A4o28资讯网——每日最新资讯28at.com

  • 启动类加载器:由C++语言实现,负责加载Java中的核心类。
  • 扩展类加载器:负责加载Java扩展的核心类之外的类。
  • 应用程序类加载器:负责加载用户类路径上指定的类库。

整个加载架构如下:A4o28资讯网——每日最新资讯28at.com

Java类加载器结构Java类加载器结构A4o28资讯网——每日最新资讯28at.com

双亲委派机制保证了收到类加载请求的时候,优先让父类加载器去加载,父类加载器处理不了的时候,才会自己去加载,保证了类加载机制的稳定性。A4o28资讯网——每日最新资讯28at.com

2. Android类加载

我们上面提过,由于CPU和功耗环境不一致,Android虚拟机和Jvm有着很大的不同,Android里面的虚拟机在4.4.4以后,就是ART虚拟机了。早期的时候,安装的时候,会将dex文件直接编译成.oat这样的机器码,不过这样会有其他问题:A4o28资讯网——每日最新资讯28at.com

  • 提高安装和升级应用的时间

于是,在 Android 7.0 以后,第一次启动的时候,使用 Jit,针对dex,边解释边执行,然后在空闲的时候,将剩余的 dex 文件编译成机器码。A4o28资讯网——每日最新资讯28at.com

所以,我们可以注意到,每次应用升级的一段时间内,我们的启动时长会出现波动,过了几天以后,又会达到稳定的状态。因此,很多大厂,会针对这个过程优化,如:A4o28资讯网——每日最新资讯28at.com

  • 如何更多的触发 dex2aot 过程
  • 对启动热点代码预先aot,比如谷歌的BaselineProfile方案,很多大厂也有自己的方案

我们再来看一下类加载机制,Android里面类加载的单位是dex,类加载器包括:A4o28资讯网——每日最新资讯28at.com

  • BootClassLoader:用来解决Android系统启动时的核心基础类
  • PathClassLoader:Android中默认的类加载器,主要用来加载应用程序自身的类以及系统类库之外的本地代码
  • DexClassLoader:加载指定路径下的Apk、Jar包的类
  • InMemoryDexClassLoader:Android 8.0 中可以用来加载内存中的Dex文件

整个结构是这样的:A4o28资讯网——每日最新资讯28at.com

Android类加载器Android类加载器A4o28资讯网——每日最新资讯28at.com

如果是指定路径下的Apk或者jar包,我们需要将 PathClassLoader 替换成 DexClassLoader。到这里,第一个问题的解决思路就很清晰了,我们可以通过 DexClassLoader 加载插件Apk。A4o28资讯网——每日最新资讯28at.com

3. 方案实现

DexClassLoader的原理主要是通过DexPathList管理DexFile列表信息,从而加载到具体的类。A4o28资讯网——每日最新资讯28at.com

DexClassLoaderDexClassLoaderA4o28资讯网——每日最新资讯28at.com


A4o28资讯网——每日最新资讯28at.com

基于DexClassLoader,通常有两种方案:A4o28资讯网——每日最新资讯28at.com

  • 单个DexClassLoader方案
  • 多个DexClassLoader方案

单个DexClassLoader

单个DexClassLoader指的我们可能有多个插件Dex,多个插件Dex使用同一个DexClassLoader,如图:A4o28资讯网——每日最新资讯28at.com

单ClassLoader结构A4o28资讯网——每日最新资讯28at.com

将所有的插件中的类都由统一的DexClassLoader加载。A4o28资讯网——每日最新资讯28at.com

多个DexClassLoader

多个DexClassLoader指的是对于多个插件Dex,每一个Dex都会有自己的DexClassLoader,如图:A4o28资讯网——每日最新资讯28at.com

多ClassLoader结构多ClassLoader结构A4o28资讯网——每日最新资讯28at.com

由各自DexClassLoader负责相关的插件的类加载。A4o28资讯网——每日最新资讯28at.com

看一下各自的优缺点:A4o28资讯网——每日最新资讯28at.com

分类A4o28资讯网——每日最新资讯28at.com

优点A4o28资讯网——每日最新资讯28at.com

缺点A4o28资讯网——每日最新资讯28at.com

单DexClassLoaderA4o28资讯网——每日最新资讯28at.com

类之间不隔离,可以互相调用A4o28资讯网——每日最新资讯28at.com

需要处理一些适配问题,比如不同插件加载了同一库的不同版本,可能引发兼容性问题A4o28资讯网——每日最新资讯28at.com

多DexClassLoaderA4o28资讯网——每日最新资讯28at.com

安全、稳定A4o28资讯网——每日最新资讯28at.com

类之间隔离,需要处理互相调用的问题A4o28资讯网——每日最新资讯28at.com

对于我们安卓系统来讲,仅仅能够加载插件中的类显然是不够的,还要能够启动插件中的的四大组件,并正确的执行四大组件的生命周期,为什么不能够执行四大组件的生命周期呢?A4o28资讯网——每日最新资讯28at.com

这是因为,只有在我们宿主包中Manifest文件中注册的四大组件才能够启动,如果没有注册,就会抛出异常,提醒你在Manifest中注册。这也是我们遇到的第二个问题。A4o28资讯网——每日最新资讯28at.com

三、组件加载

Android 中四大组件包括Activity、Service、广播和ContentProvider,我们主要介绍一下Activity。A4o28资讯网——每日最新资讯28at.com

1. Activity解决方法

如果我们想让对应的Activity启动,一般有如下几种方法:A4o28资讯网——每日最新资讯28at.com

  1. 宿主包提前声明组件
  2. 占位组件 + 手动调用组件
  3. 占位组件 + 欺骗系统

我们针对这几种分别解释一下。A4o28资讯网——每日最新资讯28at.com

1.1 宿主包提前声明组件

将所有的四大组件在宿主包中都提前声明,这是最简单粗暴的方式。A4o28资讯网——每日最新资讯28at.com

但这种方式会丢失插件化的动态性,也就是说,如果想在插件包中,加入宿主包没有注册的Activity,这就会有问题。A4o28资讯网——每日最新资讯28at.com

那这种方式的优点呢?解决包体积的问题的同时不用处理复杂的组件加载以及伴随的生命周期的问题。A4o28资讯网——每日最新资讯28at.com

1.2 占位组件 + 手动调用组件

那如果想要保存插件的动态化加载呢?也就是说我们想要在插件包中的 Manifest 文件中进行注册。A4o28资讯网——每日最新资讯28at.com

默认情况下,如果我们启动一个没有在插件 Manifest 中注册的的 Activity,会发生 error,原因是启动过程中的 Instrumentation 中的 checkStartActivityResult 方法:A4o28资讯网——每日最新资讯28at.com

public class Instrumentation {    public static void checkStartActivityResult(int res, Object intent) {        if (!ActivityManager.isStartResultFatalError(res)) {            return;        }        switch (res) {            case ActivityManager.START_INTENT_NOT_RESOLVED:            case ActivityManager.START_CLASS_NOT_FOUND:                if (intent instanceof Intent && ((Intent)intent).getComponent() != null)                    throw new ActivityNotFoundException(                            "Unable to find explicit activity class "                            + ((Intent)intent).getComponent().toShortString()                            + "; have you declared this activity in your AndroidManifest.xml?");                throw new ActivityNotFoundException(                        "No Activity found to handle " + intent);                ...        }    }}

所以我们传入的Activity必须要在宿主包中注册,这样系统才能检验通过,那怎么才能实现动态化呢?A4o28资讯网——每日最新资讯28at.com

答案是使用占位Activity,这其实就是使用的代理模式。每次需要启动插件中的Activity的时候,先启动一个占位Activity实例,然后在占位Activity实例里面持有目标Activity的实例对象,从而通过反射或者其他方法调用实例的生命周期。A4o28资讯网——每日最新资讯28at.com

生命周期处理生命周期处理A4o28资讯网——每日最新资讯28at.com

这种方法的问题主要如下:A4o28资讯网——每日最新资讯28at.com

  1. 代码的入侵性比较强,需要统一继承PluginActvity。
  2. 对于Activity的启动模式,处理比较繁琐。
  3. 改造已有的模块比较繁琐。

1.3 欺骗系统

第三种方法我们称之为欺骗系统,具体怎么个欺骗方法呢?A4o28资讯网——每日最新资讯28at.com

先看一下具体Activity的启动流程,默认大家对Activity的启动流程比较了解了:A4o28资讯网——每日最新资讯28at.com

Activity启动流程Activity启动流程A4o28资讯网——每日最新资讯28at.com

我们在整个过程中,同样也需要一个占位Activity。A4o28资讯网——每日最新资讯28at.com

使用步骤如下:A4o28资讯网——每日最新资讯28at.com

  1. 在途中的第一步,启动PluginActivity跳转的时候,通过Instrument处理的时候,会将PluginActivity的Intent改成占位Activity的Intent,并存入原始Activity的信息。
  2. 在图片中的第十三步,等系统验证完成回来创建占位Activity的实例对象,就替换成PluginActivity。

最终,系统以为自己调用的是占位Activity的对象,并且和实际上调用的是PluginActivity进行绑定。A4o28资讯网——每日最新资讯28at.com

在最终使用之前,我们在插件中的Android资源文件并不能使用,比如说图片、字符串、布局文件等,原因是插件的资源路径并没有被添加。A4o28资讯网——每日最新资讯28at.com

四、资源加载

Apk安装以后,我们都是通过 Resource 对象去访问资源,简单看一下 Resouce 的构造方法:A4o28资讯网——每日最新资讯28at.com

@Deprecated  public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config) {      this(null);      mResourcesImpl = new ResourcesImpl(assets, metrics, config, new DisplayAdjustments());  }

可以看到,构造函数中有一个参数是 AssetManager,我们可以通过在 AssetManager 中,加入我们插件的资源地址,就可以访问到插件中的资源。A4o28资讯网——每日最新资讯28at.com

1 解决方法

现在可以访问具体的资源了,和之前的类加载方式类似,也有两种加载方式:A4o28资讯网——每日最新资讯28at.com

  • 合并式:插件和宿主资源可以互相访问,要处理资源冲突
  • 独立式:无需处理资源冲突,宿主和插件的资源访问比较难处理

首先,我们想一下为什么会有资源冲突问题?其实是因为宿主和插件包都是独立编译的,所以打包的时候生成的资源Id会存在相同的情况,这个时候,访问的的时候就存在资源冲突。A4o28资讯网——每日最新资讯28at.com

我们项目之前采用的 Qigsaw 方案,所以简单介绍一下合并式的方案,资源id是8位16进制数表示:A4o28资讯网——每日最新资讯28at.com

QigsawQigsawA4o28资讯网——每日最新资讯28at.com

如上图:A4o28资讯网——每日最新资讯28at.com

  • PP为Package Id,代表应用类型:如系统应用、第三方应用、dynamic feature等。
  • TT为资源类型:如drawabl、layout和string。
  • EEEE为Entry:代表资源顺序

所以我们对不同的插件包,进行打包的时候,前面的PP字段,可以进行依次递减,可以避免资源冲突的问题。常用的方案有:A4o28资讯网——每日最新资讯28at.com

  1. 修改AAPT生成ResourceId,在编译期间完成修改
  2. 修改resouce.arsc文件

Qigsaw使用的第一种方案。A4o28资讯网——每日最新资讯28at.com

总结

本文是一篇入门插件化的文章,主要回答了插件化是什么,有什么难点,又是怎么解决的,其中没有涉及到很多代码,非常适合入门。A4o28资讯网——每日最新资讯28at.com

A4o28资讯网——每日最新资讯28at.com

本文链接://www.dmpip.com//www.dmpip.com/showinfo-26-112727-0.html面试官:你对插件化有什么了解?

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 停止使用 `let` 或为什么它在 JavaScript/TypeScript 中是不必要的

下一篇: 聊一聊Spring事务失效的12种场景

标签:
  • 热门焦点
  • 官方承诺:K60至尊版将会首批升级MIUI 15

    官方承诺:K60至尊版将会首批升级MIUI 15

    全新的MIUI 15今天也有了消息,在官宣了K60至尊版将会搭载天玑9200+处理器和独显芯片X7的同时,Redmi给出了官方承诺,K60至尊重大更新首批升级,会首批推送MIUI 15。也就是说虽然
  • 石头智能洗地机A10 Plus体验:双向自清洁治好了我的懒癌

    石头智能洗地机A10 Plus体验:双向自清洁治好了我的懒癌

    一、前言和介绍专为家庭请假懒人而生的石头科技在近日又带来了自己的全新旗舰新品,石头智能洗地机A10 Plus。从这个产品名上就不难看出,这次石头推出的并不是常见的扫地机器
  • JavaScript 混淆及反混淆代码工具

    JavaScript 混淆及反混淆代码工具

    介绍在我们开始学习反混淆之前,我们首先要了解一下代码混淆。如果不了解代码是如何混淆的,我们可能无法成功对代码进行反混淆,尤其是使用自定义混淆器对其进行混淆时。什么是混
  • JavaScript学习 -AES加密算法

    JavaScript学习 -AES加密算法

    引言在当今数字化时代,前端应用程序扮演着重要角色,用户的敏感数据经常在前端进行加密和解密操作。然而,这样的操作在网络传输和存储中可能会受到恶意攻击的威胁。为了确保数据
  • 一文掌握 Golang 模糊测试(Fuzz Testing)

    一文掌握 Golang 模糊测试(Fuzz Testing)

    模糊测试(Fuzz Testing)模糊测试(Fuzz Testing)是通过向目标系统提供非预期的输入并监视异常结果来发现软件漏洞的方法。可以用来发现应用程序、操作系统和网络协议等中的漏洞或
  • 破圈是B站头上的紧箍咒

    破圈是B站头上的紧箍咒

    来源 | 光子星球撰文 | 吴坤谚编辑 | 吴先之每年的暑期档都少不了瞄准追剧女孩们的古偶剧集,2021年有优酷的《山河令》,2022年有爱奇艺的《苍兰诀》,今年却轮到小破站抓住了追
  • 腾讯盖楼,字节拆墙

    腾讯盖楼,字节拆墙

    来源 | 光子星球撰文 | 吴坤谚编辑 | 吴先之“想重温暴刷深渊、30+技能搭配暴搓到爽的游戏体验吗?一起上晶核,即刻暴打!”曾凭借直播腾讯旗下代理格斗游戏《DNF》一
  • 华为Mate 60保护壳曝光:硕大后置相机模组 凸起程度有惊喜

    华为Mate 60保护壳曝光:硕大后置相机模组 凸起程度有惊喜

    这段时间以来,关于华为新旗舰的爆料日渐密集。据此前多方爆料,今年华为将开始恢复一年双旗舰战略,除上半年推出的P60系列外,往年下半年的Mate系列也将
  • SN570 NVMe SSD固态硬盘 价格与性能兼具

    SN570 NVMe SSD固态硬盘 价格与性能兼具

    SN570 NVMe SSD固态硬盘是西部数据发布的最新一代WD Blue系列的固态硬盘,不仅闪存技术更为精进,性能也得到了进一步的跃升。WD Blue SN570 NVMe SSD的包装外
Top
Baidu
map