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…...
Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
一、前言说明 在2011版本的gb28181协议中,拉取视频流只要求udp方式,从2016开始要求新增支持tcp被动和tcp主动两种方式,udp理论上会丢包的,所以实际使用过程可能会出现画面花屏的情况,而tcp肯定不丢包,起码…...
Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...
从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...
关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
