聊聊 APK —— AAR 的合并进 APK

我们知道,Android 对于多人协作的方式,是使用 AAR 作为 Android 的库来给 App 引入参与编译的。Android 之于 Java 应用,在编译上最大的不同有两个,一个是 res 下面的资源,一个是 class 文件需要转成 dex 文件才能被加载和运行。

那么,在 AAR 的使用过程中,我们的 Gradle 到底对 AAR 做了什么动作呢?其实这部分内容,在以下的文章提过一些,不过我们今天想再仔细讲讲资源。

Gradle Builds Everything —— 处理依赖(aar)

我们来看看 AAR 中存在的东西

如果你解压看 classes.jar,可以看到里面就是 class 文件。

然后 res 下面是资源文件,这些资源文件都还没经过压缩

然后是一个 R.txt

image.gif

那么,这里只有一个 R.txt,如果我们仔细检查 classes.jar,发现里面也没有带 R.class 或者 R.java,这是为什么呢?

R 与资源

如果我们去看一个 apk 的 R 文件,它里面看 smali 字节码是这样的:

其实里面存的都是一个 int 值,大部分还是 0x7f 开头,我们把他们叫做 id,或者资源的索引
既然在这看见了索引,索引所指向的条目在哪里呢?答案是resources.arsc这个文件:

注意到 ID 这一栏,是不是特别熟悉?我们把右边的列结合起来看。我想你一下子就明白这个意思了

ID 是索引,根据 R 指明的 ID,结合手机当下的场景,比如 v20,v21 等使用特定的资源,如果没有找到相关的资源,就使用 default 下的资源。

这样我们就实现了机器自动找资源的功能,R 最伟大的功能就明了了 —— 从 resources.arsc 这个文件中,根据特定的场景,找到正确的资源并加载。开发无需再在代码里判断机器当时的场景来做特定的处理了。这的确大大简化了国际化等功能的开发。

那么新的问题来了,为什么 aar 里面不带 R 这个文件呢?

R 文件的生成

首先我们来看 ID 这个值,显然这个值不能重复,假设 aar 里面带了 R,意味着这个 R 里面的值需要保证唯一,那么如果互联网上有这么多的 aar,里面的 R 都需要维护「全局唯一性」未必要求也太高了点,一个低成本的做法是:

把 AAR 在合并进 apk 的过程中,对所有的资源 ID 进行重生成,使得这个 R 在这个 app 内全局唯一。

这件事比起全世界 R 唯一就简单很多,那么说完了 R 的原理和 ID 生成逻辑,我们就要说说这件事是怎么做到的了。

R 的 regeneration

我们清楚的知道一点,一个 aar 里面的代码,当然可以使用自己的一些资源文件,即有自己的 R;那么同时,使用这个 AAR 的 App 自然也要用到这个 aar 里的资源文件。那么这个生成就有讲究了。

第一件事,提醒各位注意到,我们在写 library 的过程中,生成的 R 文件的 id —— 比如 R.id.textview 它的声明是非 final 的,直观一点,就是我们不可以在 library 中这么写:

switch(view.getId()){   case R.id.textview: {       //....       break;   }}

为什么呢?因为如果这里的 R.id.textview 是 final 的话,可能在编译 class 的过程中,被直接内敛,编译后的代码可能是这样:

switch(view.getId()){   case 0x7f000001: {       //....       break;   }}

假设这时候我们在 app 合并 AAR 的过程中重新生成了 id,那么这个 0x7f000001 指向的资源,几乎肯定不是原先我们想要的 R.id.textview,所以在 library module 中,AGP 不会生成带 final 的 R,我们用 if 改写 switch 的方案就是这样:

if (view.getId() == R.id.textview) {    // .....}

那么编译后,R 也不会被编译器优化内联。

还有一件事不要忘了,我们所有编译出的 R 都是带一个包名的,也就是说,如果你的 library module 中的 AndroidManifest.xml 写的 package 值是 com.gemini.demo.library (作为例子)的话,那么你生成的 R 的完整类名就是

com.gemini.demo.library

R 在 App 工程中的合并

那么,刚刚在 library module 编译出的 aar 中我们没有找到 R 这个类,最终在 app 中我们是如何运行的呢?群里朋友交流「手工创建 APK」的时候就碰到这样的问题:

在 app 最终编译出 apk 的过程中,因为缺少了 AAR 中的 R,导致 apk 包找不到类的错误。

这里引用下一位朋友的截图,大概是这样:

那么,gradle 或者 android gradle plugin 是怎么解决这个问题的呢?

其实很简单,android gradle plugin 事实上是针对合并进来的 aar 的资源重新根据 aar 的 package 生成了一次 R,我们来看看证据,我们在 app 的工程中,中间产物找到这么一个文件:

反编译后我们可以看见这些类

注意到,我们所有引入的 aar,都根据 package 的值生成了一份 R。同时,我们 app package 下面也生成了一份 R。

这份 R 是所有引入 aar + app 工程资源的一份汇总和冗余,请注意,这里所有的 R 全是 final 的值,因为已经在最终合并阶段了。

这样我们就解决了刚刚说的 library R 的类找不到的问题。

本文在开源项目:https://github.com/Android-Alvin/Android-LearningNotes 中已收录,里面包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中...

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容