欢迎加入开源鸿蒙 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,支持 2in1tablet,目标 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 / GDIArkTS 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.soIndex.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 的 MainWndProcMsgCommand()、各类 IDM_* 命令、Win32 对话框与 Scintilla 窗口消息形成了稳定但强耦合的桌面外壳。全量改写这些代码不是首个可运行版本的最短路径。适配中先把平台无关库、文档行为与界面边界分开,才能在不伪装全功能的前提下得到真正可运行的 HAP。

难点二:Qt 已经进程内加载,仍可能只看到空白窗口

QPA 插件、XComponentlibentry.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 和真机上的实际编辑行为作为验收依据。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐