Notepad3 鸿蒙 PC 适配全记录:以 Qt 建立原生编辑闭环,接入 uchardet 与 PCRE2
欢迎加入开源鸿蒙 PC 社区:https://harmonypc.csdn.net/
欢迎在 PC 社区平台申请新建项目:https://atomgit.com/OpenHarmonyPCDeveloper
适配开源地址:https://atomgit.com/OpenHarmonyPCDeveloper/ohos_Notepad3
环境搭建文章:https://blog.csdn.net/weixin_52908342/article/details/161343743
一、为什么要适配 Notepad3
Notepad3 是一款典型的 Windows 原生文本编辑器。它不以复杂的工程管理为核心,而是把启动速度、文本查找、编码识别、换行符控制和语法处理做得足够扎实。无论是修改配置、查看日志,还是临时处理一段源码,这种轻量工具都有着大型 IDE 无法替代的使用价值。
选择 Notepad3 进行 HarmonyOS PC 适配,不只是为了增加一款记事本。这个项目长期围绕 Win32、Scintilla 和 Lexilla 演进,具有完整的菜单命令、文件编码、搜索替换、配置与本地化体系。它很适合用来检验一个实际问题:当成熟的 Windows C/C++ 应用无法直接跨平台编译时,如何先把最有价值的用户工作流程带到鸿蒙 PC,同时给后续复用原项目内核留出清晰边界。
当前鸿蒙工程的应用版本为 6.0.0,包名为 org.rizonesoft.notepad3,支持 2in1 与 tablet,目标 Native ABI 为 arm64-v8a。仓库同时保留 Scintilla 5.5.8、Lexilla 5.4.6 以及 Notepad3 原有 Win32 源码,但本次可运行产物采用的是分阶段迁移方案。
二、先划清边界:不把编译通过当成适配完成
Notepad3 原版的主窗口、菜单分发、对话框、文件监控、工具栏、MUI 资源和外部工具集成都直接依赖 Windows API。Scintilla 在仓库中使用的也是 Win32 平台后端。如果仅以“消除头文件报错”为目标,即使最终生成动态库,也不等于获得了可交互、可读写、可安装的桌面编辑器。
因此,当前项目先实现一个 Qt Widgets 原生编辑器外壳,并把可以跨平台复用的 Notepad3 组件接入真实运行路径。这个选择可以概括为:先完成稳定的文本编辑闭环,再逐步替换与复用更深的原版能力。
| 层次 | 原项目实现 | 鸿蒙侧当前方案 |
|---|---|---|
| 应用入口 | wWinMain 与 Win32 消息循环 | Stage 模型 EntryAbility |
| 窗口承载 | HWND / GDI | ArkTS XComponent + Qt for OpenHarmony QPA |
| 编辑界面 | Notepad3 + Scintilla Win32 后端 | Qt Widgets + 扩展的 QPlainTextEdit |
| 编码识别 | Notepad3 Encoding 链路 | 复用项目内 uchardet |
| 正则搜索 | Scintilla 中的 PCRE2 | 复用 PCRE2 10.47 的 16-bit 构建 |
| 原子保存 | Win32 临时文件替换 | Qt QSaveFile |
| 语法高亮与折叠 | Scintilla / Lexilla | 本阶段尚未接入鸿蒙外壳 |
这个边界尤其重要:当前版本是可安装、可交互的 HarmonyOS PC 文本编辑器,但不是原 Win32 Notepad3 全部功能的原样搬运。
三、鸿蒙版的整体架构
鸿蒙工程集中在仓库根目录的 harmony_pc/。ArkTS 层处理 Ability 生命周期、用户目录权限、外部文件 URI 和资源提取;Index.ets 创建全屏 NODE 类型 XComponent;Qt for OpenHarmony 的 QPA 插件把 Native 窗口接入系统,最终由 libentry.so 运行编辑器主窗口。
EntryAbility
├── 目录权限、Want / URI 参数、rawfile 资源提取
└── Index.ets / XComponent
└── Qt for OpenHarmony QPA
└── libentry.so
├── Qt Widgets 菜单、工具栏、编辑区与状态栏
├── uchardet 编码探测
├── PCRE2 16-bit 查找与替换
└── QSaveFile 文本格式保留与原子写入
主要目录如下:
ohos_Notepad3/
├── src/ # Notepad3 Win32 主程序与通用库
├── scintilla/ # Scintilla 与 PCRE2
├── lexilla/ # 词法分析器
├── language/ # MUI 语言资源
└── harmony_pc/
├── AppScope/app.json5 # 包名、版本和应用资源
├── build-profile.json5 # SDK、产品和签名配置
└── entry/src/main/
├── ets/ # Ability 与 XComponent 宿主
├── resources/rawfile/share/ # 随 HAP 携带的 Notepad3 资源
└── cpp/
├── CMakeLists.txt # Native 依赖与构建模式
└── np3_ohos_shell.cpp # Qt 主窗口与编辑主流程
四、把编辑器的核心工作流程跑在真机上
下列五张图均由本项目当前签名 HAP 在 HarmonyOS PC 真机上运行后截取。测试设备为 HUAWEI MateBook Pro(HAD-W32,2in1),系统版本为 OpenHarmony-6.1.0.115,屏幕分辨率为 3120×2080。本次整理文档前重新执行了 Native 编译、ArkTS 编译、HAP 打包和签名,再完成真机安装与启动。
1. ArkTS 到 Qt 的桌面窗口链路
应用启动后呈现标准的 PC 窗口,包含菜单栏、工具栏、行号区、文本画布和状态栏。窗口能在鸿蒙桌面上最大化、最小化和关闭,Qt 绘制区域与系统窗口装饰保持独立。

2. 文本输入、行号与状态同步
编辑区使用扩展的 QPlainTextEdit,左侧行号不是静态图片,而是随文档 block 变化重新计算与绘制。光标移动和选区变化会同步更新底部的行、列、选中字符数、插入/覆盖模式、换行符与编码状态。这些信息对排查日志、定位配置和检查文本格式都很实用。

3. PCRE2 正则查找不是界面占位
查找/替换对话框支持大小写、整词、环绕、上一个、下一个与全部替换。开启“Regular expression (PCRE2)”后,查找会进入仓库内 PCRE2 10.47 的 16-bit 匹配链路。图中使用 error_[0-9]+ 实际匹配文档中的 error_404,命中内容已在编辑区选中,状态栏同时显示选区长度。

PCRE2 16-bit 并非为了绕过原项目另造一套规则。Qt 的 QString 以 UTF-16 代码单元存储文本,PCRE2 16-bit 返回的 offset 因此能直接对应 QTextDocument 位置,避免 UTF-8 字节位置与界面字符位置之间的反复换算。
4. 编码是文档状态,不是一次性解码选项
文件打开时首先检查 UTF-8、UTF-16 LE/BE 的 BOM;没有明确 BOM 时,再调用 Notepad3 项目中的 uchardet 进行编码探测。当前界面支持 UTF-8、UTF-8 BOM、UTF-16 LE/BE、GB18030、Big5、Shift-JIS、EUC-KR、Windows-1252 和 ISO 8859-1,也允许指定编码重新载入已打开文件。

保存时会根据当前选择恢复目标编码与 BOM,而不是强制把所有文件转成 UTF-8。写入由 QSaveFile 完成,只在临时文件写入成功后提交替换,以减少中途异常破坏原文件的风险。
5. 换行符保留要与编码同等对待
代码、配置和日志经常在 Windows 与 Unix 工具链之间流转。鸿蒙版在加载文本时统计 CRLF、LF 与 CR,内部统一为编辑器可处理的换行,保存前再按文档状态输出。用户也可通过菜单在 Windows (CR+LF)、Unix (LF) 与 Classic Mac (CR) 之间显式切换。

五、核心适配过程
1. 先打通 Ability、XComponent 与 Qt QPA
EntryAbility.ets 在窗口创建时先处理资源和权限,再整理启动参数,最后调用 QPA 插件启动 libentry.so。Index.ets 只保留一个全屏 XComponent,文档、光标、搜索和菜单状态都放在 Qt 侧,避免 ArkTS 和 C++ 同时维护一份编辑器数据。
Qt 平台插件本身不与 entry 直接链接,而是由 ArkTS 加载;libentry.so 则显式链接 Qt Core、Gui、Widgets、Svg、Network、PrintSupport 和 OpenGL。这种区分让桌面窗口承载与应用业务保持清晰。
2. 把 Notepad3 的可移植组件编进同一个 Native 产物
Native CMake 同时构建 PCRE2 8-bit 和 16-bit 静态库。当前 Qt 外壳实际调用 16-bit 版本完成查找与替换,8-bit 版本则为后续接回 Scintilla 现有正则链路保留。uchardet 的语言模型与探测器一起交叉编译,不需要在运行时调用外部程序。项目中的 Rijndael 与 SHA-256 可移植算法核心也已进入鸿蒙 Native 构建,但当前外壳还没有提供加密界面,因此不把它列为已交付功能。
3. 从“打开一段文本”延伸到完整文档状态
文档模型不只记录字符内容,还保存文件路径、编码、BOM、换行符和修改状态。打开文件时会对 64 MB 以上文件进行保护,对无 UTF-16 BOM 却包含 NUL 字节的内容进行二进制文件提示。保存、重载和关闭前都会检查修改状态;最近文件和上次使用目录通过 QSettings 保存。
4. 处理鸿蒙文件 URI、权限与资源沙箱
module.json5 声明 Documents 和 Download 目录的读写权限,并注册 ohos.want.action.viewData,覆盖纯文本、源码、脚本、Markdown、XML、JSON 和日志等类型。文件管理器发来的 URI 会被加入 Qt 启动参数;应用已在运行时,onNewWant 则继续把新请求交给 QPA 层处理。
Notepad3 的 INI、主题、语言与图片资源位于 HAP rawfile/share/ 中。由于当前系统版本不能按普通目录遍历 rawfile 子目录,工程使用 share_manifest.txt 列出需要的文件,Ability 首次启动时逐项提取到可写沙箱,并通过标记文件避免重复复制。
六、适配中遇到的几个难点
难点一:Win32 边界比源文件数量更关键
Notepad3 的 MainWndProc、MsgCommand()、各类 IDM_* 命令、Win32 对话框与 Scintilla 窗口消息形成了稳定但强耦合的桌面外壳。全量改写这些代码不是首个可运行版本的最短路径。适配中先把平台无关库、文档行为与界面边界分开,才能在不伪装全功能的前提下得到真正可运行的 HAP。
难点二:Qt 已经进程内加载,仍可能只看到空白窗口
QPA 插件、XComponent、libentry.so 和 Qt 图像格式插件之间存在运行时依赖。例如 SVG 图像插件需要 libQt5Svg.so,若只根据源码的直接调用删减 Qt 模块,HAP 可以构建成功,但 QPA 加载主窗口时会失败。这类问题不能只看 CMake 和 Hvigor 的退出码,必须结合真机画面与 hilog 定位。
难点三:正则匹配位置要与 Qt 文档坐标一致
如果直接在 UTF-8 字节上做匹配,中文、Emoji 和补充平面字符都会让匹配 offset 与 Qt 选区位置产生差异。适配版把 PCRE2 16-bit 建立在 QString::utf16() 上,查找、反向查找和替换都使用同一套代码单元坐标。“匹配成功”与“界面正确选中”在这里必须是同一个验收点。
难点四:文本正确性不能让位于界面相似度
文本编辑器对编码和换行符的错误往往不会在首屏暴露,而是在用户保存后破坏原文件。因此,工程不把编码作为文件打开时的临时参数,而是把编码、BOM 和 EOL 持续保存在文档状态中。这比“窗口看起来像 Notepad3”更能决定工具是否可用。
难点五:PC 文件权限和签名必须纳入主流程
HarmonyOS PC 上的 Documents、Download 与 Desktop 目录不是普通桌面进程可以默认遍历的路径。当前调试签名不包含 Desktop 目录的 ACL,工程因此只请求当前 Profile 允许的 Documents 和 Download 权限,Desktop 文件则可通过系统“打开方式”获得单文件授权。调试 Profile 同时与包名、设备和有效期绑定,更换开发机或真机后应重新生成匹配的签名材料。
七、编译、安装与启动
首次构建可直接使用 DevEco Studio 打开 harmony_pc/,为 org.rizonesoft.notepad3 配置与目标设备匹配的调试签名。项目内置 Qt for OpenHarmony SDK,compatible SDK 与 target SDK 均为 5.0.5(17)。
macOS 上的命令行构建示例如下,实际路径需按 DevEco Studio 安装位置调整:
cd harmony_pc
export JAVA_HOME=/Applications/DevEco-Studio.app/Contents/jbr/Contents/Home
export DEVECO_SDK_HOME=/Applications/DevEco-Studio.app/Contents/sdk
export HOS_SDK_HOME=/Applications/DevEco-Studio.app/Contents/sdk/default/hms
/Applications/DevEco-Studio.app/Contents/tools/hvigor/bin/hvigorw \
--mode module -p module=entry assembleHap --no-daemon
签名产物位于:
harmony_pc/entry/build/default/outputs/default/entry-default-signed.hap
本次真机验证所用 HAP 大小约 37.7 MiB。连接设备后可以安装并启动:
HDC=/Applications/DevEco-Studio.app/Contents/sdk/default/openharmony/toolchains/hdc
"$HDC" list targets
"$HDC" install -r harmony_pc/entry/build/default/outputs/default/entry-default-signed.hap
"$HDC" shell aa start -a EntryAbility -b org.rizonesoft.notepad3
本次执行结果为 BUILD SUCCESSFUL,HAP 覆盖安装成功,EntryAbility 启动成功,真机进程 org.rizonesoft.notepad3 保持运行。文档中的五张截图来自这次安装后的实际操作。
八、当前功能边界
当前 HarmonyOS PC 版已经覆盖文本编辑的基础闭环:
- 可安装的 HAP、Stage 模型 Ability、XComponent 和 Qt Native 窗口;
- 新建、打开、重载、保存、另存为与未保存修改确认;
- 撤销、重做、剪切、复制、粘贴、全选和跳转到行;
- 行号、当前行高亮、插入/覆盖模式、缩放与自动换行;
- 基于 PCRE2 的普通/正则查找与替换;
- 基于 uchardet 的编码检测、BOM 处理、指定编码重载;
- CRLF、LF、CR 检测、状态显示与保存转换;
- 最近文件、上次目录、二进制文件提示和 64 MB 大文件保护;
- 系统“打开方式”文本类型注册与启动 URI 传递。
尚未进入当前可运行外壳的能力主要包括 Scintilla 编辑控件、Lexilla 多语言语法高亮、代码折叠、书签、自动补全、原 Notepad3 INI 全量配置、26 种 MUI 语言资源、原版主题、文件变更监控、打印、MiniPath 以及依赖 Windows 可执行文件的 grepWin 集成。CMake 中的 NP3_FULL_APP=ON 会对完整移植模式进行显式阻断,避免将未完成的路径误判为可交付产物。
因此,当前版本更准确的定位是“Notepad3 HarmonyOS PC 原生编辑基础版”。它已完成从构建、签名、安装到文本编辑、正则检索和格式控制的真实链路,同时把原版高级编辑能力保留为后续阶段性目标。
九、总结
Notepad3 的适配价值,不在于用 Qt 复制一个文本框,而在于找到适合这类 Win32 应用的渐进路径。当前工程用 Stage 模型和 XComponent 解决应用入口,用 Qt QPA 承载原生桌面窗口,再把 uchardet、PCRE2 与可移植算法核心纳入同一个 arm64-v8a Native 产物。最终得到的不是一个静态演示页,而是能在 HarmonyOS PC 真机上安装、启动和交互的编辑器。
后续工作的重心也因此很明确:为 Scintilla 建立稳定的 Qt 平台后端,接入 Lexilla 词法器与主题系统,再按功能边界逐步迁移 Notepad3 的命令分发、配置、本地化和文件监控。每完成一步,都应以可构建的 HAP 和真机上的实际编辑行为作为验收依据。
更多推荐




所有评论(0)