Android虚拟机的动态加载技术分为两种:一种是加载基于NDK的so库;另一种是加载用java语言开发的zip包。我今天主要讨论后者。
先简单说明一下so库加载。NDK的执行效率很高,加密性很好,但同时开发入门难度大,一般用于加解密、数学运算等场合。so的加载很简单,如果APK发布时已经携带了so文件,只需要在加载时调用System.loadLibrary(libName)方法即可。由于软件的安装目录中存放so的目录是没有写权限的,开发者不能更改该目录的内容,所以如果要动态加载存放在其他地方的so文件,用System.load(pathName)方法即可。
现在我们重点来看一下如何用java开发android的动态包。之所以前面称之为zip包,是因为jar和apk其实都是zip格式的。android虚拟机支持这两种文件后缀的包。android虚拟机支持加载zip包中的dex格式的代码文件。所以我们要用到一个很重要的类DexClassLoader,这个类是动态加在技术的关键。提到动态加载,还需要用到的一个就是java的反射技术,下面就举一个调用伪代码:
DexClassLoader dcl = new DexClassLoader(zip文件所在绝对路径, zip文件所在目录, 默认加载so所在目录,Context包含的classLoader);
Class<?> clazz = dcl.loadClass(想要加载类的完整包名);
Method getInstance = clazz .getMethod(方法名, 参数类);
getInstance.invoke(null, 参数); //第一个参数为null表示是静态方法
这样就把zip文件中的类加载起来了,图片等资源也可以放在zip包中加载。有了这个技术,很多的执行逻辑可以通过网络下载的方式动态调整,实现了应用的多样性。
不过动态加载是有一些限制的,比如zip包中的Activity、Service类是不能动态加载的,因为缺少声明;即使你在Manifest文件中进行了声明,系统默认也是到安装apk所在的路径中去寻找类,所以你会遇到一个ClassNotFound的异常。插件里你可以用apk中先前放入的layout、strings等资源。但是插件中自带的界面只能用纯代码进行编写,插件中是不能加载zip包中的xml作为layout等资源使用的。所以在开发上一些特效会比较困难些,建议预先植入apk中。
对于Activity、Service的动态加载,有一种变通的方法来解决,那就是在apk开发的时候预留各种Activity、Service的包装类,定义最常用的处理event的方法,然后在事件处理的时候调用插件内定义的方法即可。
zip插件的制作:将代码和资源导出成jar文件。通常在这一步的基础上我们用混淆器对代码进行一次混淆。最后通过命令行dx命令将jar中的class文件转换成dex文件。
来源:oschina
链接:https://my.oschina.net/u/175755/blog/111575