从复制源码到本地Maven:Android多工程共享组件的完整实践
做Android开发久了几乎都会被同一件事绊住自己封装好的通用组件比如网络层、图片加载封装、一套带基础ViewModel的UI库忽然要在第二个、第三个工程里使用。我最早的处理办法很粗暴——把源码文件夹直接复制进新工程改bug改到一半才发现两边已经各走各路了。后来改用Git submodule又遇到子模块地址、分支同步和主工程构建时间被拖长的问题。直到认真把本地Maven库跑通之后发布一个库变成一条Gradle命令引用方只需写一行implementation版本号一变就能整体切换。这篇文章就是我当时从零搭建到实际使用的完整记录按为什么选它、坐标和目录怎么对应、发布侧怎么配、使用侧怎么接、坑在哪里的顺序展开适合正在为多工程共享代码发愁的Android工程师。1. 分发姿势选型从复制源码到本地Maven这一步怎么走1.1 三种分发方式实际体验对比刚开始维护通用库时很多人第一反应是就一个小组件直接复制过去不就行了。库只有一个类、几个接口时确实没问题但一旦它开始依赖其他第三方库、开始有版本迭代复制源码的代价就变得非常明显B工程还停留在1.0逻辑A工程已经在调试2.0的重构方案修复的bug要么忘记同步要么同步时把本地的定制改动一起覆盖掉。相比之下模块依赖至少让每个工程编译的是同一份源码通过Git子模块的方式共享但它的绑定粒度是源码级的——主工程打开就要去拉子模块子模块改动会直接影响所有引用方想固定某个历史版本反而不自然。分发方式引用形式更新粒度典型问题复制源码源码直接入工程手动覆盖多份副本逻辑漂移Git Submodule / 工程模块依赖implementation project(:lib)随主工程构建需要同步整个源码树版本锚定不便本地Maven仓库implementation com.example:lib:1.0.0按版本号发布更新时需要重新发布私服 / 公开仓库坐标依赖按版本号发布需要服务端和团队规范模块依赖适合还在快速演进、需要频繁和主工程联动调试的库本地Maven适合已经相对稳定、但还没有条件上公司级私服的中小型团队。它的本质是把源码共享切换成构件共享引用方拿到的是一份带版本标识的AAR产物不需要关心库内部怎么组织。1.2 坐标依赖到底赢在哪里Maven坐标依赖看起来只是写法上的区别但它改变了库的交付形态。implementation com.example.common:network:1.0.0这条声明里com.example.common是groupnetwork是artifactId1.0.0是version三者合起来定位到一个不可变的产物。消费者工程构建时Gradle会根据坐标去声明的仓库里找对应文件并按POM里记录的传递依赖继续解析。这个模型最实用的价值是版本锚定。我用1.0.0发布一版即使第二天在库工程里修改了代码继续开发2.0.0引用1.0.0的工程完全不受影响。协作时也可以明确告诉对方我的库是哪个版本而不是你拉一下最新代码试试。对于还在自己折腾的中间态库它会逼着养成发版意识——每次对外可见的改动都应该对应一个版本号。虽然本地Maven多了一道发布步骤但实际执行成本约等于执行一个Gradle Task后面第三节会详细写配置。相比起来它换来的多工程之间彻底解耦是非常划算的。2. 核心基础目录布局与Maven坐标的对应关系2.1 一个坐标怎么变成一堆文件路径在配Gradle之前建议先弄明白Maven仓库在磁盘上长什么样因为后面所有的路径、缓存、清理操作都和它有关。一个标准的Maven仓库路径遵循groupId转目录 artifactId version的规律。以com.example.common:network:1.0.0为例它在仓库目录下会变成network-repo/ └── com/ └── example/ └── common/ └── network/ └── 1.0.0/ ├── network-1.0.0.aar ├── network-1.0.0.pom └── network-1.0.0-sources.jargroupId里的点号会替换成目录分隔符artifactId和version直接作为下一级目录名文件名的前缀是artifactId后半段是version扩展名对于Android Library通常是.aar而不是.jar。POM文件记录了这个构件的基本信息以及它依赖了哪些库Gradle解析传递依赖靠的就是它sources.jar则是IDE跳转源码时的素材后面会有专门说明。理解这个映射关系对排查问题很有帮助。比如去本地仓库目录翻了半天找不到network.aar很可能就是把version目录层级搞错了再比如某个构件在缓存目录里多出一串哈希值子目录那是Gradle的模块缓存不是发布时生成的。2.2 仓库目录放哪才更稳妥仓库目录的位置选择直接决定后面所有命令和配置文件里写什么路径。我见过两种主流做法一种是把仓库目录放在某个公共磁盘路径下比如Windows上的D:/repos/android-local-repo所有工程在settings.gradle里统一引用这个绝对路径另一种是把它放在某个工程根目录下发布和引用都通过相对位置定位。绝对路径适合自己单机使用或者团队把目录放到共享盘上但一旦换电脑或者克隆到别的目录路径变了引用就断。相对路径更适合把本地Maven仓库作为一个普通目录提交到Git仓库里管理团队克隆项目时仓库目录也一起带过来。我在团队协作阶段更倾向于后者在安卓工程根目录下建一个localMavenRepo目录库模块发布时写死输出到${rootDir}/localMavenRepo消费者工程在settings.gradle里用相对路径引用。这样新同学clone后不需要改任何配置就能构建。还需要考虑的是要不要直接用Gradle内置的mavenLocal()仓库。它默认指向用户主目录下的~/.m2/repository单独一台机器上确实省事但这个目录是全机共享的各个项目往里丢的构件混杂在一起清理时容易误删别人正在用的版本。一旦多个开发者之间共享同一台构建机mavenLocal()的隔离性问题会非常突出。相比之下显式指定一个目录所有构件都在自己掌控下出问题时整个文件夹删掉重来也不心疼。2.3 本地Maven、mavenLocal、私服的本质差异理论上mavenLocal()也是本地Maven的一种但它背后对应的是Maven构建工具的传统本地仓库Gradle的mavenLocal()只是把它当作一个远程仓库的本地缓存来看待。如果只是自己一个人开发用mavenLocal()确实最快。但到了两个人以上协作时它的缺点就暴露了A开发者发布到自己的~/.m2B开发者根本读不到如果团队约定大家把公共仓库放到同一台共享服务器上那么本地Maven库的定义也只是一条file://协议的URL而已发布端和消费端指向同一个网络共享路径。本地Maven库解决的是还没有私服/不方便上私服阶段的共享问题。它与私服最大的差别是缺少权限管理和全局构建面板但只要能保证团队所有人都指向同一个仓库路径版本流转就能跑通。等库数量多了、需要对外分发时再把repository地址从file://换成https://配置结构基本不需要大改。3. 发布侧实操把Android Library变成可发布构件3.1 最小可用的 publishing 配置理解了目录结构后发布侧配置就很好理解了。我以Gradle Groovy DSL为例在库模块的build.gradle里添加maven-publish插件并配置一个MavenPublicationplugins { id com.android.library id maven-publish } publishing { publications { release(MavenPublication) { groupId com.example.common artifactId network version 1.0.0 afterEvaluate { from components.release } } } repositories { maven { name localRepo url uri(${rootDir}/localMavenRepo) } } }这里有三个容易忽视的点。第一afterEvaluate不能省。Android Library的components.release是在Android插件执行阶段才注册的如果在配置阶段就调用from components.release会碰到Publication only contains dependencies and/or configuration metadata之类的报错最终生成的POM缺少关键的AAR文件信息。第二name localRepo不是随便写的。它会被拼进发布任务的名称里后面在命令行里会用得到。如果仓库名写成了中文或者带空格任务名会变得很奇怪所以尽量用驼峰英文。第三url的写法。uri(${rootDir}/localMavenRepo)会基于当前构建根目录拼接路径不需要关心是Windows还是macOS斜率方向Gradle会处理。不要直接写D:\\repo这样的字符串判断系统差异可移植性会差很多。3.2 发布任务名是怎么拼出来的Gradle的maven-publish插件会自动生成一组发布任务任务名遵循固定规则publish{Publication名}PublicationTo{仓库名}Repository。上面的配置中Publication名是release仓库名是localRepo生成的任务名就是publishReleasePublicationToLocalRepoRepository。执行./gradlew :network:publishReleasePublicationToLocalRepoRepository也可以直接执行./gradlew publish它会把所有Publication发布到所有配置好的仓库。如果库模块名是:network前面要带上模块路径否则Gradle会提示找不到任务。执行成功后去localMavenRepo目录看一眼应该能看到com/example/common/network/1.0.0/目录和对应的aar、pom文件。如果POM文件里packaging不是aar多半是from components.release没生效需要回来检查配置。3.3 顺手把 sources 一起发出去默认配置发布的只有AAR和POM。如果只做到这一步消费者虽然能正常编译但想在Android Studio里点进库的类看实现时看到的会是被反编译的字节码注释和变量名完全没法看。为了开发体验通常还会追加一个sources包android { // ...已有配置 } tasks.register(sourcesJar, Jar) { archiveClassifier.set(sources) from android.sourceSets.main.java.srcDirs from src/main/kotlin // 如果库有Kotlin源码把kotlin目录也打进去 } publishing { publications { release(MavenPublication) { // groupId/artifactId/version... afterEvaluate { from components.release artifact sourcesJar } } } }archiveClassifier会决定生成文件的中间名sources对应network-1.0.0-sources.jar。如果库是纯Kotlin写的单独留java.srcDirs可能拿不到代码需要显式把src/main/kotlin也加入from列表。发布后再去看目录应该能看到-sources.jar文件。3.4 components.release到底做了什么from components.release这行代码是最容易被跳过又最关键的。它告诉发布插件从Android插件注册的release组件里提取产物信息包括主AAR包、依赖列表、BuildConfig相关属性等。POM里为什么能自动带上dependencies节点就是因为AGP在组件里记录了这些依赖坐标。如果不使用组件而是手动artifact file(build/outputs/aar/network-release.aar)确实也能发布出AAR文件但POM里的依赖信息需要手动拼pom.withXml非常痛苦。所以那句afterEvaluate不是绕弯子而是为了让AGP先把组件准备好发布插件再去读取。理解了这一点以后遇到发布的库能编译但传递依赖全丢失时第一反应就应该是检查有没有正确用组件而不是手写artifact。4. 使用侧接线仓库声明、坐标引用与版本管理4.1 settings.gradle 里的仓库配置仓库声明写在根工程settings.gradle里而不是模块的build.gradle。Android Gradle Plugin 7.0之后的推荐写法是使用dependencyResolutionManagement统一管理// settings.gradle dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS) repositories { google() mavenCentral() maven { url uri(../localMavenRepo) } } }这里的路径是相对于settings.gradle所在目录的。如果仓库目录就在当前工程根目录下直接写../localMavenRepo即可如果放在本地磁盘固定位置则用绝对路径maven { url uri(file:///D:/repos/android-local-repo) }注意Windows盘符写三斜杠file:///D:/...第一个/表示协议后面的空主机名后面的D:/才是真实路径。很多人在这一步写错导致Gradle识别不了。仓库声明顺序同样影响依赖解析Gradle会按顺序查找仓库所以如果本地Maven和远程仓库里有同名同版本的构件先声明的生效。团队内部要求本地仓库放在google()之后就行不必刻意插到中间。4.2 dependencies 里如何引用配置好仓库后在需要的模块的build.gradle里添加依赖dependencies { implementation com.example.common:network:1.0.0 }这里的坐标要和发布侧严格一致哪怕大小写不对都会解析失败。构建时Gradle会先去google()和mavenCentral()里找找不到再去localMavenRepo里找。找到后会把AAR下载到Gradle模块缓存里之后即使你删除本地仓库里那个AAR文件项目依然能继续构建——因为已经缓存过了。版本切换时只需要改依赖里的version比如从1.0.0改成1.0.1重新构建就会去本地仓库找新版本。想验证一个还在开发中的库时也可以直接把版本写成最新并发布测试完再改回正式版本这个流程比模块依赖的代码切换干净得多。4.3 多模块下版本统一一个大型App往往有多个模块都依赖同一个基础库。如果每个模块的build.gradle里都写死版本号升级时漏改一个模块就会导致版本不一致运行时出现奇怪问题。两种常用做法第一种在gradle.properties中定义变量commonNetworkVersion1.0.0模块里引用dependencies { implementation com.example.common:network:${commonNetworkVersion} }第二种使用libs.versions.toml版本目录。在gradle/libs.versions.toml里定义[versions] commonNetwork 1.0.0 [libraries] common-network { group com.example.common, name network, version.ref commonNetwork }模块里配合version catalog自动生成的访问器dependencies { implementation libs.common.network }两种方案都比散落版本号强。我在项目里偏向第二种因为可以看到所有依赖的统一清单升级时一目了然。对于多个工程共用一个基础库版本的情况建议把这份toml也纳入版本管理发版时同步改动。5. 我实际踩过的五个坑及排查记录5.1 改了发布内容后消费者构建仍是旧版本这是本地Maven最常见的问题。明明删掉了localMavenRepo里的旧AAR重新发布后其他工程依赖的还是旧版本。原因在于Gradle会把解析到的构件缓存到~/.gradle/caches/modules-2下缓存键是坐标信息和时间戳。本地仓库的内容变了但Gradle认为这个坐标已经解析过直接用缓存。处理方法是在消费端执行./gradlew build --refresh-dependencies如果版本号完全没变比如还在用1.0.0但内容已经更新--refresh-dependencies有时仍不够因为Gradle会复查元数据但动态内容仍可能命中。最彻底的办法是手动清理缓存目录中对应坐标的文件夹rm -rf ~/.gradle/caches/modules-2/files-2.1/com.example.common/network删掉后再构建Gradle会重新去本地仓库读取。为了避免这种折腾我后来养成了一个习惯本地发布测试时每次都把version递增到带-SNAPSHOT的测试版本正式发布才用稳定版本号。这样至少能减少同版本内容更换的概率。5.2 “components.release”被 afterEvaluate 之外的时间点引用某次我图省事没有加afterEvaluate直接在publishing.publications里写了from components.release。构建时Gradle抛出类似的提示Publication only contains dependencies and/or configuration metadata。这是因为AGP的配置阶段还没执行完components里还没有实际的release组件信息。排查的完整过程是先执行./gradlew :network:tasks --group publishing看看发布任务是否正常接着加上afterEvaluate重新执行。这里afterEvaluate的意思是等待整个项目的配置阶段评估完成后再执行这段闭包所以组件信息已经被AGP填充了。理解这个先后顺序后类似的报错都不会再觉得玄学。5.3 POM里的依赖坐标解析不到构建反复联网失败使用侧除了引用基础库基础库内部可能还依赖第三方库。比如我的network库依赖了OkHttp发布时POM会记录OkHttp坐标。消费者工程解析network时会继续用消费者声明的仓库去解析OkHttp。如果消费者工程的settings.gradle里没有声明mavenCentral()或者仓库顺序不对这次传递解析就会失败。排查方法是在构建命令后加--info日志里能看到它尝试解析的完整坐标列表。这个现象也提醒我一个库在发布前必须想清楚它暴露了多少外部依赖尽量把不必要的外部依赖收进库内部或者确保消费者能访问到这些依赖所在的仓库。传递依赖是Maven生态的便利之处也是本地Maven工程最容易翻车的地方。5.4 IDE 无法跳转到库的源码发布库之后接入主工程发现按Ctrl/Cmd点击NetworkApi类只能看到反编译的Class文件。这个问题的根源就是上面提到的没有发布sources构件。Android Studio本质上也是通过下载sources包来提供源码跳转的本地仓库有sources文件时IDE会自动关联。处理办法自然是补发sources包。除了配置sourcesJar之外还要注意如果之前发布过同版本但是没有sources构件重新发布同版本后消费者工程需要清理模块缓存才能看到新文件。所以最好在第一次发版时就带上sources省得后面给同事带去为什么我不能点进去看的困惑。5.5 文件URL路径写错导致Gradle始终找不到本地仓库Windows路径和Unix路径的混用是另一个高发问题。有一次我在settings.gradle里写maven { url D://repos/android-local-repo }缺少file:协议前缀Gradle会把D://...当作一个不认识的URL scheme直接报错。正确写法只能是maven { url uri(file:///D:/repos/android-local-repo) }如果路径包含空格比如D:/My Repos/test-repo空格必须做URL编码或者用uri(new File(...))maven { url uri(new File(D:/My Repos/test-repo).toURI()) }路径问题排查起来很耗时因为报错信息不一定直接说file not found有时是Could not find com.example.common:network:1.0.0这种掩人耳目的提示。后来我学会先到磁盘上确认目录存在再去检查URL写法能少走很多弯路。本地Maven这套流程跑顺之后我最大的体会是它逼着你尽早建立版本意识。以前复制源码的时候根本不会想过哪天库会以版本的形式被其他工程引用也不会去设计API的兼容性。现在每次发布前都会先看一遍改动确认是否属于破坏性变化再决定递增主版本还是次版本。团队里几个人共用同一个仓库路径后协调方式也变得很直接——只需要约定好group和artifactId命名规则不互相覆盖就行。如果你也在多工程共享代码的泥潭里挣扎先从今天这篇里的最小配置开始把第一个库发布到本地仓库改成坐标依赖后面的一切都会顺畅很多。

相关新闻

STM32+nRF24L01全双工对讲实现原理与实时调度优化

STM32+nRF24L01全双工对讲实现原理与实时调度优化

简介:本资源是一套基于STM32与NRF24L01实现全双工对讲机功能的完整嵌入式开发工程,面向嵌入式初学者及无线通信实践者,解决短距离实时语音双向通信的硬件驱动、协议配置与音频编解码集成难题。压缩包共641个文件,涵盖120个C语言源…

2026/10/15 17:01:06 阅读更多 →
如何扩展 chatbot-template:添加自定义 Tool 与 Part 组件完整步骤

如何扩展 chatbot-template:添加自定义 Tool 与 Part 组件完整步骤

【免费下载链接】chatbot-template A minimal chatbot template built with Next.js, AI SDK, shadcn/ui, shadcn/react, shadcn/typeset. It runs on the Vercel AI Gateway. 项目地址: https://gitcode.com/gh_mirrors/chatbo/chatbot-template 点击查看 免费下载…

2026/10/15 17:01:06 阅读更多 →
Chinese-LLaMA-Alpaca-2 的 llama.cpp 本地部署指南:chat.sh 交互对话与 server curl API 调用

Chinese-LLaMA-Alpaca-2 的 llama.cpp 本地部署指南:chat.sh 交互对话与 server curl API 调用

人工智能大模型预训练微调RLHFLoRA本地部署模型量化 【免费下载链接】Chinese-LLaMA-Alpaca-2 中文LLaMA-2 & Alpaca-2大模型二期项目 64K超长上下文模型 (Chinese LLaMA-2 & Alpaca-2 LLMs with 64K long context models) 项目地址: https://gitcode.com/…

2026/10/15 17:01:06 阅读更多 →

最新新闻

VLC 3.0.11 定制版支持 AVS+ 与 DRA 软解实战指南

VLC 3.0.11 定制版支持 AVS+ 与 DRA 软解实战指南

简介:本资源为适配Windows 7及以上系统的VLC媒体播放器3.0.11定制增强版,专为需播放国产音视频编码内容的开发者、广电从业人员及高清影音爱好者设计,解决主流播放器对AVS和DRA格式兼容性不足的问题。压缩包为7z格式,大小130.6MB&…

2026/10/15 17:48:03 阅读更多 →
Android属性动画解析:从补间动画缺陷到ObjectAnimator实战与原理

Android属性动画解析:从补间动画缺陷到ObjectAnimator实战与原理

做Android开发这些年,我最早接触的是补间动画,一个AnimationSet往上一套,平移、旋转、透明度都有现成接口,看起来挺方便。但真正在复杂交互里遇到按钮“飞过去但点不到”的问题之后,我才重新理解了属性动画的价值。而O…

2026/10/15 17:48:03 阅读更多 →
2026 最新 Codex 新手教程:用 cc-switch + TaoToken 零基础跑通 AI 编程

2026 最新 Codex 新手教程:用 cc-switch + TaoToken 零基础跑通 AI 编程

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

2026/10/15 17:48:03 阅读更多 →
CAN总线协议详解:从物理层差分信号到采样点配置与工程实践

CAN总线协议详解:从物理层差分信号到采样点配置与工程实践

1. 内容整体设计与思路拆解CAN,全称Controller Area Network,控制器局域网络。做嵌入式或者汽车电子的人,对这三个字母再熟悉不过。不管是车身控制、电池管理、电机驱动,还是一些工业自动化设备,几乎所有需要多个节点可…

2026/10/15 17:48:03 阅读更多 →
预编译libssh2类库接入CMake工程:链接配置与避坑指南

预编译libssh2类库接入CMake工程:链接配置与避坑指南

简介:这份资源是面向C/C开发者的libssh2预编译类库及配套头文件包,适合需要为网络管理工具、自动化脚本或远程控制软件集成SSH2能力的开发者使用,可省去自行编译的繁琐过程。压缩包共9个文件,约1.38MB,包含4个h头文件、…

2026/10/15 17:48:03 阅读更多 →
51单片机数码管动态显示与中断系统实战:从原理到代码

51单片机数码管动态显示与中断系统实战:从原理到代码

很多人学51单片机,一开始点个LED觉得挺简单,一到数码管动态显示就开始懵了。不是显示错位就是亮度不均,再往后遇到中断更是云里雾里。我当年自学的时候也在这个节点卡了差不多两周,后来把原理彻底理清楚才发现,数码管动…

2026/10/15 17:47:03 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

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

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 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/15 0:14:36 阅读更多 →
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/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练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/15 9:49:14 阅读更多 →