仿谷歌验证器Android源码解析:TOTP/HOTP生成与加密备份

简介:一份面向“仿谷歌身份验证器”场景的 Android 端开源工程,基于 Java 8 实现动态口令验证核心逻辑,适合需要了解 TOTP 机制、或准备为自有账号体系添加两步验证的移动端开发者。项目围绕“固定密钥 + 实时时间戳”生成每 30 秒刷新的 6 位验证码,源码中可以看到密钥保存、二维码/密钥串导入、验证码展示与后台校验等关键环节,也有助于理解无网状态下凭密钥恢复验证器的设计思路。下载包共 114 个文件,包含 35 个 Java 源码、31 个 XML 界面与配置、26 张 PNG 图示,还附带 3 个可直接安装的 APK、Gradle 构建脚本及签名文件,压缩后仅 5.72MB。目前已有 442 人学习下载。想快速跑通验证器全流程或改造成自有工具,可直接编译运行;需要深入原理时,可结合文档与演示 GIF 分析验证码刷新节奏、异常处理与密钥管理方式,对开发同类安全组件很有参考价值。

1. 开场:一份可以自己掌控的验证器源码

出差路上临时要登录系统后台,打开新手机却找不到动态口令,旧手机里的账号又导不过来,这种场景想必不少人都经历过。这份仿谷歌验证器的Android开源源码,正是为了解决「验证器绑定容易、迁移难」的痛点而存在的。它基于Java8编写,完整覆盖扫码添加账户、TOTP/HOTP动态口令生成、SQLite本地持久化、列表倒计时刷新四个核心环节,工程不大但五脏俱全。想给自己维护一套两因素认证工具,或者在Android端摸一遍基于时间的签名算法,这份源码比翻原理PPT直观得多。

2. 架构设计:一个小而全的Java8客户端怎么分层

这类工具型App最怕的是把逻辑全堆在Activity里,读起来像一本流水账,后续加云端同步、指纹解锁都无从下手。这份源码的包结构按职责切分得比较清楚,主界面、扫码、算法、数据库各占一块,下面从模块划分、技术选型、目录结构三个角度过一遍。

2.1 模块划分与数据流

整体是一个典型的三明治结构:UI层、算法层、数据层。MainListActivity负责账户列表和悬浮扫码按钮,ScanActivity封装ZXing扫码流程,扫码拿到的原始字符串交给OtpAuthUri解析成Account对象,再写入SQLite。TokenListAdapter订阅一个每秒触发的tick事件,实时计算当前窗口的动态码并刷新列表。

数据流是单向的:扫码结果 -> URI解析 -> 入库 -> 刷新列表。单向流的好处是每个环节都能独立测试,算法不依赖数据库,URI解析也不依赖界面。比如想改成从本地相册选二维码图片解析,只要替换ScanActivity的数据来源,后面逻辑完全不用动。第一次读源码的开发者,建议从MainListActivity的onActivityResult开始跟踪,扫码页返回的那段回调就是整条链路的入口。

2.2 技术选型:为什么坚持Java8而不是Kotlin

项目标题把Java8写在最前面,说明这是有意为之。Java8自带的JCE里已经有HmacSHA1和SecretKeySpec,TOTP算法不需要额外引加密库;Stream和Lambda在处理账户列表排序、过滤时也很顺手。Android对Java8的支持靠Gradle的compileOptions开启desugar,构建时会自动把Lambda等语法翻译成兼容字节码。

| 模块 | 选型 | 理由 | | 扫码 | ZXing core + embedded | 二维码识别的事实标准,只取条码扫描能力 | | 数据库 | SQLite + SQLiteOpenHelper | 单机账户数据量小,原生方案最轻 | | 列表 | RecyclerView | 每秒刷新一次,RecyclerView的局部刷新比ListView稳 | | 算法 | Java8 JCE内置HmacSHA1 | 避免第三方加密库的体积和安全审查负担 | | 构建 | Gradle + compileOptions | desugar机制让Java8语法在低版本Android上可用 |

这里有个容易被新手忽略的点:desugar只解决语法层面的兼容,像java.time这种新API默认不提供,代码里如果用了LocalDateTime,在minSdk 21以下会崩。所以源码里时间戳几乎全是System.currentTimeMillis加手工计算,这不是偷懒,是为了兼容面更宽。有人可能问:怎么不用Room?引入Room要加注解处理器和KSP,构建链路会重不少。SQLiteOpenHelper手写SQL虽然原始,但胜在零依赖、易调试,数据库字段变了直接改onCreate迁移即可。研究型项目保持最小依赖,更容易把算法讲清楚。

2.3 源码目录速览:从包名看职责边界

解压后的工程结构大致如下,包名路径在不同发布版本里可能略有差异,但职责划分一致。

| 包路径 | 职责 | 关键类 | | activity | 界面入口与扫码页 | MainListActivity、ScanActivity | | adapter | 列表项绑定与倒计时刷新 | TokenListAdapter | | model | 数据模型与otpauth URI解析 | Account、OtpAuthUri | | db | 账户表读写 | AuthDbHelper、AccountDao | | code | 核心算法封装 | TotpGenerator、Base32Decoder | | util | 时间窗口与格式化工具 | TimeUtils |

建议阅读顺序从model开始,Account字段定下来后,code层生成算法、db层持久化、ui层展示都围绕同一个模型转。很多开发者上手直接看Activity,容易被界面逻辑带偏,其实这个项目的核心在code和model两个包里。

2.4 数据模型:一张表装下一个账户的完整信息

Account是贯穿全项目的核心对象,字段比预想的多一点:id、label、issuer、secret、type、counter、createdAt。label是显示在列表上的名称,issuer是颁发方,secret就是那条32位左右的Base32种子密钥,type标记TOTP还是HOTP,counter是HOTP专用的事件计数。

这里要特别强调:secret是敏感数据,一旦泄露等于拿到了动态口令的种子。很多开源版本把数据库放在私有目录就直接存明文,自己二次开发时至少应该用Android Keystore做一次加密,后面第6章会给出具体改造示例。理解这个模型后再看整个项目的功能就很好归类了——扫码只是在批量创建Account,列表刷新是在把Account变成长得像的六位数字,备份恢复则是把数据库里的Account序列化到文件。

3. 核心模块拆解:一条验证码从扫码到上屏的完整链路

动态验证码看似是一个密码学黑匣子,实际上核心代码加起来不超过一百行。从扫码到上屏可以拆成三步:解析otpauth URI、生成TOTP、驱动列表刷新。下面按这个顺序逐段讲,每段代码都可以直接拿出来单独测试。

3.1 TOTP生成:RFC 6238在Android上的落地方案

TOTP本质上是用时间计数器替代事件计数器的HMAC签名。整段算法固定,参数也就几个:共享密钥、时间步长、输出位数。下面是去掉边界判断后的核心方法。

public static String generateTotp(String base32Secret, long currentTimeMillis, int periodSeconds, int digits) { // 密钥清洗:去掉空格、转大写,很多扫码结果里的secret带空格或小写 String cleanedSecret = base32Secret.replace(" ", "").toUpperCase(Locale.US); byte[] keyBytes = Base32Decoder.decode(cleanedSecret); // 时间窗口计数器:Unix时间戳除以周期,再转成8字节大端整数 long counter = currentTimeMillis / 1000L / periodSeconds; byte[] counterBytes = ByteBuffer.allocate(8).putLong(counter).array(); // 用密钥对计数器做HMAC-SHA1签名,得到20字节摘要 Mac mac = Mac.getInstance("HmacSHA1"); mac.init(new SecretKeySpec(keyBytes, "HmacSHA1")); byte[] hash = mac.doFinal(counterBytes); // 动态截断:取摘要最后一位的低4位作为偏移,再拼出31位整数 int offset = hash[hash.length - 1] & 0x0F; int binary = ((hash[offset] & 0x7F) << 24) | ((hash[offset + 1] & 0xFF) << 16) | ((hash[offset + 2] & 0xFF) << 8) | ((hash[offset + 3] & 0xFF)); int otp = binary % (int) Math.pow(10, digits); return String.format(Locale.US, "%0" + digits + "d", otp); }

这里把动态截断拆成了四行,很直观。hash[offset] 与 0x7F 是把最高位清零,避免符号位干扰,很多移植版本就是漏了这一步导致生成了负数。函数参数向外暴露currentTimeMillis,是为了单元测试时能注入固定时间,不需要真等30秒。生产环境调用时直接传System.currentTimeMillis()即可,periodSeconds通常传30,digits传6。如果服务器端有容差机制,可以在边界处前后各扩展一个窗口,那就是把counter分别减一、加一再各算一遍,这个细节很多二次开发教程不会点破。

3.2 扫码解析:otpauth协议比想象中简单

扫码结果不是普通字符串,而是otpauth协议。标准格式是otpauth://totp/Label?secret=XXX&issuer=YYY。解析时用Uri.parse比手写正则更安全,系统会处理URL编码和特殊字符。

public Account parseUri(String rawText) { Uri uri = Uri.parse(rawText); // 只接受otpauth协议,且类型为totp if (!"otpauth".equals(uri.getScheme()) || !"totp".equals(uri.getHost())) { return null; } String secret = uri.getQueryParameter("secret"); if (TextUtils.isEmpty(secret)) { return null; } String issuer = uri.getQueryParameter("issuer"); // pathSegments第一段是label,个别服务端会把中文做二次编码,所以这里手动decode String label = uri.getPathSegments().isEmpty() ? "" : Uri.decode(uri.getPathSegments().get(0)); return new Account(label, issuer, secret); }

注意这里返回null的情况要单独处理,不能直接空指针。issuer允许为空,很多个人网站搭建的TOTP服务不会填这个参数。保存进数据库前,secret还要过一次清洗,把换行符、空格都去掉,否则后续生成验证码时Base32解码就会报错。

3.3 列表刷新:倒计时的线程状态管理

验证码每30秒变一次,但列表上的进度条和剩余秒数需要每秒更新。常见做法是用Handler往主线程发送延迟消息,这里有个性能雷点:如果脑抽在子线程里直接调notifyDataSetChanged,RecyclerView会直接抛异常。正确姿势是让Handler跑在主线程,每次回调里重算剩余时间。

private final Handler refreshHandler = new Handler(Looper.getMainLooper()); private final Runnable tickRunnable = new Runnable() { @Override public void run() { long now = System.currentTimeMillis(); adapter.setCurrentTime(now); adapter.notifyDataSetChanged(); // 算下一次刷新的延迟,让刷新点对齐秒边界 long delay = 1000 - (now % 1000); refreshHandler.postDelayed(this, delay); } }; @Override protected void onResume() { super.onResume(); refreshHandler.post(tickRunnable); } @Override protected void onPause() { super.onPause(); // 页面不可见时立刻移除回调,避免空转耗电 refreshHandler.removeCallbacksAndMessages(null); }

delay的计算值得细看:如果不对齐秒边界,刷新时刻会逐渐漂移,最后出现秒数跳变。另外很多改版者会在onPause里忘记移除回调,导致页面关闭后Handler还在跑,这是隐蔽的耗电元凶。这套写法同样适用于所有需要秒级刷新的列表,比如时钟App、抢购倒计时页面。

4. 编译与运行:从源码包到APK上机的完整步骤

拿到源码包第一件事是别急着双击,先确认环境。这个项目本身不复杂,但Android生态的版本错位经常比代码bug更折腾人。把环境对齐后,一条命令就能出包。

4.1 环境准备:JDK8是硬性要求

| 工具 | 版本建议 | 说明 | | JDK | 1.8 | 项目标题就是java8,用新JDK编译老工程会碰到javac编码警告 | | Android SDK | API 26-30 | minSdk通常设置在21,targetSdk在28附近问题最少 | | Android Studio | 3.5以上 | 老版本Gradle同步会出现DSL弃用警告 | | Gradle | 5.1-5.5 | 与Android Gradle Plugin 3.4-3.5匹配度最好 |

如果本机装了多个JDK版本,注意Android Studio的Gradle JVM配置要手动切到JDK8,否则sync阶段就会报Unsupported class file major version。这个报错和项目代码没关系,纯粹是工具链错位,血泪经验。

4.2 导入Android Studio:先改gradle再sync

打开工程后先别急着sync,看一眼根目录的build.gradle里的依赖版本。多数情况下,把compileSdkVersion调整为本机已安装的API级别即可。

android { compileSdkVersion 28 defaultConfig { minSdkVersion 21 targetSdkVersion 28 } compileOptions { // 开启Java8语法支持,核心步骤 sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } }

sourceCompatibility和targetCompatibility两个字段缺一不可,只配前者可能在Lambda表达式上翻车。这里的28不是写死值,家里SDK装了30就改成30,dynamic version在部分插件版本上不兼容,显式写数字最稳。sync成功后,IDE会自动下载依赖,如果网络环境一般,可以先在工程根目录执行一次gradlew --offline试试。

4.3 命令行构建:不用IDE也能产出Debug包

Gradle同步完成后,构建反而是最简单的一步。打开终端进入工程根目录:

# 构建debug包,产物在app/build/outputs/apk/debug/目录下 ./gradlew assembleDebug # 安装到已连接的真机或模拟器 ./gradlew installDebug

assembleDebug只产包不安装,installDebug会先构建再调用adb install。如果设备没开启USB调试,installDebug会在最后一步报错,这时用数据线连上手机,在开发者选项里打开USB调试即可。生成的app-debug.apk可以直接发到手机上安装,不需要签名配置。

4.4 真机调试要留意的细节

装好后第一件事不是扫码,而是先把系统时间改成自动获取。TOTP算法对时间同步极度敏感,手机时间偏差超过30秒,动态码就会在服务端校验失败。这个项目是纯本地应用,不依赖网络,飞行模式下照样能生成验证码,测试时别误以为是App坏了。建议准备一个已知secret的测试二维码,用zxing官方demo生成一张,能稳定跑通扫码、解析、出码、倒计时整个链路。

5. 常见问题避坑:移植与二次开发的五个翻车点

开源项目拿来跑通不难,难的是改成自己的过程中踩坑。下面五条都是从实际移植场景里爬出来的高频问题,按现象、原因、解决三个步骤记录。

5.1 验证码对不上:先从手机时间开刀

现象:扫码添加账户成功后,输入的六位数字在服务端总校验失败。原因:手机系统时间不准,或者开启了手动时间而没有自动同步。TOTP依赖时间窗口,系统时间和真实时间偏差越大,越容易踩到窗口边界。解决:进入系统设置把日期时间改为自动获取,等时钟同步完成后再试。调试时可以把代码里的periodSeconds临时改成60,变相扩大验证窗口,快速定位是不是时间问题。

5.2 扫码闪退:动态权限不是加一行就能过

现象:点击扫码按钮直接闪退,LogCat里报SecurityException,或者相机界面黑屏后返回。原因:Android 6.0以上运行时权限,源码的Manifest里虽然声明了CAMERA,但ScanActivity没有在运行时申请权限。解决:在启动扫码前先检查ContextCompat.checkSelfPermission,没有授权就走requestPermissions回调,授权成功后再初始化ZXing的CaptureManager。这是个高频坑,任何Android扫码项目都绕不过。

5.3 Base32解码抛IllegalArgumentException

现象:添加部分账户时程序直接崩溃,异常指向Base32Decoder.decode。原因:otpauth URI里的secret参数可能带空格、小写字母,极少数服务端还会把secret转成包含换行的格式,解码器不认识这些脏字符。解决:解码前统一做一次字符串清洗,用replace去掉所有空白符再toUpperCase,清洗动作必须在decode之前,放进工具类里复用。顺手把parseUri里的TextUtils.isEmpty判断加上,能拦截一半这类崩溃。

5.4 列表秒数跳变:别维护自己的计数器

现象:列表倒计时不是每秒递减,偶尔从29跳到27,看起来像刷新卡顿。原因:适配器里用了自增计数器,每次tick减一,但Handler在系统休眠或主线程卡顿时会跳过消息,之后没有用真实时间校准。解决:每次刷新都用System.currentTimeMillis重新计算剩余秒数,显示值永远跟随真实时钟走。这行代码看起来只是改了一个计算方式,实际上是把显示逻辑从增量式改成自校正式,一劳永逸。

5.5 Release包扫码白屏:混淆规则要跟上

现象:Debug包扫码正常,打Release包后扫码页白屏或直接崩溃。原因:混淆阶段把ZXing里通过反射调用的类干掉了,或so库没有跟随打包。解决:在proguard-rules.pro里加keep规则,保留com.google.zxing.**全量类,并检查jniLibs是否有armeabi-v7a、arm64-v8a目录。这条经验建议提前写进模板工程,不然每次发版都要翻LogCat。

6. 二次开发:给验证器加上加密备份与恢复

原版验让器最大的痛点就是换手机时没法导出账户。既然手里有源码,第一优先级的改造应该是做一个带加密的备份恢复功能。备份文件本质上就是把Account列表序列化成JSON,再加密写进文件。

6.1 改造思路

不要用简单的AES固定密钥,那把密钥写死在代码里等于没有加密。Android自带的Android Keystore可以让密钥永不离开安全硬件,用AES/GCM模式做对称加密,GCM自带完整性校验,密文被篡改一字节都解不出来。文件格式上先存IV长度、IV、密文长度、密文,导入时按长度拆开读取,避免踩到流结束判断的坑。

public void backupToFile(File target) throws Exception { List<Account> accounts = authDbDao.getAll(); JSONArray array = new JSONArray(); for (Account account : accounts) { array.put(account.toJson()); } String json = array.toString(); KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null); SecretKey secretKey = (SecretKey) keyStore.getKey("backup_key", null); Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); cipher.init(Cipher.ENCRYPT_MODE, secretKey); byte[] encrypted = cipher.doFinal(json.getBytes(StandardCharsets.UTF_8)); try (FileOutputStream fos = new FileOutputStream(target); DataOutputStream dos = new DataOutputStream(fos)) { dos.writeInt(cipher.getIV().length); dos.write(cipher.getIV()); dos.writeInt(encrypted.length); dos.write(encrypted); } }

先写IV长度再写IV,不要直接writeAll,否则导入时你不知道到底读了多少字节才算完。数据库读取、JSON序列化、加密这三个环节各自独立,可以分开测试。导入逻辑是这段代码的逆向,读长度、创建对应数组、按序填充、解密、批量入库。

6.2 验证与上线习惯

验证方法很直接:先添加两个测试账户,导出备份文件,然后卸载App或清除数据,重新安装后导入备份,账户列表应原样恢复,动态码继续正常工作。这个流程建议做成自动化脚本,每次改动存储相关代码就跑一遍。从那以后我每次改完这类认证模块,都会先走一遍备份、卸载、恢复的完整演练,确认数据不丢才敢放出去。希望帮到你。

本文还有配套的精品资源,点击获取

相关新闻

diagram-design:从草图到系统,构建可维护的图表设计工作流

diagram-design:从草图到系统,构建可维护的图表设计工作流

1. 从一张草图到一套系统&#xff1a;diagram-design 到底在解决什么问题第一次看到 diagram-design 这个词&#xff0c;很多人会以为它只是“画图”的另一种说法。但真正在项目里摸爬滚打过几年的人都知道&#xff0c;图这件事从来不是“画得好看”那么简单。它背后牵扯的是信…

2026/10/22 12:26:10 阅读更多 →
开放式代码审查实践:从流程设计到自动化落地

开放式代码审查实践:从流程设计到自动化落地

1. 项目概述&#xff1a;代码审查为什么值得当成正经事来做先说一个真实场景。某个周末晚上&#xff0c;我收到线上告警&#xff0c;用户下单后库存被多扣了一次。查到最后&#xff0c;根因是一段在 Merge Request 里被“简化”掉的事务边界。那段代码上星期过审查时&#xff0…

2026/10/22 12:26:13 阅读更多 →
SpringBoot+ElementUI自关联字典表与el-tree树形方案

SpringBoot+ElementUI自关联字典表与el-tree树形方案

字典表这个东西&#xff0c;做过管理后台的人应该都不陌生。系统里总有一堆"类型""状态""分类""层级"之类的数据&#xff0c;它们数量不多、变动不频繁、但到处都要用。很多团队一开始图省事&#xff0c;直接在代码里写死枚举&#xf…

2026/10/22 13:16:06 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年&#xff0c;我大部分时间都在跟浏览器标签页打交道&#xff0c;直到第一次把桌面应用跑起来&#xff0c;才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词&#xff0c;最开始是在某段时间频繁出现在同事的讨论里&#xff0c;一个用HTML…

2026/10/22 10:18:38 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介&#xff1a;亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档&#xff0c;主要面向智能锁安装人员、终端用户及售后维护者&#xff0c;帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件&#xff0c;大小4.37MB&#xff0c;内容结构清晰&#xff…

2026/10/22 11:01:53 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统&#xff0c;整车要求空载跑到8m/s&#xff0c;电机转速已经拉到额定点&#xff0c;驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令&#xff0c;转速纹丝不动&#xff0c;三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/10/22 9:44:47 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年&#xff0c;用它写过嵌入式驱动、做过游戏服务端&#xff0c;也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词&#xff0c;我其实挺感慨的——这门语言的难点从来不是语法多&#xff0c;而是知识点之间的耦合太深…

2026/10/22 10:42:00 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介&#xff1a;亚太天能T109滑盖智能锁产品说明书以PDF格式发布&#xff0c;适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开&#xff0c;先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能&#xff0c;再给出完整安装步骤&…

2026/10/22 10:40:08 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历&#xff1a;翻开源码注释、论文摘要或者一份专业报告&#xff0c;每个字都认识&#xff0c;连在一起却像天书。想找人聊聊&#xff0c;身边要么没人懂&#xff0c;要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型&#xff0c;几秒钟之后&a…

2026/10/22 10:56:37 阅读更多 →

日新闻

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/22 1:47:45 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/21 21:32:28 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/22 5:12:39 阅读更多 →

月新闻

我发现了一个新思路:用 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/21 21:50:56 阅读更多 →
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/21 21:51:55 阅读更多 →
黑夜航拍船只数据集训练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/21 16:24:48 阅读更多 →