最近不忙了,闲下来就有时间去思考,如何让打包更轻松(写更少的脚本,做更少的事情)。因为工作的原因,日常不是在打包就是在修改打包脚本的路上。这边想采用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脚本来修改文件。
在开发库模块和相关应用时,请注意以下行为和限制。
向 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,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)


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


事已至此,不能简单的由public.xml生成R.txt,所以我不由得开始琢磨起这R文件是用来干嘛的了。
官方文档关于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可以简化成如下图所示

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的所以不会出现问题
最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路
A/ctohttp://wiki.nginx.org/CoreModule#usermaster进程曾经以root用户运行,是否可以以不同的用户运行nginxmaster进程? 最佳答案 只需以非root身份运行init脚本(即/etc/init.d/nginxstart),就可以用不同的用户运行nginxmaster进程。如果这真的是你想要做的,你将需要确保日志和pid目录(通常是/var/log/nginx&/var/run/nginx.pid)对该用户是可写的,并且您所有的listen调用都是针对大于1024的端口(因为绑定(
我在我的rails应用程序中安装了来自github.com的acts_as_versioned插件,但有一段代码我不完全理解,我希望有人能帮我解决这个问题class_eval我知道block内的方法(或任何它是什么)被定义为类内的实例方法,但我在插件的任何地方都找不到定义为常量的CLASS_METHODS,而且我也不确定是什么here,并且有问题的代码从lib/acts_as_versioned.rb的第199行开始。如果有人愿意告诉我这里的内幕,我将不胜感激。谢谢-C 最佳答案 这是一个异端。http://en.wikipedia
我正在尝试解决http://projecteuler.net/problem=1.我想创建一个方法,它接受一个整数,然后创建一个包含它前面的所有整数的数组,并将整数本身作为数组中的值。以下是我目前所拥有的。代码不起作用。defmake_array(num)numbers=Array.newnumcount=1numbers.eachdo|number|numbers 最佳答案 (1..num).to_a是您在Ruby中需要做的全部。1..num将创建一个Range对象,以1开始并以任意值num结束是。Range对象有to_a方法通过
我有这样的HTML代码:Label1Value1Label2Value2...我的代码不起作用。doc.css("first").eachdo|item|label=item.css("dt")value=item.css("dd")end显示所有首先标记,然后标记标签,我需要“标签:值” 最佳答案 首先,您的HTML应该有和中的元素:Label1Value1Label2Value2...但这不会改变您解析它的方式。你想找到s并遍历它们,然后在每个你可以使用next_element得到;像这样:doc=Nokogiri::HTML(
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。我最近开始学习Ruby,这是我的第一门编程语言。我对语法感到满意,并且我已经完成了许多只教授相同基础知识的教程。我已经写了一些小程序(包括我自己的数组排序方法,在有人告诉我谷歌“冒泡排序”之前我认为它非常聪明),但我觉得我需要尝试更大更难的东西来理解更多关于Ruby.关于如何执行此操作的任何想法?
我在游戏和帐户模型之间存在多对多关系,如下所示:classAccount:destroyhas_many:games,:through=>:account_gamesendclassGame:destroyhas_many:accounts,:through=>:account_gamesendclassAccountGame现在我知道让我们说我想创建一个类似这样的记录:@account=Account.new(params[:user])@account.games但是我应该如何在执行此操作时更新AccountGame中的某些属性?假设AccountGame有一些名为score的字段
我在Ruby中遇到了一个关于Dir[]和File.join()的简单程序,blobs_dir='/path/to/dir'Dir[File.join(blobs_dir,"**","*")].eachdo|file|FileUtils.rm_rf(file)ifFile.symlink?(file)我有两个困惑:首先,File.join(@blobs_dir,"**","*")中的第二个和第三个参数是什么意思?其次,Dir[]在Ruby中有什么用?我只知道它等价于Dir.glob(),但是,我对Dir.glob()确实不是很清楚。 最佳答案
1.回顾.TransportServicepublicclassTransportServiceextendsAbstractLifecycleComponentTransportService:方法:1publicfinalTextendsTransportResponse>voidsendRequest(finalTransport.Connectionconnection,finalStringaction,finalTransportRequestrequest,finalTransportRequestOptionsoptions,TransportResponseHandlerT>
目录一.大致如下常见问题:(1)找不到程序所依赖的Qt库version`Qt_5'notfound(requiredby(2)CouldnotLoadtheQtplatformplugin"xcb"in""eventhoughitwasfound(3)打包到在不同的linux系统下,或者打包到高版本的相同系统下,运行程序时,直接提示段错误即segmentationfault,或者Illegalinstruction(coredumped)非法指令(4)ldd应用程序或者库,查看运行所依赖的库时,直接报段错误二.问题逐个分析,得出解决方法:(1)找不到程序所依赖的Qt库version`Qt_5'