joplin-hap:当 Joplin 遇上鸿蒙,一个从零重写的 HarmonyOS NEXT 原生笔记客户端

joplin-hap:当 Joplin 遇上鸿蒙,一个从零重写的 HarmonyOS NEXT 原生笔记客户端

Joplin 是一款广受欢迎的开源笔记应用,但官方移动端基于 React Native 构建,在 HarmonyOS NEXT 上无法运行。joplin-hap 项目选择了一条硬核路线:用 ArkTS / ArkUI 从零重写,并与官方 Joplin Server 保持数据和同步协议的完全兼容。本文带你深入了解这个项目的架构设计与实现细节。


一、背景:Joplin 为什么上不了鸿蒙?

Joplin 是 Laurent Cozic 开发的开源笔记应用,以 Markdown 编辑、端到端加密、多端同步著称,官方桌面端和移动端都有着庞大的用户群体。

但它的移动端是 React Native 应用,依赖 JavaScriptCore/Hermes 引擎和一系列原生桥接模块。HarmonyOS NEXT 彻底移除了 AOSP 兼容层,RN 应用无法直接运行,Joplin 官方也没有鸿蒙适配计划——这就留出了一个空白:鸿蒙用户想要一个能和官方客户端数据互通的 Joplin 客户端。

joplin-hap 的答案是:不做套壳,不做 RN 适配层,直接用鸿蒙原生的 ArkTS / ArkUI 重写整个客户端,同时在数据层和同步协议层与官方实现严格对齐。

二、核心亮点

1. 真正的原生,不是移植壳

整个应用约 5000 行 ArkTS 代码,页面、状态管理、数据库、同步引擎全部原生态实现:

  • UI 层:ArkUI 声明式范式,侧栏(笔记本/标签)+ 笔记列表 + 编辑器的经典三段式布局
  • 数据层:SQLite 本地落盘,支持系统级备份
  • 同步层:完整实现 Joplin Server REST 协议

2. 与官方客户端数据互通

这是项目最硬核的部分。它复刻了三层 Joplin 的数据契约:

契约层 复刻方式
SQLite 表结构 按官方 JoplinDatabase.ts 1:1 复刻 folders/notes/tags/note_tags/resources 等表
条目序列化格式 复刻 BaseItem.serialize() 的 title\n\nbody\n\nkey: value… 文本格式
同步协议 实现 Joplin Server REST:会话、增量游标、批量删除、附件 blob 上传下载

也就是说:官方桌面端创建的笔记,joplin-hap 能读;joplin-hap 里写的笔记,官方客户端也能同步到。设置项甚至直接落在 Joplin 标准键位(sync.9.path / sync.9.username / sync.9.password)上,语义完全一致。

3. 全中文界面

集中式的 I18n 字符串表实现了全应用中文化,对于中文用户来说比官方客户端更友好。

三、功能全景

功能模块 状态
笔记本(树形组织、新建/删除、侧栏笔记数统计) ✅
笔记(创建/编辑/删除/移动到其他笔记本) ✅
标签(管理、附加、按标签筛选、同步后自动刷新) ✅
全文搜索(标题 + 正文) ✅
Markdown 编辑(工具栏快捷插入:粗体/标题/列表/待办/代码块/链接/图片) ✅
Markdown 预览(真实 Web 渲染,支持代码块、任务清单、引用、分割线等) ✅
附件(图片内嵌、PDF 调起系统查看器、本地新建附件上传) ✅
回收站(deleted_time 同步、侧栏虚拟入口) ✅
双向同步(delta 增量游标、冲突时间戳、失败自动重试) ✅
端到端加密(E2EE) ⬜ 计划中

四、架构解析

项目结构

1
2
3
4
5
6
7
8
9
10
11
12
13
entry/src/main/ets/
├── common/I18n.ets # 中文字符串表
├── core/
│ ├── db/Database.ets # Joplin 兼容 schema + 版本化迁移
│ ├── models/Entities.ets # Note/Folder/Tag/Resource 实体
│ ├── services/Repositories.ets # 仓储层(带 track 标志避免同步回环)
│ ├── sync/
│ │ ├── ItemSerializer.ets # Joplin 条目文本格式编/解码
│ │ ├── JoplinApi.ets # Joplin Server REST 客户端
│ │ └── Synchronizer.ets # 同步主循环(上传→删除→拉取 delta)
│ └── markdown/MarkdownRenderer.ets # 手写 Markdown 扫描器
├── viewmodel/AppStore.ets # 全局状态
└── pages/ # Index / NoteEditor / NoteList / NoteSearch / TagList / Settings

一个有意思的技术细节:Markdown 渲染

ArkTS 出于安全考虑不支持 String.replace 的回调形式,所以 JS 生态里现成的 marked 解析器无法直接移植。作者的解法是自己写了一个字符级扫描器,逐字符分析 Markdown 语法产出 HTML,再交给 ArkWeb 渲染。这是从零重写路线的典型代价,也是典型收获——整个渲染管线完全可控。

同步协议的踩坑记录

README 里记录的同步调试过程堪称一份 Joplin Server 协议的「坑位地图」,摘录几条:

现象 根因与解法
Invalid path format: root:/delta delta 端点实际是 api/items/root:/:/delta(注意中间两个冒号),需按官方 file-api-driver-joplinServer.ts 拼接
Not found: root:/<id>: item body 要走 /content 后缀
Could not parse form (1): no parser found 上传 PUT body 的 Content-Type 必须是 application/octet-stream,发 text/plain 服务端 formidable 不识别
SQLite: Insert failed 迁移被守卫跳过,改为版本号强制重迁移、迁移幂等无条件执行

这种「逐个击破」的调试链路,对想自己对接 Joplin Server API 的开发者来说参考价值极高。

五、构建与使用

环境要求

项 版本
DevEco Studio 6.x(内含 hvigor 6.24.4)
HarmonyOS SDK API 24 / 6.1.1
JDK 17+(可直接用 DevEco 自带 JBR 21)
设备 HarmonyOS NEXT 手机 / 平板 / 2in1

命令行一键构建

项目提供了 scripts/dev-build.sh,一条命令完成「定位 JDK/SDK → 注入本机调试证书 → 构建 → 签名 → 还原配置」:

1
2
3
4
5
6
7
8
# 构建调试包
bash scripts/dev-build.sh

# 构建并安装到已连接设备
bash scripts/dev-build.sh debug install

# 构建 release 包
bash scripts/dev-build.sh release

产物路径:dist/joplin-hap-<版本>-<模式>.hap

脚本自动处理了三个鸿蒙构建的常见坑:PackageHap 阶段需要 Java、DEVECO_SDK_HOME 必须指向含 default/ 的父目录、调试 profile 与 bundleName 强绑定。

配置同步

应用内进入设置,填入 Joplin Server 地址、邮箱、密码,点击「立即同步」即可。如果你的服务器按照我之前那篇 Joplin Server 部署教程搭建,这里直接就能用上。同步异常时可以点「强制全量重新同步」清空游标重来。

六、当前状态与路线图

项目处于活跃早期(2026 年 8 月下旬完成了首个端到端可运行版本,随后快速迭代了回收站、附件双向同步、标签管理等功能),后续计划包括:

  • E2EE 端到端加密
  • 笔记本拖拽排序、嵌套笔记本 UI
  • 待办(is_todo)专用视图
  • 冲突笔记的可视化处理
  • 路由从已弃用的 @ohos.router 迁移到 Navigation + NavPathStack

⚠️ 重要提醒:早期版本请勿将其作为唯一数据副本,建议先在测试 Joplin Server 上验证。本项目为独立第三方移植,与官方 Joplin 无隶属关系,许可证为 AGPL-3.0。

七、写在最后

joplin-hap 代表了鸿蒙生态里一类很有价值的项目:不是把成熟应用「搬」过来,而是吃透原项目的数据模型与协议后用原生技术栈重新表达。它对 Joplin 的价值在于打开了鸿蒙用户群,对鸿蒙生态的价值在于多了一个真正原生、真正开源的笔记应用,而对开发者的价值则在于——它把「如何在一个新平台上复刻一个成熟开源软件」这件事完整地示范了一遍,包括架构取舍、协议对接和踩坑记录。

如果你恰好是 Joplin 用户又拿着 HarmonyOS NEXT 设备,不妨去 GitHub 或 Gitee 仓库点个 Star,自己构建一个试试。