鸿蒙应用要在端内打开 Office 文档,常见工程问题是:预览页、编辑页、带水印的审批页各自复制一份OpenFileRequest构造逻辑;换 HAR 或换交付包后,注册与打开参数又对不齐,联调日志里 reject、1013、ERROR 交替出现。WPS Open SDK 鸿蒙统一版把对外模型收成单例WPSApi与同一套OpenFileRequest字段,业务侧可以把「多套平行 Helper」压成一条 Facade。本文按调用链说明统一接口解决了哪些工程痛点,并给出 TypeScript 收敛写法;字段语义以官方对接文档为准。
一、痛点对照:从「多份打开代码」到「一条链路」
| 工程现象 | 根因 | 统一接口侧的收敛方式 |
|---|---|---|
| 预览/编辑各写一套打开 | 参数散落、默认值不一致 | 单一openDoc(mode),内部设enableEdit |
| 冷启动连点 reject | 未注册就sendRequest | ensureRegistered门禁 +wpsReady短路 |
| 正式包 1013 | bundleName与凭据不匹配 | flavor 注入 key,注册失败即停 |
| 选择器路径 ERROR | URI 未进沙箱 | copyToSandbox后再OpenFileRequest |
OK却无data | 未开回传却当上传成功 | 按是否配置wpsTransferType分支 |
推荐时序固定为:
onCreate → ensureRegistered 用户选文件 → copyToSandbox → buildOpenRequest → sendRequest策略字段(水印、extraOptions、回传)在「最小打开」跑通后再叠加,避免一次堆参难以归因。
二、统一入口:WPSApi 与 Request 模型
对接文档对外入口是单例WPSApi:注册走RegisterAppRequest,打开走OpenFileRequest,结果统一为Result(requestType/code/msg/data)。统一版的工程价值不在于「页面零分支」,而在于学习成本与 Code Review 面收敛:全仓搜索new OpenFileRequest应只有 Facade 一处命中。
import{common}from'@kit.AbilityKit';import{WPSApi,RegisterAppRequest,OpenFileRequest,Result,ResultCode,}from'@wps/wps_sdk';/** 由 flavor / 构建脚本注入:当前 HAR 是否需要 setWpsFileToken */declareconstBUILD_NEEDS_ACTIVATION_SN:boolean;exportletwpsReady=false;exportfunctionlogResult(tag:string,r:Result):void{console.info(`[${tag}] type=${r.requestType}code=${r.code}msg=${r.msg??''}`);}exportasyncfunctionensureRegistered(ctx:common.UIAbilityContext):Promise<void>{if(wpsReady)return;constr=awaitWPSApi.sendRequest(newRegisterAppRequest(ctx,APP_KEY,APP_SECRET));logResult('register',r);if(r.code===ResultCode.ERROR_CODE_AUTH_FAILURE){thrownewError(`register 1013:${r.msg??''}`);}if(r.code!==ResultCode.OK){thrownewError(`register code=${r.code}`);}// 是否注入激活序列号由构建配置决定(与当前 HAR 交付约定对齐),勿在页面猜客户端包名if(BUILD_NEEDS_ACTIVATION_SN&&ACTIVATION_SN){WPSApi.setWpsFileToken(ACTIVATION_SN);}wpsReady=true;}是否调用setWpsFileToken应由构建配置(BUILD_NEEDS_ACTIVATION_SN)与申请材料对齐,避免在页面层根据 WPS 包名做运行时猜测。序列号通过setWpsFileToken全局注入,不要在每次OpenFileRequest上重复赋值旧字段。多 flavor 工程把 key、secret、序列号放进rawfile或 CI 密钥,业务模块只读 Facade 导出常量。
三、打开层:沙箱路径与 enableEdit 显式化
统一接口下,打开失败最常见两类:ResultCode.ERROR(路径不可读)与「只能预览」(未设enableEdit = true)。前者用沙箱拷贝解决,后者用模式参数显式化。
importfsfrom'@ohos.file.fs';functioncopyToSandbox(ctx:common.UIAbilityContext,src:string):string{constdir=`${ctx.filesDir}/wps_docs`;fs.mkdirSync(dir,true);constdest=`${dir}/${Date.now()}.docx`;fs.copyFileSync(src,dest);returndest;}exportasyncfunctionopenDoc(ctx:common.UIAbilityContext,srcPath:string,editable:boolean):Promise<void>{awaitensureRegistered(ctx);constpath=copyToSandbox(ctx,srcPath);constreq=newOpenFileRequest(ctx,path);req.enableEdit=editable;try{constr=awaitWPSApi.sendRequest(req);logResult(editable?'open-edit':'open-read',r);if(r.code!==ResultCode.OK){thrownewError(`open code=${r.code}msg=${r.msg??''}`);}}catch(e){console.error('open failed (not registered?)',e);throwe;}}预览入口传editable = false,编辑入口传true。合入前全仓搜索enableEdit,确认与产品入口一一对应。
四、结果层:回传与空 data 的语义
未配置wpsTransferType时,code === OK且data为空表示「WPS 已拉起」,不是上传失败。开启关窗回传后,才在 Promise resolve 时读取Result.data并拷贝到本应用沙箱。把「拉起」与「回传落盘」拆成两个 UI 状态,可避免误报。
| 场景 | code | data | 业务含义 |
|---|---|---|---|
| 只读预览 | OK | 空 | 正常 |
| 可编辑未开回传 | OK | 空 | 正常 |
| 已开回传且用户保存关窗 | OK | 有fileUri等 | 再消费data |
| 路径/参数错误 | ERROR | — | 查沙箱与字段 |
五、维护成本:Facade 与交付对齐
统一版降低的是接口分裂成本,不是抹掉交付差异。工程上建议:
- 依赖与凭据按 flavor 注入,业务模块只 import Facade。
- 注册断言集中在一处,页面禁止散落
new RegisterAppRequest。 - 打开策略收进
openDoc可选参数,水印、extraOptions后续扩展不复制构造代码。 - Release 禁止打印完整 secret;日志带
stage=register|open|transfer。
换 HAR 后 clean 重装;核对当前bundleName与申请材料一致,可消除大半 1013。
六、策略扩展、联调清单与小结
联调清单:
- 冷启动在
wpsReady前禁用打开按钮 - 注册失败不继续
OpenFileRequest - 选择器文件已
copyToSandbox - 编辑入口显式
enableEdit = true - 区分 throw(未注册)与
result.code(已注册失败) - 未开回传时不把空
data当失败 - 全仓仅一处
new OpenFileRequest - 日志含
requestType/code/msg
最小打开稳定后,水印、wpsRevisionParams、extraOptions仍挂在同一个OpenFileRequest上,只是赋值时机后移:
最小打开稳定后,水印、wpsRevisionParams、extraOptions仍挂在同一个OpenFileRequest上,只是赋值时机后移。建议在 Facade 增加可选参数对象,而不是新建openWithWatermark.ts:
typeOpenPolicy={editable?:boolean;waterMark?:WaterMark;extra?:OpenFileExtraOptions;};exportasyncfunctionopenWithPolicy(ctx:common.UIAbilityContext,sandboxPath:string,policy:OpenPolicy):Promise<void>{awaitensureRegistered(ctx);constreq=newOpenFileRequest(ctx,sandboxPath);req.enableEdit=policy.editable??false;if(policy.waterMark){req.wpsWaterMarkParams=policy.waterMark;}if(policy.extra){req.extraOptions=policy.extra;}constr=awaitWPSApi.sendRequest(req);logResult('open-policy',r);if(r.code!==ResultCode.OK){thrownewError(`open-policy code=${r.code}`);}}评审时关注两点:WaterMark/OpenFileExtraOptions是否在 Facade 内集中构造;页面是否仍直接new OpenFileRequest。统一接口的价值在于策略可组合,而不是页面各自拼字段。
关窗回传(wpsTransferType)与「能否编辑」正交:可先只读预览,再在「提交审批」入口开启回传并等待data。日志建议打印editable、transferOn两个布尔,方便和 ERROR 区分。
鸿蒙 WPS 二开里,统一接口解决的核心工程痛点是:把多套平行打开链路收成单例WPSApi+ 单一 Facade,用注册门禁、沙箱路径与enableEdit显式化消掉高频联调噪声。策略字段在最小打开稳定后再叠,维护时按 flavor 对齐 HAR 与凭据即可,无需为每个页面重写一套 SDK 调用面。把ensureRegistered、copyToSandbox、openWithPolicy提交进基础库后,新需求通常只需扩可选参数,联调时间会从「猜原因」缩短为「对表排查」。发版评审建议同时核对 HAR 文件名、注册code与本次策略赋值,避免「能注册不能打开」被误判为 SDK 缺陷。
基于 WPS Open SDK 鸿蒙版对接实践整理,仅供开发者参考。
官方对接文档:https://365.kdocs.cn/l/clQl5cek2NoT