Android Gradle8.0以上多渠道写法以及针对不同渠道导入包的方式,填坑!
目录
多渠道的写法
针对多渠道引用不同的包
There was a failure while populating the build operation queue: Could not stat file E:\xxxx\xxxx\xxxx\app\src\UAT\libsUAT\xxx-provider(?)-xx.aar
最近升级了Gradle8.3之后,从Groovy 迁移到 Kotlin,很多写法都有发生改变。
其他的不细说了,针对这篇文章的主题,多渠道写法 以及 不同渠道如何导入不同的包 来讲。
多渠道的写法
日常单一渠道的话,一般会用这种方式去区分环境。在8.0以下的写法是:
productFlavors {DEV {dimension 'XXXXX'applicationIdSuffix '.dev'buildConfigField "String", "DOMAIN", '"https://XXXXX/"'buildConfigField "String", "XXXX_RETURN_URL", '"scheme://host"'buildConfigField "String", "XXXX_RETURN_URL", '"scheme://host"'buildConfigField "String", "XXXX_RETURN_URL", '"scheme://host"'buildConfigField "Long", "BUILD_DATE", "${buildDate}L"manifestPlaceholders = [app_name : "(DEV)XXXX",DEEP_LINK_HOST : "DOMAINXXXXX",]}UAT {}PROD {}
}
但在8.0以上,写法要改成
productFlavors {create("DEV").apply {this.dimension = "xxxxx"this.applicationIdSuffix = ".dev"this.buildConfigField("String", "DOMAIN", "\"https://XXXXXX/\"")this.buildConfigField("String", "XXXX_RETURN_URL", "\"scheme://host\"")this.buildConfigField("String", "XXXX_RETURN_URL", "\"scheme://host\"")this.buildConfigField("String", "XXXX_RETURN_URL", "\"scheme://host\"")this.buildConfigField("Long", "BUILD_DATE", "${buildDate}L")this.manifestPlaceholders.apply {this["app_name"] to "(DEV)XXXXX"this["DEEP_LINK_HOST"] to "DOMAINXXXX"}}create("UAT").apply {}create("PROD").apply {}
}
针对多渠道引用不同的包
这个可能不是每个人都需要,我是遇到是这个问题。
背景:台湾的支付平台SDK,UAT跟PROD给了两个SDK,同时导入会引发重复包的错误,不然就需要在开发阶段,放置UAT的SDK,等上线的时候记得替换PROD的SDK,这样存在一定的风险,可能会忘记替换等等原因。我希望做成当切换渠道(环境)的时候,自动切换到不同的SDK。
正常引用SDK,我们是使用下面这两种方式
dependencies {implementation(files("XXXX"))implementation(fileTree(mapOf("dir" to "../XXXX/libs", "include" to listOf("*.jar","*.aar"))))
}
我没在Gradle8.0以下针对不同渠道引用不同的SDK,没办法给出8.0以下的写法,我将8.0以上的写法直接贴出来
// 对于特定的flavor,使用特定的dependencies
val libsProdPath = "src/PROD/libsPROD/XXXXX.aar"
val libsUATPath = "src/UAT/libsUAT/XXXXX.aar"configurations {"PRODImplementation" {extendsFrom(configurations.implementation.get())}"UATImplementation" {extendsFrom(configurations.implementation.get())}
}dependencies {// implementation(fileTree(mapOf("dir" to "../XXXXX/libs", "include" to listOf("*.jar","*.aar"))))"PRODImplementation"(files(libsProdPath))"UATImplementation"(files(libsUATPath))
}
这样在build的时候,就能根据不同的渠道(环境)去拿到对应的路径下的SDK文件了。
我需要加载多个SDK,所以改成了
// 对于特定的flavor,使用特定的dependencies
val libsProdPath = listOf("src/PROD/libsPROD/XXXXX.aar","src/PROD/libsPROD/XXXXX.aar","src/PROD/libsPROD/XXXXX.aar"
)
val libsUATPath = listOf("src/UAT/libsUAT/XXXXX.aar","src/UAT/libsUAT/XXXXX.aar","src/UAT/libsUAT/XXXXX.aar"
)
configurations {"PRODImplementation" {extendsFrom(configurations.implementation.get())}"UATImplementation" {extendsFrom(configurations.implementation.get())}
}dependencies {// implementation(fileTree(mapOf("dir" to "../XXXXX/libs", "include" to listOf("*.jar","*.aar"))))"PRODImplementation"(files(libsProdPath))"UATImplementation"(files(libsUATPath))
}
后面又觉得把版本号写固定在路径下并不方便,于是把版本号抽出来,由于我其他的libs的版本号都写在libs.versions.toml下统一管理,于是也很自然而然的去这个文件下添加了
[versions]
xxxxxVersion = "x.y.z"
但当我回来build.gradle.kts修改为如下之后
// 对于特定的flavor,使用特定的dependencies
val libsProdPath = listOf("src/PROD/libsPROD/XXX-${libs.versions.xxxxxVersion}-XX.aar","src/PROD/libsPROD/XXX-${libs.versions.xxxxxVersion}-XX.aar","src/PROD/libsPROD/XXX-${libs.versions.xxxxxVersion}-XX.aar"
)
val libsUATPath = listOf("src/UAT/libsUAT/XXX-${libs.versions.xxxxxVersion}-XX.aar","src/UAT/libsUAT/XXX-${libs.versions.xxxxxVersion}-XX.aar","src/UAT/libsUAT/XXX-${libs.versions.xxxxxVersion}-XX.aar"
)
configurations {"PRODImplementation" {extendsFrom(configurations.implementation.get())}"UATImplementation" {extendsFrom(configurations.implementation.get())}
}dependencies {// implementation(fileTree(mapOf("dir" to "../XXXXX/libs", "include" to listOf("*.jar","*.aar"))))"PRODImplementation"(files(libsProdPath))"UATImplementation"(files(libsUATPath))
}
出现了问题,Sync的时候提示错误:
There was a failure while populating the build operation queue: Could not stat file E:\xxxx\xxxx\xxxx\app\src\UAT\libsUAT\xxx-provider(?)-xx.aar
找不到文件?为什么找不到,因为版本号没有被正确的加载,变成了provider(?)。
猜测是因为Gradle在执行阶段的时候引用了没有被正确解析的变量,最后通过provider来延迟加载版本号,以确保在配置阶段能够正确加载到版本号。
于是,最终代码如下:
val xxxxxVersionProvider: Provider<String> = providers.provider { libs.versions.xxxxxVersion.get() }// 对于特定的flavor,使用特定的dependencies
val libsProdPath = listOf("src/PROD/libsPROD/XXX-${xxxxxVersionProvider.get()}-XX.aar","src/PROD/libsPROD/XXX-${xxxxxVersionProvider.get()}-XX.aar","src/PROD/libsPROD/XXX-${xxxxxVersionProvider.get()}-XX.aar"
)
val libsUATPath = listOf("src/UAT/libsUAT/XXX-${xxxxxVersionProvider.get()}-XX.aar","src/UAT/libsUAT/XXX-${xxxxxVersionProvider.get()}-XX.aar","src/UAT/libsUAT/XXX-${xxxxxVersionProvider.get()}-XX.aar"
)
configurations {"PRODImplementation" {extendsFrom(configurations.implementation.get())}"UATImplementation" {extendsFrom(configurations.implementation.get())}
}dependencies {// implementation(fileTree(mapOf("dir" to "../XXXXX/libs", "include" to listOf("*.jar","*.aar"))))"PRODImplementation"(files(libsProdPath))"UATImplementation"(files(libsUATPath))
}
这样就能完美根据Build Variants中选择的Active Build Variant,build.gradle.kts自动去找到相对应的SDK了。
代码中所有实际项目相关的内容,都用【xxxxx】隐去,相应的路径、文件名,大家便根据各自实际情况修改了,有问题可以留言。
本文终。
相关文章:
Android Gradle8.0以上多渠道写法以及针对不同渠道导入包的方式,填坑!
目录 多渠道的写法 针对多渠道引用不同的包 There was a failure while populating the build operation queue: Could not stat file E:\xxxx\xxxx\xxxx\app\src\UAT\libsUAT\xxx-provider(?)-xx.aar 最近升级了Gradle8.3之后,从Groovy 迁移到 Kotlinÿ…...

hdlbits系列verilog解答(向量门操作)-14
文章目录 一、问题描述二、verilog源码三、仿真结果 一、问题描述 构建一个具有两个 3 位输入的电路,用于计算两个向量的按位 OR、两个向量的逻辑 OR 以及两个向量的逆 (NOT)。将b反相输出到out_not上半部分,将a 的反相输出到out…...
工厂模式(初学)
工厂模式 1、简单工厂模式 是一种创建型设计模式,旨在通过一个工厂类(简单工厂)来封装对象的实例化过程 运算类 public class Operation { //这个是父类private double num1; //运算器中的两个值private double num2;public double getNu…...
python试题实例
背景: 在外地出差,突然接到单位电话,让自己出一些python考题供新人教育训练使用,以下是10道Python编程试题及其答案: 1.试题:请写一个Python程序,计算并输出1到100之间所有偶数的和。 答案&am…...
Java Heap Space问题解析与解决方案(InsCode AI 创作助手)
Heap Space问题是Java开发中常见的内存溢出问题之一,我们需要理解其原因和表现形式,然后通过优化代码、增加JVM内存和使用垃圾回收机制等方法来解决。 一、常见报错 java.lang.OutOfMemoryError: Java heap space二、Heap Space问题的原因 对象创建过…...

基于遥感影像的分类技术(监督/非监督和面向对象的分类技术)
遥感图像分类技术 “图像分类是将土地覆盖类别分配给像素的过程。例如,类别包括水、城市、森林、农业和草原。”前言 – 人工智能教程 什么是遥感图像分类? 遥感图像分类技术的三种主要类型是: 无监督图像分类监督图像分类基于对象的图像分析…...
插入兄弟元素 insertAfter() 方法
insertAfter() 方法在被选元素后插入 HTML 元素。 提示:如需在被选元素前插入 HTML 元素,请使用 insertBefore() 方法。 语法 $(content).insertAfter(selector)例子: $("<span>Hello world!</span>").insertAfter(…...

【C++项目】高并发内存池第二讲中心缓存CentralCache框架+核心实现
CentralCache 1.框架介绍2.核心功能3.核心函数实现介绍3.1SpanSpanList介绍3.2CentralCache.h3.3CentralCache.cpp3.4TreadCache申请内存函数介绍3.5慢反馈算法 1.框架介绍 回顾一下ThreadCache的设计: 如图所示,ThreadCache设计是一个哈希桶结构&…...

Git基础教程
一、Git简介 1、什么是Git? Git是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或大或小的项目。 Git是Linus Torvalds为了帮助管理Linux内核开发而开发的一个开放源代码的版本控制软件。 Git与常用的版本控制工具CVS、Subversion等不同&#…...

stm32外部时钟为12MHZ,修改代码适配
代码默认是8MHZ的,修改2个地方: 第一个地方是这个文件的这里: 第二个地方是找到这个函数: 修改第二个地方的这里:...
【数据结构】八大排序
目录 1. 排序的概念及其作用 1.1 排序的概念 1.2 排序运用 1.3 常见的排序算法 2. 常见排序算法的实现 2.1 插入排序 2.1.1 基本思想 2.1.2 直接插入排序 2.1.3 希尔排序(缩小增量排序) 2.2 选择排序 2.2.1 基本思想 2.2.2 直接选择排序 2.2…...

MYSQL(事务+锁+MVCC+SQL执行流程)理解
一)事务的特性: 一致性:主要是在数据层面来说,不能说执行扣减库存的操作的时候用户订单数据却没有生成 原子性:主要是在操作层面来说,要么操作完成,要么操作全部回滚; 隔离性:是自己的事务操作自己的数据,不会受到到其…...

解密一致性哈希算法:实现高可用和负载均衡的秘诀
解密一致性哈希算法:实现高可用和负载均衡的秘诀 前言第一:分布式系统中的数据分布问题,为什么需要一致性哈希算法第二:一致性hash算法的原理第三:一致性哈希算法的优点和局限性第四:一致性哈希算法的安全性…...

Python脚本:让工作自动化起来
Python是一种流行的编程语言,以其简洁和易读性而闻名。它提供了大量的库和模块,使其成为自动化各种任务的绝佳选择。 本文将探讨Python脚本及其代码,可以帮助您自动化各种任务并提高工作效率。无论您是开发人员、数据分析师还是只是想简化工…...

香港科技大学广州|可持续能源与环境学域博士招生宣讲会—广州大学城专场!!!(暨全额奖学金政策)
香港科技大学广州|可持续能源与环境学域博士招生宣讲会—广州大学城专场!!!(暨全额奖学金政策) “面向未来改变游戏规则的——可持续能源与环境学域” ���专注于能源环…...

uni-app:多种方法写入图片路径
一、文件在前端文件夹中 1、相对路径引用 从当前文件所在位置开始寻找图片文件的路径。../../ 表示返回两级目录,即从当前文件所在的 wind.vue 所在的位置开始向上回退两级。接着,进入 static 目录,再进入 look 目录,最后定位到 …...

共谋工业3D视觉发展,深眸科技以自研解决方案拓宽场景应用边界
随着中国工业领域自动化程度逐渐攀升,“机器换人”这一需求进一步提升。在传统2D工业视觉易受环境光干扰、无法进一步获取物体深度信息的限制条件下,工业3D视觉凭借着更强的空间和深度感知能力,以及通过点云数据获取物体距离和三维坐标信息的…...
前端面试基础面试题——11
1.什么是 vue 的计算属性? 2.vue怎么实现页面的权限控制 3.watch的作用是什么 4.响应式系统的基本原理 5.vue-loader 是什么?使用它的用途有哪些? 6.vuex 工作原理详解 7.vuex 有哪几种属性? 8.什么是 MVVM? 9…...
SQL server中内连接和外连接的区别、表达(表的连接)
SQL server中内连接与外连接的区别、表达 区别表达内连接外连接 待续 首先,内连接和外连接都是对表的连接操作 区别 内连接:连接结果仅包含符合连接条件的行,其中至少一个属性是共同的;注意区分在嵌套查询时使用的any以及all的区…...

Linux中的shell外壳与权限(包含目录文件的权限,粘滞位的来龙去脉)
Linux中的shell外壳与权限[包含目录文件的权限,粘滞位的来龙去脉] 一.shell外壳的理解1.为什么需要有shell外壳的存在?2.什么是shell外壳?3.shell外壳的运行原理是什么?4.shell和bash的关系 二.Linux中的用户权限1.用户分类与身份切换1.用户分类2.root用户切换为普通用户1.s…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...

相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:
根据万维钢精英日课6的内容,使用AI(2025)可以参考以下方法: 四个洞见 模型已经比人聪明:以ChatGPT o3为代表的AI非常强大,能运用高级理论解释道理、引用最新学术论文,生成对顶尖科学家都有用的…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)
本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

代码规范和架构【立芯理论一】(2025.06.08)
1、代码规范的目标 代码简洁精炼、美观,可持续性好高效率高复用,可移植性好高内聚,低耦合没有冗余规范性,代码有规可循,可以看出自己当时的思考过程特殊排版,特殊语法,特殊指令,必须…...