本文通过学习:聊聊 APK —— 直接运行 Dex 总结。
1.运行工具分析
在java学习时,如果想顺利的运行java程序,需要安装JRE,对于开发者而言,需要安装JDK,但最终执行Java程序的是在JVM中运行。将**.java文件转为一个或多个字节码.class文件,然后将其打包到.jar包中,JVM从相应的.class文件和.jar中获取相应的字节码。
.java---.class--JVM运行加载
对于Android程序,除了将.java文件转为.class文件外,还需要在.class文件的基础上转为.dex(Dalvik Execuable)格式,该格式是转为Dalvik设计的,适合内存和处理器速度有限的系统中运行,同时Dalvik允许在有限的内存中同时运行多个虚拟机实例,每个实例作为独立的Linux进程执行,互相之间不影响(安卓中的APP,每个APP运行在独立的虚拟机实例中,作为独立的Linux进程)。
.java---.class--.dex--ART/Dalvik运行加载
安卓中有两种虚拟机Dalvik和ART,其中ART(Android Runtime)是在2014年I/O大会上正式代替Dalvik,两者区别如下:
对比项 | ART | Dalvik |
---|---|---|
安装 | 安装时间久,占用内存空间大 | 安装时间较短,占用内存空间较小 |
编译 | 预编译(AOT:Ahead-Of-Time ) :应用在第一次安装时字节码预先编译成机器码 | 运行时编译(JIT:Just-In-Time) :在每次运行时编译 |
运行 | 运行效率较高,不需要再次编译字节码(空间换时间) | 运行效率较低,需要每次编译字节码(时间换空间) |
性能 | 减少编译,手机电池续航能力和CPU运行效率提高 | 耗费较多电量和cpu资源 |
以下关于安卓运行的虚拟机都简称为Dalvik。
2、Java运行
在文本中编辑一个.java的程序,如下所示:
public class HelloWorld {
public static void main (String [] args){
System.out.println("Hello World!");
}
}
在cmd中通过javac命令将其转为.class文件,如果运行javac命令不成功,可参考javac配置后通过cmd操作时显示不是内部命令。
javac HelloWorld.java
生成.class文件后,执行java命令后,会打印出程序中运行的输出字段。如下所示:
java -cp . HelloWorld
以上操作是在HelloWorld.java所在的目录中运行的,如在其他文件中运行,需要先指定文件目录,否则会提示“错误: 找不到或无法加载主类 HelloWorld”,上面语句中的“cp”
就是类似于classpath的意思,指明文件的目录。例如将cmd切换至C根目录,则执行如下语句:
java -cp C:\Users\XK\Desktop\APKtest\ HelloWorld
其中HelloWorld位于桌面(Desktop)的APKtest文件中,在指定目录时,需要注意按照以下方式:
java空格 -cp 空格C:\Users\XK\Desktop\APKtest(文件根目录)\空格 HelloWorld
3、Android中运行
3.1生成dex文件
在第二部分中生成的.class文件,需要通过dx生成dex文件,才可运行在Dalvik中。在AndroidStudio开发时,该IDE自动将文件帮我们转换好,可通过查看Project Structure中SDK Location\build-tools,获取版本信息,如下所示:
这里使用28.0.3中的dx.bat生成dex文件,直接在该目录打开cmd,并执行如下所示:
dx --dex --output=classes.dex HelloWorld.class
dx可以将class文件转为.dex.jar.apk.zip。
3.2 运行dex文件
将生成的dex文件push至手机的sdcard目录下,如下所示:
adb push classes.dex /sdcard
通过class文件和dex文件生成的过程可以看出一个class文件由java生成,dex由class文件生成,class文件中包含多个public类,因此dex文件类似,其可以包含多个class文件,类似于jar。其过程类比于文件的压缩过程。
将dex推送至手机目录后,执行adb shell,进入sdcard目录,执行如下执行,就会打印为程序运行的HelloWorld!信息。
HWSTF:/sdcard $ dalvikvm -cp classes.dex HelloWorld
Hello World!