2016-03-28 14:06:13 456浏览
在Android软件开发中通常情况下,一般的开发方式和代码架构就能满足我们的普通需求。但是有些特殊问题,常常引发我们进一步的沉思。我们从沉思中产生顿悟,从而产生新的技术形式。
如何开发一个可以自定义控件的Android开发应用?就像eclipse一样,可以动态加载插件;如何让Android应用执行服务器上的不可预知的代码?如何对Android应用加密,而只在执行时自解密,从而防止被破解?
android开发从零开始之Java技术类加载器灵活加载执行类
熟悉Java技术的朋友,可能意识到,我们需要使用类加载器灵活的加载执行的类。这在Java开发安卓应用里中已经算是一项比较成熟的技术了,但是在Android开发应用中,我们都还比较陌生。
(1)类加载机制
Dalvik虚拟机如同其他Java虚拟机一样,在运行程序时首先需要将对应的类加载到内存中。而在Java标准的虚拟机中,类加载可以从class文件中读取,也可以是其他形式的二进制流。因此,我们常常利用这一点,在程序运行时手动加载Class,从而达到代码动态加载执行的目的。但是Dalvik虚拟机毕竟不算是标准的Java虚拟机,因此在类加载机制方面它们有相同的地方,也有不同之处。我们必须区别对待。例如,在使用标准Java虚拟机时,经常自定义继承自ClassLoader的类加载器。然后通过defmeClass0方法来从一个二进制流中加载Class,但是这在Android里是行不通的,这一点可以从Android源码知道。Android中ClassLoader的defineClass0方法,具体是调用VMClassLoader的defineClass0本地静态方法。
(2)Dalvik虚拟机类的加载机制
那如果在Dalvik虚拟机里,ClassLoader不好使,我们该如何实现动态加载类呢?Android为我们从ClassLoader派生出了两个类:DexClassLoader和PathClassLoader。DexClassLoader和PathClassLoader其实都是通过类DexFile实现类加载功能的。这里需要顺便提一下的是,Dalvik虚拟机识别的是dex文件,而不是class文件。因此,我们供类加载的文件也只能是dex文件,或者包含有dex文件的.apk或.jar文件。
PathClassLoader是通过构造函数new DexFile(path)来生成生DexFile对象的;而DexClassLoader则是通过其静态方法loadDex(path,outpath,O)得到DexFile对象的。这两者的区别在于DexClassLoader需要提供一个可写的outpath路径,用来释放.apk包或者.jar包中的dex文件。也就是说,PathClassLoader不能主动从zip包中释放出dex,因此只支持直接操作dex格式文件,或者已经安装的apk(因为已经安装的apk在cache中存在缓存的dex文件)。而DexClassLoader可以支持.apk、.jar和.dex文件,并且会在指定的ou。
(3)具体操作
在具体操作时,可能需要使用到的工具有:javac、dx、eclipse等。其中在使用dx工具时,最好指明:…no strict,因为class文件的路径可能不匹配。当加载好类后,通常可以通过Java反射机制来使用这个类。但是这样做的效率相对不高,而且老用反射代码也比较复杂凌乱。更好的做法是定义一个interface,并将这个interface写进容器端。待加载的类,继承自这个interface,并且有一个参数为空的构造函数,以使我们能够通过Class的newlnstance方法产生对象。然后将对象强制转换为interface对象,于是就可以直接调用成员方法了。
(4)代码加密
在加密代码时,最初设想将dex文件加密,然后通过JNI将解密代码写在Native层。解密之后直接传入二进制流,再通过def'meClass将类加载到内存中。但是由于不能直接使用defineClass,而必须传文件路径给Dalvik虚拟机内核,因此解密后的文件需要写到磁盘上,增加了被破解的风险。
Dalvik虚拟机内核仅支持从dex文件加载类的方式是不灵活的,由于没有非常深入的研究内核,我不能确定是Dalvik虚拟机本身不支持还是Android在移植时将其阉割了。不过坚信的是,Dalvik或Android开源项目都正在向能够支持raw数据定义类的方向努力。
在RawDexFile出来之前,我们只能使用这种存在一定风险的加密方式。我们需要注意释放的dex文件路径及权限管理。另外在类加载完毕之后,除非出于其他目的,否则应该马上删除临时的解密文件。