HarmonyOS WPS Open SDK 工程实践:把 registerApp 做成就绪门禁

把 WPS Open SDK 接进 HarmonyOS 工程后,registerApp 经常被当成"启动时顺手调用一下"的代码。真正上线时,这段初始化会同时面对页面重建、按钮连点、调试包与正式包切换、HAR 升级等变量。只要某个入口在注册回调到达前发起 sendRequest,日志里就会出现看似是文档打开失败、实际却属于初始化时序的异常。

更稳的做法不是给调用点补几个 if,而是把注册视为应用级就绪门禁:由一个模块负责注册、重试和状态广播,页面只等待就绪结果。本文从架构分工出发,给出一套适合鸿蒙页面生命周期的最小实现,并把 1013、空凭据和未注册异常拆到不同排查路径。

一、注册应该属于应用层,而不是按钮层

WPSApi.registerApp(appKey, appSecret, callback) 完成的是应用调用资格校验。校验成功前,sendRequest 不具备执行条件;失败后也不应该继续叠加文档参数实验。因此它天然属于应用初始化,而不属于某个页面的点击动作。

一个常见错误是把注册写在文档页的 aboutToAppear。页面返回一次就注册一次,两个 Tab 同时存在时还可能并发注册。即使回调都返回成功,业务侧保存的就绪状态也可能互相覆盖。更麻烦的是,用户已经进入页面并点击打开时,首次注册还没有结束,最终只能收到 Promise 异常。

可以把数据流固定为:

层级 责任 对外结果
应用初始化层 调用 registerApp、处理回调、设置序列号 ready / failed
文档服务层 等待就绪、构造请求、调用 sendRequest Result 或异常
页面层 展示初始化、打开成功或失败状态 用户提示

这样拆分后,页面不需要知道凭据,也不需要判断当前 SDK 形态。它只消费一个明确状态。

二、用 Promise 消除重复注册

注册回调是异步的,页面可能在同一时间多次请求打开。用一个 Promise 表示"初始化进行中",能把并发调用合并到同一次注册上:

typescript 复制代码
import { WPSApi, Result, ResultCode } from '@wps/wps_sdk';

type WpsState = 'idle' | 'booting' | 'ready';

let state: WpsState = 'idle';
let bootTask: Promise<void> | null = null;

export function bootWps(
  appKey: string,
  appSecret: string,
  activationSn?: string
): Promise<void> {
  if (state === 'ready') {
    return Promise.resolve();
  }
  if (state === 'booting' && bootTask) {
    return bootTask;
  }

  state = 'booting';
  bootTask = new Promise<void>((resolve, reject) => {
    WPSApi.registerApp(appKey, appSecret, {
      onCallback: (result: Result) => {
        if (result.code !== ResultCode.OK) {
          state = 'idle';
          bootTask = null;
          reject(new Error(`WPS register ${result.code}: ${result.msg ?? ''}`));
          return;
        }

        if (activationSn) {
          WPSApi.setWpsFileToken(activationSn);
        }
        state = 'ready';
        resolve();
      },
    });
  });

  return bootTask;
}

这段状态机解决三个问题。并发调用复用同一个 bootTask;失败后允许下一次操作重新初始化;成功后再进入文档页会立即返回,不再重新注册。activationSn 作为可选配置传入,调用方不需要在页面中判断是否设置。

三、打开 helper 要区分两类失败

文档服务层先等待门禁,再构造 OpenFileRequest。sendRequest 返回的 Promise 异常与 Result.code 非零并不是同一种错误,应分别记录:

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

export async function openSandboxFile(options: {
  context: common.UIAbilityContext;
  path: string;
  appKey: string;
  appSecret: string;
}): Promise<Result> {
  await bootWps(options.appKey, options.appSecret);

  const request = new OpenFileRequest(options.context, options.path);
  request.enableEdit = false;

  try {
    const result = await WPSApi.sendRequest(request);
    if (result.code !== ResultCode.OK) {
      console.error('[WPS] request non-ok', result.code, result.msg);
    }
    return result;
  } catch (error) {
    console.error('[WPS] request exception', error);
    throw error;
  }
}

如果 Promise 直接 reject,优先回到注册状态检查;如果返回了 Result 但 code 非零,才继续检查文件路径、请求参数或文档能力配置。日志中固定 register 与 request 两个前缀,可以避免两类错误混在一起。

四、序列号配置要收口

不同交付形态对激活序列号的要求并不相同。SDK 提供 SdkConstants.isPersonalSdk() 用于运行时判断,但业务页面不应直接使用这个分支。序列号属于初始化配置,应该在注册成功回调中一次完成。

交付形态 注册 激活序列号
需要 WPS 产品授权 registerApp 成功 在成功回调中调用 setWpsFileToken
轻量打开形态 registerApp 成功 不需要设置

还要清理历史写法中的 OpenFileRequest.wpsToken。如果全局序列号和请求字段同时存在,排查会变得困难。统一的规则是:序列号只在应用初始化层设置,文档服务层不感知。

五、1013 的诊断顺序

1013 对应 ERROR_CODE_AUTH_FAILURE,含义是接入凭据校验失败。遇到它时,不要先修改 enableEdit 或水印参数,而应先建立一张身份对照表:

  1. 运行时 Bundle 名称,通过 bundleManager 打印。
  2. 申请凭据时提交的包名。
  3. 当前 HAR 文件名与交付批次。
  4. registerApp 返回的完整 code 与 msg。
  5. 凭据是否过期,近期是否更换签名或包名。

如果是空 key 或空 secret,通常表现为 ResultCode.ERROR,应检查构建配置是否注入了编译期常量;如果是 1013,重点则是身份不一致。两类问题都不应通过反复重启应用来碰运气。

六、升级 HAR 时的回归方式

HAR 批次升级会改变 SDK 内部实现,但对外调用顺序仍应保持一致。建议每次替换依赖后执行同一条回归链:

  1. clean 后重新执行 ohpm install,确认 import 都来自 @wps/wps_sdk。
  2. 冷启动应用,记录一次注册成功日志。
  3. 验证需要序列号的交付形态已在回调中完成设置。
  4. 用沙箱文件完成只读打开,再验证可编辑模式。
  5. 检查旧代码是否仍在使用 request.wpsToken。

把注册、打开和页面状态分开后,每次升级只需要回归两个模块。对团队协作来说,这比在全仓搜索散落的 registerApp 更可靠。鸿蒙 WPS 二开真正需要长期维护的,不是某一次调用成功,而是这套可观察、可重试、不会越过门禁的初始化结构。


基于 WPS Open SDK 鸿蒙版对接实践整理,仅供开发者参考。 官方对接文档:365.kdocs.cn/l/clQl5cek2... 技术交流 QQ 群:628436767

相关推荐
Hello.Reader6 小时前
tsrs 技术解析用 Rust 移植 TypeScript 7,类型检查还能怎样提速?
开发语言·rust·typescript
大雷神7 小时前
HarmonyOS7应用《拼棋派对》实战:双人键盘操作与窗口焦点恢复
harmonyos·arkui·harmonyos 7.0·玩转 arkts
2501_946244789 小时前
开源鸿蒙平台 CMP 三方库「compose-continuous-rounded-corner-shape」适配全流程
华为·开源·harmonyos
KevinChaos9 小时前
灶台菜谱设计手记 03|HarmonyOS 7.0 空间化:沉浸光感反馈
harmonyos
大雷神9 小时前
HarmonyOS7应用《拼棋派对》实战:折叠屏与电脑的窗口布局适配
harmonyos·arkui·harmonyos 7.0·玩转 arkts
2501_946244789 小时前
开源鸿蒙平台 CMP 三方库「Waterfall」适配全流程
华为·开源·harmonyos
2401_zq136y039 小时前
开源鸿蒙平台 CMP 三方库「Jewel」适配全流程
华为·开源·harmonyos
2601_9494800611 小时前
开源鸿蒙平台 KMP 三方库「AutoLinkText」适配全流程
华为·开源·harmonyos
JoyCong199811 小时前
ToDesk鸿蒙PC端又焕新!远控更稳、操作更准,跨端办公如本地
运维·华为·智能手机·harmonyos·远程工作