Android——app基础
Android Application基础
系统启动过程
APK文件介绍
APK是Android Package的缩写,即android安装包。APK 文件其实是zip 格式,但后缀名被修改为apk ,可以通过解压程序直接解压查看。apk 解压后,一般的可看到的目录结构如下:
文件或目录 | 作用 |
AndroidManifest.xml文件 | 程序全局配置文件,它描述了应用的名字、版本、权限、引用的库文件等等信息。在apk中的AndroidManifest.xml是经过压缩的,可以通过AXMLPrinter2工具解开,具体命令为:java -jar AXMLPrinter2.jar AndroidManifest.xml |
META-INF目录 | 存放的是签名信息,用来保证apk包的完整性和系统的安全。在eclipse编译生成一个apk包时,会对所有要打包的文件做一个校验计算,并把计算结果放在META-INF目录下。这就保证了apk包里的文件不能被随意替换。比如拿到一个apk包后,如果想要替换里面的一幅图片,一段代码, 或一段版权信息,想直接解压缩、替换再重新打包,基本是不可能的。如此一来就给病毒感染和恶意修改增加了难度,有助于保护系统的安全。 |
res目录 | 存放资源文件。包括图片,字符串等等。 |
lib目录 | 子目录armeabi存放的是一些so文件。这个地方多讲几句,都是在开发过程中摸索出来的。eclipse在打包的时候会根据文件名的命名规则(lib****.so)去打包so文件,开头和结尾必须分别为“lib”和“.so”,否则是不会打包到apk文件中的。其他非eclipse开发环境没有测试过。如果你是用SDK和NDK开发的话,这部分很重要,甚至可以通过把一些不是so文件的文件通过改名打包到apk中,具体能干些什么那就看你想干什么了。 |
assets目录 | 存放一些配置文件,这些文件的内容在程序运行过程中可以通过相关的API获得。 |
classes.dex文件 | DEX(DalvikVM executes的简称)是Android Dalvik执行程序文件,是Dalvik的字节码而非Java的字节码(首先是java文件通过jdk编译成字节码文件然后经过dex编译成classes.dex) |
resources.arsc文件 | 编译后的二进制资源文件的索引(apk文件的资源表) |
Android在运行程序时首先需要解压apk文件,然后获取编译后的AndroidManifest.xml文件中配置信息,执行dex程序。
系统基础
每个Android应用程序的都运行在它自己的安全沙箱中:
- 而Android操作系统是一个多用户Linux系统中,每个应用程序是一个不同的用户。
- 默认情况下,每个应用程序的系统分配一个唯一的Linux用户ID(该ID仅用于系统,对应用程序来说是未知)。系统为每一个app的所有文件都设置权限,以便只有分配了该用户ID的应用程序可以访问它们。
- 每个进程都有它自己的虚拟机(VM),因此应用程序的代码和其他应用程序是隔离运行的。
- 默认情况下,每个应用程序运行在它自己的Linux进程。当应用程序的任何组件需要被执行时,Android会启动一个进程。当该进程不再需要或者系统需要为其它程序恢复内存时,都会关闭该进程。
以这种方式,Android就实现了最小特权原则:每个app之间只能通过访问组件达到工作目的;app不能访问系统未给与权限的部分。
然而,还是有方法使app之间能分享数据和访问系统服务:
- 当两个app共享一个Linux用户ID时,它们就能互相访问文件。为了节约系统资源,拥有相同用户ID的app还可以被安排运行在相同的Linux进程中并且共享相同的VM(app必须有相同的签名)。
- app能请求权限去访问设备数据,比如联系人、短信、SD卡……所有的app权限必须在安装时被授予。
Zygote
Zygote是一个虚拟机进程,同时也是一个虚拟机实例的孵化器,每当系统要求执行一个 Android应用程序,Zygote就会fork出一个子进程来执行该应用程序。这样做的好处显而易见:
- Zygote进程是在系统启动时产生的,它会完成虚拟机的初始化,库的加载,预置类库的加载和初始化等等操作。
- 而在系统需要一个新的虚拟机实例时,Zygote通过复制自身,快速的提供一个执行进程。
- 另外,对于一些只读的系统库,所有虚拟机实例都和Zygote共享一块内存区域,大大节省了内存开销。
Zygote工作流程如下图:
App组件
app组件是Android程序最重要的构造模块。每一个组件都是系统进入app的不同入口。app组件有四种不同的类型,分别为Activities、Services、Content providers和Broadcast receivers,它们都有自己的用途和生命周期。
当系统启动一个组件之后,如果这个组件所在的程序之前没有运行的话,系统会自动开始这个程序的进程,并初始化这个组件所需要的相关类。比如,你的程序开启了一个拍照功能程序的Activity,这时系统会启动这个Activity所在的程序,所以这个Activity运行在拍照功能的程序当中,而不是在你的程序中。所以,不像其他操作系统的中的程序一样,Android程序没有一个单独的入口点(比如没有我们常见的main()函数)。
因为系统中的程序运行在自己的独立进程中,并且程序中的文件都有自己的限制其他程序访问的权限,所以,你的程序不能直接激活其他程序中的组件。但是Android系统就可以。为了激活其他程序中的组件,你必须向系统发送一个消息来详细说明你要启动其他组件的意图,这样系统才会为你激活这个组件。
四大组件中的三个组件——activities、services和broadcast receiver——是由一种叫intent的异步消息来激活的。这些intents在运行时(runtime)将特定的组件绑定在一起(bind),你可以把这些intents看作来自其他组件请求活动的messengers。最后一种组件类型content provider并不是由intent来激活的(activate)。而是由接收到ContentResolver的请求时激活的。
Manifest
在Android系统可以启动一个应用程序组件之前,Android系统必须通过读取这个程序的AndroidManifest.xml(即manifest文件)文件来确定要启动的组件存在。你的程序必须在这个manifest文件声明用到的所有的组件,并且这个manifest文件必须在项目的根目录下。
另外,这个manifest文件还声明一些其他的东西,比如:
- 确定这个程序需要的所有权限,比如Internet访问权限或者读取用户联系人权限。
- 声明这个运行这个程序所需要的最低API版本,这个可以根据开发该程序所使用的API版本。
- 声明该程序所需要的硬件或软件特征(features),比如照相机、蓝牙服务或者多点触屏。
- 声明该程序需要链接(link against)的API库(不是Andorid的framework APIs),比如Google Maps library。
- 等等。
App Resources
一个应用程序不仅仅由代码组成——它需要与代码分隔的资源。使用应用程序资源文件,可以更容易地更新你的应用程序的特性而无需修改代码,并且 — 通过提供多套备选资源文件 — 使您能够针对各种设备配置优化你的应用程序(比如不同语言或屏幕大小)。
对于你的安卓工程里面包含的每一项资源, SDK 构建工具定义一个唯一的正整数 ID 标识符,你可以使用该标识符从你的应用程序代码中或者从XML文件中定义的其他资源中特指该资源。
将资源提供工作同你的源代码分隔开来最重要的原因之一是能够使你为不同的设备配置提供可替换的资源文件。 对于备选资源,Android 支持许多不同的限定符(qualifiers)。限定符是包含在你的资源文件夹名称中的一个短字符串,以便界定哪些设备配置可使用这些资源(比如drawable-hdpi)。