Android Contacts 联系人读取实战:从权限申请到 Cursor Base URL 改到 TaoToken 的完整链路
1. Android Contacts 读取联系人完整链路权限、Cursor 遍历与列表展示Android Contacts 是系统通讯录数据库的对外接口通过 ContentResolver 加 ContactsContract 这套组合你能在自己的 App 里读取联系人姓名、电话、邮箱、地址、备注等信息。它适合做通讯录备份、来电识别、社交类 App 的好友匹配、企业通讯录同步这类场景。我这次要做的是一条完整链路从 AndroidManifest 声明权限到运行时动态申请再到 ContentResolver 查询、Cursor 遍历、组装数据模型最后用 RecyclerView 展示出来并且把开发过程中用到的 AI 编码工具 Cursor 的 Base URL 统一改到 TaoToken 管理 API Key方便团队里多人共用一套调用入口。很多人第一次写 Contacts 会卡在两个地方一是以为在 Manifest 里写了 READ_CONTACTS 就万事大吉结果 Android 6.0 以上直接 SecurityException二是拿到 Cursor 后不知道联系人主表和电话、邮箱这些子表是分开存的只查主表拿不到电话号码。这篇就把这两个坑连同后面的展示、排障一起讲清楚。先明确数据模型。Android 的联系人数据库是高度规范化的主表 ContactsContract.Contacts 存的是每个联系人的聚合记录字段有 _ID、DISPLAY_NAME、HAS_PHONE_NUMBER 等。而电话号码存在 ContactsContract.CommonDataKinds.Phone 这张子表里通过 CONTACT_ID 关联主表。邮箱在 Email 子表地址在 StructuredPostal备注在 Note即时消息在 Im组织信息在 Organization。这些子表大部分挂在 ContactsContract.Data 这个通用数据表下用 MIMETYPE 区分类型。理解这一点后面写查询就不会乱。环境上我用的是 Android Studio 最新稳定版Gradle 8.xcompileSdk 34minSdk 24语言用 Kotlin。模拟器选 Pixel 系列API 34。为什么强调模拟器因为模拟器默认通讯录是空的你得先手动加几条联系人不然查询返回 0 条你会误以为代码写错了。我一般会在模拟器里加三条一条只有姓名一条有姓名加两个电话一条有姓名加邮箱和地址这样能覆盖各种分支。整条链路我拆成六步走声明权限、运行时申请、查询主表、按 ID 查子表、组装模型、列表展示。每一步都有可直接复制的代码。写完之后再讲怎么把 Cursor 的 Base URL 改到 TaoToken让 AI 辅助编码时的请求走统一网关最后用日志和断点验证数据确实回来了。2. TaoToken 前置准备统一管理 API Key 与 Cursor Base URL 配置在正式写 Contacts 代码之前先把开发环境里的 AI 编码工具配置好。我用 Cursor 写 Android 代码团队里几个人如果各自管各自的 Key很容易出现额度混乱、Key 泄露、换人就得重新配的问题。TaoToken 提供统一的 API 入口把 Base URL 指过去Key 集中管理换工具也不用改代码逻辑。TaoToken 的官网入口是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 根地址是 https://taotoken.net/api 。注意 API 地址后面不加任何查询参数保持干净。你需要先去控制台创建一个 API Key控制台地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 在 API Keys 页面生成地址是 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。生成后复制那串以 sk- 开头的字符串只显示一次丢了就重新生成。Cursor 里改 Base URL 的位置在设置里。打开 Cursor进入 Settings找到 Models 或 OpenAI API Key 相关配置区。不同版本菜单名略有差异核心是找到 Override OpenAI Base URL 这一项。把它填成 https://taotoken.net/api 然后在 API Key 输入框里粘贴你刚生成的 Key。如果你用的是兼容 OpenAI 协议的自定义模型入口Base URL 同样填这个地址Model ID 按你实际要用的模型名填比如 gpt-4o、claude-3-5-sonnet 这类具体以 TaoToken 文档里列出的可用模型为准文档地址 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。这里有个细节要注意Base URL 结尾不要带斜杠也不要带 /v1 之外的路径除非文档明确说明。我见过有人填成 https://taotoken.net/api/v1/chat/completions 这种完整路径结果请求 404。正确做法是只填到 /api 这一层客户端会自己拼后面的路径。填完之后点 Verify 或保存Cursor 会发一个测试请求返回成功就说明通了。如果你用的是 Claude Code 这类命令行工具配置方式类似在环境变量或配置文件里设置 ANTHROPIC_BASE_URL 指向 TaoToken 的对应端点具体参考 https://taotoken.net/claude-code-anthropic?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。长期做编码和 Agent 任务的话可以看下 Coding Plan地址 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 适合高频调用场景。配置好之后你在 Cursor 里让 AI 帮你写 Contacts 查询代码请求就走 TaoToken 了。这样做的好处是Key 只在 TaoToken 控制台管理团队成员用同一个入口额度、日志、模型切换都在一处看。下面进入正题开始写 Android 代码。3. 可复制配置权限声明、运行时申请与 ContentResolver 查询代码这一节是全文的核心所有代码都可以直接复制到你的项目里。我按文件顺序给你跟着建就行。第一步AndroidManifest.xml 里声明权限。在application标签外面uses-sdk或manifest根节点下加uses-permission android:nameandroid.permission.READ_CONTACTS /如果你还要写联系人再加uses-permission android:nameandroid.permission.WRITE_CONTACTS /。只读的话一个就够。注意 Android 6.0API 23以上这个声明只是告诉系统你要用真正授权还得运行时申请。第二步运行时权限申请。我用 Activity Result API比老的 onRequestPermissionsResult 干净。在 Activity 或 Fragment 里private val requestPermissionLauncher registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted - if (granted) { loadContacts() } else { Toast.makeText(this, 需要通讯录权限才能读取联系人, Toast.LENGTH_SHORT).show() } } private fun checkAndLoadContacts() { when { ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) PackageManager.PERMISSION_GRANTED - { loadContacts() } shouldShowRequestPermissionRationale(Manifest.permission.READ_CONTACTS) - { AlertDialog.Builder(this) .setTitle(权限说明) .setMessage(读取联系人用于展示通讯录列表) .setPositiveButton(去授权) { _, _ - requestPermissionLauncher.launch(Manifest.permission.READ_CONTACTS) } .setNegativeButton(取消, null) .show() } else - { requestPermissionLauncher.launch(Manifest.permission.READ_CONTACTS) } } }第三步查询主表。核心是 ContentResolver.queryURI 用 ContactsContract.Contacts.CONTENT_URIprivate fun loadContacts() { lifecycleScope.launch(Dispatchers.IO) { val result mutableListOfContactModel() val resolver contentResolver val cursor resolver.query( ContactsContract.Contacts.CONTENT_URI, arrayOf( ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME, ContactsContract.Contacts.HAS_PHONE_NUMBER ), null, null, ${ContactsContract.Contacts.DISPLAY_NAME} ASC ) cursor?.use { c - val idIdx c.getColumnIndex(ContactsContract.Contacts._ID) val nameIdx c.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME) val hasPhoneIdx c.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER) while (c.moveToNext()) { val id c.getString(idIdx) val name c.getString(nameIdx) ?: 未知 val hasPhone c.getInt(hasPhoneIdx) 0 val phones if (hasPhone) queryPhones(id) else emptyList() val emails queryEmails(id) result.add(ContactModel(id, name, phones, emails)) } } withContext(Dispatchers.Main) { adapter.submitList(result) Log.d(Contacts, 共加载 ${result.size} 条联系人) } } }注意几个点query 的第二个参数我显式传了列名数组而不是 null。传 null 会返回所有列数据量大时浪费内存而且列索引不稳定。排序用 DISPLAY_NAME ASC让列表按名字排。cursor 用 use 包起来自动 close避免泄漏。查询放 IO 线程UI 更新切回主线程。第四步按联系人 ID 查电话和邮箱子表private fun queryPhones(contactId: String): ListString { val phones mutableListOfString() val cursor contentResolver.query( ContactsContract.CommonDataKinds.Phone.CONTENT_URI, arrayOf(ContactsContract.CommonDataKinds.Phone.NUMBER), ${ContactsContract.CommonDataKinds.Phone.CONTACT_ID} ?, arrayOf(contactId), null ) cursor?.use { c - val numIdx c.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER) while (c.moveToNext()) { phones.add(c.getString(numIdx)) } } return phones } private fun queryEmails(contactId: String): ListString { val emails mutableListOfString() val cursor contentResolver.query( ContactsContract.CommonDataKinds.Email.CONTENT_URI, arrayOf(ContactsContract.CommonDataKinds.Email.DATA), ${ContactsContract.CommonDataKinds.Email.CONTACT_ID} ?, arrayOf(contactId), null ) cursor?.use { c - val emailIdx c.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA) while (c.moveToNext()) { emails.add(c.getString(emailIdx)) } } return emails }数据模型 ContactModel 就是一个 data class三个字段id、name、phones、emails。RecyclerView 的 adapter 用 ListAdapter 加 DiffUtil这里不展开常规写法即可。第五步如果你要查地址、备注、组织信息它们都在 ContactsContract.Data 表里用 MIMETYPE 过滤。以地址为例val addrWhere ${ContactsContract.Data.CONTACT_ID} ? AND ${ContactsContract.Data.MIMETYPE} ? val addrParams arrayOf(contactId, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE) val addrCursor contentResolver.query( ContactsContract.Data.CONTENT_URI, null, addrWhere, addrParams, null )地址字段拆成了 POBOX、STREET、CITY、REGION、POSTCODE、COUNTRY 多个列逐个取就行。备注用 Note.CONTENT_ITEM_TYPE组织用 Organization.CONTENT_ITEM_TYPE套路完全一样。4. 验证请求与成功结果模拟器加联系人、日志与断点确认数据返回代码写完怎么确认它真的跑通了我按模拟器验证的步骤走一遍。先在模拟器里加联系人。打开模拟器的 Contacts 应用点右下角加号建三条测试数据。第一条只填姓名「张三」不填电话。第二条填「李四」加两个电话13800000001 和 13900000002。第三条填「王五」加邮箱 wangwutest.com 和一个地址。加完返回桌面。然后跑你的 App。第一次启动会弹权限对话框点允许。如果之前拒绝过会走 shouldShowRequestPermissionRationale 分支弹说明框。授权后列表应该显示三条联系人张三没有电话李四显示两个号码王五显示邮箱。看日志。我在 loadContacts 里打了Log.d(Contacts, 共加载 ${result.size} 条联系人)在 Android Studio 的 Logcat 里过滤 tag 为 Contacts应该看到「共加载 3 条联系人」。如果显示 0先检查模拟器通讯录是不是真空的再去设置里确认权限给了没有。断点调试更直观。在while (c.moveToNext())这一行打上断点用 Debug 模式启动。程序停住后在 Variables 面板里展开 cursor看它的 count 和当前行的各列值。你可以手动调 c.getString(nameIdx)看返回的姓名对不对。继续往下走进到 queryPhones看返回的 list 大小。我实测下来李四那条会返回 size 为 2 的 list张三返回空 list符合预期。还有一个验证点Cursor 的列索引。如果你用 getColumnIndex 返回 -1说明列名写错了getString(-1) 会抛异常。我建议在调试时把每个 index 打出来看一眼Log.d(Contacts, idIdx$idIdx nameIdx$nameIdx hasPhoneIdx$hasPhoneIdx)正常应该是 0、1、2 这种非负值。如果某个是 -1回去核对列名常量有没有拼错。验证通过后列表展示这块我用 RecyclerView 加一个简单的 item 布局姓名大字电话和邮箱小字。滚动流畅没有卡顿因为查询在 IO 线程数据量几百条以内没问题。如果联系人上千条建议加分页或懒加载子表数据不要一次性全查。5. 本篇常见错误排查SecurityException、Cursor 空指针与列索引 -1这一节把我踩过的坑和常见报错列出来对照着查。第一个java.lang.SecurityException: Permission Denial: reading com.android.providers.contacts。这个报错说明运行时权限没给。检查两点Manifest 里有没有声明 READ_CONTACTS代码里有没有在查询前调用 checkSelfPermission 并申请。很多人只在 Manifest 写了就以为完事Android 6.0 以上必崩。解决就是补上运行时申请逻辑用上面第 3 节的代码。第二个Attempt to invoke interface method int android.database.Cursor.getCount() on a null object reference。query 返回 null通常是 URI 写错或者权限问题。ContactsContract.Contacts.CONTENT_URI 这个常量别手写字符串直接用 SDK 提供的。如果权限给了还返回 null检查是不是在非主线程外的地方用了错误的 Context。第三个CursorIndexOutOfBoundsException: Index -1 requested。getColumnIndex 返回 -1说明你请求的列不在 cursor 里。常见原因是 query 的 projection 数组里没包含那一列却去 getColumnIndex 取它。比如你 projection 只传了 _ID 和 DISPLAY_NAME却去取 HAS_PHONE_NUMBER就会 -1。解决是把要用的列都加进 projection。第四个电话号码查出来是空。检查 HAS_PHONE_NUMBER 字段如果为 0 就别去查 Phone 子表了查了也是空。另外 Phone.CONTACT_ID 的过滤条件别写成 Phone._ID这俩不是一个东西。第五个Cursor 没关导致内存泄漏或CursorWindowAllocationException。每个 query 返回的 cursor 都要 close用 Kotlin 的 use 最省心。嵌套查询时外层 cursor 遍历过程中开内层 cursor内层用完立刻关别攒着。第六个如果你在 Cursor 里配了 TaoToken 的 Base URL但 AI 补全报401 Unauthorized或local proxy failed先检查 Key 有没有粘贴完整、有没有多余空格。再检查 Base URL 是不是填成了 https://taotoken.net/api 而不是带 /v1 的完整路径。如果报reading choices相关错误通常是返回体格式和客户端预期不一致确认 Model ID 填的是 TaoToken 支持的模型名。OAuth 类报错一般出现在 Claude Code 场景检查 ANTHROPIC_BASE_URL 配置。这些排障细节在接入文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 里有更全的说明。第七个模拟器联系人加了但 App 读不到。可能是模拟器的通讯录账户没同步或者你加联系人的时候选错了账户。在模拟器设置里看 Accounts确认有本地账户。实在不行重启模拟器再试。6. 接入与验证入口把 Contacts 链路和 API Key 管理串起来整条链路走完你应该已经能在自己的 App 里读出联系人姓名、电话、邮箱并且用日志和断点确认了数据正确返回。回顾一下关键点Manifest 声明权限只是第一步运行时申请不能省主表和子表分开查用 CONTACT_ID 关联Cursor 必须 close查询放 IO 线程列索引为 -1 就是 projection 没带那一列。开发过程中用 Cursor 写这些代码时把 Base URL 统一改到 TaoTokenKey 在控制台集中管理团队协作会顺很多。需要生成新 Key 或查看额度去 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。想直接测试模型对话效果可以用 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 这个入口。长期做 Android 开发、频繁让 AI 辅助写代码的话Coding Plan 地址是 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 按需选用。最后给个实用建议Contacts 查询在真机上数据量可能很大别在主线程查也别一次性把所有子表数据全加载进内存。我一般先查主表拿 ID 和姓名展示用户点进详情页再查电话邮箱地址。这样首屏快内存也稳。如果你要做通讯录备份记得处理重复联系人Android 的聚合机制会把多个账户的同一人合并_ID 是聚合后的原始 raw contact id 在 RawContacts 表里需要的话再深入查。

相关新闻

无师自通的项目式学习法:用TaoToken统一Key跑通AI辅助C++编程项目

无师自通的项目式学习法:用TaoToken统一Key跑通AI辅助C++编程项目

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

2026/10/10 21:04:49 阅读更多 →
VFS核心对象inode深度剖析:元数据、生命周期与inode耗尽排查

VFS核心对象inode深度剖析:元数据、生命周期与inode耗尽排查

在Linux内核里,如果只允许挑一个结构体来代表“文件系统”,那一定非inode莫属。它既不像dentry那样只负责路径和名字映射,也不像file那样随每次open而来、close而去;inode是整个VFS层的中枢对象,一头连着磁盘上的元数据…

2026/10/10 21:03:48 阅读更多 →
三年后还能一键重跑:OpenResearch 的可复现性是怎样炼成的

三年后还能一键重跑:OpenResearch 的可复现性是怎样炼成的

三年后还能一键重跑:OpenResearch 的可复现性是怎样炼成的 【免费下载链接】OpenResearch Turn your coding agents into research agents 项目地址: https://gitcode.com/GitHub_Trending/op/OpenResearch 科研可复现性向来是领域内最沉重的话术之一&#x…

2026/10/10 21:03:48 阅读更多 →

最新新闻

impeccable:一款面向OpenAPI契约的Python自动化校验工具

impeccable:一款面向OpenAPI契约的Python自动化校验工具

我无法基于当前输入生成符合要求的博文。原因如下:输入中仅提供了项目标题"impeccable",以及空置的“相关热搜词”“最新网络热词”和完全空白的搜索内容块(),未提供任何实质性的项目正文、关键词列表或摘要…

2026/10/10 21:47:36 阅读更多 →
X射线底片焊缝缺陷检测:2647张6类标注数据集,可直接喂给YOLO

X射线底片焊缝缺陷检测:2647张6类标注数据集,可直接喂给YOLO

简介:面向工业X射线底片焊缝缺陷检测的目标检测数据集,涵盖裂纹、未熔合、未渗透等6类焊缝缺陷,共2647张底片图像、4766个真实标注框,适合用于YOLO、Faster R-CNN等目标检测模型的训练与评测。数据采用VOC与YOLO双格式存储&#x…

2026/10/10 21:47:36 阅读更多 →
AI辅助软件测试实战:从脚本生成到日志分析的全流程经验

AI辅助软件测试实战:从脚本生成到日志分析的全流程经验

软件测试这行的工具形态,这几年变化比我入行前十年加起来都大。以前同行碰头聊提效,无非是自动化框架怎么搭、脚本怎么写更稳、CI怎么接;现在问得最多的变成了"你平时用哪个AI工具""Prompt怎么写的""AI生成的脚本你…

2026/10/10 21:47:36 阅读更多 →
开源AI测试工具落地指南:从接口自动化到自愈定位器的实践选型

开源AI测试工具落地指南:从接口自动化到自愈定位器的实践选型

软件测试这个岗位,这两年的变化比过去十年加起来都大。我记得年初帮一个测试组做评审,同事把一份AI生成的接口用例贴出来,从覆盖路径到断言写法看着都像模像样,但一跑就发现大量断言是“凭空捏造”的——它把响应里根本不存在的字…

2026/10/10 21:47:36 阅读更多 →
Inno Setup自定义安装界面:ILSpy反编译+WinForms回调实践

Inno Setup自定义安装界面:ILSpy反编译+WinForms回调实践

简介:一套面向.NET应用开发者的Inno Setup自定义安装界面资源,用于解决安装包界面模板固化、动态配置繁琐的问题。资源基于Inno Setup增强版封装,内置对.NET Framework 4的依赖支持,并将界面逻辑集中在Code.iss脚本中,…

2026/10/10 21:47:36 阅读更多 →
【Claude Code】BMad-Method 多智能体协作实战:PRD 与架构文档一键生成,TaoToken 统一 Key 接入

【Claude Code】BMad-Method 多智能体协作实战:PRD 与架构文档一键生成,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/10 21:46:35 阅读更多 →

日新闻

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

1. 从“卫星轨道分类”这个标题说起:为什么值得花时间搞懂第一次接触“卫星轨道分类”这个概念,很多人会觉得它离自己很远——不就是天上的星星怎么转吗?但如果你正在做航天任务规划、遥感数据接收、星座设计,甚至只是准备一场航天…

2026/10/10 0:00:39 阅读更多 →
Spring AOP 核心原理与实战:从概念到日志切面落地

Spring AOP 核心原理与实战:从概念到日志切面落地

1. 从一个真实痛点说起:为什么你的代码里到处都是重复逻辑刚入行那会儿,我写过一个用户管理模块,注册、登录、改密码、注销四个接口。每个接口里都塞了几乎一样的日志打印、参数校验、事务开启和提交。当时觉得没什么,能跑就行。直…

2026/10/10 0:00:40 阅读更多 →
Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

简介:这是一套面向计算机相关专业学生与项目实战学习者的Python数据采集与分析可视化完整项目,以Boss直聘岗位数据为对象,适合用作毕业设计、课程设计或期末大作业。资源包共38个文件,约246KB,以13个py源码文件为核心&…

2026/10/10 0:00:40 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

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

2026/10/10 11:14:25 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

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

2026/10/10 1:36:08 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

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

2026/10/10 11:14:58 阅读更多 →

月新闻

我发现了一个新思路:用 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/10 5:23:50 阅读更多 →
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/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练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/10 10:38:42 阅读更多 →