Android基于gradle task检查各个module之间资源文件冲突情况

做组件化开发的时候,我们经常会遇到各个不同的module之间资源文件冲突的问题,运行也不报错,但是会出现覆盖的问题,导致运行之后发送错误的效果。

所以我们需要利用一个gradlke 脚本task,来自动化检查资源文件冲突。

定义一个android gradle脚本,检查各个module之间资源文件冲突(命令重复)的task。

Android基于gradle task检查各个module之间资源文件冲突情况 点击查看原文

Android不同module资源布局文件重名被覆盖

下面是一个完整的 Gradle 脚本示例,用于检查不同模块之间的资源文件冲突。这个任务将遍历所有子模块的资源文件,并在发现同名文件时输出冲突信息。脚本中包含了详细的注释,便于理解每个步骤。

1. 根 build.gradle 文件

在项目的根目录下的 build.gradle 文件中定义任务:

groovy复制代码// 根 build.gradle 文件
buildscript {
    repositories {
        google()
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:8.1.1' // 请根据需要调整版本
    }
}

allprojects {
    repositories {
        google()
        mavenCentral()
    }
}

task checkResourceConflicts {
    doLast {
        def resourceFiles = [:] // 存储资源文件,键是文件名,值是包含文件路径和模块名的 Map

        // 遍历所有子模块
        subprojects { subproject ->
            // 检查子模块是否有 Android 配置
            if (subproject.hasProperty('android')) {
                subproject.android.sourceSets.each { sourceSet ->
                    sourceSet.res.srcDirs.each { resDir ->
                        if (resDir.exists()) {
                            println("Scanning resources in module: ${subproject.name}, path: ${resDir.absolutePath}")

                            // 遍历资源目录中的文件
                            resDir.eachFileRecurse { file ->
                                if (file.isFile() && file.name.endsWith(".xml")) {
                                    def fileName = file.name
                                    def moduleName = subproject.name // 当前模块名

                                    // 检查文件名是否已存在
                                    if (resourceFiles.containsKey(fileName)) {
                                        def existingFileInfo = resourceFiles[fileName]
                                        if (existingFileInfo.moduleName != moduleName) {
                                            // 如果文件名来自不同模块,报告冲突
                                            println "Resource conflict detected: ${fileName} exists in both ${existingFileInfo.moduleName} (${existingFileInfo.filePath}) and ${moduleName} (${file.absolutePath})"
                                        }
                                    } else {
                                        // 存储文件路径及模块名
                                        resourceFiles[fileName] = [filePath: file.absolutePath, moduleName: moduleName]
                                    }
                                }
                            }
                        } else {
                            println("No resources found in: ${resDir.absolutePath}")
                        }
                    }
                }
            } else {
                println("Skipping module: ${subproject.name} (no Android configuration)")
            }
        }

        println("Resource conflict check completed.")
    }
}

// 在构建之前执行检查任务
gradle.projectsEvaluated {
    tasks.named("preBuild").configure {
        dependsOn(checkResourceConflicts)
    }
}

2. 代码说明

  • 任务 checkResourceConflicts
    • 遍历所有子模块,检查每个模块的资源文件。
    • 使用 subprojects 来遍历每个子模块。
    • 检查每个模块是否包含 android 配置。
    • 如果存在资源文件,逐一检查是否有同名文件。
    • 如果检测到同名文件,输出冲突信息,包含模块名和文件路径。
  • preBuild 任务的依赖
    • 在所有项目评估完成后,将 checkResourceConflicts 任务与 preBuild 任务关联,这样每次构建都会执行检查。

3. 使用步骤

  1. 在项目根目录的 build.gradle 文件中添加以上代码

  2. 确保 settings.gradle 文件中包含所有子模块,例如:

    groovy
    
    
    复制代码
    include ':app', ':module1', ':module2'
    
  3. 运行构建命令

    bash
    
    
    复制代码
    ./gradlew assembleDebug
    

    该命令将触发资源冲突检查,并在控制台打印出任何资源文件冲突的信息。

4. 输出效果

当执行构建命令后,控制台将输出类似于以下的内容:

bash复制代码Scanning resources in module: module1, path: /path/to/project/module1/src/main/res
Scanning resources in module: module2, path: /path/to/project/module2/src/main/res
Resource conflict detected: string_name.xml exists in both module1 (/path/to/project/module1/src/main/res/values/string_name.xml) and module2 (/path/to/project/module2/src/main/res/values/string_name.xml)
Resource conflict check completed.

这样就完成了一个有效的资源文件冲突检查任务。你可以根据需要进一步调整和优化该脚本。

项目根目录gradle.build完整代码

// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
    id 'com.android.application' version '8.6.0' apply false//8.6.0  '7.1.0
    id 'com.android.library' version '8.6.0' apply false//8.6.0   '7.1.0
    id 'maven-publish' apply true// 引入 maven 插件
    //引入kotlin 插件
    id 'org.jetbrains.kotlin.android' version '1.9.0' apply false
}

// 根 build.gradle
apply from: 'versions.gradle'

allprojects {
    // 在这里共享版本号给所有子项目
    ext {
        kotlinVersion = kotlinVersion
        appCompatVersion = appCompatVersion
        coroutinesVersion = coroutinesVersion
    }
}

task checkResourceConflicts {
    doLast {
        def resourceFiles = [:] // 存储资源文件,键是文件名,值是包含文件路径和模块名的 Map

        // 遍历所有子模块
        subprojects { subproject ->
            // 检查子模块是否有 Android 配置
            if (subproject.hasProperty('android')) {
                subproject.android.sourceSets.each { sourceSet ->
                    sourceSet.res.srcDirs.each { resDir ->
                        if (resDir.exists()) {
                            println("Scanning resources in [module]: [${subproject.name}], path: ${resDir.absolutePath}")

                            // 遍历资源目录中的文件
                            resDir.eachFileRecurse { file ->
                                if (file.isFile() && file.name.endsWith(".xml")) {
                                    def fileName = file.name
                                    def moduleName = subproject.name // 当前模块名

                                    // 检查文件名是否已存在
                                    if (resourceFiles.containsKey(fileName)) {
                                        def existingFileInfo = resourceFiles[fileName]
                                        if (existingFileInfo.moduleName != moduleName) {
                                            // 如果文件名来自不同模块,报告冲突
                                            println "Resource conflict detected: ${fileName} exists in both ${existingFileInfo.moduleName} (${existingFileInfo.filePath}) and ${moduleName} (${file.absolutePath})"
                                        }
                                    } else {
                                        // 存储文件路径及模块名
                                        resourceFiles[fileName] = [filePath: file.absolutePath, moduleName: moduleName]
                                    }
                                }
                            }
                        } else {
                          //  println("No resources found in: ${resDir.absolutePath}")
                        }
                    }
                }
            } else {
                println("Skipping module: ${subproject.name} (no Android configuration)")
            }
        }

        println("Resource conflict check completed.")
    }
}

// 在每个子模块的 preBuild 任务上执行检查
subprojects { subproject ->
    if (subproject.hasProperty('android')) {
        subproject.tasks.named("preBuild").configure {
            dependsOn(checkResourceConflicts)
        }
    }
}


在项目根目录gradle.build文件中运行task:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

运行结果如图所示:

> Task :checkResourceConflicts
Scanning resources in [module]: [app], path: D:\Projects\Android\widgets\app\src\aliyun\res
Scanning resources in [module]: [app], path: D:\Projects\Android\widgets\app\src\main\res
Scanning resources in [module]: [app], path: D:\Projects\Android\widgets\app\src\tuya\res
Scanning resources in [module]: [app], path: D:\Projects\Android\widgets\app\src\xiaomi\res
Scanning resources in [module]: [kotlinDemo], path: D:\Projects\Android\widgets\kotlinDemo\src\main\res
Resource conflict detected: activity_main.xml exists in both app (D:\Projects\Android\widgets\app\src\main\res\layout\activity_main.xml) and kotlinDemo (D:\Projects\Android\widgets\kotlinDemo\src\main\res\layout\activity_main.xml)
Resource conflict detected: strings.xml exists in both app (D:\Projects\Android\widgets\app\src\aliyun\res\values\strings.xml) and kotlinDemo (D:\Projects\Android\widgets\kotlinDemo\src\main\res\values\strings.xml)
Scanning resources in [module]: [widgets], path: D:\Projects\Android\widgets\widgets\src\main\res
Resource conflict detected: strings.xml exists in both app (D:\Projects\Android\widgets\app\src\aliyun\res\values\strings.xml) and widgets (D:\Projects\Android\widgets\widgets\src\main\res\values\strings.xml)
Resource conflict check completed.

Deprecated Gradle features were used in this build, making it incompatible with Gradle 9.0.

You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.

For more on this, please refer to https://docs.gradle.org/8.10.2/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation.

项目task运行结果如图所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CST学习笔记(二)Floquet模式激励设置

CST学习笔记(二)Floquet模式激励设置 在CST中我们常常使用Floquet模式来仿真频率选择表面(FSS)或者超材料等,但是我们设置好Zmax的floquet模式数量后,启动仿真,会发现S参数一栏中有很多我们不想要看的S参数&#xff0…

OpenAI Canvas:提升编程与写作效率的全新工作界面

随着人工智能技术的飞速发展,大语言模型(LLM)不仅限于生成文本,还能逐步扩展至编程、设计等任务的支持。近期,OpenAI 推出了一个名为 Canvas 的全新功能,专门用于协助用户进行编程和写作。这一功能与 Claud…

【React】使用脚手架或Vite包两种方式创建react项目

1.使用脚手架搭建React项目: 在终端窗口运行如下命令即可: npx create-react-app react-basic(创建的文件目录) npx:Node.js工具命令,用于查找并执行后续的包命令。 2.使用Vite包创建React项目: 在终端窗口运行如…

【STM32 Blue Pill编程实例】-OLED显示DHT22传感器数据

OLED显示DHT22传感器数据 文章目录 OLED显示DHT22传感器数据1、DHT22介绍2、硬件准备与接线3、模块配置3.1 定时器配置3.2 DHT22引脚配置3.3 OLED配置4、代码实现在本文中,我们将介绍如何将 DHT22 温度和湿度传感器与 STM32 Blue Pill 开发板连接,并使用 HAL 库在 STM32CubeI…

学习底座架构-武汉

1 学习底座架构概述 大脑学习中心-边缘系统 一、当下教育现状 二、什么是学习底座 三、学习底座价值 七、学习底座解决问题的流程 案例:以4R注意力为例 一 注意力问题解决流程 二 注意力问题的危害 三 衡量注意力水平高低的标准 四 注意力问题4大根源 & 2大诱因…

掌握未来技能:亚马逊云科技推出生成式 AI 认证计划!

目录 前言 生成式 AI 的力量 1. 内容创造的无限可能 2. 数据增强和个性化 3. 提高生产力 4. 教育和研究的辅助工具 5. 突破语言障碍 关于亚马逊云科技生成式 AI 认证 1. 认证目标 2. 认证内容 3. 认证优势 如何获得认证 1. 在线学习 2. 实践考试 3.AWS Certifie…

无人机电机故障率骤降:创新设计与六西格玛方法论双赢

项目背景 TBR-100是消费级无人机头部企业推出的主打消费级无人机,凭借其出色的续航能力和卓越的操控性,在市场上获得了广泛认可。在产品运行过程,用户反馈电机故障率偏高,尤其是在飞行一段时间后出现电机过热、损坏以及运行不稳定…

基础入门-Web应用架构搭建漏洞HTTP数据包

网站搭建 这里给一个网站搭建的视频链接,之前又搞过搭建服务器,这里就不再重做了 https://www.bilibili.com/video/BV16A4y1X7vg/?spm_id_from333.337.search-card.all.click&vd_sourcec2c3c616b3ad1faf44a9f6f30a4dbb03 值得注意的是,…

P1320压缩技术(续集版

P1320压缩技术(续集版 感觉这题还是蛮难的对我来说,通过这题我才知道原来字符串输入不碰到空格就会一起输进来 我参考了一写题解自己又写了自己的解法,vs中的scanf_s和scanf()用法不太一样,之前按scanf写法写一直在报错&#xff…

基于springboot+vue实现的酒店在线预订系统

基于springbootvue实现的酒店在线预订系统 (源码L文ppt)4-082 4.2 系统结构设计 构图是系统的体系结构,体系结构是体系结构体系的一部分,体系结构体系是体系结…

Chromium 中chrome.cookies扩展接口c++实现分析

chrome.cookies 使用 chrome.cookies API 查询和修改 Cookie,并在 Cookie 发生更改时收到通知。 更多参考官网定义:chrome.cookies | API | Chrome for Developers (google.cn) 本文以加载一个清理cookies功能扩展为例 https://github.com/Google…

全面讲解C++

数据类型 1.1 基本数据类型 1.1.1 整型(Integer Types) 整型用于表示整数值,分为以下几种类型: int:标准整数类型,通常为4字节(32位)。short:短整型,通常…

集合框架08:LinkedList源码分析、ArrayList和LinkedList区别

视频链接:13.15 LinkedList源码分析_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1zD4y1Q7Fw?spm_id_from333.788.videopod.episodes&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5&p15 13.16 ArrayList和LinkedList区别_哔哩哔哩_bilibilihttps://…

取证之FTK Imager学习笔记

一、FTK Imager制作镜像详细教程 1、文件-创建磁盘镜像 2、参数详解: 1)物理驱动器 整个驱动器,如:识别到的是整块硬盘、U盘等,而不管你分几个分区; 2)逻辑驱动器(L&#xff09…

深入理解Transformer的笔记记录(精简版本)NNLM → Word2Vec

文章的整体介绍顺序为: NNLM → Word2Vec → Seq2Seq → Seq2Seq with Attention → Transformer → Elmo → GPT → BERT 自然语言处理相关任务中要将自然语言交给机器学习中的算法来处理,通常需要将语言数学化,因为计算机机器只认数学符号。向量是人把自然界的东西抽象出…

Redis 实现 查找附近的人 功能

文章目录 概述Redis 中 Geospatial(地理位置)Demo例子总结 概述 使用 Redis 实现“查找附近的人”功能,通常会依赖 Redis 的 Geo(地理位置) 数据类型来存储用户的经纬度,并基于此进行地理范围查询。Redis …

ChatTTS在Windows电脑的本地部署与远程生成音频详细实战指南

文章目录 前言1. 下载运行ChatTTS模型2. 安装Cpolar工具3. 实现公网访问4. 配置ChatTTS固定公网地址 前言 本篇文章主要介绍如何快速地在Windows系统电脑中本地部署ChatTTS开源文本转语音项目,并且我们还可以结合Cpolar内网穿透工具创建公网地址,随时随…

低代码开发技术:驱动MES系统创新与制造业数字化转型的融合之路

低代码开发与生产管理MES系统的融合,是当今制造业数字化转型的一个重要趋势。以下是对这一融合现象的详细分析: 一、低代码开发的概念与特点 低代码开发是一种通过图形化界面和预构建模块来简化应用程序开发过程的方法。它允许开发人员使用拖放组件和最…

请确保已在git上配置你的user.name和user.email

问题:使用vscode在远程服务器上暂存修改报错: 原因:未在远程服务器上配置该项目对应的git的username和useremail 解决方法: 在vscode中新建一个终端 命名: git config --global user.email "youexample.com&qu…

【读书笔记·VLSI电路设计方法解密】问题12:制造MOSFET晶体管的主要工艺步骤是什么

VLSI芯片是在半导体材料上制造的,这种材料的导电性介于绝缘体和导体之间。通过一种称为掺杂的工艺引入杂质,可以改变半导体的电气特性。能够在半导体材料的细小且定义明确的区域内控制导电性,促使了半导体器件的发展。结合更简单的无源元件(电阻、电容和电感),这些器件被…