android插件化介绍

#插件化是什么?
说到插件化,其实在我们生活是很常见,比如u盘,用的时候插上,不用的时候拔下,任何品牌的u盘都可以插在电脑上,无线鼠标,无线键盘,外界屏幕等等,这些都是插件化的例子。

那么android中的插件化技术,目前已经比较成熟,比如微信,淘宝,携程,360手机助手中都应用到了插件化。他的特点是无需单独安装apk,即可运行,即插即用,无需升级宿主应用,减少app的更新频率,除此之外他还可以降低模块耦合,按需加载,节省流量等特点。

拿我们自己的考试app举例,我们的app主要做英语考试,那么英语考试分很多种,sat、toefl、ielts考试题目呈现方式都不相同,有的学生需要sat,有的学生需要sat、toefl,目前的解决方案是每个考试都是一个单独app成了很多功能的耦合。

为了解决这种问题,考虑引入插件化技术,按需引入所需考试类型的安装包。

#介绍名词

插件化 – apk 分为宿主和插件部分,插件在需要的时候才加载进来

热修复 – 更新的类或者插件粒度较小的时候,我们会称之为热修复,一般用于修复bug

热更新 – 2016 Google 的 Android Studio 推出了Instant Run 功能 同时提出了3个名词

“热部署” – 方法内的简单修改,无需重启app和Activity。 “暖部署” – app无需重启,但是activity需要重启,比如资源的修改。 “冷部署” – app需要重启,比如继承关系的改变或方法的签名变化等。

所以站在app开发者角度的“热”是指在不发版的情况来实现更新,而Google提出的“热”是指值是否需要重新启动。 同时在开发插件化的时候也有两种情景,一种是插件与宿主apk没有交互,只是在用户使用到的时候进行一次吊起,还有一种是与宿主有很多的交互。

##基本原理
插件化的原理实际是 Java ClassLoader 的原理,看其他资料前请先看:Java ClassLoader基础

###Java类加载器
Android应用程序的.java文件在编译期会通过javac命令编译成.class文件,最后再把所有的.class文件编译成.dex文件放在.apk包里面。那么动态加载就是在运行时vm把插件apk直接加载到classloader里面的技术

###反射原理
主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义

###代理模式及Java实现动态代理
定义:给某个对象提供一个代理对象,并由代理对象控制对于原对象的访问,即客户不直接操控原对象,而是通过代理对象间接地操控原对象。

#为什么用?

##65535方法数天花板
随着业务的不断发展,外部库的引入,导致方法数的增加,应用中的Dex 文件方法数超过了最大值65536的上限,就会引爆android系统。这种情况可以通过削减重复方法数来治标,也有谷歌官方在API 21中提供了通用的解决方案,那就是android-support-multidex.jar. 这个jar包最低可以支持到API 4的版本(Android L及以上版本会默认支持mutidex),同时插件化也是解决方案的一种。

##减少主包大小

##编译提速

##可选模块按需下载
​例如模块可以在需要时进行加载,减少App Size,如只用到sat就只下载sat,只用toefl就只下载toefl的插件

##并行开发,独立Testing
可以独立开发A、B版本的模块,而不是将A、B版本代码写在同一个模块中。

app架构

##崩溃隔离
某一插件的崩溃,影响仅局限当前插件,不会导致其他插件以及宿主的崩溃

#有什么限制?

##通知栏限制
无法在插件中发送具有自定义资源的Notification,例如: a. 带自定义RemoteLayout的Notification b. 图标通过R.drawable.XXX指定的通知(插件系统会自动将其转化为Bitmap)

##系统适配
Dex的加载与系统版本依赖严重,可能会导致新版SDK不支持等问题

##需要预先注册权限
宿主的权限要多于插件的权限, 否则会权限不足,无法在插件中注册一些具有特殊Intent Filter的Service、Activity、BroadcastReceiver、ContentProvider等组件以供Android系统、已经安装的其他APP调用。

##国外资料少的原因
国外andrid以及所有app应用都上传google play store或apple store,这两个市场的审核较为严格,不经审核的热更新的应用很容易被下架

#限制解决办法

##占坑
对于service,ContentProvider需要提前在宿主注册

##自己实现包管理服务PMS

##使用方法与原生方式差异大
写一个“正常”的模块和写一个动态加载模块,写法是不一样的,插件内部对资源的访问只能通过自己定义的方式,包括对layout文件的inflate等,使用getResouces的方式,分分钟crash给你看,而且内部实现有些复杂,容易出现莫名其妙的

已有插件化框架对比
360 DroidPlugin
是360手机助手在Android系统上实现了一种新的插件机制,多进程实现,更新插件时,真正热更新. 后面会针对DroidPlugin详细学习

DL 动态加载框架

阿里ACCD(原OpenAtlas)
非代理Android动态部署框架

携程 DynamicAPK
实现Android App多apk插件化和动态加载,支持资源分包和热修复.携程App的插件化和动态加载框架.

#未来趋势
插件化作为近几年比较火的技术,有他的适用场景,但是有很大的局限性,在扩展性,适应性方面都赶不上react-native,未来的趋势还是移动web化更占优势

#其他资料
包建强:android插件化从入门到放弃

蘑菇街Android组件与插件化

使用DroidPlugin的示例