热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

插件化篇插件化框架对比

来看看现有插件化框架的对比。目录:MulitDex引起的问题插件化需要解决的问题与方案插件化实现方案分析对比1.MulitDex引起的问题在应用安装到手机上的时

来看看现有插件化框架的对比。

目录:


  1. MulitDex 引起的问题
  2. 插件化需要解决的问题与方案
  3. 插件化实现方案分析对比

 

 

1. MulitDex 引起的问题

在应用安装到手机上的时候 dex 文件的安装是复杂的,有可能会因为第二个 dex 文件太大导致 ANR。使用了 mulitDex 的 App 有可能在 4.0(api level 14) 以前的机器上无法启动,因为 Dalvik linearAlloc bug(Issue 22586) 。使用了 mulitDex 的 App 在 runtime期间有可能因为 Dalvik linearAlloc limit (Issue 78035) Crash。该内存分配限制在 4.0 版本被增大,但是 5.0 以下的机器上的 Apps 依然会存在这个限制。

主 dex 被 dalvik 虚拟机执行时候,哪些类必须在主 dex 文件里面这个问题比较复杂。build tools 可以搞定这个问题。但是如果你代码存在反射和 native 的调用也不保证 100% 正确。

对于 davilk 和 art 虚拟机 Mulitdex 的不同: ART 模式相比原来的 Dalvik,会在安装 APK 的时候,使用 Android 系统自带的dex2oat 工具把 APK 里面的 .dex 文件转化成 OAT 文件。

这里说一下罗迪的快速加载 Mulitdex 方案:art 虚拟机对 dex 优化需要很长时间,加载插件 dex 跳过优化实现加速,跳过会影响类加载的性能。

 

 

2. 插件化需要解决的问题与方案

 


  • 2.1 实现插件化需要解决的技术点

  • 问题 1:资源如何加载,资源冲突问题如何解决。
  • 问题 2:代码如何加载访问。
  • 问题 3:插件的管理后台包括的内容。
  • 问题 4:插件的增量更新问题。
  • 问题 5:加载插件中的 so 库。

 


  • 2.2 解决方案

针对问题 1:


原理:资源 id 是在编译时生成的,其生成的规则是 0xPPTTNNNN,PP 段是用来标记 apk 的,默认情况下系统资源 PP 是01,应用程序的 PP 是 07。TT 段,是用来标记资源类型的,比如图标、布局等,相同的类型 TT 值相同,但是同一个 TT 值不代表同一种资源,例如这次编译的时候可能使用 03 作为 layout 的 TT,那下次编译的时候可能会使用 06 作为TT的值,具体使用那个值,实际上和当前 APP 使用的资源类型的个数是相关联的。NNNN 则是某种资源类型的资源 id,默认从1 开始,依次累加。


那么我们要解决资源 id 问题,就可从 TT 的值开始入手,只要将每次编译时的 TT 值固定,即可以让资源 id 达到分组的效果,从而避免重复。例如将宿主程序的 layout 资源的 TT 固定为 33,将插件程序资源的 layout 的 TT 值固定为 03 (可不对插件程序的资源 id 做任何处理,使其使用编译出来的原生的值),即可解决资源 id 重复的问题了。

固定资源 id 的 TT 值的办法非常简单,提供一份 public.xml,在 public.xml 中指定什么资源类型以什么 TT 值开头即可。比如:

public.xml:



build.gradle:

afterEvaluate {for (variant in android.applicationVariants) {def scope = variant.getVariantData().getScope()String mergeTaskName = scope.getMergeResourcesTask().namedef mergeTask = tasks.getByName(mergeTaskName)mergeTask.doLast {copy {int i=0from(android.sourceSets.main.res.srcDirs) {include 'values/public.xml'rename 'public.xml', (i++ == 0? "public.xml": "public_${i}.xml")}into(mergeTask.outputDir)}}}
}

这样就能使用 public.xml 固定资源 id,public.xml 用来告诉 Android 资源打包工具 aapt,将类型为 drawable 的资源 ic_notice 的id 固定为 0x7f02002b。注意,在开发应用程序时,一般是不需要用到 public.xml 文件的,因为我们的资源基本上都是在内部使用的,不会导出来给第三方应用程序使用。只在内部使用的资源,不管它的 id 如何变化,我们都可以通过 R.java 文件定义的常量来正确地引用它们。只有系统定义的资源包才会使用到 public.xml 文件,因为它定义的资源是需要提供给第三方应用程序使用的。当然还有做插件化的时候,处理资源冲突问题。

还有一个方法是通过定制过的 aapt 在编译时指定插件的 PP 段的值来实现分组,重写过的 aapt 指定 PP 段来实现 id 分组。


  • 方案 1:将插件 apk 资源解压,通过操作文件的方式来使用,这个只是理论上可行,实际使用的时候还是有很多的问题。
  • 方案 2:重写 Context 的 getResource()、getAsset() 之类的方法,资源冲突需要扩展 aapt 实现。
  • 方案 3:打包后执行一个脚本修改资源 id。

 

针对问题 2:


原理说明:主要就是 classloader 加载 dex,代理模式就是本身宿主中有 Activity,通过欺骗系统来创建 Activity,欺骗系统的部分 hook 的有深有浅 (对比 DroidPlugin 和 Small),让这个 Activity 有生命周期,而动态加载模式就是运行时动态创建并编译一个 Activity 类,需要使用动态创建类的工具实现动态字节码操作。



  • 方案 1:简单加载模式。
  • 方案 2:Activity 代理模式。
  • 方案 3:动态加载模式。

 

针对问题 3:


  • 提供插件信息查询和下载,包括回滚到某一版本。
  • 管理使用插件的 apk,可以向不同版本 apk 提供不同插件。
  • MD5 校检插件的合法性。

 

 

3. 插件化实现方案分析对比

 


  • AndroidDynamicLoader

AndroidDynamicLoader 的作者是大众点评的屠毅敏,应该是最早的动态加载实现方案了。作者在介绍这个框架时形容宿主 App就好像浏览器,但它加载的并不是网页,而是运行在 Android 系统上的插件。这个方案主要是在插件中使用 Fragment,在宿主中使用 Activity 去动态加载插件中的 Fragment。
github 链接:https://github.com/mmin18/AndroidDynamicLoader


  • 23Code

23Code 并不是一个开源的项目,它是一个完整的 apk。在应用市场可以下载得到,它内部展示了一些有趣的动效,通过下载的方式,可以直接运行起来,这就是插件化的真实案例。


  • Altas

altas 是阿里的伯奎分享出来的一个插件化的方案。
分享视频链接:http://v.youku.com/v_show/id_XNTMzMjYzMzM2.html
对应的 PPT:http://club.alibabatech.org/resource_detail.htm?topicId=84

这里的分享主要是将一些思路,业务方面的场景,解决的问题。后来 github 上有了对应的开源项目叫 OpenAltas,后改名ACDD。
ACDD 的链接:https://github.com/bunnyblue/ACDD

官方对这个库的说明是非代理 Android 动态热部署框架,而且在视频介绍中,伯奎也讲到,这个方案,就是把宿主当做一个容器,动态加载对应的插件。视频中也有讲到,要做到让插件无感知地运行在这个容器中,需要 hook 很多系统层面的东西,比如:ActivityThread,LoadedApk,ContextImpl,PackageParser,ActivityManagerNative 等,即当插件需要系统的服务来提供对应功能的时候,将这个行为拦截掉,宿主就可以在插件和 Android 系统中间做些手脚了。在当时,Altas 是最为先进插件化技术了,为淘宝客户端提供了很多加载其他业务插件的能力。


  • Dynamic-load-apk

Dynamic-Load-Apk 简称 DL,这个开源框架作者是任玉刚,他的实现方式是,在宿主中埋一个代理 Activity,更改 ClassLoader后找到加载插件中的 Activity,使用宿主中的 Activity 作为代理,回调给插件中 Activity 所以对应的生命周期。这个思路与AndroidDynamicLoader 有点像,都是做一个代理,只不过 Dynamic-load-apk 加载的插件中的 Activity。
项目地址:https://github.com/singwhatiwanna/dynamic-load-apk
项目说明:http://blog.csdn.net/singwhatiwanna/article/details/40283117


  • DroidPlugin

DroidPlugin 是张勇实现的一套插件化方案,它的原理也是 Hook 客户端一侧的系统 API,可能与 Altas 所 Hook 的点不同,细想应该是基本相同的。
项目地址:https://github.com/DroidPluginTeam/DroidPlugin

项目中 DOC 文件夹有很多关于项目的讲解说明。
张勇本人对 DroidPlugin 的讲解:http://www.infoq.com/cn/presentations/the-realization-principle-and-application-of-droidplugin?utm_campaign=rightbar_v2&utm_source=infoq&utm_medium=presentations_link&utm_content=link_text
维术对这个框架的讲解:http://weishu.me/2016/01/28/understand-plugin-framework-overview/

维术的这几篇 blog 很详细滴讲解了 DroidPlugin 是如何实现四大组件的插件化的,还有几篇有规划但是没有写的方面,希望后面能补全。


  • VirtualApp

VirtualApp 作者是高中生罗迪,据说这个 Android 大牛初三的时候就开始研究双开、插件化的技术,相当了不起。项目的思路与DroidPlugin 相似,不过他没有提供 Service 的代理,而是使用 ContentProvider 来代替 Service 在宿主中作为真正的运行体。
项目地址:https://github.com/asLody/VirtualApp


  • DynamicAPK

DynamicAPK 是携程推出的动态加载方案。
项目说明:http://www.infoq.com/cn/articles/ctrip-android-dynamic-loading
项目地址:https://github.com/CtripMobile/DynamicAPK

与 ACDD 一样修改了aapt,使得插件与宿主的资源不会出现相同 id 的问题。

 

整体对比如下:

 

 

 

 


推荐阅读
  • 本文探讨了资源访问的学习路径与方法,旨在帮助学习者更高效地获取和利用各类资源。通过分析不同资源的特点和应用场景,提出了多种实用的学习策略和技术手段,为学习者提供了系统的指导和建议。 ... [详细]
  • 今天我开始学习Flutter,并在Android Studio 3.5.3中创建了一个新的Flutter项目。然而,在首次尝试运行时遇到了问题,Gradle任务 `assembleDebug` 执行失败,退出状态码为1。经过初步排查,发现可能是由于依赖项配置不当或Gradle版本不兼容导致的。为了解决这个问题,我计划检查项目的 `build.gradle` 文件,确保所有依赖项和插件版本都符合要求,并尝试更新Gradle版本。此外,还将验证环境变量配置是否正确,以确保开发环境的稳定性。 ... [详细]
  • 本文探讨了Android系统中支持的图像格式及其在不同版本中的兼容性问题,重点涵盖了存储、HTTP传输、相机功能以及SparseArray的应用。文章详细分析了从Android 10 (API 29) 到Android 11 的存储规范变化,并讨论了这些变化对图像处理的影响。此外,还介绍了如何通过系统升级和代码优化来解决版本兼容性问题,以确保应用程序在不同Android版本中稳定运行。 ... [详细]
  • 使用ArcGIS for Java和Flex浏览自定义ArcGIS Server 9.3地图
    本文介绍了如何在Flex应用程序中实现浏览自定义ArcGIS Server 9.3发布的地图。这是一个基本的入门示例,适用于初学者。 ... [详细]
  • 使用 ListView 浏览安卓系统中的回收站文件 ... [详细]
  • 在Android平台中,播放音频的采样率通常固定为44.1kHz,而录音的采样率则固定为8kHz。为了确保音频设备的正常工作,底层驱动必须预先设定这些固定的采样率。当上层应用提供的采样率与这些预设值不匹配时,需要通过重采样(resample)技术来调整采样率,以保证音频数据的正确处理和传输。本文将详细探讨FFMpeg在音频处理中的基础理论及重采样技术的应用。 ... [详细]
  • 卓盟科技:动态资源加载技术的兼容性优化与升级 | Android 开发者案例分享
    随着游戏内容日益复杂,资源加载过程已不仅仅是简单的进度显示,而是连接玩家与开发者的桥梁。玩家对快速加载的需求越来越高,这意味着开发者需要不断优化和提升动态资源加载技术的兼容性和性能。卓盟科技通过一系列的技术创新,不仅提高了加载速度,还确保了不同设备和系统的兼容性,为用户提供更加流畅的游戏体验。 ... [详细]
  • 如何使用ES6语法编写Webpack配置文件? ... [详细]
  • Netty框架中运用Protobuf实现高效通信协议
    在Netty框架中,通过引入Protobuf来实现高效的通信协议。为了使用Protobuf,需要先准备好环境,包括下载并安装Protobuf的代码生成器`protoc`以及相应的源码包。具体资源可从官方下载页面获取,确保版本兼容性以充分发挥其性能优势。此外,配置好开发环境后,可以通过定义`.proto`文件来自动生成Java类,从而简化数据序列化和反序列化的操作,提高通信效率。 ... [详细]
  • 设计实战 | 10个Kotlin项目深度解析:首页模块开发详解
    设计实战 | 10个Kotlin项目深度解析:首页模块开发详解 ... [详细]
  • 掌握PHP编程必备知识与技巧——全面教程在当今的PHP开发中,了解并运用最新的技术和最佳实践至关重要。本教程将详细介绍PHP编程的核心知识与实用技巧。首先,确保你正在使用PHP 5.3或更高版本,最好是最新版本,以充分利用其性能优化和新特性。此外,我们还将探讨代码结构、安全性和性能优化等方面的内容,帮助你成为一名更高效的PHP开发者。 ... [详细]
  • 在CentOS上部署和配置FreeSWITCH
    在CentOS系统上部署和配置FreeSWITCH的过程涉及多个步骤。本文详细介绍了从源代码安装FreeSWITCH的方法,包括必要的依赖项安装、编译和配置过程。此外,还提供了常见的配置选项和故障排除技巧,帮助用户顺利完成部署并确保系统的稳定运行。 ... [详细]
  • 本文详细解析了 MySQL 5.7.20 版本中二进制日志(binlog)崩溃恢复机制的工作流程。假设使用 InnoDB 存储引擎,并且启用了 `sync_binlog=1` 配置,文章深入探讨了在系统崩溃后如何通过 binlog 进行数据恢复,确保数据的一致性和完整性。 ... [详细]
  • 为了优化直播应用底部聊天框的弹出机制,确保在不同设备上的布局稳定性和兼容性,特别是在配备虚拟按键的设备上,我们对用户交互流程进行了调整。首次打开应用时,需先点击首个输入框以准确获取键盘高度,避免直接点击第二个输入框导致的整体布局挤压问题。此优化通过调整 `activity_main.xml` 布局文件实现,确保了更好的用户体验和界面适配。 ... [详细]
  • 在开发Xamarin.Forms应用程序时,遇到了使用Entity Framework Core 3.0访问SQLite数据库时 `Database.MigrateAsync` 方法调用的问题。本文详细探讨了该问题的根源,并提供了一种有效的解决方案,确保数据库迁移能够顺利执行。此外,还介绍了如何配置和优化EF Core以提高应用性能和稳定性。 ... [详细]
author-avatar
手机用户2602927443
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有