HarmonyOS WPS Open SDK 实践:最小打开闭环与 enableEdit 分支处理

刚接 @wps/wps_sdk 时,我最容易犯的错不是「没配水印」,而是这三类:页面按钮里直接 new OpenFileRequest,忘记进程级 registerApp;选择器 URI 原样传入,联调全是 ERROR;预览/编辑共用一套请求,把默认只读当成 SDK 异常。后来把链路收成「注册 → 拷贝 → 按模式打开 → 分支断言」,联调能稳定复现。本文按工程视角写最小闭环,代码尽量完整,并补上断言、页面拼装与后置策略扩展,方便对照真机日志接手维护。

接口时序与注册断言

推荐时序:onCreate → ensureRegistered → 按钮 copyToFilesDir → openByMode(preview|edit)then(assertOk) / catch(reject)sendRequest 在未注册时 reject ;注册后失败走 result.code(常见 ERROR、鉴权 1013)。日志固定 requestType/code/msgappKey/appSecretbundleName 绑定,调试包与上架包各申请一套。轻量阶段一般不配 wpsTransferType,此时 OK && !data 表示拉起成功,不是「没保存」。

typescript 复制代码
import { common } from '@kit.AbilityKit';
import {
  WPSApi, RegisterAppRequest, Result, ResultCode,
} from '@wps/wps_sdk';

export let wpsReady = false;

export function logResult(tag: string, r: Result) {
  console.info(`[${tag}] type=${r.requestType} code=${r.code} msg=${r.msg ?? ''}`);
}

export function assertOk(r: Result, stage: string) {
  if (r.code === ResultCode.ERROR_CODE_AUTH_FAILURE) {
    throw new Error(`${stage} 1013: ${r.msg ?? ''}`);
  }
  if (r.code === ResultCode.ERROR) {
    throw new Error(`${stage} ERROR: ${r.msg ?? 'check path/params'}`);
  }
  if (r.code !== ResultCode.OK) {
    throw new Error(`${stage} code=${r.code}`);
  }
}

export async function ensureRegistered(ctx: common.UIAbilityContext) {
  if (wpsReady) return;

  const r = await WPSApi.sendRequest(
    new RegisterAppRequest(ctx, APP_KEY, APP_SECRET)
  );
  logResult('register', r);
  assertOk(r, 'register');

  if (ACTIVATION_SN) {
    WPSApi.setWpsFileToken(ACTIVATION_SN);
  }
  wpsReady = true;
}

激活序列号只在有申请材料时注入。首页 wpsReady 前禁用打开,避免冷启动连点 reject。凭据走 flavor rawfile 或 CI 注入,Release 不打 secret。可为 assertOk 写 Mock 1013/ERROR/OK 单测,减少手测依赖。

沙箱拷贝与 enableEdit 打开

选择器路径直接 open 常见 ERROR。先拷到 filesDir,再按 mode 设 enableEdit

mode enableEdit 用途
preview false(或不设) 查看附件
edit true 修改附件
typescript 复制代码
import fs from '@ohos.file.fs';
import { OpenFileRequest, WPSApi } from '@wps/wps_sdk';

export function copyToFilesDir(
  ctx: common.UIAbilityContext,
  src: string
): string {
  const dir = `${ctx.filesDir}/wps_lite`;
  fs.mkdirSync(dir, true);
  const dest = `${dir}/${Date.now()}_${src.split('/').pop() ?? 'file.docx'}`;
  fs.copyFileSync(src, dest);
  return dest;
}

export async function openByMode(
  ctx: common.UIAbilityContext,
  sandboxPath: string,
  mode: 'preview' | 'edit'
) {
  await ensureRegistered(ctx);
  const req = new OpenFileRequest(ctx, sandboxPath);
  req.enableEdit = mode === 'edit';

  const r = await WPSApi.sendRequest(req);
  logResult(mode, r);
  assertOk(r, mode);
  return r;
}

联调先测 preview 确认路径与注册,再测 edit。不要一上来叠水印和 extraOptions,否则 ERROR 难归因。拷贝失败与打开失败要拆 toast,避免同事一直怀疑 enableEdit。修订、水印、回传可后置挂到同一 req,按钮层保持 openByMode 不变。

页面拼装与踩坑对照

typescript 复制代码
// EntryAbility.onCreate
await ensureRegistered(this.context);

async function onOpen(mode: 'preview' | 'edit') {
  try {
    if (!wpsReady) return;
    const picked = await selectOneDocument();
    const sandbox = copyToFilesDir(hostContext, picked);
    await openByMode(hostContext, sandbox, mode);
  } catch (e) {
    promptAction.showToast({ message: String(e) });
  }
}
现象 先查
reject 未注册 / wpsReady
1013 包名与凭据
ERROR 未拷沙箱
只能看不能改 enableEdit
以为没回调 轻量未开回传,或未关窗

清单:冷启动连点、多 flavor bundleName、换 HAR 后 clean、小 docx/xlsx 各测 preview/edit、弱网抽测注册超时。系统升级后再跑一轮最小闭环。切回应用 ≠ 关窗;有回传时不要在空 data 上报成功。

后置回传与策略参数

最小闭环通了以后,按需往 OpenFileRequest 加字段,不必改按钮语义:

typescript 复制代码
import { TransferType, OpenFileExtraOptions, WaterMark } from '@wps/wps_sdk';

function decoratePolicy(req: OpenFileRequest, stamp?: string) {
  req.wpsTransferType = TransferType.URI;

  if (stamp) {
    const wm = new WaterMark();
    wm.Enable = true;
    wm.WaterMaskText = stamp;
    wm.Angle = -30;
    wm.FontColor = '#19000000';
    wm.FontSize = 16;
    req.wpsWaterMarkParams = wm;
  }

  const opt = new OpenFileExtraOptions();
  opt.enableShare = false;
  opt.enableExport = false;
  req.extraOptions = opt;
}

分层联调:openByMode 稳定 → URI 回传 → 水印 → extraOptions。不落地模式下部分开关会被强制关闭,以真机菜单为准。统一解析可后抽 resolveCallbackUri(r)fileUri,FD 再扩 transferFd。业务增量通常只改水印文案或上传接口,注册模块保持不动;单元测试继续覆盖空 data、ERROR、1013。若接断点续传,只需替换上传层,打开与注册回归面更小。

工程里我还会再抽一层「打开入口」,避免页面散落字面量路径与重复 try/catch。示意如下:把 DocumentPicker、拷贝、mode、可选 decorate 串起来,业务页只传 preview|edit 与水印文案。这样换 HAR、改 flavor 凭据时,回归范围集中在 wps/ 目录而不是几十个按钮回调。Debug 包可开详细日志看完整 msg;Release 只保留 code 与精简错误映射,避免 secret 与绝对路径进崩溃上报。

typescript 复制代码
export async function pickAndOpen(
  ctx: common.UIAbilityContext,
  mode: 'preview' | 'edit',
  stamp?: string
) {
  await ensureRegistered(ctx);
  if (!wpsReady) return;
  const picked = await selectOneDocument();
  const sandbox = copyToFilesDir(ctx, picked);
  await ensureRegistered(ctx);
  const req = new OpenFileRequest(ctx, sandbox);
  req.enableEdit = mode === 'edit';
  if (stamp) {
    decoratePolicy(req, stamp);
  }
  const r = await WPSApi.sendRequest(req);
  logResult('pickAndOpen', r);
  assertOk(r, 'pickAndOpen');
  return r;
}

需要回传时再在 decoratePolicy 里打开 TransferType.URI,并用单独的 copyCallback 落盘;不要把上传成功耦合进 assertOk。同一单据多次编辑请用新时间戳文件名。机型差异主要体现在生命周期动画速度,测试用例应明确「关闭窗口」触发回传。以上叠完后,日常联调成本会明显下降,新人也不容易把注册逻辑又抄回页面。

联调检查清单我通常写成四条,交给同学按序打勾:冷启动后是否只调用一次 registerApp 且无 1013;选择器路径是否已进入 filesDir 且扩展名未丢;预览与编辑两按钮是否共用入口且仅差 enableEdit;日志是否能按 requestType 过滤。四条都绿再开 wpsTransferType。机型覆盖至少一台完整版 WPS、一台预装阉割场景,菜单项与预期不一致时优先查不落地模式与 extraOptions,而不是改注册。文档字段以对接文档为准,HAR 升级后对照 OpenFileRequestResult 各扫一遍即可。

小结

最小闭环靠时序:注册拿到 wpsReady,沙箱保证路径,enableEdit 区分预览与编辑,assertOk 分层吃错误。跑通后再叠策略参数,比一次堆满配置稳得多。字段表以官方对接文档为准;文档更新后对照 OpenFileRequest / Result 扫一遍即可。把入口与断言收进 wps/ 模块后,业务页只负责触发与提示,后续加上传或水印也不会再把鉴权逻辑摊回页面。


基于 WPS Open SDK 鸿蒙版实践整理。

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

QQ 群:628436767

相关推荐
绝世番茄1 小时前
鸿蒙原生 ArkTS 布局方式之 Stack 悬浮按钮布局(HarmonyOS NEXT / API 24)
华为·harmonyos·鸿蒙
2301_768103491 小时前
HarmonyOS趣味相机实战第5篇:CameraKit资源释放、PixelMap生命周期与预览黑屏排查
性能优化·harmonyos·arkts·camerakit·pixelmap
花开彼岸天~2 小时前
鸿蒙应用开发实战【01】— 号码助手项目概述与开发环境搭建
华为·harmonyos·鸿蒙系统
不才难以繁此生2 小时前
HarmonyOS 图片列表滑动卡顿怎么办:中式美食菜谱封面怎么做占位、缓存和失败兜底
harmonyos·image·arkui·中式美食·列表性能
心中有国也有家3 小时前
AtomGit Flutter 鸿蒙客户端:零外部资源的应用打包策略
android·javascript·flutter·华为·harmonyos
最爱老式锅包肉3 小时前
HarmonyOS技术精讲-Camera Kit(相机服务)第3篇:实现相机预览功能
数码相机·华为·harmonyos
youtootech3 小时前
HarmonyOS《柚兔学伴》项目实战02-多模块架构设计与 HSP/HAR 模块化
华为·harmonyos
不才难以繁此生4 小时前
ArkUI Tabs 切换后状态丢失怎么办:中式美食分类页怎么保留关键词、筛选和滚动位置
harmonyos·状态管理·arkui·tabs·中式美食
爱吃大芒果17 小时前
复刻 HarmonyKit 工具箱:基于新版 @kit 开发本地工具 App
华为·harmonyos