Apk2Aar,关于如何用Apk转Aar

探讨apk转aar的可行性

碎碎念

最近不忙了,闲下来就有时间去思考,如何让打包更轻松(写更少的脚本,做更少的事情)。因为工作的原因,日常不是在打包就是在修改打包脚本的路上。这边想采用apk转aar的主要原因是想直接通过AS来出包了,在我的猜想下,打包速度应该会提升,并且不需处理目前使用apktool解包替换资源回编,遇到的各种问题。但是现实往往与想象差距甚远,打包速度并没有明显的提升(哪怕少了解包的这个过程,对比apktool的完成流程并没有占据较大的优势)。而且转aar本身也需要使用到apktool(毕竟有人维护,而且一直以来也是用他 )。

前期查资料阶段,先给出我觉得有用的资料

库配置不正确

如果您的应用依赖于使用旧版 Android SDK Build Tools 构建的第三方库,您的应用可能会在运行时崩溃,且不会显示任何错误或警告。之所以会发生此崩溃,可能是因为在创建库的过程中,将 R.java 字段声明为 final,从而导致所有资源 ID 都被内嵌在该库的类中。

AAPT2 依赖于在构建应用时能够将 ID 重新分配给库资源。如果该库将这些 ID 视为 final 并将其内嵌在库 dex 中,便会出现运行时不匹配的情况。

如需解决此错误,请与库创建者联系,以使用最新版本的 Android SDK Build Tools 重新构建该库,然后重新发布该库。

从 res/ 读取资源的唯一方法是使用资源 ID

保存在 assets/ 目录中的文件没有资源 ID,因此您无法通过 R 类或在 XML 资源中引用它们。您可以改为采用类似普通文件系统的方式查询 assets/ 目录中的文件,并利用 AssetManager 读取原始数据。

不过,如果您只需要读取原始数据(例如视频文件或音频文件)的能力,则可将文件保存在 res/raw/ 目录中,并利用 openRawResource() 读取字节流。

结论

根据上面分析可知,如果我们通过修改apk,把dex里面视为 'final', 的代码 修改为引用R.java文件,并把分散在不同路径的R文件合并为一个(把不同的引用都指向同一个), 并生成R.txt , 那么Apk文件是可以转化为AAR的
转换为AAR的好处主要就是,可以直接通过AS出包(免去处理拆分dex,65536的烦恼, 替换资源文件,以及理论上应该能提升打包速度==》指二次打包,并且as能帮我们处理合并AndroidMainfests)
诚然,如果cp能直接提供aar是最好的,但是很多时候拿到我们手里的都是apk,为此以往都是采用apk二次打包,运用apktool解包,大部分都是通过python脚本来修改文件。

与 JAR 文件不同,AAR 文件会为 Android 应用提供以下功能:
  • AAR 文件可以包含多项 Android 资源和一个清单文件,让您除了能够在 Java 类和方法中进行捆绑以外,还能够在布局和可绘制对象等共享资源中进行捆绑。
  • AAR 文件可以包含 C/C++ 库,供应用模块的 C/C++ 代码使用。
库模块开发注意事项

在开发库模块和相关应用时,请注意以下行为和限制。

向 Android 应用模块添加对库模块的引用后,您可以设置它们的相对优先级。在构建时,库会按照优先级由低到高的顺序逐一与应用合并。

  • 资源合并冲突

    构建工具会将库模块中的资源与相关应用模块的资源合并。如果这两个模块中都定义了给定的资源 ID,系统会使用应用中的资源。

    如果多个 AAR 库之间发生冲突,系统会使用依赖项列表中首先列出的库(靠近 dependencies 块顶部)中的资源。

    为了避免常用的资源 ID 发生资源冲突,请考虑使用对模块具有唯一性(或在所有项目模块之间具有唯一性)的前缀或其他一致的命名方案。

  • 在多模块构建中,系统会将 JAR 依赖项视为传递依赖项

    在向输出 AAR 的库项目添加 JAR 依赖项时,JAR 会由库模块进行处理,并与其 AAR 打包在一起。

    不过,如果您的项目包含库模块,并且此模块已被应用模块使用,应用模块便会将库的本地 JAR 依赖项视为传递依赖项。在这种情况下,本地 JAR 将由使用它的应用模块进行处理,而不是由库模块进行处理。这是为了加快库代码更改导致的增量构建的速度。

    由本地 JAR 依赖项导致的所有 Java 资源冲突都必须在使用相应库的应用模块中解决。

  • 库模块可以依赖于外部 JAR 库

    您可以开发一个依赖于外部库(例如 Google 地图外部库)的库模块。在这种情况下,相关应用必须针对包含此外部库的目标(例如 Google API 插件)进行构建。另外也要注意,库模块和相关应用都必须在其清单文件的 <uses-library> 元素中声明外部库。

  • 应用模块的 minSdkVersion 必须等于或大于库定义的版本

    库是作为相关应用模块的一部分进行编译的,因此,库模块中使用的 API 必须与应用模块支持的平台版本兼容。

  • 每个库模块都会创建自己的 R 类

    在您构建相关应用模块时,库模块会先编译到 AAR 文件中,然后再添加到应用模块中。因此,每个库都有自己的 R 类,并根据库的软件包名称命名。所需的所有软件包中都会创建从主模块和库模块生成的 R 类,包括主模块的软件包和库的软件包。

  • 库模块可以包含自己的 ProGuard 配置文件

    如果有用于构建和发布 AAR 的库项目,您可以向库的构建配置添加 ProGuard 配置文件,并且 Android Gradle 插件规则适用于您指定的 ProGuard 规则。构建工具会将此文件嵌入到为库模块生成的 AAR 文件中。在您将库添加到应用模块后,库的 ProGuard 文件会附加到应用模块的 ProGuard 配置文件 (proguard.txt)。

    通过将 ProGuard 文件嵌入到库模块中,您可以确保依赖于相应库的应用模块不必手动更新其 ProGuard 文件即可使用此库。当 Android Studio 构建系统构建您的应用时,它会同时使用来自应用模块和库的指令。因此无需按照单独的步骤在库上运行代码缩减器。

    如需向库项目添加 ProGuard 规则,您必须使用 consumerProguardFiles 属性(位于库的 build.gradle 文件的 defaultConfig 块内)指定文件名称。例如,以下代码段会将 lib-proguard-rules.txt 设为库的 ProGuard 配置文件:

    不过,如果库模块是要编译到 APK 中的多模块构建的一部分,并且不会生成 AAR,您应该只在使用相应库的应用模块上运行代码缩减。如需详细了解 ProGuard 规则及其用法,请参阅缩减、混淆处理和优化应用

  • 测试库模块的方法与测试应用的方法相同

    主要区别在于,库及其依赖项会作为测试 APK 的依赖项自动包含在内。这意味着测试 APK 不仅包含自己的代码,还包含库的 AAR 及其所有依赖项。由于没有单独的“被测应用”,因此 androidTest 任务只会安装(和卸载)测试 APK。

    合并多个清单文件时,Gradle 会遵循默认的优先级顺序,并将库的清单合并到测试 APK 的主清单中。

AAR 文件详解

AAR 文件的文件扩展名为 .aar,Maven 工件类型应该也是 aar。此文件本身是一个 zip 文件。唯一的必需条目是 /AndroidManifest.xml

此外,AAR 文件可能包含以下一个或多个可选条目:

  • /classes.jar
  • /res/
  • /R.txt
  • /public.txt
  • /assets/
  • /libs/name.jar
  • /jni//abi_name/name.so(其中abi_name是 Android 支持的 ABI 之一)
  • /proguard.txt
  • /lint.jar
  • /api.jar
  • /prefab/(用于导出原生库

开始

在查阅了大量资料,并思考后,我得出了apk可以转换成aar的结论.并手动通过apk生成了一个aar然后导入到工程里面,并成功运行后,开始着手编码的过程。

首先,随便搞个apk和aar然后进行对比(同一个工程的同一个model)


aar.png
apk.png

大部分文件都认识,除了R.txt ,于是双击

R.txt.png

这看起来有点类似public.xml的文件,那就根据public.xml来生成R.txt吧,然后用Sublime来用public.xml生成R.txt,然后悲催的发现行数对不上,对比发现少了styleable (之前修正ApkIdTool填坑也是这个老朋友)
image.png

事已至此,不能简单的由public.xml生成R.txt,所以我不由得开始琢磨起这R文件是用来干嘛的了。

官方关于aar的说明

官方文档关于aar上明确说明aar文件本身是一个 zip 文件。唯一的必需条目是 /AndroidManifest.xml。
那就直接删掉aar的R.txt然后直接运行项目,结果就是程序崩毁日志显示找不到对应的R文件,那么这个R文件应该是用来生成R.java的吧

画重点

在查阅了大量资料与实践之后得出R.txt 是决定在aar的包名下生成R文件的内容, 所以有无R.txt将决定是否在aar文件的AndroidMainFest.xml的packageName下的路径下创建R.java

那么?!嗯?

可能有的小伙伴已经想到了我要干嘛了。apk文件本身就包含了常量化的资源id,如果我按照as生成的aar的方式生成aar,那我就需要把常量化的资源id改成动态引用包名下的R文件的对应id,并生成R.txt。然后我还需要把用来固定资源id的apk解包后生成的public.xml文件给删除掉。单单就对资源id由final改成动态引用,我就要做这么多操作!

既然apk已经分配了id而且也有了固定资源id的public.xml,那么我能不能直接就用这些常量化的id呢?于是,我又手动合成了一个aar,运行没有任何问题。

其实理论上也是不存在任何问题的,因为最后都是调用aapt2来生成资源id,当项目引用aar的时候,res里面包含public.xml,那也就是提前固定了对应的资源id而已,当不存在public.xml的资源也就不存在固定,也就重新生成资源id。并没有任何问题。(在写游戏sdk方面,一般都不使用R.id的方式来获取资源id。很大一部分原因就是为了规避资源id重新分配,导致的id错乱问题。关于为什么使用动态方式获取id就不会有这个问题,可以参考抖音的分享,文中称为资源文件反射我更愿意称动态获取资源id

有了上述的理论支持,那么由apk2aar可以简化成如下图所示

apk2aar.png

1.关于AndroiManifest.xml的修改,可以参考合并aar,主要按照as生成 aar的AndroidManifest.xml的形式去修改
2.关于unknown文件,我之所以这么做是基于引入了okhttp后,apk解包后会在unknown下有publicsuffixes.gz,而我这么做也是根据引用okhttp后生成的aar来的(用fat-aar,为我节省了思考的时间,感谢)
3.用dex2jar提取jar,并删除需要替换的类(因为需要更新这部分代码),资源不用做处理,因为如果多个 AAR 库之间发生冲突,系统会使用依赖项列表中首先列出的库(靠近 dependencies 块顶部)中的资源。

所以我又写了代码,整合到了tool里面,使用请参考。因为代码还很粗糙,按照最开始的设想转aar只需运行一次所以并没有过多考虑性能。并且由于使用aar用as出包并没有速度上的优势,已经失去了继续的动力(按照最开始的想法,因为转aar一次性的耗费的时间先忽略,那么打包因为没了apktool的解包回编,理论上只有编译apk这步,速度应该明显提升。但是事与愿违,实测并没有优势),所以,也就没必要优化,而且由于,缺少大量样本,可能存在,我认知外的情况。
希望能起到抛砖引玉的作用,共勉。

ps:
补充说明:AS的aar之所以不用固定id是因为多个aar的话可能有冲突,我目前的使用因为我能确保只有一个aar是用固定id的所以不会出现问题

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

推荐阅读更多精彩内容