在鸿蒙应用里嵌文档能力,团队往往先做「能打开」,再做「能改」。WPS Open SDK(@wps/wps_sdk)没有拆成两个打开类:预览和编辑都是 OpenFileRequest + WPSApi.sendRequest,差别落在 enableEdit。未设置或 false → ReadOnly;只有 true → Normal。本文从工程封装、双入口绑定和联调顺序写清楚,避免把模式问题和鉴权、路径混在一起排。读完可直接落到仓库里的 helper 与联调清单。
为什么模式开关值得单独成文
统一版把打开收成一套 API,页面却常复制两份构造逻辑:一份注释写「预览」,一份写「编辑」,某一侧漏写 enableEdit = true 就会出现「编辑按钮其实是只读」。Code Review 若只看有没有 sendRequest,发现不了布尔默认值。把模式收进单一 helper,预览传 false、编辑传 true,比事后对日志更省时间。合入前用全仓搜索核对 enableEdit 赋值点,比只靠手工点按钮更稳。
调用链仍是:
HAR → registerApp OK → (可选) setWpsFileToken → sandbox copy → OpenFileRequest → enableEdit → sendRequest
1013 停在注册层;路径权限问题多表现为泛化 ERROR;模式问题表现为「打得开但改不了」或「预览也能改」。三类现象不要共用同一段重试逻辑,否则排错成本会上去。
语义表(工程注释可直接贴)
enableEdit | 模式 | 产品映射建议 |
|---|---|---|
| unset | ReadOnly | 附件预览、只读审批 |
false | ReadOnly | 同上,显式更清晰 |
true | Normal | 起草、批注、改稿 |
enableEdit 不替代回传:关窗拿 fileUri / transferFd 要另设 wpsTransferType。未开回传时 OK + 空 data 是正常拉起,不是「保存失败」。
ToB / ToC 在统一接口下都认这个字段;激活序列号仍走注册成功后的 setWpsFileToken,不要写回 request.wpsToken。SdkConstants.isPersonalSdk() 只决定要不要注入 SN,不改变 enableEdit 语义。
封装示例
import { common } from '@kit.AbilityKit';
import fs from '@ohos.file.fs';
import {
WPSApi,
OpenFileRequest,
Result,
ResultCode,
SdkConstants,
} from '@wps/wps_sdk';
let sdkReady = false;
export function startWps(appKey: string, appSecret: string, proSn?: string): void {
WPSApi.registerApp(appKey, appSecret, {
onCallback: (r: Result) => {
if (r.code !== ResultCode.OK) {
console.error('[WPS] register', r.code, r.msg);
return;
}
if (!SdkConstants.isPersonalSdk() && proSn) {
WPSApi.setWpsFileToken(proSn);
}
sdkReady = true;
},
});
}
function toInbox(ctx: common.UIAbilityContext, src: string, ext: string): string {
const dir = `${ctx.filesDir}/wps_mode`;
fs.mkdirSync(dir, true);
const dest = `${dir}/${Date.now()}.${ext}`;
fs.copyFileSync(src, dest);
return dest;
}
export async function openDoc(
ctx: common.UIAbilityContext,
src: string,
ext: string,
editable: boolean
): Promise<Result> {
if (!sdkReady) {
throw new Error('register first');
}
const path = toInbox(ctx, src, ext);
const req = new OpenFileRequest(ctx, path);
// 预览:false;编辑:必须 true
req.enableEdit = editable;
return WPSApi.sendRequest(req);
}
Ability onCreate 调 startWps。预览按钮:openDoc(ctx, uri, 'docx', false)。编辑按钮:第四参 true。日志同时打 editable 与 sdkReady,减少口头描述「有的能改有的不能」。
处理结果时分支清楚:
export function onOpenResult(r: Result): void {
if (r.code !== ResultCode.OK) {
console.error('[WPS] open fail', r.code, r.msg ?? '');
return;
}
if (r.data == null) {
console.info('[WPS] open ok, no transfer payload');
return;
}
// URI/FD 拷贝回本应用后再入库 —— 另模块
}
未注册异常进 .catch,不要伪造 Result。
页面绑定建议
- 两个入口共用
openDoc,禁止列表项各自new OpenFileRequest aboutToAppear只同步sdkReady到@State,不在点击里注册- 产品文案:只读入口不要暗示「可保存」;可编辑且未开回传不要暗示「已上传」
- PR 勾选:预览未传
true、编辑必传true、全仓无req.wpsToken
联调顺序与产品文案
推荐固定四步绿点:注册 OK → 沙箱只读 → 沙箱可编辑 → (可选)回传拷贝。换 HAR 后先只读回归,再开编辑。调试包与商店包凭据分开。extraOptions / 水印放到模式双绿之后再叠。
现象对照:
| 现象 | 优先查 |
|---|---|
| 抛异常 | 是否未注册就 sendRequest |
| 1013 | Bundle / key / HAR |
| 打不开 | 是否未拷沙箱 |
| 打得开改不了 | 编辑入口是否未设 true |
| 预览也能改 | 是否误传 true |
| OK 空 data | 是否未开回传(预期) |
编辑能力与回传能力经常被产品写成同一句话:「改完要能传上去」。在 SDK 里这是两步:enableEdit = true 只保证客户端可改;关窗后拿到业务路径还要 wpsTransferType 与沙箱拷贝。未开回传时,可编辑打开成功仍可能是 OK + 空 data。UI 应拆成两种状态文案:「已在 WPS 中打开」与「已收集编辑结果」。把两种文案绑错,测试会以为模式开关坏了。
列表页多个附件时,循环调用 openDoc,每次带上该条目自己的 editable 与扩展名。不要在 aboutToAppear 里预先构造一堆 Request。按钮 enabled 绑定 sdkReady;若业务允许未就绪时展示按钮,也要禁用点击并提示「文档组件初始化中」。
小结
建议目录:wps/bootstrap.ts(startWps / sdkReady)、inbox.ts(toInbox)、open.ts(openDoc / onOpenResult)。README 写清:预览必须 false,编辑必须 true;ToB 注入只在 bootstrap;打开层禁止写 token。发版 checklist 增加「双入口布尔」一项。换 HAR 后 CHANGELOG 记录只读回归与可编辑回归是否通过。
远程协助一次带齐:Bundle 打印值、HAR 文件名、注册 code/msg、打开 code/msg、本次 enableEdit、是否已拷沙箱。列齐全再讨论选择器权限或回传。
鸿蒙 WPS 二开里,打开模式不是第二条 API,而是 enableEdit 的三态语义收成两支:只读与可编辑。工程价值在于双入口共用封装、日志带布尔、联调顺序不跳步。统一版仍要求注册门禁与沙箱路径;序列号与模式正交。把对接文档入口写进 README,发版评审同时看 HAR、注册 code 与本次 enableEdit 取值。坚持四步绿点,预览可写、编辑只读、空 data 误报上传这类问题会少很多。合入前再搜一遍 new OpenFileRequest 与 enableEdit = true,确认与产品入口一一对应。
技术交流 QQ 群:628436767。申请 SDK HAR 与凭据时注明包名与专业版 / 个人版需求。
基于 WPS Open SDK 鸿蒙版对接实践整理,仅供开发者参考。 官方对接文档:365.kdocs.cn/l/clQl5cek2…