鸿蒙 PC Markdown 编辑器系统剪贴板权限与中文回归

📅 2026/7/24 20:48:55 👁️ 阅读次数 📝 编程学习
鸿蒙 PC Markdown 编辑器系统剪贴板权限与中文回归

鸿蒙 PC Markdown 编辑器系统剪贴板权限与中文回归

仓库地址:https://gitcode.com/VON-/codex_md_oh

代码基线:b11519c7410227之后的 G3-09 设备收口提交。

剪贴板问题为什么直到设备阶段才暴露

桌面 Markdown 编辑器的复制、剪切和粘贴看起来是最基础的能力,实际却跨越了 CodeMirror、ArkWeb、系统剪贴板权限、输入法和焦点路由五层。浏览器自动化运行在 Chromium 测试上下文中,page.keyboard.press('Control+V')使用的是测试浏览器自己的剪贴板模型;ArkWeb 在 HarmonyOS PC 模拟器中则要遵守系统剪贴板访问策略。两者能验证的事实不同,所以 Playwright 全绿仍然不能证明系统中文粘贴已经可用。

G3-09 的真实设备用例在源码编辑区输入“鸿蒙PC剪贴板验证”,全选并剪切后正文正确变空,说明 CodeMirror 选择、剪切命令和写剪贴板都正常;执行粘贴时正文却没有恢复。此时如果只检查快捷键监听,很容易误判为Ctrl+V被命令路由吞掉。进一步对照焦点状态和系统日志后可以确认:按键已经进入 ArkWeb,缺失的是应用读取系统剪贴板的许可声明。

这类问题体现了鸿蒙 PC 应用验证的一个基本原则:跨系统边界的能力必须在系统环境中闭环。Web 测试适合证明编辑器命令不会回归,ArkTS 构建适合证明权限名和资源存在,只有设备剪切再粘贴才能证明最终用户任务成立。

权限声明必须和使用场景一致

最终修复没有在 JavaScript 中绕开系统剪贴板,也没有引入自建剪贴板缓存,而是在 entry 模块声明ohos.permission.READ_PASTEBOARD。真实代码如下:

{ "name": "ohos.permission.READ_PASTEBOARD", "reason": "$string:pasteboard_permission_reason", "usedScene": { "abilities": ["EntryAbility"], "when": "inuse" } }

when: "inuse"表明能力只与前台使用中的 EntryAbility 相关。Markdown 编辑器没有后台监听剪贴板、自动分析剪贴内容或跨会话采集历史,因此不应申请比当前任务更宽的使用场景。权限范围越小,用户越容易理解,安全评审也越容易证明“没有内容外发或后台读取”。

用途说明不能写成笼统的“应用正常运行所需”。中文资源明确为“将系统剪贴板中的文本和文件粘贴到 Markdown 编辑器”,英文资源则说明 paste text and files into the editor。说明同时覆盖文本与文件,因为编辑器既支持普通 Markdown 粘贴,也支持 G3-04 的图片和 URI 资源导入;但它没有承诺读取任意应用私有数据,也没有把剪贴板描述成同步服务。

为什么不应该拦截所有 Ctrl+V

OhMarkdown 的快捷键体系分成浏览器原生编辑保留键和应用命令键。保存、打开、快速打开和命令面板可以进入统一命令路由,复制、剪切、粘贴、撤销、重做等文本编辑保留键必须继续由 CodeMirror 和 ArkWeb 默认行为处理。如果外层为了“统一快捷键”对所有组合键调用preventDefault(),即使权限完整也会破坏粘贴。

Web 层采用白名单命令映射,而不是把每个 Ctrl 组合都变成应用命令。设置页允许录制十二项可配置命令,但保留键参与冲突检测,不能被用户分配成应用动作。这样做有三个直接收益:输入法组合过程不被干扰;CodeMirror 能使用标准编辑历史;系统剪贴板事件继续由受信运行时处理,应用无需读取纯文本再手工插入。

对于图片粘贴,Web 的paste事件只在发现支持的图片或文件项时走资源 Bridge。普通text/plaintext/html不进入图片落盘服务,仍由编辑器默认语义接管。把两条路径分开,能避免用户粘贴 Markdown 文本时触发文件权限或资源目录逻辑。

中文回归比 ASCII 回归更有价值

只用hello做剪贴板测试无法覆盖 UTF-16 光标、UTF-8 保存、中文输入法和系统剪贴板编码。设备用例选用“鸿蒙PC剪贴板验证”八个可见字符,包含中文和 ASCII。测试步骤是:进入源码模式,确保编辑区获得真实焦点;输入固定文本;全选;剪切;确认字数变为 0;粘贴;确认文本逐字恢复且状态栏显示 8 字。

这里同时观察正文和字数,而不是只看屏幕上似乎出现了文字。字数来自编辑器状态回传,如果视觉层出现残影而文档事实来源没有更新,保存后仍会丢内容。正文、字数和脏标记一起变化,才能证明 CodeMirror transaction 已经提交。

测试还要避开一种假阳性:先在 HDC 中向输入框注入文本,再执行应用内部撤销,可能看见相同字符串重新出现,却没有真正读取系统剪贴板。本轮通过真实虚拟键盘快捷键完成剪切和粘贴,并在缺权限版本上复现失败、加权限版本上复验成功,构成对照证据。

应用内部设备证据

下图来自 MateBook Pro 2in1 模拟器中的真实 OhMarkdown。源码编辑器右键菜单已经显示 Cut、Copy、Paste、Select All,说明 ArkWeb 编辑面和系统文本命令处于可操作状态;同一最终 HAP 完成了中文剪切再粘贴回归。

截图本身只能证明菜单和应用内部界面,中文内容恢复结论来自设备操作、状态栏字数和最终测试记录的共同证据。技术文章不能把一张静态图扩写成它没有证明的全部事实,所以仓库中的 G3-09test-cases.mdtest-report.md继续保留步骤、期望、结果和 HAP 哈希。

焦点路由是剪贴板链路的一部分

桌面工作台包含文件树、搜索框、标签、设置输入框、命令面板和 ArkWeb。用户按下 Ctrl+V 时,系统只会把事件发送给当前焦点控件。若执行命令面板后焦点仍停在隐藏输入框,粘贴可能进入查询字段;若点击标签后 ArkWeb 未恢复焦点,快捷键可能被 ArkUI 外层接收。

G3-09 之前已经修复命令执行后的焦点归还。命令面板关闭并不是终点,执行编辑相关命令后需要显式请求编辑器聚焦;打开搜索或设置时则保留相应原生控件焦点。剪贴板测试因此也承担了焦点回归:它不是孤立验证权限,而是证明源码面在多面板切换后的键盘所有权仍正确。

可靠的焦点设计不能依赖固定延时“碰碰运气”。ArkUI 面板状态完成更新后再发受限 Bridge 命令,Web 根据编辑器实例执行focus();状态回传只报告编辑事实,不把 DOM 节点或任意脚本暴露给原生层。这与项目既有 Bridge 白名单保持一致。

权限资源为什么必须中英文同步

OhMarkdown 已支持“跟随系统、简体中文、English”三种界面语言。模块权限用途属于系统可能展示给用户的文本,不能只在 base 资源添加英文,也不能把中文硬编码在 module.json5。最终修改同时进入:

{"name":"pasteboard_permission_reason","value":"将系统剪贴板中的文本和文件粘贴到 Markdown 编辑器。"}

以及 base 英文资源。模块只引用资源 ID,系统根据当前语言选择文本。这样避免功能在中文设置页可用、权限说明却突然变成英文,也避免将来调整措辞时修改模块结构。

资源同步还应进入构建门禁。缺少 base 资源通常会导致打包失败,缺少某个 locale 资源却可能静默回退,所以人工设备检查仍要分别切换语言。当前用例重点是中文剪贴板,英文用途说明由资源与 HAP 构建验证;G3-10 的语言矩阵还应补系统权限页面的两种显示。

安全边界:本地优先不等于无需权限

本地优先意味着文档和剪贴板内容不上传,不意味着应用可以跳过平台授权。恰恰相反,本地桌面工具接触的是用户最敏感的工作资料,更应使用系统声明、前台场景和最小 Bridge。OhMarkdown 不提供剪贴板历史、不在后台轮询、不将内容写入遥测,也不把剪贴板文本拼进日志。

ArkWeb 仍保持fileAccess(false)geolocationAccess(false)domStorageAccess(false)和无外网加载策略。READ_PASTEBOARD 只让系统编辑命令在用户主动粘贴时完成任务,不等于给 Web 页面开放任意系统 API。页面能调用的原生对象仍是ohMarkdownBridge的固定方法列表,剪贴板权限不会扩大 JavaScript Proxy 的命令集合。

Web({src:$rawfile('editor/index.html'),controller:this.editorController}).domStorageAccess(false).fileAccess(false).geolocationAccess(false).javaScriptProxy({object:this.editorBridge,name:'ohMarkdownBridge',methodList:['onReady','onState','onChange','onSnapshot','onAssetImport','onAssetRead','onCommand']})

安全评审应特别检查未来功能是否偷偷改变这个语义。例如“检测剪贴板中是否有 Markdown”如果在窗口激活时自动读取,就从用户主动操作变成环境扫描,需要重新评估隐私、提示和使用场景;不能因为已经声明权限就默认允许。

文本剪贴板与图片剪贴板的事务差异

文本粘贴由 CodeMirror transaction 一次提交,失败通常不修改文档。图片粘贴则要读取系统 URI、验证 MIME 和尺寸、决定 Copy/Move/Reference、创建资源目录、冲突命名、写入并 fsync,最后才插入 Markdown 链接。两者都从粘贴开始,但可靠性模型完全不同。

G3-04 已规定“写入成功后才插入链接”。READ_PASTEBOARD 修复不能绕过 AssetService,也不能把读取到的任意文件交给 Web。系统 URI 仍由 ArkTS 解析和授权,图片内容通过受限协议返回;普通文本则不跨自定义 Bridge。把系统权限看成入口条件,而不是业务校验替代品,是避免路径越权的关键。

中文文本测试通过后还要保留图片安全回归。G3-09 使用最终 HAP 复验了 Copy 图片拖放并生成相对链接,同时 Reference 模式拒绝工作区外资源。虽然它们不是剪贴板同一个手势,却能证明权限修改没有破坏既有资源规则。

自动化分层和门禁

最终门禁包含三层。第一层 Playwright43/43,覆盖 CodeMirror 常规编辑、快捷键保留、命令面板、资源 Bridge 和专业输出状态。第二层 Debug HAP 与 ArkTS UnitTestBuild,证明权限资源、模块配置和原生代码能完整编译。第三层 MateBook Pro 2in1 模拟器,执行中文剪切粘贴和 ohosTest9/9

最终 Debug HAP 大小为 8,542,985 字节,SHA-256 为8c344874f74f178aade4ff6405e1fe5a3f7a5f48ec41e2b1bb1a0d1ee0641990;ohosTest HAP 为 9,311,431 字节,SHA-256 为e8adf08a939b5be09dfd96a5856deced6c328e1c94adee4150b1ae6df8f82f0f。记录哈希可以把设备证据绑定到唯一产物,避免后来重建 HAP 后仍引用旧截图。

权限修复后的测试顺序也有讲究:先卸载或覆盖安装最终 HAP,强停并重启,确认不是旧进程继承状态;再执行剪切粘贴;最后跑原生测试。仅热重载 Web rawfile 不能验证 module.json5,因为权限声明属于安装包和系统注册信息。

失败诊断应该从边界向内收敛

当粘贴失败时,可按以下顺序缩小范围:确认当前是否为源码编辑面;确认编辑器有焦点;确认 Ctrl+V 没有被快捷键配置占用;确认剪切后系统剪贴板确实有内容;确认 HAP 包含 READ_PASTEBOARD;确认当前安装的是带修复哈希的产物;最后再检查 CodeMirror transaction。

这个顺序比直接修改编辑器键盘代码更可靠,因为它先检查跨系统边界和安装事实。设备日志若显示权限拒绝,就不应在 Web 层增加navigator.clipboard轮询;焦点不对,也不应扩大权限。每个假设都要用最小对照验证。

对中文输入还要区分“输入法组合失败”和“剪贴板读取失败”。前者通常发生在 composing 阶段,表现为候选或光标异常;后者是在剪切成功后粘贴无变化。本轮固定字符串由正常输入完成,问题只在系统粘贴步骤出现,因此权限结论有明确证据链。

PC 产品体验中的隐形质量

用户不会因为编辑器“支持 READ_PASTEBOARD”而选择产品,但会因为一次粘贴失败立即失去信任。桌面编辑器的优势往往由这些不可见的底层保证组成:标准快捷键无需学习;中文与英文一致;从命令面板返回后仍能粘贴;失败不吞掉正文;图片继续遵守资源目录规则;应用不在后台读取。

因此剪贴板能力在竞争记分卡中不应按功能数量计分,而应按统一任务成功率。至少需要中文、英文、混合文本、跨应用富文本、超长文本、图片和无权限/失焦失败恢复七类任务;在真机键盘、触控板和输入法矩阵下重复。模拟器通过可把工程能力标为设备可用,但不能替代不同 HarmonyOS PC 设备的系统策略差异。

后续测试矩阵

G3-10 应继续覆盖:简体中文输入法下的组合态复制粘贴;从浏览器、文件管理器和办公软件复制;包含 CRLF、Tab、Emoji 和零宽字符的文本;大于 1 MiB 的纯文本;只读文档与操作进行中状态;切换标签后的剪贴板目标;设置快捷键冲突后的保留键;系统深色模式权限提示。

还应验证权限被系统撤销或设备策略限制时,应用能否给出可恢复说明,而不是静默失败。当前系统默认流程足以完成正常粘贴,异常提示是否需要产品层增强,应根据真机可复现行为再决定,不能预先添加频繁弹窗。

结论

鸿蒙 PC Markdown 编辑器的中文粘贴不是一个 JavaScript API 问题,而是一条由系统权限、ArkWeb 默认编辑语义、CodeMirror transaction、焦点路由和本地资源安全共同组成的链路。OhMarkdown 通过最小前台 READ_PASTEBOARD 声明修复真实设备失败,同时保留 Web Bridge 白名单、编辑保留键和图片事务边界。

最终模拟器用固定中文文本完成剪切再粘贴,Playwright43/43、ohosTest9/9和最终 HAP 哈希共同绑定证据。这个小阶段的价值不在于新增一个设置项,而在于把最常用、也最容易被忽略的桌面动作从“浏览器里应该可用”变成“鸿蒙 PC 设备上已经验证”。