Gradle Kotlin DSL依赖管理:从基础语法到进阶实践
1. 从脚本到代码为什么是Kotlin DSL如果你是从传统的build.gradle文件迁移过来或者刚开始接触 Gradle看到build.gradle.kts这个后缀可能会有点懵。简单来说.kts代表Kotlin Script。这意味着你的构建脚本现在是用 Kotlin 语言来写的而不是之前的 Groovy。这不仅仅是换了一种语法糖。在 Groovy 时代Gradle 的构建脚本虽然灵活但存在几个痛点一是 IDE 的智能提示代码补全、跳转到定义几乎为零全靠记忆和查文档二是动态类型和宽松的语法导致很多错误只能在运行时才暴露出来比如依赖坐标写错了一个字母不到执行gradle build那一刻你都不知道三是脚本的可维护性差复杂的构建逻辑写起来像在玩“猜谜游戏”。Kotlin DSL 的出现就是为了解决这些问题。它将构建脚本从一种“配置语言”提升为“真正的编程语言”。你可以在脚本里使用 Kotlin 的所有特性强类型、空安全、扩展函数、Lambda 表达式等等。更重要的是IDE如 IntelliJ IDEA 或 Android Studio能将其视为 Kotlin 代码提供完整的代码补全、重构、静态检查和即时错误提示。当你输入dependencies {时IDE 能告诉你接下来可以调用哪些方法当你输入一个依赖的 group 名时它能提示可能的 artifact甚至能帮你自动补全版本号。所以使用build.gradle.kts添加依赖本质上是在用一门更现代、更安全、工具链支持更好的语言来编写构建逻辑。这不仅仅是语法上的改变更是开发体验和项目健壮性的一次升级。对于新项目我强烈建议直接使用 Kotlin DSL对于老项目如果构建逻辑复杂或团队深受 Groovy 脚本维护之苦逐步迁移也是值得的投资。2. 依赖声明的基础语法implementation与它的朋友们在build.gradle.kts中依赖是在dependencies { ... }代码块内声明的。这个代码块通常位于模块级Module-level的构建脚本中。最核心、最常用的配置就是implementation。2.1 理解配置Configuration的含义在 Gradle 中implementation、api、compileOnly这些关键词被称为“配置”Configuration。你可以把它们理解为一个个“桶”或者“作用域”用来声明依赖在构建和运行时不同阶段的作用。implementation最常用这是你绝大多数情况下应该使用的配置。用implementation声明的依赖对于当前模块是“私有”的。它们会被编译并打包到最终的输出如 AAR、JAR中但不会暴露给任何依赖当前模块的其他模块。这遵循了“依赖隐藏”原则是 Gradle 官方推荐的做法能有效减少编译时的类路径长度加快构建速度并避免依赖泄露导致的意外冲突。dependencies { implementation(com.google.code.gson:gson:2.10.1) }api谨慎使用用api声明的依赖会“传递”给所有依赖当前模块的其他模块。这相当于旧版compile配置的行为。只有当你的模块是一个库Library并且需要将其某些接口或类的公开签名暴露给使用者时才应该使用api。滥用api会导致依赖关系网变得复杂和脆弱。dependencies { // 假设你正在编写一个网络库其公开接口使用了OkHttp的Request类 api(com.squareup.okhttp3:okhttp:4.12.0) }compileOnly依赖仅在编译时需要不会被打包到最终的输出中。常用于编译时注解处理器如 Lombok、Dagger或者仅提供编译期 API 的库如androidx.annotation。dependencies { compileOnly(org.projectlombok:lombok:1.18.30) annotationProcessor(org.projectlombok:lombok:1.18.30) }runtimeOnly与compileOnly相反依赖仅在运行时需要编译时不需要。例如数据库的 JDBC 驱动实现。dependencies { runtimeOnly(mysql:mysql-connector-java:8.0.33) }testImplementation用于声明单元测试JUnit, Mockito等的依赖不会被打包到主输出中。dependencies { testImplementation(junit:junit:4.13.2) testImplementation(org.mockito:mockito-core:5.11.0) }androidTestImplementation用于声明 Android 仪器化测试Espresso, UI Automator等的依赖。实操心得养成习惯默认使用implementation。只有在明确需要将依赖的接口暴露出去时比如你在写一个公共库才考虑api。定期使用./gradlew :app:dependencies命令查看项目的依赖树检查是否有不必要的api依赖导致了传递依赖膨胀。这个命令的输出非常详细能帮你理清依赖关系。2.2 依赖坐标的三种写法在 Kotlin DSL 中声明一个依赖主要有三种字符串格式它们本质上是等价的但可读性和适用场景略有不同。简写字符串Shortcut Notation最常见和推荐的方式。implementation(com.google.android.material:material:1.11.0)格式为group:name:version。清晰直接IDE 支持最好。Map 形式当需要额外属性时使用例如排除传递依赖或指定分类器classifier。implementation(group com.google.android.material, name material, version 1.11.0)这种写法显式地命名了参数在某些复杂场景下更清晰。字符串模板不推荐用于固定版本可以将版本号提取为变量但通常有更好的管理方式见下文版本管理部分。val materialVersion 1.11.0 implementation(com.google.android.material:material:$materialVersion)3. 进阶依赖管理技巧告别硬编码直接在implementation语句里写死版本号是最简单的但对于多模块项目或需要统一升级依赖的情况这是灾难的开始。下面介绍几种进阶管理方式。3.1 使用buildSrc管理版本推荐这是 Gradle 官方推荐的最佳实践。buildSrc是一个特殊的目录Gradle 会自动将其编译并添加到所有模块构建脚本的类路径中。你可以在这里用 Kotlin/Java 代码来定义和管理所有依赖。步骤在项目根目录创建buildSrc文件夹。在buildSrc下创建build.gradle.kts文件plugins { kotlin-dsl } repositories { google() mavenCentral() }在buildSrc/src/main/kotlin目录下需要手动创建这些子目录创建一个 Kotlin 文件例如Dependencies.ktobject Versions { const val kotlin 1.9.23 const val material 1.11.0 const val retrofit 2.9.0 const val junit 4.13.2 } object Libraries { const val material com.google.android.material:material:${Versions.material} const val retrofit com.squareup.retrofit2:retrofit:${Versions.retrofit} const val junit junit:junit:${Versions.junit} }在模块的build.gradle.kts中你就可以这样引用dependencies { implementation(Libraries.material) implementation(Libraries.retrofit) testImplementation(Libraries.junit) }好处极致优雅。所有依赖和版本集中在一处纯 Kotlin 代码享受完整的 IDE 支持跳转、补全、重构。修改一个版本号所有模块同步更新。3.2 使用extra属性兼容性方案如果你的项目暂时不想引入buildSrc或者有历史包袱可以在根项目的build.gradle.kts中使用extra属性通常被定义为ext的扩展。在根build.gradle.kts中// 定义扩展属性 extra.apply { set(materialVersion, 1.11.0) set(retrofitVersion, 2.9.0) }或者更 Kotlin 的风格buildscript { extra.apply { set(materialVersion, 1.11.0) } } // 或者直接定义顶层属性需要在所有脚本中可访问的配置 val materialVersion by extra(1.11.0)在模块的build.gradle.kts中需要先读取这些属性val materialVersion: String by rootProject.extra dependencies { implementation(com.google.android.material:material:$materialVersion) }或者使用更安全的查找方式避免属性不存在时报错val materialVersion rootProject.extra.get(materialVersion) as String踩坑提醒使用extra属性时类型安全是弱项。如果你拼错了属性名或者类型转换失败错误可能到运行时才出现。buildSrc方案在编译期就能发现这类问题是更安全的选择。3.3 使用版本目录Version Catalogs—— Gradle 新特性从 Gradle 7.0 开始引入了更正式的版本目录Version Catalogs功能通过libs.versions.toml文件来管理。这是介于extra和buildSrc之间的一个平衡方案得到了 Gradle 的原生支持。在根项目的gradle文件夹下没有则创建创建libs.versions.toml文件。编辑该文件[versions] material 1.11.0 retrofit 2.9.0 [libraries] material { group com.google.android.material, name material, version.ref material } retrofit { module com.squareup.retrofit2:retrofit, version.ref retrofit } [bundles] networking [retrofit] # 可以定义依赖包 [plugins] # 管理插件版本 android-application { id com.android.application, version 8.2.0 }在模块的build.gradle.kts中通过生成的libs对象访问dependencies { implementation(libs.material) implementation(libs.retrofit) implementation(libs.bundles.networking) // 引入整个包 }优点Gradle 原生无需buildSrc的编译开销有较好的 IDE 支持较新版本的 IDEA/AS语法简洁。缺点TOML 文件的编辑体验和静态检查不如 Kotlin 代码。对于极其复杂的依赖逻辑灵活性稍逊于buildSrc。4. 处理复杂依赖场景4.1 排除传递依赖Transitive Dependency Exclusion当一个依赖本身又依赖了其他库传递依赖而那个传递依赖与你项目中的其他库存在版本冲突或你根本不需要时就需要排除它。例如libraryA依赖了unwantedLib:1.0而你的项目直接依赖了unwantedLib:2.0可能会冲突。dependencies { implementation(com.example:libraryA:1.0) { // 排除整个 group exclude(group com.unwanted) // 或者排除特定的 module exclude(module unwantedLib) // 也可以同时指定 group 和 module 进行精确排除 exclude(group com.unwanted, module unwantedLib) } }注意排除传递依赖要谨慎。被排除的依赖如果确实是运行时必需的可能会导致ClassNotFoundException。最好先通过./gradlew :app:dependencies --configuration compileClasspath命令分析依赖树确认冲突后再排除。4.2 强制使用特定版本Force如果你确定整个项目必须使用某个依赖的特定版本覆盖所有传递依赖带来的版本可以使用强制策略。这通常在根项目的build.gradle.kts中配置。subprojects { configurations.all { resolutionStrategy { // 强制所有对 com.google.guava:guava 的依赖使用 32.1.3-jre 版本 force(com.google.guava:guava:32.1.3-jre) // 另一种方式遇到任何版本冲突时优先选择指定的版本 failOnVersionConflict() } } }警告force是强力手段可能掩盖了真实的依赖冲突问题导致运行时行为不可预测。优先考虑通过排除或升级直接依赖来解决冲突。4.3 依赖分类器Classifier与扩展名Extension有些依赖会发布带有分类器的变体例如测试包tests、源码包sources或者针对不同 JDK 版本的包jdk11。dependencies { // 引入带有 tests 分类器的 JAR testImplementation(org.ow2.asm:asm:9.6) { artifact { classifier tests } } // 引入源码包通常用于IDE反编译查看 implementation(com.example:lib:1.0) { artifact { classifier sources } } }4.4 引入本地文件或模块本地 JAR/AAR 文件dependencies { implementation(files(libs/local-library.jar)) // 引入 libs 目录下所有 jar 文件 implementation(fileTree(mapOf(dir to libs, include to listOf(*.jar)))) }项目内子模块dependencies { // 引入名为 mylibrary 的本地模块 implementation(project(:mylibrary)) // 如果模块在子目录中 implementation(project(:subproject:anotherlib)) }5. 插件、仓库与构建脚本依赖依赖不仅限于项目代码构建脚本本身也可能需要依赖。5.1 声明构建脚本的依赖buildscript传统上buildscript块用于声明 Gradle 插件自身运行所需的依赖比如自定义的 Gradle 插件或特定的工具类。在 Kotlin DSL 中它通常位于脚本顶部。// 在模块的 build.gradle.kts 顶部 buildscript { // 声明仓库从哪里下载构建脚本所需的依赖 repositories { google() mavenCentral() gradlePluginPortal() // Gradle 插件门户 } // 声明构建脚本本身需要的依赖 dependencies { classpath(com.android.tools.build:gradle:8.2.2) classpath(org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.23) // 自定义的 Gradle 插件 classpath(com.example:custom-gradle-plugin:1.0) } }需要注意的是在 Gradle 新版本中对于核心插件如com.android.application,org.jetbrains.kotlin.android更推荐使用插件 DSL在plugins {}块中声明这更简洁且能享受更好的 IDE 支持。5.2 插件 DSL (plugins {})这是声明和应用插件的现代方式。它更简洁并且能自动解析和下载插件无需在buildscript中手动添加classpath。// 在模块的 build.gradle.kts 顶部 plugins { id(com.android.application) version 8.2.2 apply false // 根项目常用 apply false id(org.jetbrains.kotlin.android) version 1.9.23 apply false id(com.android.library) // 在库模块中应用版本通常在根项目统一管理 kotlin(android) // kotlin-android 插件的简写形式 }apply false表示将插件添加到项目的类路径但不立即应用到当前模块这常用于根项目的构建脚本用于统一管理插件版本然后在子模块中通过无版本的id(...)来应用。5.3 配置仓库repositories告诉 Gradle 去哪里下载你声明的依赖。通常配置在项目级别的build.gradle.kts或模块级别的dependencyResolutionManagement块中现代方式。模块级配置传统repositories { mavenCentral() // 最经典的中央仓库 google() // Android 和 Google 相关库 maven { url uri(https://jitpack.io) } // 托管在 GitHub 等平台的库 mavenLocal() // 本地 Maven 仓库 (~/.m2/repository) }项目级统一配置推荐Gradle 新特性在settings.gradle.kts中dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() maven { url uri(https://jitpack.io) } } }这样配置后所有模块的构建脚本都会默认使用这些仓库无需在每个模块中重复声明便于统一管理。6. 实战中的常见问题与排查6.1 依赖解析失败网络与仓库问题现象Could not resolve ...Connection timed out。排查检查网络连接特别是代理设置。Gradle 的代理需要在gradle.properties文件中配置systemProp.http.proxyHostproxy.company.com systemProp.http.proxyPort8080 systemProp.https.proxyHostproxy.company.com systemProp.https.proxyPort8080检查仓库地址是否正确。google()和mavenCentral()是预定义的。自定义maven仓库的 URL 务必准确。尝试将仓库顺序调整一下把最常用的如公司私服放在前面。运行./gradlew build --refresh-dependencies强制刷新依赖缓存。6.2 依赖冲突版本不兼容现象运行时NoSuchMethodError,NoClassDefFoundError或构建时提示多个版本冲突。排查使用./gradlew :app:dependencies查看完整的依赖树找出冲突的库和版本。分析冲突原因。是直接依赖了不同版本还是传递依赖导致的解决升级/降级统一项目中的直接依赖到兼容的版本。排除使用exclude排除不需要的传递依赖见4.1。强制在根项目使用resolutionStrategy.force见4.2作为最后手段。依赖替换使用dependencySubstitution在settings.gradle.kts中替换依赖。dependencyResolutionManagement { resolutionStrategy { dependencySubstitution { substitute(module(com.old:library)).using(module(com.new:library:2.0)) } } }6.3 Kotlin DSL 特有的语法错误字符串与类型安全Kotlin DSL 中依赖坐标是字符串但配置名如implementation是函数调用。确保括号和引号配对正确。缺少导入如果你在buildSrc中定义了依赖对象确保在模块脚本中正确导入。通常buildSrc的内容会自动可用但跨子项目引用时可能需要显式导入。版本变量未定义如果你使用了val version ...确保该变量在当前的脚本作用域内可访问。推荐使用buildSrc或extra来集中管理。6.4 构建速度优化依赖缓存与离线模式Gradle 构建缓存确保在gradle.properties中启用org.gradle.cachingtrue。Gradle 会缓存任务的输出下次构建时直接复用。依赖缓存Gradle 会将下载的依赖缓存在本地~/.gradle/caches目录。通常不需要手动清理除非遇到诡异的依赖问题。离线模式在确认所有依赖已下载后可以使用./gradlew build --offline进行离线构建这能强制 Gradle 不使用网络仅用本地缓存非常适合在CI/CD环境或网络不稳定时验证构建可靠性。使用更快的仓库镜像在国内可以考虑将mavenCentral()替换为阿里云镜像等以加速下载。maven { url uri(https://maven.aliyun.com/repository/public) } maven { url uri(https://maven.aliyun.com/repository/google) }从基础的implementation语法到使用buildSrc进行优雅的版本管理再到处理棘手的依赖冲突和构建优化掌握build.gradle.kts中的依赖管理是迈向高效、稳健的 Gradle 构建的第一步。核心原则是追求清晰、集中和类型安全。开始时可能会觉得 Kotlin DSL 比 Groovy 更繁琐但一旦适应其带来的开发体验和项目维护性的提升是巨大的。下次当你添加依赖时不妨先想想这个版本号放在哪里最合适这个依赖真的需要暴露给其他模块吗多花一分钟思考这些问题可能会在未来的某一天为你节省数小时的排查时间。

相关新闻

腾讯元宝AI助手深度解析:闭源商业产品的技术架构与场景应用

腾讯元宝AI助手深度解析:闭源商业产品的技术架构与场景应用

1. 腾讯元宝:一个“非典型”AI助手的深度拆解 最近圈子里聊AI助手,除了那几个国际大厂的明星产品,国内也有不少选手在发力。其中“腾讯元宝”这个名字出现的频率越来越高,但很多人对它的认知还停留在“又一个聊天机器人”的层面。…

2026/10/12 1:14:42 阅读更多 →
PostgreSQL版本查询全攻略:从SQL命令到系统探查的运维实践

PostgreSQL版本查询全攻略:从SQL命令到系统探查的运维实践

1. 项目概述:为什么“查看版本”是PostgreSQL运维的基石 刚接触PostgreSQL的朋友,可能会觉得“查看版本”这个操作太基础了,不就是一条命令的事吗?但在我十多年的数据库运维和开发经历里,恰恰是这些最基础的操作&…

2026/9/28 9:10:36 阅读更多 →
VICBench:多语言代码漏洞检测基准的实战应用与评估指南

VICBench:多语言代码漏洞检测基准的实战应用与评估指南

大家好,我是专注于技术实战与经验分享的博主。在软件安全领域,代码漏洞检测一直是保障应用质量与安全性的核心环节。然而,无论是学术界的研究还是工业界的工具开发,都面临一个共同的挑战:如何在一个统一、公平且贴近真…

2026/10/10 4:04:08 阅读更多 →

最新新闻

机器学习最小可行知识链:从公式到可调试代码的完整实践

机器学习最小可行知识链:从公式到可调试代码的完整实践

简介:本资源是邹博主讲的《机器学习全方位解析:从基础到实践》配套教学包,面向零基础入门者与希望系统夯实理论与工程能力的学习者,解决机器学习概念抽象、代码实践脱节、算法调优无从下手等核心痛点。压缩包共613个文件&#xff…

2026/10/12 13:00:09 阅读更多 →
Harbor v2.13.1 ARM64离线部署实战:内网镜像仓库搭建与避坑指南

Harbor v2.13.1 ARM64离线部署实战:内网镜像仓库搭建与避坑指南

简介:本资源为 Harbor 最新 v2.13.1 的 ARM64 架构离线安装包,面向在 ARM64 服务器或 Kubernetes 集群上部署私有镜像仓库的运维与开发人员,解决国产化平台、信创环境及边缘节点无法直接拉取官方 x86 安装包的问题。压缩包共 6 个文件&#x…

2026/10/12 13:00:09 阅读更多 →
物联网平台二次开发选型指南:架构边界、扩展点与实战避坑

物联网平台二次开发选型指南:架构边界、扩展点与实战避坑

1. 为什么“适合二开”才是物联网平台选型的硬指标做物联网平台选型这件事,我踩过不少坑。早年做某智慧园区项目,技术评审时大家盯着功能清单看——设备接入、规则引擎、数据大屏、告警中心,列表很丰满,厂商演示也很流畅。结果签完…

2026/10/12 13:00:09 阅读更多 →
批处理驱动Matlab实现参数自动扫描:原理、传参与排错指南

批处理驱动Matlab实现参数自动扫描:原理、传参与排错指南

说实话,用批处理去反复跑Matlab这事儿,我最早是在一次大规模参数寻优中被逼出来的。那时候手里有一堆实验数据要拟合,模型参数有四五种组合方式,每组参数跑一遍得几十秒,加起来几百个组合,手动改一个跑一个…

2026/10/12 13:00:08 阅读更多 →
PyTorch新手必学:ResNet18从原理到手写实现详解

PyTorch新手必学:ResNet18从原理到手写实现详解

1. 项目概述:为什么ResNet18是PyTorch新手绕不开的“第一座桥”如果你刚打开Jupyter Notebook,敲下import torch,接着想跑一个真正能分类图像的模型——不是MNIST手写数字那种玩具级任务,而是能在CIFAR-10上稳定达到92%准确率、结…

2026/10/12 13:00:08 阅读更多 →
LCA最近公共祖先算法详解:倍增法、Tarjan与树链剖分

LCA最近公共祖先算法详解:倍增法、Tarjan与树链剖分

1. 从一道面试题说起:为什么LCA值得花时间搞透第一次接触LCA是在刷题的时候,题目很直白:给一棵树,多次询问两个节点的最近公共祖先。当时我的第一反应是暴力——两个节点分别往上走,标记走过的路径,第一个相…

2026/10/12 12:59:08 阅读更多 →

日新闻

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

在数码相机、高清显示屏与现代矢量图形技术高度发达的今天,画面可以做到绝对的锐利、平滑与无瑕。然而,当一张秋日手账插画或拍立得照片过于“平整无瑕”时,往往会散发出一种冰冷生硬的“数码塑料感(Digital Plasticity&#xff0…

2026/10/12 0:00:59 阅读更多 →
活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

在现代网页与移动端设计中,横排(Horizontal Layout)早已经成为了绝对的主流。然而,当我们翻开泛黄的线装古籍、宋版木刻诗集,或是欣赏一张茶道雅集的手写便签时,那种**自上而下纵向书写、自右向左逐列铺展&…

2026/10/12 0:00:59 阅读更多 →
周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

每到周日的晚上八点到十点,很多人心里都会悄悄亮起一盏警示灯。 在心理学上,这种现象有一个专门的称谓——“周日夜晚焦虑症(Sunday Scaries)”。明天又是周一,闹钟又要重新在七点响彻卧房;脑海里仿佛有一个…

2026/10/12 0:00:59 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/12 0:16:30 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/12 0:16:43 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 10:45:37 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:53 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:54 阅读更多 →