前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >❤️Android 应用的诞生 ❤️ 只需两幅图

❤️Android 应用的诞生 ❤️ 只需两幅图

原创
作者头像
Android 帅次
修改于 2021-10-20 10:10:48
修改于 2021-10-20 10:10:48
1K0
举报
文章被收录于专栏:Android 进阶之路Android 进阶之路

前言

在分析安装过程之前,需要先了解一下 Android 项目是如何经过编译->打包生成最终的 .apk 格式的安装包。谷歌有一张官方图片来描述 apk 的打包流程,如下图所示。

Android 应用模块的构建过程(如上图所示)遵循以下一般步骤:

  • 1、编译器将你的源代码转换为 DEX(Dalvik 可执行文件)文件,其中包括在 Android 设备上运行的字节码,以及其他所有内容到编译资源中。
  • 2、APKPackager将DEX文件和编译后的资源组合成一个APK。但是,在将你的应用安装并部署到Android设备之前,必须对APK进行签名。
  • 3、APKPackager使用调试或发布密钥库对你的 APK 进行签名:
    • 3.1如果你正在构建应用程序的调试版本,即你打算仅用于测试和分析的应用程序,则打包程序会使用调试密钥库对你的应用程序进行签名。Android Studio 使用调试密钥库自动配置新项目。
    • 3.2如果你正在构建你打算在外部发布的应用程序的发布版本,则打包程序会使用发布密钥库对你的应用程序进行签名。
  • 4、在生成最终的 APK 之前,打包程序使用zipalign工具来优化你的应用程序,以便在设备上运行时使用更少的内存。

在构建过程结束时,你将拥有应用的调试 APK 或发布 APK,可用于部署、测试或发布给外部用户。

以上是官方介绍。下面咱开始自己的理解。

开始新项目时,Android Studio 会自动为您创建其中的部分文件,并为其填充合理的默认值。所以不管一个完整的 Android 项目可能包含多个 module,而从宏观上看每一个 module 中的内容可以分为 2 部分:

  • Resources 资源文件
  • Java 或者 Kotlin 源代码

因此整个项目的编译打包过程也是针对这 2 部分来完成,如下图:

编译阶段

Resources 资源文件

资源文件包括项目中 res 目录下的各种 XML 文件、动画、drawable 图片、音视频等。AAPT 工具负责编译项目中的这些资源文件,所有资源文件会被编译处理,XML 文件(drawable 图片除外)会被编译成二进制文件,所以解压 apk 之后无法直接打开 XML 文件。但是 assets 和 raw 目录下的资源并不会被编译,会被原封不动的打包到 apk 压缩包中。

资源文件编译之后的产物包括两部分:resources.arsc 文件和一个 R 文件。前者保存的是一个资源索引表,后者定义了各个资源 ID 常量。这两者结合就可以在代码中找到对应的资源引用。如 下图 文件:

可以看出,R 文件 中的资源 ID 是一个 4 字节的无符号整数,用 16 进制表示。其中,最高的 1 字节表示 Package ID,次高的 1 个字节表示 Type ID,最低的 2 字节表示 Entry ID。

resources.arsc 相当于一个资源索引表,也可以理解为一个 map 映射表。其中 map 的 key 就是 R.java 中的资源 ID,而 value 就是其对应的资源所在路径。实际上 resources.arsc 里面还有其他信息,关于 resource.arsc 的解析可以参考 解析编译之后的Resource.arsc文件格式。

源码部分

项目中的源代码首先会通过 javac 编译为 .class 字节码文件,然后这些 .class 文件连同依赖的三方库中的 .class 文件一同被 dx(D8) 工具优化为 .dex 文件。如果有分包,那么也可能会生成多个 .dex 文件。

实际上源代码文件也包括 AIDL 接口文件编译之后生成的 .java 文件,Android 项目中如果包含 .aidl 接口文件,这些 .aidl 文件会被编译成 .java 文件。

打包阶段

最后使用工具 APK Builder 将经过编译之后的 resource 和 .dex 文件一起打包到 apk 中,实际上被打包到 apk 中的还有一些其他资源,比如 AndroidManifest.xml 清单文件和三方库中使用的动态库 .so 文件。

APK文件结构

APK(Android Package),APK 文件由一个 Zip 压缩文件组成,其中包含构成应用的所有文件。这些文件包括 Java 类文件、资源文件和包含已编译资源的文件。其文件结构如下:

  • APK 包含以下目录:
    • META-INF/:包含 CERT.SF 和 CERT.RSA 签名文件,以及 MANIFEST.MF 清单文件。系统安装APK时,应用管理器会按照对应算法对包里文件做校验,如果校验结果与META-INF中内容不一致,则不会安装这个APK。
    • assets/:包含应用的资源;应用可以使用 AssetManager 对象检索这些资源。
    • res/:包含未编译到 resources.arsc 中的资源。
    • lib/:包含特定于处理器软件层的已编译代码。此目录包含每种平台类型的子目录,如 armeabi、armeabi-v7a、arm64-v8a、x86、x86_64 和 mips。
  • APK 还包含以下文件。在这些文件中,只有 AndroidManifest.xml 是必需的。
    • resources.arsc:包含已编译的资源。此文件包含 res/values/ 文件夹的所有配置中的 XML 内容。打包工具会提取此 XML 内容,将其编译为二进制文件形式,并压缩内容。此内容包括语言字符串和样式,以及未直接包含在 resources.arsc 文件中的内容(例如布局文件和图片)的路径。
    • classes.dex:包含以 Dalvik/ART 虚拟机可理解的 DEX 文件格式编译的类。
    • AndroidManifest.xml:包含核心 Android 清单文件。此文件列出了应用的名称、版本、访问权限和引用的库文件。该文件使用 Android 的二进制 XML 格式。

apk 创建好之后,还不能直接使用。需要使用工具 jarsigner 对其进行签名,因为 Android 系统不会安装没有进行签名的程序。签名之后会生成 META_INF 文件夹,此文件夹中保存着跟签名相关的各个文件。

PackageManagerService(PKMS) 在安装过程中会检查 apk 中的签名证书的合法性。

常理来说,签名之后的 apk 应该是可以正常安装使用了,但是实际打包过程还会多一步使用工具 zipalign 对 apk 优化操作。

zipalign:是一种 zip 归档文件对齐工具。它对 apk 中的未压缩资源(图片、视频等)进行对齐操作,相对于文件开头都是对齐的。这样一来,你便可直接通过 mmap(2) 访问这些文件,而无需在 RAM 中复制相关数据并减少了应用的内存用量。

在将 APK 文件分发给最终用户之前,应该先使用 zipalign 进行优化。如果你使用 Android Studio 进行构建,则此步骤会自动完成。

mmap(2):mmap, munmap - 将文件或设备映射或取消映射到内存中。

至此一个完整的 apk 安装包就创建成功。

整个编译打包流程可以用下图来描述:

  • AIDL:AIDL 是 Android 中 IPC(进程间通信)方式中的一种,AIDL的作用是让让你可以在自己的 APP 里绑定一个其他 APP 的Service,这样你的 APP 可以和其他 APP 交互。注意:只有在需要不同应用的客户端通过 IPC 方式访问服务,并且希望在服务中进行多线程处理时,你才有必要使用 AIDL。如果你无需跨不同应用执行并发 IPC,则应通过实现 Binder 来创建接口;或者,如果你想执行 IPC,但不需要处理多线程,请使用 Messenger 来实现接口。

无论如何,在实现 AIDL 之前,请您务必理解绑定服务(绑定服务是 Service 类的实现,可让其他应用与其进行绑定和交互。)。

  • aapt2 compile:将 res 资源编译成 .flat 的二进制文件。
  • aapt2 link:将 .flat 和 AndroidManifest 进行连接,转化成不包含 dex 的 apk 和 R.java:
  • javac:将所有 .java 文件 (包括 R 文件和 aidl 生成的 .java 文件),通过 javac 工具生成 .class 文件。
  • dx(d8):.class 文件连同依赖的三方库中的 .class 文件一同被 dx(d8) 工具优化为 **.dex 文件。

这里说一下,aab包打包正常,传到Google后台,谷歌还是会生成apk 文件提供给玩家下载,而不是直接使用aab文件。

Apk 已经打包好了。后面咱们看看 Android 应用是如何启动的

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
【C语言】动态内存管理:malloc、calloc、realloc、free
申请的空间不要了,还要手动换回去。C语言提供了另一个函数free,专门是用来做动态内存释放和回收的,函数原型如下。
羚羊角
2024/10/21
5760
【C语言】动态内存管理:malloc、calloc、realloc、free
动态内存分配(malloc和free​、calloc和realloc​)
但是上述的开辟空间的方式有两个特点: • 空间开辟大小是固定的。 • 数组在申明的时候,必须指定数组的长度,数组空间一旦确定了大小不能调整
走在努力路上的自己
2024/01/26
4360
动态内存分配(malloc和free​、calloc和realloc​)
C语言calloc()函数:分配内存空间并初始化——stm32中的应用
经常在代码中看到使用malloc来分配,然后memset清零,其实calloc更加方便,一句顶两句~
用户4645519
2020/09/07
1.7K0
【C】动态内存管理 malloc calloc relloc free 函数详解
但是上述的开辟空间的方式有两个特点: 1. 空间开辟大小是固定的。 2. 数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配。
阿伟@t
2023/10/10
3340
【C】动态内存管理 malloc calloc relloc free 函数详解
【C语言】动态内存管理之4个内存函数`malloc`,`free`,`calloc`和`realloc`深度了解
本小节,我们学习动态内存管理:为什么要有动态内存分配?4个动态内存开辟函数:malloc,free,calloc和realloc,这些C标准库中的内存管理函数都声明在在 stdlib.h 头⽂件中。干货满满!学习起来吧😃!
学习起来吧
2024/02/29
4280
【C语言】动态内存管理之4个内存函数`malloc`,`free`,`calloc`和`realloc`深度了解
练习使用动态内存相关的4个函数:malloc、calloc、realloc、free
首先,我们已经掌握了一种开辟内存的方式,就是直接使用int i=20;但是这样开辟空间有两个特点,1:空间开辟大小是固定的,2:数组在创建时,必须设定数组的长度,数组空间的大小一旦确定就不能更改
用户11039545
2024/03/28
1470
练习使用动态内存相关的4个函数:malloc、calloc、realloc、free
C 语言中的 malloc,free,calloc,realloc
malloc函数 原型:extern void* malloc(unsigned int size); 功能:动态分配内存; 注意:size 仅仅为申请内存字节大小,与申请内存块中存储的数据类型无关,故编程时需要通过以下方式给出:长度 * sizeof(数据类型); 示例: //动态分配内存,输入5个数据,并把低于60的值打印出来 #include <stdio.h> #include <stdlib.h> int main() { int *ptr = (int *)ma
村雨遥
2022/06/15
4490
【动态内存管理】malloc&calloc和realloc和笔试题和柔性数组
但是如果我们所需要的空间大小在程序编译时并不确定,而是到程序运行起来的时候才能知道,那上述的空间开辟的方式就不适合了,动态内存管理就应运而生。
MicroFrank
2023/01/16
5060
【C语言进阶】C语言动态内存管理:深入理解malloc、calloc与realloc
前言:在C语言的世界里,动态内存管理是一项既强大又复杂的特性,它赋予了程序员在程序运行时动态地分配和释放内存资源的能力。这一特性是C语言灵活性和高效性的重要基石,同时也是初学者踏入C语言高级编程领域时必须跨越的一道门槛
Eternity._
2024/09/13
3040
【C语言进阶】C语言动态内存管理:深入理解malloc、calloc与realloc
【C语言进阶篇】常用动态内存分配 malloc calloc realloc free
🎬 鸽芷咕:个人主页 🔥 个人专栏:《C语言初阶篇》 《C语言进阶篇》
鸽芷咕
2023/12/25
5750
【C语言进阶篇】常用动态内存分配 malloc calloc realloc free
C语言动态内存分配函数malloc(),calloc(),realloc()用法对比分析
特点: 所开辟的内存是在栈中开辟的固定大小的 ,如a是4字节 ,数组b是40字节 ,并且数组在申明时必须指定其长度 , 如果是全局数组的话,内存是在编译时分配好的,如果是局部变量数组的话,运行时在栈上静态分配内存。
CtrlX
2022/10/04
1.4K0
C语言动态内存分配函数malloc(),calloc(),realloc()用法对比分析
【熟视C语言】C语言动态内存管理(malloc,calloc,realloc,free)
这样的空间开辟方式,在后续操作中,是无法改变以上数据所占空间大小的,并且对于数组来说,开辟空间是必须指明数组长度的。而在我们实际生活中又确实会出现一组数据量会随时变化的数据组。这时我们就需要使用动态内存函数来为数组,变量来开辟空间。
Crrrush
2023/06/23
2020
【熟视C语言】C语言动态内存管理(malloc,calloc,realloc,free)
【C语言】动态内存开辟的使用『malloc』
​ 所谓动态内存分配(Dynamic Memory Allocation)就是指在程序执行的过程中动态地分配或者回收存储空间的分配内存的方法。动态内存分配不象数组等静态内存分配方法那样需要预先分配存储空间,而是由系统根据程序的需要即时分配,且分配的大小就是程序要求的大小。
謓泽
2022/12/12
8300
【C语言】动态内存开辟的使用『malloc』
C/C++【内存管理】
C++中的内存管理机制和C语言是一样的,但在具体内存管理函数上,C语言的malloc已经无法满足C++面向对象销毁的需求,于是祖师爷在C++中新增了一系列内存管理函数,即 new 和 delete 著名段子:如果你还没没有对象,那就尝试 new 一个吧
北 海
2023/07/01
1790
C/C++【内存管理】
【C语言】calloc()函数详解(动态内存开辟函数)
我们先来看一下cplusplus.com - The C++ Resources Network网站上calloc()函数的基本信息:
修修修也
2024/04/01
3750
【C语言】calloc()函数详解(动态内存开辟函数)
C语言-动态内存管理(malloc、calloc、realloc)
2)堆区:是用来动态内存开辟的,malloc、calloc、free、realloc等函数都是在堆区上进行操作的。
HABuo
2024/11/19
2.1K0
C语言-动态内存管理(malloc、calloc、realloc)
C++:内存管理|new和delete
为什么需要内存管理呢??因为我们在程序的运行过程中会需要各种各样的数据,而我们根据数据的不同存储在不同的区域里面,是为了更高效地处理数据。而C语言相比Java来说在内存的权限上尽可能给了程序员更多的操作空间,这也是为什么C更追求性能。
小陈在拼命
2024/03/01
1410
C++:内存管理|new和delete
C&C++内存管理
在C语言中我们经常说,局部变量存放在栈区,动态内存开辟的空间是向堆区申请的,只读常量存放在常量区等等。其实这里我们所说的区域都是虚拟进程地址空间的一部分,具体划分如下:
始终学不会
2023/03/28
1.3K0
C&C++内存管理
【C++】探索C++内存管理:机制揭秘与内存安全
需要注意的是,C标准库中的malloc函数的具体实现可能因编译器和操作系统的不同而有所差异,上述步骤仅为一种常见的实现方式。
大耳朵土土垚
2024/05/03
1580
【C++】探索C++内存管理:机制揭秘与内存安全
C/C++内存详解
malloc、realloc、calloc 和 free 是C语言中用于动态内存管理的标准库函数,它们定义在<stdlib.h>头文件中。这些函数允许程序在运行时根据需要分配和释放内存,而不是在编译时静态地分配内存。这对于处理未知大小的数据或需要动态增长的数据结构(如链表、树等)特别有用。
破晓的历程
2024/09/04
1110
C/C++内存详解
推荐阅读
相关推荐
【C语言】动态内存管理:malloc、calloc、realloc、free
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文