在 HarmonyOS 应用里接入 @wps/wps_sdk 后,「能打开文档」只是验收的一半。产品常要求同一文件既可预览又可编辑,或默认预览、点按钮再进入编辑。对接文档把这一开关收敛到 OpenFileRequest.enableEdit:未设置或为 false 时只读,仅显式赋 true 时可编辑。本文按调用链讲清该字段的语义边界、封装写法与联调误判,字段细节以官方对接文档为准。
一、模式控制在打开链路中的位置
典型时序:registerApp 回调 ResultCode.OK → 文件进入应用沙箱 → new OpenFileRequest(context, path) → 写入 enableEdit → WPSApi.sendRequest 拉起 WPS。
| 环节 | 关注点 | 与模式的关系 |
|---|---|---|
| 注册 | 未 OK 就打开会抛异常 | 模式字段来不及生效 |
| 路径 | 建议沙箱绝对路径 | 路径错误常被误判成「不能编辑」 |
| 模式 | enableEdit |
只读 / 可编辑的主开关 |
| 策略 | 水印、extraOptions |
与模式独立,后叠 |
| 回传 | wpsTransferType |
与是否可编辑独立 |
模式控制属于打开层能力。不要把「菜单隐藏」「水印」「关窗回传」和 enableEdit 绑死在同一个布尔里;联调时应先固定只读跑绿,再切可编辑,最后叠策略字段。
二、enableEdit 的文档语义
对接文档对 enableEdit 的约定可以概括成三句话:
- 类型为可选布尔值。
- 未设置或
false→ 只读(ReadOnly)。 - 仅
true→ 可编辑(Normal)。
工程含义是:忘记赋值不等于「默认可编辑」,而是默认只读。业务同学说「我明明要点编辑」时,先查对象上是否写过 req.enableEdit = true,再查封装是否把布尔传到了 Request。
typescript
import {
WPSApi,
OpenFileRequest,
Result,
ResultCode,
} from '@wps/wps_sdk';
function applyMode(req: OpenFileRequest, editable: boolean): void {
// 显式赋值,避免「未设置」与业务预期不一致
req.enableEdit = editable;
}
建议封装层永远显式赋值,不要依赖「字段缺省」。缺省语义属于 SDK,业务层应把意图写进代码。
三、注册就绪后再谈模式
未注册成功就 sendRequest 会抛异常。此时讨论只读或可编辑没有意义。把注册收成可 await 的准备,打开按钮在就绪前禁用。
typescript
let ready = false;
export function prepareWps(key: string, secret: string): Promise<void> {
return new Promise((resolve, reject) => {
if (ready) {
resolve();
return;
}
WPSApi.registerApp(key, secret, {
onCallback: (result: Result): void => {
if (result.code === ResultCode.ERROR_CODE_AUTH_FAILURE) {
reject(new Error(`1013: ${result.msg ?? ''}`));
return;
}
if (result.code !== ResultCode.OK) {
reject(new Error(`register ${result.code}`));
return;
}
ready = true;
resolve();
},
});
});
}
换 HAR 或换正式包包名后 clean,再验注册。1013 优先查凭据与包名,不要先怀疑 enableEdit。
四、预览与编辑共用一个打开入口
产品若有「预览」「编辑」两个按钮,不要复制两套 OpenFileRequest 构造逻辑。共用路径拷贝与 sendRequest,只差模式参数。
typescript
import { common } from '@kit.AbilityKit';
import fs from '@ohos.file.fs';
function toSandbox(ctx: common.UIAbilityContext, src: string): string {
const dir = `${ctx.filesDir}/wps_mode`;
fs.mkdirSync(dir, true);
const dest = `${dir}/${Date.now()}.docx`;
fs.copyFileSync(src, dest);
return dest;
}
export async function openLocalDoc(
ctx: common.UIAbilityContext,
src: string,
mode: 'preview' | 'edit'
): Promise<Result> {
await prepareWps(APP_KEY, APP_SECRET);
const path = toSandbox(ctx, src);
const req = new OpenFileRequest(ctx, path);
applyMode(req, mode === 'edit');
return WPSApi.sendRequest(req);
}
路径仍建议先落沙箱。选择器 URI 权限不足时,常见泛化 ERROR,容易被说成「编辑模式坏了」。先用只读 + 沙箱路径证明能拉起,再切 edit。
五、模式与其它字段的边界
| 字段 / 能力 | 是否替代 enableEdit |
|---|---|
| 水印参数 | 否,策略层 |
extraOptions 菜单开关 |
否,需显式赋值才生效 |
wpsTransferType 关窗回传 |
否,与可否编辑独立 |
enableLocalization |
否,落地策略 |
可编辑并不自动开启回传;回传成功也不代表当初以可编辑打开。未开回传时 OK 且 data 为空属正常,UI 不要提示「已保存」。评审时要求注释写清:模式、策略、回传分属三层。
六、联调误判与日志
| 现象 | 优先查 |
|---|---|
| 抛异常 | 是否等 prepareWps 完成 |
1013 |
key/secret/bundleName |
| 能开不能改 | enableEdit 是否显式 true |
| 泛化 ERROR | 路径是否沙箱 |
| 以为保存成功 | 是否开了回传 |
日志固定打:code、msg、ready、是否沙箱、enableEdit。全仓搜索 new OpenFileRequest:打开阶段应只有一处 Facade。产品临时要求「预览也要水印」,只扩可选参数,不新开 openReadonlyWithWatermark 平行文件。
七、小结
HarmonyOS 上 WPS Open SDK 的只读与可编辑,核心是 OpenFileRequest.enableEdit 的显式赋值:未设或 false 只读,仅 true 可编辑。注册就绪、沙箱路径、模式布尔、策略与回传分层叠加,联调从猜原因变成对表排查。字段语义以官方对接文档为准;把「打开只走 Facade、模式必须显式写入」写进项目约定,比口头说「参考 Demo」更耐看。
周五可用正式包包名再验注册,真机各跑预览与编辑一次。命中数与模式相关误报是否下降,比写长周报有用。路径务必先落沙箱;换 HAR 后 clean;Release 不打印完整 secret。把预览/编辑双入口收成一个函数后,后续叠水印或回传通常只改可选参数。
接入评审时建议同时确认:当前 HAR 是否与申请批次一致、沙箱目录是否全仓统一、enableEdit 是否在封装内显式赋值、正式包包名是否与凭据归档一致。缺一环就容易把「默认只读」误判成客户端缺陷。统一版减少的是页面层分裂,它不会自动把选择器 URI 变成沙箱路径,也不会在你漏写布尔时猜你想可编辑。
冷启动注册、打开按钮禁用、预览与编辑各跑通,做成检查表后新人合入会稳很多。若产品临时要求预览带水印或编辑后回传,仍然只改 Facade 可选参数,不新开平行文件。注释里写清「本项目约定:模式必须显式写入 Request」,比口头传承更耐看。把对照表与 PR 模板坚持几周,联调通常会从猜原因变成对表排查,打开封装也会从「两处拷贝」收敛到「一处带 mode 的入口」。
基于 WPS Open SDK 鸿蒙版对接实践整理,仅供开发者参考。