Android Gradle开发与应用 (八) :Kotlin DSL
1. 前言
本文介绍了Gradle Kotlin DSL
相关的一些知识点
2. DSL是什么
DSL
是为特定领域设计的专门的语言,也就是设计了一门语言,然后解决某个特定的领域的特定问题。
2.1 举例说明
以下的这些都可以称之为DSL
- 正则表达式 :用于文本处理的特定语言
- SQL :用于数据库查询的领域特定语言
- HTML : 用于描述网页结构的领域特定语言
- CSS:用于描述网页样式的领域特定语言
- Android XML布局 : 用于描述Android页面的领域特定语言
而Gradle 中的 Groovy DSL 和 Kotlin DSL 就用来编写Gradle
构建脚本的领域特定语言
像Kotlin它不仅可以做一些Android开发,还可以做后端,它不属于DSL,但是我们可以通过Kotlin的一些语法规则,来开发一些特定领域的DSL语言。
2.2 Kotlin DSL
Kotlin
当中的DSL
,使用高阶函数和一些Lambda表达式配合来进行编写的。
对于DSL
没有明确的语法规定,只要能编写出一门语言,一种语法规则,解决特定领域的问题,那么他就可以称之为DSL
。
Gradle
构建工具现在也使用Kotlin
作为Gradle
的主要编写语言了。
我们去创建Kotlin
的Gradle
的时候,可以发现,它里面的内容和以前的Gradle
没什么区别,但是语言上是用的Kotlin。
其实就是用Kotlin
写了一个专门为Gradle
使用的DSL
。
3. kotlin-dsl是什么
在用Kotlin编写的Gradle插件中,会有kotlin-dsl
这一句
plugins {`java-gradle-plugin``kotlin-dsl`
}
我们点进去可以看到kotlin-dsl
中间的-
不是标准的kotlin
语法,所以要加上``来做区分。
public val val PluginDependenciesSpec.`kotlin-dsl`: PluginDependencySpecget() = id("org.gradle.kotlin.kotlin-dsl") version "2.4.1"
也就是说 kotlin-dsl
就是PluginDependencySpec
的一个扩展属性。
其实就是相当于id("org.gradle.kotlin.kotlin-dsl") version "2.4.1"
所以如果把kotlin-dsl
这行代码改为id("org.gradle.kotlin.kotlin-dsl") version "2.4.1"
,效果是一样的。
可以在Kotlin插件项目里,全局搜索
org.gradle.kotlin.kotlin-dsl
3.1 kotlin-dsl插件的作用
提供Kotlin
编写Gradle
脚本的能力,从而可以替代传统的Groovy语言。
-
使用Kotlin DSL的编程风格,可以使程序更加简单干净、直观简洁。这有助于提升开发效率,降低出错的可能性,并使得构建脚本更易于理解和维护。
-
此外,Kotlin DSL还提供了强大的类型检查和智能代码补全功能,这些功能可以进一步提高开发者的编写体验。同时,由于Kotlin语言的强大功能,Kotlin DSL也支持更复杂的构建逻辑和更灵活的脚本编写方式。
4. groovy和kotlin的语法糖
4.1 apply plugin
4.1.1 groovy中的apply plugin
apply plugin : MyPlugin
等价于
apply([plugin : MyPlugin])
当方法的参数是一个map
的时候,可以将方括号[]
去掉
apply(plugin: MyPlugin)
当不引起歧义的时候,可以把圆括号去掉
apply plugin : MyPlugin
4.1.2 kotlin中的apply plugin
apply(plugin = "com.android.application")
实际上也是个函数调用
public fun org.gradle.api.plugins.PluginAware.apply(from: kotlin.Any? = COMPILED_CODE, plugin: kotlin.String? = COMPILED_CODE, to: kotlin.Any? = COMPILED_CODE): kotlin.Unit { }
4.2 gradle和kotlin中的plugins
4.2.1 groovy中的plugins
plugins {id 'com.android.application'id 'org.jetbrains.kotlin.android'
}
本质是有一个plugins
的方法,调用了一个闭包
实质上是
plugins({id('com.android.application').version('8.1.3').apply(false)
})
4.2.2 kotlin中的plugins
plugins {id("com.android.application") version "8.1.3" apply false
}
本质上也就是一个函数调用
public final fun plugins(block: org.gradle.kotlin.dsl.PluginDependenciesSpecScope.() -> kotlin.Unit): kotlin.Unit { /* compiled code */ }
id
方法会返回一个PluginDependencySpec
,PluginDependencySpec
中有version
和apply
方法
public interface PluginDependencySpec {PluginDependencySpec version(@Nullable String version);default PluginDependencySpec version(Provider<String> version) {return this.version((String)version.get());}PluginDependencySpec apply(boolean apply);
}
4.2.3 apply plugin 和 plugins的区别
- plugins是Gradle较新的方式,用于声明性地应用插件。有更简洁的语法,更好的插件版本控制
- 传统的apply方法机制则更加灵活,可以动态地加载和应用插件
现在一般情况下都用plugins即可,除非是要使用build.gradle
中自己写的gradle插件,采用apply plugin
进行引用。
5. Groovy DSL 和 Kotlin DSL的区别
5.1 gradle中,如下Groovy和Kotlin的写法为什么会有不同 ?
比如下面的这行代码 greeting.message = 'Hi from Gradle'
和 the<GreetingPluginExtension>().message.set("Hi from Gradle")
在 Gradle
中,Groovy DSL
和 Kotlin DSL
提供了不同的语法和风格来配置构建脚本。这两种语言不同的写法来配置插件扩展,是由于这两种 DSL
在语法和设计哲学上的差异造成的。
首先,来看 Groovy DSL
的写法:
greeting.message = 'Hi from Gradle'
在 Groovy DSL
中,插件的扩展对象通常会被添加到项目的 extensions
集合中,并且可以直接通过扩展对象的名称(在这个例子中是 greeting
)来访问。Groovy
语言允许直接对属性进行赋值操作,因此可以非常方便地通过点号 .
操作符来设置属性的值。
接下来,看 Kotlin DSL
的写法:
the<GreetingPluginExtension>().message.set("Hi from Gradle")
在 Kotlin DSL
中,由于 Kotlin
是一种静态类型语言,它提供了更严格的类型检查和更丰富的类型系统。因此,访问插件的扩展对象需要使用 the<T>()
函数,这个函数是 Gradle Kotlin DSL
提供的一个帮助函数,用于获取指定类型的扩展对象。这样做可以提供更好的类型安全,并且使代码更加清晰和易于理解。
另外,set
方法的使用也是 Kotlin 语言特性的体现。在 Kotlin 中,属性默认是不可变的(val),如果需要修改属性的值,通常需要提供一个 set
方法。虽然 Kotlin 也支持可变属性(var),但在 Gradle Kotlin DSL
的上下文中,使用 set
方法可能是为了遵循 Gradle API
的约定,或者是为了强调这是一个设置操作。
总结来说,Groovy DSL
和 Kotlin DSL
在语法和风格上的差异导致了配置插件扩展时的不同写法。Groovy DSL
提供了更加直接和简洁的语法,而 Kotlin DSL
则强调了类型安全和清晰的代码结构。这些差异使得两种 DSL
都有其独特的优点,开发者可以根据个人喜好和项目需求选择使用哪一种。
5.2 gradle中,tasks.register(‘xxx’)和task xxx这两种新建Task方式,有什么区别 ?
在Gradle中,tasks.register('xxx')
和task xxx
这两种方式用于新建Task, 但它们之间存在一些区别:
-
Groovy 和 Kotlin 语法:
task xxx
是 Groovy 语法,它使用 Groovy 闭包来配置任务。tasks.register('xxx')
是 Kotlin 语法,它通过流式 API 调用来配置任务。
-
任务创建时机:
task xxx
是在配置文件(如 build.gradle)执行期间立即创建任务的。tasks.register('xxx')
可以延迟任务的创建,直到需要时才注册到任务注册表中。
-
可读性和维护性:
task xxx
的语法更接近传统的 Gradle 构建脚本,对于熟悉早期版本的 Gradle 的用户来说可能更易读。tasks.register('xxx')
提供了一种更一致和流畅的任务配置方式,与 Gradle 推向的 Kotlin DSL 相契合。
-
API 兼容性:
task xxx
的语法可能会在未来的 Gradle 版本中被弃用,因为 Gradle 正在推动使用 Kotlin DSL。tasks.register('xxx')
是当前推荐的方式,因为它与 Gradle 的 Kotlin DSL 兼容,并且有更好的未来兼容性保证。
-
任务名称:
task xxx
中的任务名称(‘xxx’)通常不包含引号。tasks.register('xxx')
中的任务名称必须包含引号。
-
示例:
- 使用
task xxx
语法创建一个名为 ‘myTask’ 的任务:task myTask {doLast {println 'Hello from myTask!'} }
- 使用
tasks.register('xxx')
语法创建同样的任务:tasks.register('myTask') {doLast {println 'Hello from myTask!'} }
- 使用
总的来说,虽然 task xxx
和 tasks.register('xxx')
都可以用来创建新的任务,但是 tasks.register
是更现代、更灵活且未来兼容的方式。随着 Gradle
的发展,推荐使用 Kotlin
语法和 tasks.register
方法进行任务创建和配置。
6. 自定android闭包
使用Kotlin DSL
模拟android
闭包来实现一个myandroid
的闭包,将MyAndroidBean
传入。
首先创建一个MyAndroidBean
和DefaultConfig
传参类
class MyAndroidBean {var namespace = ""var compileSdk = 0var myDefaultConfig = DefaultConfig()fun Project.myDefaultConfig(call: DefaultConfig.() -> Unit) {val defaultConfig = DefaultConfig()defaultConfig.call()}
}class DefaultConfig {var applicationId = ""var minSdk = 0var targetSdk = 0
}
然后实现一个自定义的myandroid
闭包
fun Project.myandroid(call: MyAndroidBean.() -> Unit) {val myAndroidBean = MyAndroidBean()myAndroidBean.call()val defaultConfig = myAndroidBean.myDefaultConfig//打印传参println("namespace:${myAndroidBean.namespace}")println("namespace:${myAndroidBean.compileSdk}")println("applicationId:${defaultConfig.applicationId}")println("minSdk:${defaultConfig.minSdk}")println("targetSdk:${defaultConfig.targetSdk}")
}
进行调用
myandroid {namespace = "com.heiko.mytest"compileSdk = 34myDefaultConfig {applicationId = "com.heiko.mytest"minSdk = 21targetSdk = 34}
}
7. 其他
gradle中Kotlin和Groovy的差异 :
将 build 配置从 Groovy 迁移到 Kotlin | Android Studio | Android Developers (google.cn)
Gradle Kotlin DSL 入门
Android Gradle系列文章
Android Gradle 开发与应用 (一) : Gradle基础-氦客-CSDN博客
Android Gradle开发与应用 (二) : Groovy基础语法-CSDN博客
Android Gradle开发与应用 (三) : Groovy语法概念与闭包-CSDN博客
Android Gradle开发与应用 (四) : Gradle构建与生命周期-CSDN博客
Android Gradle开发与应用 (五): 基于Gradle 8.2,创建Gradle插件-CSDN博客
Android Gradle 开发与应用 (六) : 创建buildSrc插件和使用命令行创建Gradle插件-CSDN博客
Android Gradle 开发与应用 (七) : 实现打包自动复制文件插件
Android Gradle开发与应用 (八) :Kotlin DSL
相关文章:
Android Gradle开发与应用 (八) :Kotlin DSL
1. 前言 本文介绍了Gradle Kotlin DSL相关的一些知识点 2. DSL是什么 DSL是为特定领域设计的专门的语言,也就是设计了一门语言,然后解决某个特定的领域的特定问题。 2.1 举例说明 以下的这些都可以称之为DSL 正则表达式 :用于文本处理的特定语言SQ…...
phpstorm 快捷键
PHPstorm最常用的快捷键,提高开发效率 - 知乎 (zhihu.com) 四年精华PHP技术文章整理合集——PHP框架篇 (qq.com) 四年精华PHP技术文合集——微服务架构篇 (qq.com) Vue3 打印票据 预览的库:vue3打印解决方案:Vue-Plugin-HiPrint - 掘金 (j…...

浦大喜奔APP8.0智能升级,发力数字金融深化五大金融篇章服务
1. 浦大喜奔立足科技赋能持续迭代升级,筑牢用户体验护城河 浦发信用卡中心坚持数字科技与客户体验双轮驱动,以科技赋能发展,优化整体系统性能,全方位支撑浦大喜奔 APP提高线上客户服务能力与体验,积极服务民生消费&a…...

自然语言处理、大语言模型相关名词整理
自然语言处理相关名词整理 零样本学习(zero-shot learning)词嵌入(Embedding)为什么 Embedding 搜索比基于词频搜索效果好? Word2VecTransformer检索增强生成(RAG)幻觉采样温度Top-kTop-p奖励模…...

移动开发避坑指南——内存泄漏
在日常编写代码时难免会遇到各种各样的问题和坑,这些问题可能会影响我们的开发效率和代码质量,因此我们需要不断总结和学习,以避免这些问题的出现。接下来我们将围绕移动开发中常见问题做出总结,以提高大家的开发质量。本系列文章…...

太好玩了,我用 Python 做了一个 ChatGPT 机器人
毫无疑问,ChatGPT 已经是当下编程圈最火的话题之一,它不仅能够回答各类问题,甚至还能执行代码! 或者是变成一只猫 因为它实在是太好玩,我使用Python将ChatGPT改造,可以实现在命令行或者Python代码中调用。…...

STM32存储左右互搏 SDIO总线读写SD/MicroSD/TF卡
STM32存储左右互搏 SDIO总线读写SD/MicroSD/TF卡 SD/MicroSD/TF卡是基于FLASH的一种常见非易失存储单元,由接口协议电路和FLASH构成。市面上由不同尺寸和不同容量的卡,手机领域用的TF卡实际就是MicroSD卡,尺寸比SD卡小,而电路和协…...

累积分布函数图(CDF)的介绍、matlab的CDF图绘制方法(附源代码)
在对比如下两个误差的时候,怎么直观地分辨出来谁的误差更低一点?: 通过这种误差时序图往往不容易看出来。 但是如果使用CDF图像,以误差绝对值作为横轴,以横轴所示误差对应的累积概率为纵轴,绘制曲线图&am…...
代码随想录算法训练营第四十一天|343.整数拆分、96不同的二叉搜索树
文档链接:https://programmercarl.com/ LeetCode343.整数拆分 题目链接:https://leetcode.cn/problems/integer-break/ 思路: j * (i - j) 是单纯的把整数拆分为两个数相乘,而j * dp[i - j]是拆分成两个以及两个以上的个数相乘…...
全量知识系统 程序详细设计之 统一资产模型(QA-SmartChat)
Q1. 下面我们聊聊整个全知系统的设计 的矩阵和函数,矩阵表示的是“活物”,分别 类似 一个基因的活性、一个实体的辨识度和某种特征的可区分度。 函数的可微、可积和可导性 则表示 运动的控制方式 在全知系统设计中,矩阵和函数是两个核心的组…...
已解决org.springframework.web.client.HttpClientErrorException: 400异常的正确解决方法,亲测有效!!!
已解决org.springframework.web.client.HttpClientErrorException: 400异常的正确解决方法,亲测有效!!! 文章目录 问题分析 报错原因 解决思路 解决方法 总结 在日常开发过程中,通过Spring框架提供的RestTemplat…...

内网渗透-Windows内网渗透
内网渗透-Windows内网渗透 文章目录 内网渗透-Windows内网渗透前言一、信息收集 1.1、SPN1.2、端口连接1.3、配置文件1.4、用户信息1.6、会话收集1.7、凭据收集 navicat:SecureCRT:Xshell:WinSCP:VNC: 1.8、DPAPI1.9、域信任1.10、…...

机器人方向控制中应用的磁阻角度传感芯片
磁阻传感器提供的输出信号几乎不受磁场变动、磁温度系数、磁传感器距离与位置变动影响,可以达到高准确度与高效能,因此相当适合各种要求严格的车用电子与工业控制的应用。所以它远比采用其它传感方法的器件更具有优势。 机器人的应用日渐广泛࿰…...

如何在树莓派安装Nginx并实现固定公网域名访问本地静态站点
文章目录 1. Nginx安装2. 安装cpolar3.配置域名访问Nginx4. 固定域名访问5. 配置静态站点 安装 Nginx(发音为“engine-x”)可以将您的树莓派变成一个强大的 Web 服务器,可以用于托管网站或 Web 应用程序。相比其他 Web 服务器,Ngi…...

Ubuntu与主机windows共享文件夹
一、创建共享文件夹: 虚拟机->设置->选项->共享文件夹->总是启用->选择本地的共享文件夹(如E:\Share)->确定。 二、设置挂载: 首先赋予/etc/fstab文件可编辑的权限; sudo chmod 777 /…...

(四)C++自制植物大战僵尸游戏启动流程
植物大战僵尸游戏开发教程专栏地址http://t.csdnimg.cn/ErelL 一、启动方式 鼠标左键单机VS2022上方工具栏中绿色三角按钮(本地Windows调试器)进行项目启动。第一次启动项目需要编译项目中所有代码文件,编译生成需要一定的时间。不同性能的电…...

华为的AI战略地图上,才不是只有大模型
图片来源:pixabay© 钛媒体ToB深水区 图片来源:pixabay 大模型火热了一年,现在还没做AI化改造的企业,就像是工业革命浪潮伊始与火车赛跑的那辆马车。 最早的蒸汽火车缓慢又笨重,甚至铁轨上还预留了马匹行走的空…...

采用C#.Net +JavaScript 开发的云LIS系统源码 二级医院应用案例有演示
采用C#.Net JavaScript 开发的云LIS系统源码 二级医院应用案例有演示 一、系统简介 云LIS是为区域医疗提供临床实验室信息服务的计算机应用程序,可协助区域内所有临床实验室相互协调并完成日常检验工作,对区域内的检验数据进行集中管理和共享࿰…...

Vue3(三):生命周期、路由、自定义hooks
这里终于明白了为什么一直有这个语法报错,就是在提示你哪里错的地方上方注释一行/*eslint-disable*/,之前一直警告这个错误感谢老师! 一、vue2和vue3生命周期 还有一个问题就是父组件和子组件哪个先挂载完毕呢?答案是子组件先挂…...

UE4_导入内容_骨架网格体
FBX 导入支持 骨架网格体(Skeletal Mesh) 。这提供了一种简化的处理流程来将有动画的网格体从 3D应用程序中导入到虚幻引擎内,以便在游戏中使用。除了导入网格体外,如果需要,动画和变形目标都可以使用FBX格式 在同一文…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...
CSS | transition 和 transform的用处和区别
省流总结: transform用于变换/变形,transition是动画控制器 transform 用来对元素进行变形,常见的操作如下,它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...
NPOI Excel用OLE对象的形式插入文件附件以及插入图片
static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...
解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist
现象: android studio报错: [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决: 不要动CMakeLists.…...