谈一谈如何加快android的项目的编译速度

随着android的组件化的到来,一个项目后期功能越来越多,模块拆分的越来越多,作为android的开发的小伙伴就不得不面对运行一下android项目可能需要5,6分钟甚至10几分钟的等待期,开发时间都浪费在编译上了,你说烦不烦呢!那么怎么解决这个困境,总不能就这么一直凑合着吧,反正也没太大影响开发,只是速度慢了一点而已。

那么怎么让编译加快呢,自从把eclipse改用android studio之后后,出现了一种新的引用格式aar,aar格式是编译好的资源和类,那么有没有一种可能将主模块依赖的的所有模块库转化为aar依赖,在某个模块库变化的时候将它转化为aar依赖,不变化的时候转化为库依赖,那么编译速度会不会大大提高,答案是肯定的了。有人为说了,把库都部署到maven不就行了,当然,maven远程库确实有这个功效,但是,每写一个新的模块库是不是都得把它部署到maven上,有没有一种可能就是写一个脚本插件上这么新的模块自动转化为Maven的库文件,这种方案就就非常ok了。

要实现这个方案,首先咱们要面对以下这些问题:

  • 需要通过 gradle plugin 的形式动态修改没有改动过的 module 依赖为 相对应的 aar 依赖,如果 module 改动,退化成 project 工程依赖,这样每次只有改动的 moduleapp 两个模块编译。
  • 需要把 implement/api moduleB,修改为implement/api aarB,并且需要知道插件中如何加入 aar 依赖和剔除原有依赖
  • 需要构建 local maven 存储未被修改的 module 对应的 aar(也可以通过 flatDir 代替速度更快)
  • 编译流程启动,需要找到哪一个 module 做了修改
  • 需要遍历每一个 module 的依赖关系进行置换, module 依赖怎么获取?一次性能获取到所有模块依赖,还是分模块各自回调?修改其中一个模块依赖关系会阻断后面模块依赖回调?
  • 每一个 module 换变成 aar 之后,自身依赖的 child 依赖 (网络依赖,aar),给到 parent module (如何找到所有 parent module) ? 还是直接给 app module ? 有没有 appmodule 依赖断掉的风险? 这里需要出一个技术方案。
  • 需要hook 编译流程,完成后置换 loacal maven 中被修改的 aar
1、如何手动添加 aar 依赖,分析implement 源码实现入口在 DynamicAddDependencyMethods 中的 tryInvokeMethod 方法。他是一个动态语言的 methodMissing 功能
 public DynamicInvokeResult tryInvokeMethod(String name, Object... arguments) {//省略部分代码 ...return DynamicInvokeResult.found(this.dependencyAdder.add(configuration, normalizedArgs.get(0), (Closure)null));}private class DirectDependencyAdder implements DependencyAdder<Dependency> {private DirectDependencyAdder() {}public Dependency add(Configuration configuration, Object dependencyNotation, @Nullable Closure configureAction) {return DefaultDependencyHandler.this.doAdd(configuration, dependencyNotation, configureAction);}}public Dependency add(String configurationName, Object dependencyNotation) {return this.add(configurationName, dependencyNotation, (Closure)null);}public Dependency add(String configurationName, Object dependencyNotation, Closure configureClosure) {//这里直接调用到了 doAdd return this.doAdd(this.configurationContainer.getByName(configurationName), dependencyNotation, configureClosure);}

doAdd 方法三个参数通过 debug 源码发现,configuration 就是 "implementation", "api", "compileOnly" 这三个字符串生成的对象,dependencyNotation 是一个 LinkHashMap 有两个键值对,分别是 name:aarName, ext:aar,最后一个configureActionnull 就可以了,调用 project.dependencies.add 最终会调到 doAdd 方法,也就是说直接调用 add 即可。

2、localMave 优先使用 flatDir 实现通过指定一个缓存目录 getLocalMavenCacheDir 把生成 aar/jar 包丢进去,依赖修改时候通过 上面的 4.1 添加对应的 aar 即可

fun flatDirs() {val map = mutableMapOf<String, File>()map.put("dirs", File(getLocalMavenCacheDir()))appProject.rootProject.allprojects {it.repositories.flatDir(map)}}

3、编译流程启动,需要找到哪一个 module做了修改

  • 使用遍历整个项目的文件的 lastModifyTime 去做实现
  • 已每一个 module 为一个粒度,递归遍历当前 module 的文件,把每个文件的 lastModifyTime 整合计算得出一个唯一标识 countTime
  • 通过 countTime 与上一次的作对比,相同说明没改动,不同则改动. 并需要同步计算后的 countTime 到本地缓存中

计算每个module文件改变的时间代码如下:

  project.rootProject.allprojects.onEach {if (it == project.rootProject || it.childProjects.isNotEmpty()) {return@onEach}var countTime = 0Lit.projectDir.eachFileRecurse { file ->// 过滤掉build目录及该目录下的所有文件isCodeFile = !(file.isDirectory && Contants.BUILD == file.name)if (isCodeFile) {countTime += file.lastModified()count++}return@eachFileRecurse isCodeFile}newModuleList.add(ModuleChangeTime(it.path, countTime))}

原理就是将所有moudle下的代码和资源的最后修改时间累加,在编译的时候对比前后时间,如果一只就用aar依赖,如果不一致就用项目依赖。

4、module 依赖关系 project 替换成 aar 技术方案

  • 每一个 module 依赖关系替换的遍历顺序是无序的,所以技术方案需要支持无序的替换
  • 目前使用的方案是:如果当前模块 A 未改动,需要把 A 通过 localMaven 置换成 A.aar,并把 A.aar 以及 Achild 依赖,给到第一层的 parent module 即可

5、hook 编译流程,完成后置换 loacal maven 中被修改的 aar

  //如果当前模块是改动模块,需要打 aarif (mAllChangedProject?.contains(childProject.path) == true) {//打包aarval bundleTask = getBundleTask(childProject, buildType.capitalize())?.apply {task.configure {it.finalizedBy(this)}}if (enableLocalMaven) {// publish local mavenbundleTask?.let { bTask ->LogUtil.d("bTask=$bTask")val buildType = if (bTask.name.contains("release")) {"Release"} else {"Debug"}try {val publishMavenTask =childProject.project.tasks.named("publishMaven${buildType}PublicationToLocalRepository").orNullpublishMavenTask?.let {bTask.finalizedBy(it)}} catch (e: Throwable) {e.printStackTrace()}}} else {//copy aarval localMavenTask =childProject.tasks.maybeCreate("uploadLocalMaven" + buildType.capitalize(),FlatTask::class.java)localMavenTask.localMaven = this@AarFlatLocalMavenbundleTask?.finalizedBy(localMavenTask)}}

这些代码的意思就是获取将每个moudle转化为aar的任务,然后在这个任务结束后创建新的任务FlatTask将这些aar放到localMaven中。FlatTask源码如下

 open class FlatTask : DefaultTask() {@Internalvar inputPath: String? = null@Internalvar inputFile: File? = null@Internalvar outputPath: String? = null@Internalvar outputDir: File? = null@Internallateinit var localMaven: AarFlatLocalMaven@TaskActionfun uploadLocalMaven() {val flatAarName = getFlatAarName(project)this.inputPath = FileUtil.findFirstLevelAarPath(project)this.outputPath = FileUtil.getLocalMavenCacheDir()inputFile = inputPath?.let { File(it) }outputDir = File(this.outputPath)inputFile?.let {File(outputDir, flatAarName + ".aar").let { file ->if (file.exists()) {file.delete()}}it.copyTo(File(outputDir, flatAarName + ".aar"), true)localMaven.putIntoLocalMaven(flatAarName, flatAarName + ".aar")}}}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/47956.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python分析实战(4)--获取某音热榜

1. 分析需求 打开某音热搜&#xff0c;选择需要获取的热榜如图 查找包含热搜内容的接口返回如图 将url地址保存 2. 开发 定义请求头 headers {Cookie: 自己的cookie,Accept: application/json, text/plain, */*,Accept-Encoding: gzip, deflate,Host: www.douyin.com,…

陕西科技大学改考408!附考情分析

改考信息 8月14日&#xff0c;陕西科技大学公布了2024年硕士研究生招生目录&#xff08;初稿&#xff09;&#xff0c;其中不难发现083500软件工程初试专业课由819数据结构改为408计算机学科专业基础 图片&#xff1a;陕西科技大学24专业目录-软件工程学硕 https://yjszs.sus…

eslint 配置和用法

在一个使用Webpack的项目中配置ESLint&#xff0c;你可以按照以下步骤操作&#xff1a; 首先&#xff0c;你需要在你的项目中安装ESLint和对应的Webpack loader。你可以使用npm或者yarn来安装。在你的项目根目录下打开终端&#xff0c;然后运行以下命令&#xff1a; 使用npm&…

优化指南:带宽限制的可行策略

大家好&#xff01;作为一名专业的爬虫程序员&#xff0c;我们经常面临的一个挑战就是带宽限制。尤其是在需要快速采集大量数据时&#xff0c;带宽限制成为了我们提升爬虫速度的一大阻碍。今天&#xff0c;我将和大家分享一些解决带宽限制的可行策略&#xff0c;希望能帮助大家…

LeetCode //C - 71. Simplify Path

71. Simplify Path Given a string path, which is an absolute path (starting with a slash ‘/’) to a file or directory in a Unix-style file system, convert it to the simplified canonical path. In a Unix-style file system, a period ‘.’ refers to the curr…

[C++ 网络协议编程] 域名及网络地址

1. DNS服务器 DNS&#xff08;Domain Name System&#xff09;&#xff1a;是对IP地址和域名&#xff08;如:www.baidu.com等&#xff09;进行相互转换的系统&#xff0c;其核心是DNS服务器。 我们输入的www.baidu.com是域名&#xff0c;是一种虚拟地址&#xff0c;而非实际地…

微服务篇

微服务篇 springcloud 常见组件有哪些 面试官&#xff1a; Spring Cloud 5大组件有哪些&#xff1f; 候选人&#xff1a; 早期我们一般认为的Spring Cloud五大组件是 Eureka&#xff1a;注册中心Ribbon&#xff1a;负载均衡Feign&#xff1a;远程调用Hystrix&#xff1a;…

UE5 groom 毛发转Abc文件

将metahuman groom资产导出到blender二次编辑并倒回到引擎的教程. 这个视频里面有groom 毛发转Abc文件的插件

leetcode 1996. 游戏中弱角色的数量(排序的魅力)

题目 题意: 给定n个人的攻击力和防御力&#xff0c;对于一个人来说&#xff0c;如果存在某个人的攻击力和防御力都比他高&#xff0c;那么称这个人为弱角色。统计弱角色的数量 思路: 排序&#xff0c;攻击力按从大到小排序&#xff0c;这样遍历的时候某个数时前边的攻击力都比他…

或的方式触发多个条件

或的方式触发多个条件 #include <iostream> using namespace std; typedef enum Binary {ConditionA 0x0, ConditionB 0x1, ConditionC 0x2, ConditionD 0x4, ConditionE 0x8, ConditionF 0x10,ConditionG 0x20,ConditionH 0x40,ConditionI 0x80 }Bin;void func…

C# API 文档注释规范

C# API 文档注释规范 1. 命名空间注释(namespace)2. summary3. remarks and para4. param5. returns6. example and code7. exception8. typeparam 最近在开发工作中需要实现 API 帮助文档&#xff0c;如果根据所写的代码直接重写 API 帮助文档将会是意见非常大的工作量&#x…

新版本Qt Creator无法提示错误、不报红

问题 更新新版本Qt Creator后无法实时提示错误&#xff0c;在开发中非常难受 如图&#xff0c;此时w后面少了;Qt Creator却只有红色横线标识&#xff0c;没有具体的错误。 解决方法 首先要知道&#xff0c;提供这个错误显示功能是ClangCodeModel插件提供的&#xff0c;因此…

ModaHub魔搭社区:AI Agent在操作系统场景下的AgentBench基准测试

近日,来自清华大学、俄亥俄州立大学和加州大学伯克利分校的研究者设计了一个测试工具——AgentBench,用于评估LLM在多维度开放式生成环境中的推理能力和决策能力。研究者对25个LLM进行了全面评估,包括基于API的商业模型和开源模型。 他们发现,顶级商业LLM在复杂环境中表现出…

外网连接局域网的几种方式?快解析内网穿透安全便利吗?

外网连接局域网是一项网络连接中的关键技术&#xff0c;它能够让远程用户通过互联网访问内部局域网中的资源和服务。外网连接局域网为企业提供了更大的灵活性和便捷性&#xff0c;但也需要严格的安全措施来防止未经授权的访问。 外网连接局域网的几种方式 在将外网连接到局域…

Ubuntu发布java版本

1、连接服务器 2、进入目录 cd /usr/safety/app/3、上传jar文件 4、杀掉原java进程 1. 查看当前java进程 2. ps -ef|grep java 3. ycmachine:/usr/safety/app$ ps -ef|grep java root 430007 1 6 01:11 pts/0 00:02:45 /usr/local/java/jdk1.8.0_341/bin/j…

ChatGLM2-6B、ChatGLM-6B 模型介绍及训练自己数据集实战

介绍 ChatGLM-6B是开源的文本生成式对话模型,基于General Language Model(GLM)框架,具有62亿参数,结合模型蒸馏技术,实测在2080ti显卡训练中上(INT4)显存占用6G左右, 优点:1.较低的部署门槛&#xff1a; FP16 半精度下&#xff0c;ChatGLM-6B 需要至少 13GB 的显存进行推理&a…

算法工程题(记忆化搜索)

* 题意说明&#xff1a; * 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 * 每次你可以爬 1 或 2 个台阶。你有多 * * 示例 1&#xff1a; * 输入&#xff1a;n 2 * 输出&#xff1a;2 * 解释&#xff1a;有两种方法可以爬到楼顶。 * 1. 1 阶…

ARM M33架构入门

概述 Arm Cortex-M33核心处理器专为需要高效安全或数字信号控制的物联网和嵌入式应用而设计。该处理器具有许多可选功能&#xff0c;包括数字信号处理扩展 (DSP)、用于硬件强制隔离的TrustZone 安全性、内存保护单元 (MPU)和浮点单元 (FPU)。 Cortex-M33 的性能比 Cortex-M…

I2S/PCM board-level 约束及同步(latencyskewbitsync)

I2S/PCM是典型的低速串口&#xff0c;在两个方向上分别有两组信号&#xff0c;我们已soc为视角分为soc-adif和外设audio-codec。 那么adif输入&#xff1a; sclk_i, ws_i, sdi 当然并不是三个输入信号同时有效&#xff0c;只有adif RX slave时&#xff0c;三个输入都会有效…

Python爬虫(十四)_BeautifulSoup4 解析器

CSS选择器&#xff1a;BeautifulSoup4 和lxml一样&#xff0c;Beautiful Soup也是一个HTML/XML的解析器&#xff0c;主要的功能也是如何解析和提取HTML/XML数据。 lxml只会局部遍历&#xff0c;而Beautiful Soup是基于HTML DOM的&#xff0c;会载入整个文档&#xff0c;解析整…