DexClassLoader pluginClassLoader = new DexClassLoader(dexPath, optimizedDirectory, libraryPath, parentClassLoader);可动态加载的内容包括 apk、dex、jar 等
我也利用这个原理及开源项目实现了一个版本,并且整理了 Android 插件化的作用、概念以及不错的资料(包括开源项目)和解决方案。
其中包括 65535 问题,Android 插件化、Android 组件化、Android 动态加载、Android 动态升级;介绍 DexClassLoader 和 PathClassLoader 的区别;如何解决生命周期管理、资源访问问题,如何消除公共依赖
详细可见我的博客:利用 DexClassLoader 实现 Android 插件化,从而达到动态加载
编辑于 2014-09-24赞同 2116 条评论收藏喜欢收起继续浏览内容知乎发现更大的世界打开浏览器继续知乎用户92 人赞同了该回答插件化技术发展到现在其实已经很成熟了,但是相应的问题,如果没有真正地去实践过,根本不了解其中有多少问题,会牵涉到多少技术细节,多少被外人膜拜的外表光鲜的技术大牛都被『插件化』这三个字折磨地死去活来,这对于 Android 整个生态的损害也让人无法忽视。
昨天的 MDCC ,冯森林老师提出了一个很有意思的思路『组件化』。
我们首先要想一下,我们做插件化的目的是什么?为了满足产品随时上线的需求?
为了修复因为我们对自己要求不严格而写出来的 bug ?为了向人炫耀自己的技术实力?很抱歉,如果是为了这些目的,那就真的太对不起自己是『开发者』这个如此高逼格的身份了。
做插件化真正的目的:是为了去适应并行开发,是为了解耦各个模块,是为了避免模块之间的交叉依赖,是为了加快编译速度,从而提高并行开发效率。
明确了这些,我们再来看插件化的结果,每个模块都支持独立运行测试,分为稳定的 release 版本和不稳定的 snapshot 版本,每个模块都高度解耦,没有交叉依赖,不会出现一个模块依赖了另一个模块,其中一个人改了这个模块的代码,对另一个模块造成影响。这时候,我们再看冯老师的『组件化』思想。
那么这个『组件化』是什么意思呢?我说下我自己的理解,可能不对,还请指教:
通过 gradle 配置的方式,将打 debug 包和 release 包分开。这样会有一个好处,开发一个模块,在 debug 的时候,可以打成一个 apk ,独立运行测试,可以完全独立于整个宿主 APP 的其他所有组件;待到要打 release 包的时候,再把这个模块作为一个 library ,打成 aar ,作为整个宿主 APP 的一部分。而 debug 和 release 的切换都是通过 gradle 配置,可以做到无缝切换。至于模块之间的跳转,可以用别名的方式,而不是用 Activity 和 Fragment 类名。这样所有的模块和宿主 APP 都是完全解耦的,彻底解决了并行开发的可能造成的交叉依赖等问题。
按照这个思路,我们再来看看一些其他的细节:
在 Android 里有一个比较爽的一点是,作为 library 的时候,aar 里的引用依赖,在宿主 Application 里也有同样的引用依赖,并不会打包两份到宿主 Application 里;
即然电脑可以以这种形式进行组装,哪我们android程序是不是也可以这样?答案是肯定的,我们的各个独立的功能模块都可以打包成apk,让宿主程序把apk加载进来,再运行里面的各个activity,service等
插件化的分类插件化在技术难度上可以为分两种:独立插件化和非独立插件
非独立插件是宿主程序与插件发开约定好插件开发规则,插件开发者要遵循这个规划进行开发,这种方式要求的技术难度相对来说低很多,但是增加了开发者的调用成本。类似比较成熟的解新局面方案有Small,需要说明的是small支持Android和iOS两个平台
独立插件完全支持android的兼容四大组件的大部份的属性,这种方式对于开发者可以说是完全透明,是十分完善的插件化解决方案。但是偏写这类框架需要对android底层的代码非常熟悉,要对种种api进行hook处理,所以技术要求也非常的高。类似比较成熟的方案有DroidPlugin等等非独立插件原理因为我们下载的apk里面activity没有在宿入的manifest.xml注册,如果我们直接调用startActivity方法,就会报activity没有注册的异常。我们可以在宿主activity中先注册一个代理Activity,然后通过宿主activity去调用插件里面的activity的方法。
哪我们怎样去加载我们插件apk里面的类呢?下面让我们了解下java里面几个类加载器:
DexClassLoader :可以加载文件系统上的jar、dex、apk
PathClassLoader :可以加载/data/app目录下的apk,这也意味着,它只能加载已经安装的apk
URLClassLoader :可以加载java中的jar,但是由于dalvik不能直接识别jar,所以此方法在android中无法使用,尽管还有这个类由上面的解释可以了解到我们可以通过DexClassLoader把插件apk里面的类加载出来让我们使用。
非独立插件实现首先我们先摸拟apk下载的流程,把assets目录下面的apk下载下来,存放在缓存目录中,但是下载下来我们还不能直接使用,我们还要对apk包进行以下处理
解密我们下载下来的apk包
校验apk的签名是否正确
校验apk包所需的权限是否在主包中都包函
File mApkPath = this.getDir(ProxyActivity.APK_PATH, MODE_PRIVATE);try {String mApkName = “myapplication-release-unsigned.apk”;InputStream inputStream = getResources.getAssets.open(mApkName);byte datas = FileUtil.readFromInputStream(inputStream);String fullPath = mApkPath.getAbsolutePath + File.separator + mApkName;FileUtil.writeByteToFile(datas, new File(fullPath));} catch (IOException e) {e