HarmonyOS WPS Open SDK:OpenFileRequest 构造参数与 sendRequest 打开链路

HarmonyOS 应用要在端内预览或编辑 Word、Excel、PPT,常见做法是集成 @wps/wps_sdk,用 WPSApi 拉起本机已安装的 WPS。打开动作本身不分散在多个入口类里:构造 OpenFileRequest,填路径与是否可编辑,再调用 WPSApi.sendRequest。联调里把「点按钮没反应」写成打开失败,多数时候其实是注册未完成、路径不在应用沙箱,或把 Promise 异常当成了 Result.code。本文按接口语义写打开链路:构造参数、沙箱拷贝、enableEdit、结果分支与可复用封装。字段以官方对接文档为准,随 HAR 批次核对后再合入。

一、打开链路在 SDK 调用中的位置

完整顺序固定为:集成 HAR → 启动阶段 registerApp → 回调到 ResultCode.OK → 按凭据约定可选调用 setWpsFileToken → 把待打开文件拷进本应用沙箱 → new OpenFileRequest(context, path) → 设置 enableEditsendRequest。打开层只消费已经就绪的 SDK 与可读路径,不负责签发 appKey

层级 职责 入口
依赖 HAR 与包名绑定凭据 @wps/wps_sdk
门禁 应用注册 registerApp
打开 沙箱路径、只读或可编辑 OpenFileRequest
调度 拉起 WPS 并返回结果 WPSApi.sendRequest

当前请求类型只有 OPEN_FILE。水印、extraOptions、关窗回传都是 OpenFileRequest 上的附加字段,不要在只读打开尚未稳定时一起打开。出现 1013 时暂停改路径与 enableEdit,先对齐 bundleName、HAR 与申请归档。

二、构造参数:context 与 fileUri

签名是 new OpenFileRequest(context: common.UIAbilityContext, fileUri: string)。两个参数都必填。context 必须是当前 UIAbility 的上下文,页面里用错 Ability 或把 undefined 传进去,打开侧常见泛化 ResultCode.ERRORfileUri 文档写成本地文件路径;实践上应传入本应用沙箱内可读路径。系统文件选择器给出的 URI 往往没有跨进程读权限,WPS 进程打不开,日志却不一定写「权限」二字。

建议在打开前把源文件拷到 context.filesDir 下的固定子目录,再把拷贝后的路径交给构造函数。目录按业务拆分可以,但全仓应共用同一个拷贝函数,避免每个页面各写一套临时文件名规则。

typescript 复制代码
import { common } from '@kit.AbilityKit';
import fs from '@ohos.file.fs';

export function copyIntoSandbox(
  ctx: common.UIAbilityContext,
  src: string,
  ext: string = 'docx'
): string {
  const dir = `${ctx.filesDir}/wps_inbox`;
  fs.mkdirSync(dir, true);
  const dest = `${dir}/${Date.now()}.${ext}`;
  fs.copyFileSync(src, dest);
  return dest;
}

拷贝失败应在打开前抛给调用方,不要带着半截路径去 sendRequest。扩展名与真实文件类型保持一致,避免客户端按后缀解析失败。调试包与商店包的 filesDir 相互隔离,不要把调试机上的绝对路径写进正式包配置。

三、enableEdit:未赋值即只读

赋值 实际模式
未设置 只读(ReadOnly)
false 只读
显式 true 可编辑(Normal)

预览入口与编辑入口应走同一封装,只差一个布尔参数。两套 new OpenFileRequest 很容易在后续叠水印时漂移。enableEdit 与关窗回传独立:能编辑不等于必须回传;只读预览也可以不设 wpsTransferType。联调顺序建议:注册 OK → 沙箱只读打开 → 同一路径 enableEdit = true → 再叠策略字段。

不推荐在每次构造时写 request.wpsToken。需要激活序列号时,在 registerApp 回调 ResultCode.OK 之后调用 WPSApi.setWpsFileToken,后续所有打开请求自动携带。Request 字段与全局设置同时存在时,以全局设置为准,日志会误导排查。

四、sendRequest 的两种失败形态

WPSApi.sendRequest(request) 返回 Promise<Result>。对接文档写明:注册尚未成功时抛异常,而不是返回一个带 codeResult。UI 必须同时处理 .then 里的非 OK,以及 .catch 里的异常。把异常文案直接展示成「文档损坏」会误导测试。

Result 常用字段:requestTypecodemsgdata。未开启关闭回传时,拉起成功即 code === ResultCode.OKdata 为空,这是正常语义,不要弹「已保存」。开启回传后,用户关窗且回传成功才在 data 里带 fileUritransferFd

现象 优先核对
Promise reject 是否等到注册 OK
1013 appKey / appSecret / bundleName
ResultCode.ERROR(-2) 路径是否沙箱、Context 是否有效
OK 且 data 为空 是否根本没开回传
typescript 复制代码
import { WPSApi, OpenFileRequest, Result, ResultCode } from '@wps/wps_sdk';
import { common } from '@kit.AbilityKit';

export async function openLocalDoc(
  ctx: common.UIAbilityContext,
  sandboxPath: string,
  editable: boolean
): Promise<Result> {
  const req = new OpenFileRequest(ctx, sandboxPath);
  req.enableEdit = editable;
  try {
    const result = await WPSApi.sendRequest(req);
    console.info('[WPS] open', result.code, result.msg ?? '', !!result.data);
    return result;
  } catch (e) {
    console.error('[WPS] sendRequest threw', e);
    throw e;
  }
}

日志前缀固定为 [WPS] open[WPS] register,便于把打开失败和注册失败拆开看。Release 构建不要打印完整 appSecret 或序列号。

五、把注册门禁和打开函数拆开

页面点击回调里直接 registerApp 再立刻 sendRequest,时序上几乎必然撞上未注册异常。把注册做成可 await 的一次性准备,打开函数只检查就绪标记。

typescript 复制代码
let sdkReady = false;

export function waitUntilRegistered(
  appKey: string,
  appSecret: string,
  activationSn?: string
): Promise<void> {
  return new Promise((resolve, reject) => {
    if (sdkReady) {
      resolve();
      return;
    }
    WPSApi.registerApp(appKey, appSecret, {
      onCallback: (r: Result): void => {
        if (r.code === ResultCode.ERROR_CODE_AUTH_FAILURE) {
          reject(new Error(`1013:${r.msg ?? ''}`));
          return;
        }
        if (r.code !== ResultCode.OK) {
          reject(new Error(`register:${r.code}`));
          return;
        }
        if (activationSn) {
          WPSApi.setWpsFileToken(activationSn);
        }
        sdkReady = true;
        resolve();
      },
    });
  });
}

冷启动在 Ability onCreate 里发起 waitUntilRegistered。打开按钮用 sdkReady 控制 enabledactivationSn 由构建配置注入:需要序列号的产物传真实值,不需要的产物传空,封装内部跳过 setWpsFileToken。不要在每个 Page 的 aboutToAppear 里再调一次注册。

六、联调清单与现象对照

建议写进测试用例而不是口头约定:

  1. 冷启动日志出现注册 code=0
  2. 选择器文件经 copyIntoSandbox 后再打开
  3. 只读入口未写 enableEdit = true,工具栏不可改
  4. 编辑入口显式 true,可保存
  5. 未开回传时 OK 且 data 为空,UI 不提示保存成功
  6. 未就绪时点击打开,走 catch,不伪造 Result
  7. 换 HAR 后 ohpm install 并 clean,重跑只读打开
口头描述 更可能的原因
点了没反应 按钮未等 sdkReady,异常被吞
提示失败但文件能在文件管理器打开 没拷沙箱
以为只读也能改 漏写 enableEdit 或写成了 true
以为保存成功 把拉起 OK 当成回传 OK

策略字段放到只读与可编辑都稳定之后再叠。extraOptions 仅显式赋值的项生效,不要整表拷默认值。换 flavor 后 bundleName 与凭据必须重新归档;调试包绿、商店包红,优先查包名而不是再改 OpenFileRequest 字段。

七、小结

OpenFileRequest 打开本地文档可以收成四条工程纪律:注册等到 ResultCode.OK;文件先进入本应用沙箱;默认只读,可编辑必须显式赋值;sendRequest 的异常与 Result.code 分开处理。统一版把打开面收敛到一套 API,工程上仍要把路径与时序做对。把 waitUntilRegisteredcopyIntoSandboxopenLocalDoc 分成三个符号后,预览页与编辑页只差一个布尔值,后续叠水印或回传也不必再复制一套构造代码。

接入评审时把当前 HAR 文件名、凭据环境、是否注入序列号、沙箱目录约定写成一页对照。测试按表验收,比口头说「都能打开」可靠。合入后全仓搜索 new OpenFileRequest,命中应集中在打开封装文件。外部 URI 权限不足时常见泛化 ERROR;正式包与调试包包名不同时,凭据批次分开存放。字段语义继续以官方对接文档为准,随 SDK 小版本更新注释,而不是把整张参数表贴进业务页。


基于 WPS Open SDK 鸿蒙版对接实践整理,仅供开发者参考。

官方对接文档:https://365.kdocs.cn/l/clQl5cek2NoT

相关推荐
huainingning1 小时前
华三华为锐捷迈普中兴交换机二三层接口切换命令
服务器·网络·华为
贾伟康2 小时前
【时光清单|11】HarmonyOS ArkTS 每日语录实战:从本地仓库稳定生成首页内容
harmonyos·arkts·状态管理·arkui·本地数据
ymwlchina2 小时前
华为手机P40 Plus如何通过adb无线连接
adb·华为·智能手机
tsqtsqtsq03092 小时前
鸿蒙系统深色模式功能详解与开发适配指南
harmonyos
贾伟康2 小时前
【时光清单|16】HarmonyOS ArkTS 多设备布局实战:适配手机、平板和 PC/2in1 的窗口变化
harmonyos·arkts·arkui·响应式布局·多设备适配
lilian23311 小时前
HarmonyOS 7 新特性(二十五)|智慧手势:意图识别与误触治理
华为·harmonyos
贾伟康13 小时前
【时光清单|14】HarmonyOS ArkTS 主导航实战:统一页面入口、返回路径和参数校验
harmonyos·arkts·arkui·navigation·路由管理
贾伟康17 小时前
【时光清单|05】HarmonyOS ArkTS 倒计时卡片实战:适配 2x2、2x4 与 4x4 多尺寸
harmonyos·arkts·arkui·服务卡片·formextensionability
小雨青年18 小时前
【HarmonyOS 7 悬浮页签深度实战】07 折叠屏、平板与宽窗口的布局适配
华为·harmonyos