上架 3 个月就登顶鸿蒙闪卡软件好评榜首,接近第二名的两倍:记得闪卡的“断崖式”优势与从哪来?为什么甚至在整个移动端软件中堪称鸿蒙独占的优势软件之一?
上架 3 个月好评榜首,接近第二名两倍:【记得闪卡】的“断崖式”优势从哪来?为什么甚至在整个移动端软件中能成为鸿蒙独占的优势软件之一?
3 个月 | 鸿蒙端闪卡类好评第一 | 接近第二名两倍
先说结论:
它不是“鸿蒙里还行”,而是放到整个移动端闪卡赛道,体验仍然是断崖式的。
它的核心与 AnkiDroid 同级,差异化来自鸿蒙的图形、手写、语音、窗口、卡片服务,以及开源的 Agent 生态。
它已经是目前鸿蒙端少数具备独占优势的软件之一。
一、成绩:3 个月榜首,说明的不只是“有人喜欢”
据应用市场公开评价数据,记得闪卡上架 3 个月,在鸿蒙端闪卡类软件中好评数排名第一,接近第二名的两倍。
这个成绩至少说明三件事:
- 以新胜老 3 个月时间少于大多数原生鸿蒙闪卡类型软件的上架时间,却能成功实现弯道超车
- 不是靠单一功能赢的。 有人要 Anki 兼容,有人要好看,有人要 FSRS,有人要平板手写;只满足一类人,很难拿到接近第二名两倍的好评数。
- 踩中了鸿蒙端的空位。 既有 Anki 级内核、又有原生体验的闪卡产品极少;多数产品要么套壳 WebView,要么自建轻量算法。
但成绩只是结果。真正要回答的是:为什么是它?
二、难题:闪卡为什么难做?
移动端闪卡长期被困在一个三角里:
- 好看的,往往算法浅。 自建 SM-2 或简化间隔,短期能用,长期数据没有迁移价值。
- **算法强的,往往界面像十年前的桌面软件。**例如ankidroid
所以,做一款“鸿蒙端闪卡”并不难;难的是同时做到:
- 不重造调度器,让已有 Anki 牌组、复习记录、同步关系继续用;
- 不牺牲原生体验,让界面、动效、手势、键鼠都像鸿蒙原生应用;
- 不放弃平台能力,把鸿蒙独有的手写、图形、语音、卡片服务用起来;
- 不闭门造车,让 Agent、桌面插件、其他工具都能接进来。
记得闪卡的选择是:核心不造轮子,体验重做一遍,平台能力用到极致,生态接口保持开放。
三、体验层(一):液态玻璃不是滤镜,是实时光学
一句话: 真玻璃 = 实时采样 + 位移折射 + 生命周期 + 性能预算。

注意菜单背后的卡片标题、蓝色选中描边和渐变背景:它们没有被白色贴纸盖住,而是被玻璃轻微模糊、染色,并在边缘产生位移。这是实时采样与折射,不是半透明色块。
常见的“玻璃风”是半透明白底 + 阴影 + 背景模糊,缺两个关键行为:
- 背景是实时变化的,不是静态模糊图;
- 边缘有折射,越靠近圆角和轮廓,背景线条位移越明显。
记得闪卡的做法:
- 用
componentSnapshot抓取面板背后的真实正文; - 对结果做 5.5vp 高斯模糊;
- 用位移网格对纹理逐顶点采样,模拟边缘折射;
- 位移在 36vp 过渡带内按距离场衰减,最大约 10vp;
- 用
drawVertices画到面板区域,而不是贴矩形图。
// 36vp 过渡带;位移在轮廓和带内缘归零
const band = Math.min(36 * density, Math.min(width, height) * 0.4);
const depth = Math.min(10 * density, band * 0.3);
const shift = Math.min(depth, band * 0.3) * 4 * frost * (1 - frost);
难点不是画出来,而是什么时候画、画哪一帧、什么时候释放:
- 每个
UIContext一个采集会话,同一背景一帧只采一次; - 面板打开时按 50ms 采样,关闭且无监听者立即停止;
- 面板是采样源外的兄弟节点,避免把自己采进去;
- 内嵌弹层传
freezeDuringPanels=true,首个弹层出现即冻结源; - 旧纹理延迟一帧释放;
- 异步截图完成时再次检查许可,丢弃迟到帧。
这解决三个问题:闪、脏、卡。面板初始 opacity=0.01,等真实纹理就绪后,玻璃和文字一起展开,不用假底色过渡。
性能上,模糊后的背景是低频信息,不需要全分辨率:
// 最长边不超过 512 像素,且不超过原尺寸一半
return Math.min(0.5, 512 / Math.max(width, height));
| 指标 | 优化前 | 优化后 |
|---|---|---|
EffectImageRender::Render 中位 | 40.48ms | 16.88ms |
| 最大 | 50.84ms | 20.48ms |
| hitrace 样本 | 10 次 | 18 次 |
同一轮 UIVsyncTask 最大 14.89→16.76ms,所以项目文档明确写了:不能把后台处理下降报告成“已消除视觉闪动或掉帧”。
玻璃也不是全局滤镜:默认扁平,玻璃可选;只用于菜单、弹窗、选择器、浮动工具栏、评分面板;卡片正文、代码编辑区、白板保持实底。同一语义复用同一入口,不允许业务页面自己写一份半透明白底。
颜值不是换皮肤,是材质系统、生命周期、性能预算和组件纪律的总和。
四、体验层(二):把三步操作压成一步
一句话: 直觉不是手势多,是完成一件事的步骤少。
普通菜单是“点击 → 弹出 → 找到目标 → 再点”;记得闪卡的很多菜单是“按住 → 滑到目标 → 松手执行”。
- 按住 200ms 展开;
- 滑过时实时高亮可用项;
- 松手执行,移出/取消/第二指按下都不执行;
- 子菜单停留 220ms 只展开,松手落在叶项才执行;
- 菜单滚动边缘只滚动,不误触。
这套机制来自对 Telegram ActionBarMenuItem / BottomSheet 的源码阅读,然后用 ArkUI 重实现,覆盖首页更多/新建、牌组预览、学习/浏览更多、筛选/排序、设置模式等入口。
编辑轮盘把格式工具放到拇指边:旋转或纵向移动选择,松手定位;粗体/斜体/下划线/荧光多选;键盘、旋转、多指、后台切换都会取消复位。
学习手势支持上下左右滑、双击、两指/三指/四指、摇一摇、4/9 宫格 Tap Zone,并可按题面/答案面分别绑定。默认只保留最常用的“左滑良好、右滑困难、双击翻面”。
动效上,记得闪卡有两档,但不是所有地方都加动画:
- 菜单:克制 150ms,灵动 220ms,关闭 140ms 只淡出;
- 页面:16vp 平移 + 淡入;
- 按钮:按下缩到 97.5%,松手恢复;
- 数字变化:120/180ms 局部过渡;
- 列表:稳定 key +
maintainVisibleContentPosition(true)。
反常识的是:学习页显示答案、切换卡片没有额外翻卡动画。翻卡再漂亮,也是在用户和知识之间加延迟。
平板/PC 也不是把手机界面拉宽:宽屏主从布局、键鼠快捷键、右键菜单、传统多列表格、12 种语言和地区。
直觉不是手势数量,是完成一件事的操作成本。
五、地基层(一):记忆算法,不造轮子但把轮子用到底
一句话: 算法不重写,但每个参数都要能落地。
闪卡最容易被低估的是算法。界面可以一个月做出来,调度错了,用户三个月的数据就废了。
记得闪卡的调度、FSRS、队列、埋藏/暂停、完成判定全部来自 Anki Core,前端不另写算法。
调用链:
ArkUI → ArkTS Service(protobuf)
→ 后端会话 → C++ Node-API
→ Rust C ABI → Anki 26.05 Rust Core
两条不变量:
- ArkTS 不直接读写
collection.anki2,也不实现 SM-2/FSRS/队列选择; SchedulingStates保持原始 protobuf 字节并原样回写,避免“看起来一样、字段已经丢了”。
FSRS 不是开关,而是一整套参数:目标记忆保持率、最大间隔、简单日权重、复习顺序、学习/重学步骤、历史保持率、Leeches 策略,以及 17/19/21 个参数的三代格式。
参数优化走 Core 的真实拟合,支持忽略指定日期前的历史:
search: config.config.paramSearch.trim() || presetSearch,
currentParams: fsrsParams(config.config),
ignoreRevlogsBeforeMs: timestamp,
numOfRelearningSteps: config.config.relearnSteps.length,
还支持复习负担模拟:给定参数、目标保持率、每日上限、最大间隔,模拟未来最多 3650 天的到期量。它回答的是“我按这个设置学一年,会不会被压垮”。
自定义调度脚本用 QuickJS + Wasm 沙箱:3 秒、燃料、内存、最大 60000 字节;不提供 DOM、网络、await、计时器;原生侧按字段打补丁,current 和未修改字段保持原始字节;失败不静默回退。
统计把 FSRS 拆开:稳定度、难度、可提取性、真实保持率、未来到期、热力图、间隔分布、小时分布、回答按钮分布。
算法不是黑箱,才有调整的依据。
六、地基层(二):内核调度,让 Rust Core 在鸿蒙上“像原生”
一句话: 快不是“用了 Rust”,是每个等待都能被调度、取消、预取。
“内核调度”分三层:
- 记忆调度:FSRS 决定下一张卡什么时候出现;
- 运行时调度:原生桥决定调用怎么排队、取消、预取;
- 任务调度:首页决定启动先做什么、什么可以等。
C++ 层只导出三个函数:openBackend、runMethodRaw、closeBackend。它不理解卡片、牌组、FSRS,也不拼业务错误文案。
Rust 侧用全局注册表分配句柄,Arc<Mutex<...>> 保证同一 Backend 串行、不同句柄独立;每个跨边界调用包在 catch_unwind() 里,panic 不会穿过 C ABI 带走 ArkTS 进程。
取消是最能体现功力的地方:
// AbortSync 只发取消信号;不依赖可能被集合调用占满的工作线程池。
if (call->input.empty() &&
((call->service == RPC_SYNC_SERVICE && call->method == RPC_ABORT_SYNC) ||
(call->service == RPC_COLLECTION_SERVICE &&
(call->method == RPC_LATEST_PROGRESS || call->method == RPC_SET_WANTS_ABORT)))) {
ExecuteCall(env, call.get());
CompleteCall(env, napi_ok, call.release());
return promise;
}
AbortSync 直接在当前线程执行,只发取消信号,不排队、不等锁。但取消同步 ≠ 回滚完成:Core 停下后,已发生的写入仍按事务语义处理。
预取只缓存一张候选卡,最长 30 秒;当前卡面确认后才开始准备;不提前执行未来卡的模板 JS、不播放未来音频;评分后重新读取队首,只有 cardId 匹配才复用。
切卡用双 Web 槽:备用槽完成脚本、公式、布局,等两次动画帧确认绘制,再切换可见槽;当前槽保留旧帧,备用槽不参与输入。
MathJax 按需加载:静态无公式卡省掉约 2.3MB 引擎;任一面含 TeX、MathML、实体或脚本就保守加载完整引擎。浏览器 4 倍 CPU 降速下,中位数从 245ms 降到 106ms。
首页任务分层:HomeDataRepository.load() 读完牌组树就放行学习;统计单独队列;HomeWorkCoordinator 规定“外部文件 → 待执行导航 → 手动同步 → 公告 → 引导”。
快不是“用了 Rust”,是把每一个等待都拆开、排好序、能取消。
七、上限层:移动端不是阉割版
一句话: 移动端不是“功能少一点”,是把桌面主链路完整搬过来。
- 数据:
.apkg导入/导出、.colpkg备份/恢复、CSV/TSV/TXT、系统文件打开、空间预检、自动安全副本、媒体检查/回收站、自动历史备份。 - 同步:AnkiWeb 集合与媒体、自定义端点、自动同步、全量上传/下载、冲突确认、实验性设备直连。
- 浏览/编辑:Cards/Notes、Anki 搜索语法、保存搜索、全选/Shift 区间、批量改牌组/旗标/暂停/到期、传统多列表格、笔记类型/模板、富文本、绘图、图片遮罩、视频、白板、未保存预览。
- 平台:手机/平板/2-in-1、12 种语言、七套配色 + 幻彩、提醒、2×4 桌面卡片、DeepLink、键鼠、CoreSpeechKit TTS、Pen Kit 手写、HTML/CSS/JS 模板、jQuery、MathJax、mhchem。
移动端不是“功能少一点”,而是把桌面主链路完整搬过来,再用原生能力重做一遍。
八、生态层:Agent 时代,客户端要做“落地端”
一句话: Agent 负责生产,客户端负责落地。
2026 年的制卡方式在变:让 Agent 读讲义、PDF、网页,先生成一版,再人工校对。问题随之而来:Agent 生成的卡怎么进闪卡?进来后怎么改?改完怎么不丢复习记录?卡片之间怎么建立关系?
记得闪卡的答案不是“做一个万能 Agent”,而是做 Agent 的落地端。
讲义 / PDF / 网页
→ 外部 Agent(WorkBuddy / TRAE)
→ .apkg
→ 导入确认
→ Anki Core / FSRS
外部 Agent 用 APKG 作为通用接口:制卡时要求交付可导入的 .apkg;改卡时导出 APKG,让 Agent 补充解析、精简答案、纠错,但保留原笔记标识和媒体;导入前备份、核对。零 SDK、零账号、零私有协议。
应用内 JIDE 则是另一种形态:读取当前牌组、笔记类型、字段、标签,生成结构化草稿;支持 PDF/Office/图片/视频取帧/OCR;所有卡库修改先生成 ChangeDraft,用户确认后才写入;高风险操作二次确认。
外部 Agent 通过 APKG 制卡,内部 JIDE 通过受控工具制卡。前者开放,后者安全。
双向引用:开源才做得了的跨端知识网络
正文引用用标准 HTML 锚点:
<a href="#jide-note:<encodeURIComponent(目标GUID)>">本处显示文字</a>
完整关系保存在隐藏注释:
<!--jide-links:v1:<encodeURIComponent(JSON)>-->
规范细节:不加字段、不改笔记类型、不改模板;正向关系存下来,反向关系本地推导;逐处文字,不是全局别名;ArkTS 与桌面 Python 插件共用同一套 UTF-8/GUID/v1 JSON 规则;字段、媒体、标签、关系同一次 Core 落盘;单牌组导入目标缺失时保留引用并提示;预览循环最多 32 层。
桌面端通过 note_will_flush 钩子,在 Core 提交前同步正文与元数据。
闭源 App 也能定义私有链接格式,但只有它自己能读;记得闪卡把规范、隐藏注释、桌面插件和回归都公开了,其他工具(包括 Agent)可以按同一规范读写。这才叫“制定规范”。
鸿蒙独占:压感白板不是“画布 + 笔刷”
手写直接挂载 HarmonyOS Pen Kit 的官方 HandwriteComponent:
- 钢笔、圆珠笔、铅笔、马克笔、荧光笔、马赛克笔、橡皮擦、套索、激光笔;
- 笔刷、历史、一笔成形、报点预测由官方引擎管理;
- 压感等笔特性由系统手写引擎处理,应用不自己造笔刷;
- 白板覆盖在卡片上,卡片仍可读;手写期间暂停自动前进/时间盒;
- 检测到笔后,绘图区手指不落墨;掌托隔离、双指缩放、笔 Up 清理;
- SDK 不可用/超时/布局无效时,自动回退原版 Canvas 白板。
同样的 Anki 数据,在鸿蒙上可以有一块接近系统级手写笔感的白板。
九、定位:与 AnkiDroid 同级,为什么成了鸿蒙端的独占优势?
| 维度 | AnkiDroid / 传统 Anki 移动端 | 记得闪卡 |
|---|---|---|
| 核心与调度 | Anki Core、FSRS、四档评分 | 锁定 Anki 26.05,FSRS/自定义调度 |
| 数据与同步 | APKG/COLPKG、AnkiWeb | 同,并增加外部 Agent 的 APKG 工作流 |
| 界面 | Android 原生 | ArkUI + 实时光学玻璃 + 双材质 |
| 手写 | 应用内画布/第三方笔刷 | HarmonyOS Pen Kit 官方手写引擎 |
| 系统集成 | Android 能力 | 鸿蒙卡片、提醒、TTS、2-in-1、设备直连 |
| 跨端引用 | 通常没有内置规范 | #jide-note: + jide-links:v1 + 桌面插件 |
| 开源 | 是 | 是,AGPL-3.0-or-later,规范可复用 |
在核心协议、调度算法、数据兼容上,它和 AnkiDroid 是同一量级;它没有在 Anki 语义上偷工减料。
但在平台能力上,它不是“鸿蒙版 AnkiDroid”,而是把鸿蒙的图形、手写、语音、窗口、卡片服务用到了别人用不到的地方。
所以,“断崖”不是说核心算法比 AnkiDroid 强一个数量级,而是说:
在核心同级的前提下,体验层和平台层可以拉开一个数量级的差距。
这就是为什么它的断崖式体验是整个移动端的,而不只是“鸿蒙里比一比”:
- 和轻量闪卡 App 比,它有 Anki 级内核、FSRS、APKG/COLPKG、AnkiWeb、自定义调度;
- 和 AnkiDroid 比,它有原生材质、双 Web 槽、Pen Kit 手写、系统 TTS、桌面卡片、2-in-1、设备直连、双向引用;
- 和桌面 Anki 比,它是移动端,能把“随手打开就学”做到桌面端做不到。
同级是底线,差异化才是上限。
也正因为这些差异化能力高度依赖鸿蒙的系统能力,记得闪卡已经不只是“鸿蒙端一个不错的闪卡 App”,而是目前鸿蒙端少数具备独占优势的软件之一。
十、证据与边界:为什么这些不是 PPT
一个开源项目最容易骗人的地方是“文档写了等于做了”。记得闪卡反过来:先写清楚边界,再拿证据说话。
- 当前工作树
entry/src/main/ets约 755 个 ArkTS/TS 文件、12.8 万行;native/约 1.39 万行 Rust;tools/tests约 366 个测试文件; - 3.8.0 发布说明记录:完整 Node 回归 3595 项通过、35 项失败,失败项逐条记录,没有“全绿”话术;
- 玻璃采样优化有 hitrace 中位数和样本数,并注明“不是严格帧率基准”;
- MathJax 优化有 4 倍 CPU 降速对照,并注明“不含 Core、ArkUI 与设备合成”。
边界也要说清楚:
- “液态玻璃”是社区叫法,不是鸿蒙官方 API。API 21/22 或采样不可用时会降级为扁平材质。
- 玻璃性能数据不是帧率,不等于所有场景 60fps。
- 第三方模板/脚本没有穷尽验证,桌面端与 ArkWeb 可能有差异。
- 自定义调度是同步 JS 子集,不支持
await、DOM、网络、计时器,上限 3 秒/60KB。 - 部分设备场景仍在持续验收:API21/22、所有语言/字体比例、真实两机设备直连等。
- 源码版本和应用市场版本不是一回事:源码 3.8.1(3102),商店版本以 AppGallery 为准(本文写作时 2.9.98)。
- “断崖领先”是本文的判断,不是跑分结论:不表示每个单项都绝对第一。
一个敢把“没做到”写清楚的项目,才值得相信它说“做到了”的部分。
十一、结语:3 个月榜首只是结果,六层系统才是原因
真正难抄的不是功能列表,而是:
- 一块玻璃背后的采样、模糊、折射、生命周期和 512px 性能预算;
- 一个菜单背后的 200ms 按住、220ms 子菜单、实时命中、取消语义;
- 一套调度背后的 Anki Core、FSRS 参数、脚本沙箱和统计闭环;
- 一次切卡背后的双 Web 槽、两次动画帧确认、单卡预取和失败恢复;
- 一个 Agent 背后的 APKG 互换、草稿确认、双向引用规范和桌面插件;
- 一块白板背后的 HarmonyOS Pen Kit 官方手写引擎。
不是某一项跑分第一,而是六层能力同时成立,且每一层都能被源码、测试和设备验收验证。
3 个月榜首只是结果。六层系统,才是原因。
体验与源码
- 应用市场:搜索“记得闪卡”,或访问 AppGallery
- 官网:jidecards.com
- 开源仓库:github.com/wuweiyouzuoju/jidecards-anki-harmonyos
- 源码版本:3.8.1(versionCode 3102);Anki Core:26.05(commit
e64c6b1) - 许可证:AGPL-3.0-or-later
更多推荐



所有评论(0)