做鸿蒙文档二开的 ISV 常遇到三种结构性成本:只能覆盖某一类 WPS 客户端、专业版与个人版各维护一套打开代码、以及每次换交付包就要全仓搜 wpsToken 和注册片段。WPS Open SDK 鸿蒙统一版把对外模型对齐到 WPSApi + OpenFileRequest,差异收在 HAR/凭据与 SdkConstants.isPersonalSdk() 分支。本文按「覆盖范围 → 接口一致 → 维护收敛」写工程解法,附可落地的 TypeScript Facade。
痛点 1:用户覆盖窄,交付场景受限
以往若 SDK 只面向专业版 WPS,面向个人用户的 App 要么放弃端内编辑,要么另找绕行方案。统一版在保留专业版能力的前提下,扩容个人版打开路径——厂商按客户场景申请对应 HAR 与凭据,业务代码骨架可共用,换的是依赖与初始化参数,不是重写页面。
工程含义:同一代码仓库可以服务「政企合规」与「大众市场」两条产品线,Adapter 层处理序列号与不落地等差异,UI 层只调 openDoc。
痛点 2:两套 API 文档,研发学习曲线翻倍
平行 API 的隐性成本在 Code Review:有人写 request.wpsToken,有人写 setWpsFileToken;有人把注册写在 Activity,有人写在按钮里。统一版把范式固定为:
registerApp → (按需 setWpsFileToken) → OpenFileRequest → sendRequest → Result
全仓只允许一处 new OpenFileRequest,评审时一眼能看出是否绕过 Facade。
痛点 3:长期维护与版本分支
多 flavor、多客户定制时,最怕「A 客户改了水印逻辑,B 客户忘了同步」。把打开策略收进带可选参数的 helper,比复制三份 OpenFileRequest 便宜一个数量级。
import { common } from '@kit.AbilityKit';
import {
WPSApi,
RegisterAppRequest,
OpenFileRequest,
ResultCode,
SdkConstants,
TransferType,
} from '@wps/wps_sdk';
let ready = false;
export async function prepareWps(ctx: common.UIAbilityContext): Promise<void> {
if (ready) return;
const r = await WPSApi.sendRequest(
new RegisterAppRequest(ctx, APP_KEY, APP_SECRET)
);
if (r.code === ResultCode.ERROR_CODE_AUTH_FAILURE) {
throw new Error(`1013 ${r.msg}`);
}
if (r.code !== ResultCode.OK) {
throw new Error(`register ${r.code}`);
}
// ToB 凭据:注册 OK 后注入序列号;ToC 通常跳过
if (!SdkConstants.isPersonalSdk() && ACTIVATION_SN) {
WPSApi.setWpsFileToken(ACTIVATION_SN);
}
ready = true;
}
type OpenOpts = {
editable?: boolean;
enableTransfer?: boolean;
};
export async function openDoc(
ctx: common.UIAbilityContext,
sandboxPath: string,
opts: OpenOpts = {}
): Promise<void> {
await prepareWps(ctx);
const req = new OpenFileRequest(ctx, sandboxPath);
req.enableEdit = opts.editable ?? false;
if (opts.enableTransfer) {
req.wpsTransferType = TransferType.URI; // 按文档选型
}
const r = await WPSApi.sendRequest(req);
if (r.code !== ResultCode.OK) {
throw new Error(`open ${r.code} ${r.msg}`);
}
}
prepareWps 在 Application.onCreate 或首屏 aboutToAppear 里 await 一次;页面只消费 ready 状态。ToB/ToC 差异不要散落在每个 Vue/ArkUI 页面,留在 bootstrap 模块。
四、差异点、联调归因与沙箱拷贝
诚实列三条仍须按场景配置的红线:HAR 与凭据按客户申请;激活序列号在 ToB 常见(setWpsFileToken);不落地/水印走 enableLocalization / wpsWaterMarkParams。统一的是 TypeScript 调用面,不是「一个 HAR 打天下」。申请邮件写清包名,比上线后追 1013 便宜。
reject(未注册)、1013、ERROR 仍会出现。归因顺序:先看 wpsReady,再看沙箱,再看 enableEdit,最后查策略字段。日志带 stage 方便驻场导出。冷启动连点 reject 时,不要急着改打开参数,先确认 Application.onCreate 是否 await prepareWps。
沙箱拷贝示例:
import fs from '@ohos.file.fs';
export function copyIntoSandbox(ctx: common.UIAbilityContext, src: string): string {
const dir = `${ctx.filesDir}/wps_queue`;
fs.mkdirSync(dir, true);
const dest = `${dir}/${Date.now()}_${src.split('/').pop() ?? 'doc.docx'}`;
fs.copyFileSync(src, dest);
return dest;
}
选择器返回的路径在 WPS 进程未必可读。统一 Facade 里把拷贝做成必经步骤,比在每个页面手写 copyFileSync 更少遗漏。拷贝失败要在 UI 上提示「文件准备失败」,不要继续 sendRequest 浪费一轮联调。
未开 wpsTransferType 时,OK && !data 合法。若产品弹「保存成功」,用户会以为已经上传——这是统一链路里最常见的「非 SDK 问题」。开启回传后,在 sendRequest resolve 再读 data,并同步拷贝到本应用沙箱后再触发上传模块。上传订阅「回传就绪事件」,而不是在打开按钮回调里假设 data 一定有值。
五、评审清单、迁移与小结
PR 模板建议检查:
| 项 | 通过标准 |
|---|---|
| 注册 | 仅 bootstrap 调用 RegisterAppRequest |
| 打开 | 仅 Facade 内 new OpenFileRequest |
| 模式 | 编辑入口 enableEdit=true |
| 路径 | 打开前 copyIntoSandbox |
| 日志 | 含 stage/code/msg,无完整 secret |
| 旧写法 | 全仓无 request.wpsToken |
旧工程迁移:若仍有双 Helper,先让两者都转调同一个 openDoc,再把 prepareWps 序列号分支用 SdkConstants.isPersonalSdk() 收口,最后删除平行 Helper。每个 PR 可独立合入,降低迁移风险。合入后全仓搜索 new OpenFileRequest 命中数应为 1;换 HAR 后 clean 重装,避免旧 so 让错误码看起来随机。
对 ISV 而言,统一版解决的是交付模型的重复建设:一套 Facade 覆盖双客户端场景,学习一次 sendRequest 范式,维护时只扩可选参数而不是复制页面。把 prepareWps 与 openDoc 提交进基础库,比写十页接入说明更能证明「统一版落在了仓库里」。字段以官方对接文档为准;发版评审同时看 HAR、注册 code 与策略赋值。
落地时建议把 Facade 放进独立 module(如 @app/wps-bridge),业务 Feature 只 import prepareWps / openDoc,禁止直接依赖 @wps/wps_sdk 的 Request 类。这样换 HAR 或调整注册时序,影响面可控。多人协作时冻结「平行 Helper」:新需求只允许扩 OpenOpts,不允许新建 openXxx.ts。每周用全仓 grep 检查 new OpenFileRequest 命中数,若大于 1 则在周会里优先还债。真机联调保留三段日志:注册成功、open-read OK、open-edit OK,作为回归基线贴进 Wiki,减少「我这边能开你那边不能开」的无效往返。若客户同时要求水印与回传,请在 Facade 用可选 OpenOpts 扩展,而不是复制 openApproval.ts;评审时核对 waterMark.Enable 与 enableEdit 是否同时赋值。
基于 WPS Open SDK 鸿蒙版对接实践整理,仅供开发者参考。 官方对接文档:365.kdocs.cn/l/clQl5cek2… 技术交流 QQ 群:628436767