Android AAPT 详解(上篇)

阿凡达2018-07-04 10:28

目录

  • AAPT解释,作用
  • AAPT基本命令
  • AAPT编译资源源码解析
  • AAPT打包和系统不一致的资源ID

AAPT是什么

AAPT - Android Asset Packaging Tool

看全称,就可知道AAPT是Android资源打包工具。讲这个之前,是有必要简单说下Android是如何构建一个APK的。

上图是Google官方发布的一张非常经典的Apk打包流程图。

流程概述:

  1. 工程的资源文件(res文件夹下的文件),通过AAPT打包成R.java类(资源索引表),以及.arsc资源文件
  2. 如果有aidl,通过aidl工具,打包成java接口类
  3. R.java和aidl.java通过java编译成想要的.class文件。
  4. 源码class文件和第三方jar或者library通过dx工具打包成dex文件。dx工具的主要作用是将java字节码转换成Dalvik字节码,在此过程中会压缩常量池,消除一些冗余信息等。
  5. apkbuilder工具会将所有没有编译的资源,.arsc资源,.dex文件打包到一个完成apk文件中中。
  6. 签名,5中完成apk通过配置的签名文件(debug和release都有),jarsigner工具会对齐签名。得到一个签名后的apk,signed.apk
  7. zipAlign工具对6中的signed.apk进行对齐处理,所谓对齐,主要过程是将APK包中所有的资源文件距离文件起始偏移为4字节整数倍,这样通过内存映射访问apk文件时的速度会更快。对齐的作用主要是为了减少运行时内存的使用。

总结:

  • 输入:res文件夹所有的资源(layout\drawable\string\array等),asset下的资源,AndroidManifest.xml,Android.jar文件
  • 工具: aapt 地址(/your sdk path/build-tools/your build tools version/aapt)
  • 输出:res下的资源都会被编译成一个资源索引文件resource.arsc以及一个R.java类。asset下的资源不会编译,直接压缩进apk。

AAPT命令详解

按照上面aapt的地址配置好环境变量后,在终端中输入 aapt v 会得到aapt版本信息,如下:

再输入 aapt 命令会列出所有的aapt命令集合,下面我们一条条来使用并且分析其作用:

1.aapt l[ist] [-v] [-a] file.{zip,jar,apk}

作用:列出压缩文件(zip,jar,apk)中的目录内容。

例如:

    aapt l /Users/zfxu/work/androidstudio_workspace/AAPTDemo/app/build/outputs/apk/app-debug.apk

结果如下: 可以看出来不加任何参数,aapt只是简单的罗列压缩文件中每一项的内容。

    aapt l -v /Users/zfxu/work/androidstudio_workspace/AAPTDemo/app/build/outputs/apk/app-debug.apk

结果如下: 从图中可以看出,加上-v后,输出的内容很详细,并且以列表的形式标识出很多参数,其中表目有:

  • Length:原始文件的长度
  • Date:日期
  • Time:时间
  • Name:名称
  • Method:压缩方法,Deflate及Stored两种,即该Zip目录采用的算法是压缩模式还是存储模式;可以看出resources.arsc、*.png采用压缩模式,而其它采用压缩模式。
  • Ratio:压缩率
  • Size:这个是压缩省掉的大小,即如果压缩率是xx%。那Size是原始长度*(1-xx%)
  • CRC-32:循环冗余校验。这个计算是有特定的算法的。
  • offset:zipfile中偏移量的意思

      aapt l -a /Users/zfxu/work/androidstudio_workspace/AAPTDemo/app/build/outputs/apk/app-debug.apk 
    

    结果如下: -a表示会详细输出压缩文件中所有目录的内容,详细到什么程度的,可以看上图,上图截取的只是很小的一部分,这部分是manifest.xml文件的所有数据,可以看出来基本上所有的manifest信息都列了出来。

2.aapt d[ump] [--values] [--include-meta-data] WHAT file.{apk} [asset [asset ...]]

作用:通过参数配置可以dump apk中各种详细信息。

  • strings 官方解释:

    Print the contents of the resource table string pool in the APK


即打印apk中所有string资源表


    aapt dump strings /Users/zfxu/work/androidstudio_workspace/AAPTDemo/app/build/outputs/apk/app-debug.apk

结果: 不太了解这个结果是什么具体的意思,猜测应该是序列化的string字段。

  • bading 官方解释:

    Print the label and icon for the app declared in APK.

      aapt dump badging /Users/zfxu/work/androidstudio_workspace/AAPTDemo/app/build/outputs/apk/app-debug.apk
    

结果:

查看APK中的配置信息,包括包名,versionCode,versionName,platformBuildVersionName(编译的时候系统添加的字段,相当targetSdkVersionCode的描述)等。同事该命令还列出了manifest.xml的部分信息,包括启动界面,manifest里配置的label,icon等信息。还有分辨率,时区,uses-feature等信息。

  • permissions 官方解释:Print the permissions from the APK

较简单,输出APK中使用到的权限信息。

  • resources 官方解释:

    Print the resource table from the APK

      aapt dump resources /Users/zfxu/work/androidstudio_workspace/AAPTDemo/app/build/outputs/apk/app-debug.apk
    

结果: 输出了apk中所有的资源信息,从这里也可以看出来aapt打包时也包含了android系统很多资源。并且这里也发现,系统通过标准的aapt构建出来的资源绝大部分的资源id都是0x7f开头的,这个也是和我们在R.java文件中看到的资源编号是对应起来的。

  • configurations 官方解释:Print the configurations in the APK

       aapt dump configurations /Users/zfxu/work/androidstudio_workspace/AAPTDemo/app/build/outputs/apk/app-debug.apk
    

结果:

可以看出该命令输出了apk所有的资源目录,仅仅是目录,里面有语言,分辨率,夜间模式相关的数据。

  • xmltree 官方解释:

    Print the compiled xmls in the given assets

      aapt d xmltree /Users/zfxu/work/androidstudio_workspace/AAPTDemo/app/build/outputs/apk/app-debug.apk res/layout/activity_main.xml
    

结果:

该命令直接反编译除了apk中某一个xml布局文件的组织结构。命令需要两个参数 第一是apk的地址 第二后面是apk中某个编译好的xml的相对路径地址

  • xmlstrings 官方解释:

    Print the strings of the given compiled xml assets

      aapt d xmlstrings /Users/zfxu/work/androidstudio_workspace/AAPTDemo/app/build/outputs/apk/app-debug.apk res/layout/activity_main.xml
    

结果:

从字面解释,输出xml文件中所有的string信息。看结果,实际上并没看出来什么特殊的,也并不是简单的string信息,猜测可能是索引吧。

3.aapt p[ackage] [-d][-f][-m][-u][-v][-x][-z][-M AndroidManifest.xml]

aapt p[ackage] [-d][-f][-m][-u][-v][-x][-z][-M AndroidManifest.xml] \
        [-0 extension [-0 extension ...]] [-g tolerance] [-j jarfile] \
        [--debug-mode] [--min-sdk-version VAL] [--target-sdk-version VAL] \
        [--app-version VAL] [--app-version-name TEXT] [--custom-package VAL] \
        [--rename-manifest-package PACKAGE] \
        [--rename-instrumentation-target-package PACKAGE] \
        [--utf16] [--auto-add-overlay] \
        [--max-res-version VAL] \
        [-I base-package [-I base-package ...]] \
        [-A asset-source-dir]  [-G class-list-file] [-P public-definitions-file] \
        [-D main-dex-class-list-file] \
        [-S resource-sources [-S resource-sources ...]] \
        [-F apk-file] [-J R-file-dir] \
        [--product product1,product2,...] \
        [-c CONFIGS] [--preferred-density DENSITY] \
        [--split CONFIGS [--split CONFIGS]] \
        [--feature-of package [--feature-after package]] \
        [raw-files-dir [raw-files-dir] ...] \
        [--output-text-symbols DIR]

官方解释:

Package the android resources. It will read assets and resources that are supplied with the -M -A -S or raw-files-dir arguments. The -J -P -F and -R options control which files are output.

android 编译资源打包资源文件的命令。

  • -d:包括一个或多个设备资源,由逗号分隔;
  • -f:覆盖现有的文件命令,加上后编译生成直接覆盖目前已经存在的R.java;
  • -m:使生成的包的目录放在-J参数指定的目录;
  • -u:更新现有的包 u = update;
  • -v:详细输出,加上此命令会在控制台输出每一个资源文件信息,R.java生成后还有注释。
  • -x:创建扩展资源ID;
  • -z:需要本地化的资源属性标记定位。
  • -M:AndroidManifest.xml的路径
  • -0:指定一个额外的扩展. apk文件将不会存储压缩
  • -g:制定像素迫使图形的灰度
  • -j:指定包含一个jar或zip文件包,这个命令很特别
  • –debug-mode:指定的是调试模式下的编译资源;
  • –min-sdk-versopm VAL:最小SDK版本 如是7以上 则默认编译资源的格式是 utf-8
  • –target-sdk-version VAL:在androidMainfest中的目标编译SDK版本
  • –app-version VAL:应用程序版本号
  • –app-version-name TEXT:应该程序版本名字;
  • –custom-package VAL:生成R.java到一个不同的包
  • –rename-mainifest-package PACKAGE:修改APK包名的选项;
  • –rename-instrumentation-target-package PACKAGE:重写指定包名的选项;
  • –utf16:资源编码修改为更改默认utf – 16编码;
  • –auto-add-overlay:自动添加资源覆盖
  • –max-res-version:最大资源版本
  • -I:指定的SDK版本中android.jar的路径
  • -A:assert文件夹的路径
  • -G:一个文件输出混淆器选项,后面加文件逗号隔开.
  • -P:指定的输出公共资源,可以指定一个文件 让资源ID输出到那上面;
  • -S:指定资源目录 一般是 res
  • -F:指定把资源输出到 apk文件中
  • -J:指定R.java输出的路径
  • raw-file-dir:附加打包进APK的文件

该命令也是aapt最核心、最复杂的命令。这边我只尝试了一下简单的实践,讲工程的资源编译到一个包里。下面是命令

aapt package -f -S /Users/zfxu/work/androidstudio_workspace/AAPTDemo/app/src/main/res -I /Users/zfxu/Library/Android/sdk/platforms/android-25/android.jar -A /Users/zfxu/work/androidstudio_workspace/AAPTDemo/app/src/main/assets -M /Users/zfxu/work/androidstudio_workspace/AAPTDemo/app/src/main/AndroidManifest.xml -F /Users/zfxu/work/androidstudio_workspace/AAPTDemo/app/out.apk

输出了一个apk文件,解压以后文件格式如下:

这个apk文件除了没有代码dex,资源都在的。这个是aapt打包的关键步骤之一,还有一个步骤就是把资源文件编译成R.java,供程序调用。命令如下:

aapt package -m -J <R.java目录> -S <res目录> -I <android.jar目录>  -M <AndroidManifest.xml目录>

4.aapt r[emove] [-v] file.{zip,jar,apk} file1 [file2 ...]

官方解释:

Delete specified files from Zip-compatible archive

就是从一个zip archive文件中删除一个文件。较简单,不做实例了。

5.aapt a[dd] [-v] file.{zip,jar,apk} file1 [file2 ...]

官方解释:

Add specified files to Zip-compatible archive.

即在一个zip包中添加一个一个指定的文件。

6.aapt c[runch] [-v] -S resource-sources ... -C output-folder ...

官方解释:

Do PNG preprocessing on one or several resource folders and store the results in the output folder.

对多个或者单个资源文件夹进行处理,并且将结果保存在输出文件夹中

6.aapt s[ingleCrunch] [-v] -i input-file -o outputfile

官方解释:

Do PNG preprocessing on a single file

预处理一个文件

相关阅读:Android AAPT 详解(下篇)

本文来自网易实践者社区,经作者徐正峰授权发布。