android 能调用gcc_【连载】聊聊 APK(三) —— Android 资源编译的秘密

43f3280e67043e4b35c33e8d89707a25.png

想进大厂,就关注「 程序亦非猿 」
时不时 8:38 推送优质文章,觉得有用,置顶加星标

船长导读:「聊聊 APK」系列,共 4 篇,由我好基友 Gemini 老师提供

【连载】聊聊 APK——直接运行 Dex文件的黑魔法

【连载】聊聊 APK(二)——Dex 热修复与 Classpath

上两期我们讲了 APK 里面 Dex 的东西,明白了 Dex 只是 classes 的某种打包形式,我们暂时不拘泥于细节,关于代码的部分就告一段落。我们知道除了代码,一个应用里,资源占用了相当大的一部分。

背景

资源本身是很简单的,我们可以理解为一个文件,但是,Android 天生为兼容各种各样不同的设备做了相当多的工作,比如屏幕大小、国际化、键盘、像素密度等等。

我们能为各种各样特定的场景下使用特定的资源做兼容————而不用改动一行代码,这是 Google 对于 Android 设计的初衷。那么,假设我们为各种各样不同的场景适配了不同的资源,如何能快速的应用上这些资源呢?

如果这些场景都需要我们用 if else 一个一个去判断,然后分别使用一个资源的特定某一个图片,那就太浪费我们的力气了。为了解决这个问题,Android 为我们提供了 R 这个类,指定了一个资源的索引(id),然后我们只需要告诉系统 ———— 在这个业务场景下,使用这个资源就好了,至于具体是指定资源里面的某一个具体文件的话,就由系统根据开发者的配置决定吧。

在这种场景下,假设我们给定的 id 是 x 值,那么当下业务需要使用这个资源的时候,手机的状态就是 y 值,有了(x,y),在一个表里面就能迅速的定位到资源文件的具体路径了。在这里我们描述的这个表大家可能很眼熟,就是 resources.arsc,它是怎么来的呢?答案是从 aapt 编译出来的。

使用 aapt 编译资源

以上我们介绍了 Android 加载资源的策略,接下来我们就要介绍资源编译了,为什么资源也需要编译?其实二进制的资源(比如图片)是不需要编译的,只不过这个“编译”的行为,是为了生成 resources.arsc 以及对 xml 文件进行二进制化等操作,resources.arsc 是上面说的表,xml 的二进制化是为了系统读取上性能更好。

AssetManager 在我们调用 R 相关的 id 的时候,就会在这个表里面找到对应的文件,读取出来。其实 R 文件的存在是没有必要的,前提是你知道 id。

当下我们的 build-tools 最新版本是 28.0.3,因为 aapt 已经 deprecated,取而代之的是 aapt2,我们就以 aapt2 为例吧。实话说两者差距还是蛮大的,aapt2 是对 aapt 的改良,但是在我看来,aapt2 并没有非常完善,没有到达完全替代 aapt 的程度。可能 Google 也是这么想的,所以其实 28.0.3 还是带了 aapt 的二进制文件 ———— 只是不让你在 gradle 中用而已(你会发现 android.enableAapt2=false 不起作用)。

学一个东西最重要的是学会如何看文档,所以先贴上文档

https://developer.android.com/studio/command-line/aapt2

这里是对 aapt2 所有命令的解释,Gradle 在编译资源的过程中,就是调用的这个命令,传的参数也在这个文档里都介绍了,只不过对开发者隐藏起了调用细节,今天我们不使用 Gradle,就来揭开 aapt 神秘的面纱了。

首先创建一个项目 ———— 当然可以手动来不经过 Android Studio,我们可以没有代码,只有资源。

那么 aapt2 主要分两步,一步叫 compile,一步叫 link。人家估计就抄 GCC 的。

构造项目

我构造了一个很简单的项目,写了两个 xml,分别是 AndroidManifest.xml 和 activity_main.xml。首先我们要把 activity_main.xml 编译出来(AndroidManifest.xml 后续留做 link 用)。

74f83f30e23944b2138f726029a1c362.png

Compile

调用命令

 ~/Code/MyFirstAndroidApplication/ mkdir compiled ~/Code/MyFirstAndroidApplication/ aapt2 compile src/main/res/layout/activity_main.xml -o compiled/

在 compiled 文件夹中,我们就看见了我们要的 layout_activity_main.xml.flat 这个文件,对 flat 有兴趣的同学可以自行搜索,这里就不再赘述,我们就理解成一个中间产物即可。它是 aapt2 特有的,aapt 没有,aapt2 用它能进行增量编译。如果我们有很多的文件的话,需要依次调用 compile 才行,其实这里也可以使用 --dir 参数,只不过这个参数就没有增量编译的效果了。

Link

那么简单的一个资源文件我们就编译完了。接下来要 link。link 的工作量比 compile 要多一点,我们可以看下 link 相关的参数,最后组装起来。它的 input 是那些 flat,然后还要指定 AndroidManifest,然后指定输出的文件,以及输出的 R.java。

注意,此处的输入是多个 flat 的文件 和 AndroidManifest.xml,外部资源,输出是只包含资源的 apk(如果你曾经研究过的话,你会发现它的后缀名是 ap_)和 R.java。那么我们的命令如下

1 aapt2 link -o out.apk \

2 -I $ANDROID_HOME/platforms/android-28/android.jar \

3 compiled/layout_activity_main.xml.flat \

4 --java src/main/java \

5 --manifest src/main/AndroidManifest.xml

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值