iApp软件怎么用什么软件打开dex文件件

在Android系统中一个App的所有代码都在┅个Dex文件里面。Dex是一个类似Jar的存储了多有Java编译字节码的归档文件因为Android系统使用Dalvik虚拟机,所以需要把

使用Java Compiler编译之后的class文件转换成Dalvik能够执行嘚class文件这里需要强调的是,Dex和Jar一样是一个归档文件里面仍然是Java代码对应的字节码文件。

当Android系统启动一个应用的时候有一步是对Dex进行優化,这个过程有一个专门的工具来处理叫DexOpt。DexOpt的执行过程是在第一次加载Dex文件的时候执行的这

个过程会生成一个ODEX文件,即Optimised Dex执行ODex的效率会比直接执行Dex文件的效率要高很多。但是在早期的Android系统中DexOpt有一个问题,也就是这篇文

章想要说明并解决的问题DexOpt会把每一个类的方法id檢索起来,存在一个链表结构里面但是这个链表的长度是用一个short类型来保存的,导致了方法id的数目不能够超过

65536个当一个项目足够大的時候,显然这个方法数的上限是不够的尽管在新版本的Android系统中,DexOpt修复了这个问题但是我们仍然需要对老系统做兼容。

一种有效的解决思路是把Dex文件分割成多个较小的Dex这就如同很多项目会把自己分割成多个Jar文件一样,不同的功能在不同的Jar文件里面通过一些配置和额外嘚操作,

可以让虚拟机有选择性的加载Jar文件但是在Android系统中,一个应用是只允许有一个Dex文件的也就是说在编译期的时候,所有的Jar文件最終会被合并成一个Dex文件

我们没有办法在Apk文件里面打包两个Dex,让DexOpt分别对两个Dex文件做处理而Android系统也不会同时为一个Apk加载两个Dex。

如果我们把Dex汾成多个文件然后在程序运行的时候,再把多的那几个动态的加载进来是否可行呢也就是说我们能否在运行时阶段把代码加入虚拟机Φ。对于虚拟机来说其

实所有的代码都是在运行时被加载进来的。而不同于C语言还存在着静态链接虚拟机在所有Java代码执行之前被启动,然后开始把字节码加载到环境中执行我们可以理解成所

有的代码都是动态加载到虚拟机里的。而说到加载不得不说的是ClassLoader。它的工作僦是加载.class文件在Android的

说,ClassLoader不是把所有的Class放到一个巨大的数组或别的什么数据结构中来处理ClassLoader在加载一个Jar中的类的时候,需要制定另一个ClassLoader作為父亲节点

如果根ClassLoader有这个类,而返回这个类的类类型否则把这个请求交给这个请求的来源子ClassLoader。这是一种向上传递向下分发的机制。這种情况下对于调用着来

说,子ClassLoader永远都是包含最多Class的ClassLoader有一点我们需要注意,父亲ClassLoader只会向请求来源分发自己的处理结果所以如果来源昰自己,那么如果没有

请求类它就会返回空而不是遍历所有子ClassLoader去请求是否有被请求的类。

这一步并不复杂首先我们把所需要的.class文件或鍺是Jar文件和一些源码一起编译生成一个Jar文件。然后使用Android SDK提供的dx工具把Jar文件转成Dex文件我们可以

提前对它进行ODex操作,让它在被DexClassLoader加载的时候跳过DexOpt的部分工作,从而加快加载的过程

现在的工作就是在运行时加载这个Dex文件了。我们可以在Application启动的onCreate方法里面加载Dex但是如果你的Dex太大,那么它会让你的App启动变慢我们也可以

使用线程去加载,但我们必须保证加载完成之后再进行某个外部类的请求当然也可以真正等到需要某个外部类的时候再进行Dex加载。这根本上取决于Dex文件本身的大小太

大了可以预加载,而比较小可以等到实际需要的时候再加载我們暂且把这个加载了外部Dex的ClassLoader成为ExternalClassLoader

上面我们提到了树形结构和系统中的多个ClassLoader,当我们加载外部Dex的时候我们是否需要指定一个父ClassLoader呢?我们当嘫需要一个父ClassLoader

否则我们ExternalClassLoader连一些基本的Java类都没有,它根本不可能成功的加载一个Dex进一步的,我们要选择哪一个ClassLoader来作为我们的父亲呢是SystemClassLoader還是

如果是后者的情况,我们的树可以被看成一个链表

我们知道,我们编写的四大组建都不是由我们自己来创建的是由系统来给我们構造并管理其生命周期的。那么这个过程是什么样的呢拿Activity来举例,我们需要通过调用

ActivityManager会收到并处理这个Intent从而决定是是启动一个新的,還是把旧的放到前台它会先查找这个Activity在哪个应用里面,这是通过扫描每个应用的AndroidManifest来确定

这些信息是在PackageManager里面被检索的。总之如果这个Activity不洅任何的manifest里面它就不可能被启动。所以仅有一个Activity类是不够的我们需要在manifest里面声明它。

上面是Activity的情况Service之类的也是同理。那么View怎么办盡管我们可以直接创建View,但是大部分的View都不是我们创建的而是通过XML布局文件Inflate出来的。

也就是说我们在XML定义了一些外部Dex里面的View,那么显嘫这个XML是不能被成功的Inflate的因为除非系统会使用我们的ExternalClassLoader,否则它肯定是找不到

我们的类的:ContextClassLoader里面并没有外部Dex中的类也就是说问题的根本茬于,对于那些Android系统为我们创建的对象它是不能包含在外部Dex里面的。

而Android系统中大部分的组建类的生命周期都交给了系统来管理我们不鈳能自己来创建这些类对象。那么另一种思路:我们是不是可以通过使用我们的ExternalClassLoader来代替ContextClassLoader呢尽管系统的ContextClassLoader是私有的,但是我们可以通过反射強制的把它替换成我们的ExternalClassLoader而对于那些外部的组建(Activity等),尽管我们没有它们的类但是并不影响我们在AndroidManifest里面声明这个Activity。因为Android系统只是把咜作为一个检索并不会真正检查它里面的组建是不是真的在虚拟机环境中已经被加载,

只有真正使用Intent启动某个组建的时候才会去检查洏只要我们保证这个时候我们已经加载了外部的ClassLoader,那么这个组建就可以被正常的启动还有一点,除了我们要为外部可能有的组建在AndroidManifest里面莋声明一外那些外部组建可能用到的权限我们也需要一一声明,例如如果外部Activity使用了相机功能那么如果我们的Manifest里面没有声明使用相机功能的权限的话,即便这个Activity能成功为加载出来仍然是不能使用的。

我要回帖

更多关于 用什么软件打开dex文件 的文章

 

随机推荐