Android 里程碑:“插件化技术”
什么是插件化?
通常,我们的app只有一个apk文件;而插件化是一种将app拆分为多个apk的技术,每一个apk都是app功能的一部分; App 的部分功能模块在打包时并不以传统方式打包进入 apk 文件中,而是以另一种形 式二次封装进 apk内部,或者放在网络上实时下载,在需要的时候动态对这些功能模块进行加载,称之为插件化
这些单独二次封装的功能模块 apk ,就称作「插件」,初始安装的 apk 称作「宿主」
总的来说:“插件化是组件化的更进一步推进”
插件化的用途
在学习一项新技能之前,我们首先要弄清楚它能为我们带来什么;那插件化能给我们带来什么呢?
从项目管理角度来说:
● 插件化将应用的不同功能划分到一个个的插件中,便于程序的维护
● 每个插件可以单独运行调试极大的提高了开发效率
● 每个插件互不影响,多人协同开发更加高效
从程序运行角度来说:
● 按需加载插件,占用内存更少
● 按需更新,更省流量
从公司运营角度来说:
● 实时更新,便于运营推广
● 修复线上BUG,将风险降到最低
使用插件化的好处
● 宿主和插件分开编译: 各个模块封装成不同的插件APK,不同模块可以单独编译,提高了开发效率
● 并发开发: 不同的团队负责不同的插件APP,这样分工更加明确
● 动态更新插件: 可以通过上线新的插件来解决线上的BUG,达到“热修复”的效果
● 按需下载模块
● 解决了方法数超过限制的问题
● 减小了宿主APK的体积
使用插件化所需要的理论基础
插件化像是一门十分高深的武功,它需要修习者有一定理论基础后才能修炼那它需要哪些理论支撑呢?
ClassLoader
● ClassLoader 叫做类加载器, 虚拟机设计团队把类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流” 这个动作放到java虚拟机外部去实现,以便让应用程序自己决定去如何获取所需要的类,实现这个动作的代模块称之为“类加载器”
● ClassLoader是由JVM平台提供的类加载器,它允许程序从网络、硬盘甚至是内存加载Class,这就为Android插件化提供了最基础的技术保障
● ClassLoader负责在运行时将Java类动态加载到JVM中,而且ClassLoader是JRE的一部分。因此,由于ClassLoader的存在,JVM无需了解底层文件和文件系统即可运行Java程序
● ClassLoader并不会一次把所有Java类加载到内存中,而是在应用程序需要的时候加载。这就是ClassLoader发挥作用的地方,它们负责将类加载到内存中
反射和Hook技术
Hook动态注入代码
● Hook机制是回调机制的一种,普通的回调是静态的,我们必须提前写好回调接口;而Hook机制在Java中则可以利用反射,针对切入点(通常是一个成员变量),采用替换的手段,使代码在运行时改变
Android Hook
● 在Android操作系统中,有一套自己的事件分发机制,所有的代码调用和回调都是按照一定顺序执行的,Hook技术存在的意义就在于,我们可以在事件传送到终点前截获并监控该事件的传输,并且做一些自己的处理
Hook的翻译是"钩子"
● 我们知道Android操作系统有一套自己的机制,例如,Activity启动流程、事件分发机制、资源管理机制等;有时候,这些机制无法满足我们的需求,通过系统的API也无能为力;这时候就需要Hook技术对原有流程进行拦截,然后将系统流程替换成我们自己的流程;而反射是Hook技术的一种必要手段
APP安装过程
Android应用程序安装有四种方式,分别如下:
● 系统启动时安装,没有安装界面
● 第三方应用安装,有安装界面,也是我们最熟悉的方式
● ADB命令安装,没有安装界面
● 通过Google Play市场安装,没有安装界面
我们知道apk文件中包含了app运行需要的Activity、Service等信息;这些信息是在程序安装过程中通过PackageManagerService解析AndroidManifest文件取得的; 只有了解了这些原理,我们才能知道如何解析插件中的Activity、Service等信息
资源管理
资源,是APK包体积过大的病因之一;插件化技术将模块解耦,通过插件的形式加载; 插件化技术中,每个插件都能够作为单独的APK独立运行;宿主启动插件的类,难免要涉及插件类中的资源问题
那么,如何加载插件资源,就成为一个待解决的问题
● 在Android打包编译时,gradle会为图片、文案等资源生成一个唯一的Id。在运行期,通过对资源Id的引用来查找相应的资源;由于宿主apk和各插件apk打包不是在一次gradle assemble命令中完成的,这就有可能造成多个apk中产生的资源id相同,我们称之为资源冲突
● 各apk中的资源是无法共享的,例如在宿主中无法引用插件中的资源
为了解决这两个问题,我们有必要掌握Android平台的资源管理机制
● 单纯解析出插件的Activity、Service等信息是不行,我们期望的是这些Activity、Service等可以像我们普通App中的一样可以正常运行
● 这就需要我们去熟悉四大组件的启动流程,然后通过Hook技术加入宿主启动插件的Activity、Service等逻辑
四大组件的启动流程
四大组件支持
Android开发中有一些特殊的类,是由系统创建的,并且由系统管理生命周期,如常用的四大组件,activity,service,broadcastReceiver和contentProvider,仅仅构造出这些类的实例是没有用的,还需要管理组件的生命周期;其中以activity的最为复杂
不同的框架有不同的方式,大致分为两种方式
● ProxyActivity代理
● hook方式
hook启动插件activity需要解决两个问题:
● 插件Activity没有在Manifest文件中注册,如何绕过检测
● 如何构造Activity实例,并同步生命周期
四大组件中除了BroadcastReceiver以外,其他三种组件都必须要在AndroidManifest注册,对于它来说,它既可以在AndroidManifest由可以代码动态注册;
在调用方式上,Activity、Service、BroadcastReceiver都需要借助Intent,而ContentProvider无需借助Intent
结语
技术是无止境的,你需要对自己提交的每一行代码、使用的每一个工具负责,不断挖掘其底层原理,才能使自己的技术升华到更高的层面
Android 架构师之路还很漫长,与君共勉
PS:有问题欢迎指正,可以在评论区留下你的建议和感受;
欢迎大家点赞评论,觉得内容可以的话,可以转发分享一下