做 HarmonyOS 文档二开时,页面里直接写 if (result.code === 0) 很快会失控:注册失败、打开参数错误、关窗回传失败都挤在同一分支,Toast 文案也难以维护。更稳妥的做法是在 SDK 边界加一层 Facade / Adapter,把 @wps/wps_sdk 的 Result 与抛异常,转成业务侧可 switch 的领域错误。本文给出一套可复用的归一化思路与 TypeScript 示例,事实对齐官方对接实践,代码按工程封装习惯重写。
WPSApi.sendRequest 在应用已注册的前提下,多数失败仍会 resolve Result ,只有「尚未注册成功」等场景会 throw 。若 UI 层只写 try/catch ,会漏掉带 code 的失败;若只看 code ,又会漏掉 throw。Facade 的职责就是:对外只暴露「成功数据」或「领域错误枚举」,把 requestType / code / msg / data 的细节留在适配层。
调用链仍建议保持清晰: registerApp 到 OK →(按形态)可选 setWpsFileToken → 选择器文件进沙箱 → OpenFileRequest → sendRequest → 解析关闭回传。Facade 不改变时序,只改变错误出口形状。
下面用一组字符串联合类型表示领域错误,便于埋点与 UI 映射:
| 领域码 | 来源特征 | UI / 运维建议 | | --- | --- | --- | | AUTH_FAILURE | code === 1013 / ERROR_CODE_AUTH_FAILURE | 引导检查凭据与包名,阻断后续打开 | | NOT_REGISTERED | sendRequest throw 或本地门闩未就绪 | 提示稍后重试,触发重新注册 | | PARAM_OR_OPEN | ResultCode.ERROR ( -2 ) | 查路径、参数、是否默认只读被误判 | | TRANSFER_BIZ | 关闭回传阶段正整数 code | 按回传失败处理,保留原始 code | | UNKNOWN | 其它非 OK | 上报 code + msg ,避免静默 |
成功时把 Result.data (如有)交给业务;失败时绝不把原始 Result 直接丢进页面组件。
import
{ common }
from
'@kit.AbilityKit'
;
import
{
WPSApi
,
OpenFileRequest
,
Result
,
ResultCode
,
ResultData
,
SdkConstants
,
}
from
'@wps/wps_sdk'
;
type
WpsDomainError
=
| {
kind
:
'AUTH_FAILURE'
; msg?:
string
}
| {
kind
:
'NOT_REGISTERED'
; msg?:
string
}
| {
kind
:
'PARAM_OR_OPEN'
;
code
:
number
; msg?:
string
}
| {
kind
:
'TRANSFER_BIZ'
;
code
:
number
; msg?:
string
}
| {
kind
:
'UNKNOWN'
; code?:
number
; msg?:
string
};
type
WpsOutcome
=
| {
ok
:
true
; data?:
ResultData
}
| {
ok
:
false
;
error
:
WpsDomainError
};
let
ready =
false
;
export
function
mapResult
(
stage:
'register'
|
'open'
|
'transfer'
, r: Result
):
WpsOutcome
{
if
(r.
code
===
ResultCode
.
OK
) {
return
{
ok
:
true
,
data
: r.
data
};
}
if
(r.
code
===
ResultCode
.
ERROR_CODE_AUTH_FAILURE
) {
return
{
ok
:
false
,
error
: {
kind
:
'AUTH_FAILURE'
,
msg
: r.
msg
} };
}
if
(r.
code
===
ResultCode
.
ERROR
) {
return
{
ok
:
false
,
error
: {
kind
:
'PARAM_OR_OPEN'
,
code
: -
2
,
msg
: r.
msg
} };
}
if
(stage ===
'transfer'
&&
typeof
r.
code
===
'number'
&& r.
code
>
0
) {
return
{
ok
:
false
,
error
: {
kind
:
'TRANSFER_BIZ'
,
code
: r.
code
,
msg
: r.
msg
} };
}
return
{
ok
:
false
,
error
: {
kind
:
'UNKNOWN'
,
code
: r.
code
,
msg
: r.
msg
} };
}
export
function
registerFacade
(
activationSn?:
string
):
void
{
WPSApi
.
registerApp
(
APP_KEY
,
APP_SECRET
, {
onCallback
:
(
result: Result
) =>
{
const
out =
mapResult
(
'register'
, result);
if
(!out.
ok
) {
ready =
false
;
console
.
error
(
'register domain'
, out.
error
);
return
;
}
if
(activationSn && !
SdkConstants
.
isPersonalSdk
()) {
WPSApi
.
setWpsFileToken
(activationSn);
}
ready =
true
;
}
});
}说明: mapResult 按 stage 解释正整数,避免把回传业务码误判成打开参数错误。注册回调里单独处理 AUTH_FAILURE 。 SdkConstants.isPersonalSdk() 用于决定是否注入序列号,页面层无需感知 HAR 形态细节。
export
async
function
openDocFacade
(
context: common.UIAbilityContext,
sandboxPath:
string
,
opts: { editable?:
boolean
; transfer?:
boolean
} = {}
):
Promise
<
WpsOutcome
> {
if
(!ready) {
return
{
ok
:
false
,
error
: {
kind
:
'NOT_REGISTERED'
,
msg
:
'gate closed'
} };
}
const
request =
new
OpenFileRequest
(context, sandboxPath);
request.
enableEdit
= opts.
editable
===
true
;
if
(opts.
transfer
) {
request.
enableTransferFile
=
true
;
}
try
{
const
result =
await
WPSApi
.
sendRequest
(request);
const
stage = opts.
transfer
?
'transfer'
:
'open'
;
const
out =
mapResult
(stage, result);
if
(!out.
ok
) {
console
.
error
(
'open/transfer domain'
, out.
error
, result.
requestType
);
}
return
out;
}
catch
(e) {
return
{
ok
:
false
,
error
: {
kind
:
'NOT_REGISTERED'
,
msg
: (e
as
Error
).
message
},
};
}
}说明:未就绪时直接返回领域错误,避免无意义 throw。 enableEdit 显式默认只读,与对接语义一致。开启回传时用 stage='transfer' 解释正整数;未开启时按 open 阶段映射 -2 等。
async
function
onOpenClicked
(
ctx: common.UIAbilityContext, path:
string
) {
const
out =
await
openDocFacade
(ctx, path, {
editable
:
true
,
transfer
:
true
});
if
(out.
ok
) {
return
;
}
switch
(out.
error
.
kind
) {
case
'AUTH_FAILURE'
:
break
;
case
'NOT_REGISTERED'
:
registerFacade
();
break
;
case
'PARAM_OR_OPEN'
:
break
;
case
'TRANSFER_BIZ'
:
break
;
default
:
break
;
}
}对接侧常量不变,Facade 只做翻译:
| SDK code | 常量 | Facade kind | | --- | --- | --- | | 0 | OK | 成功分支 | | -1 | NONE | 通常视为未就绪 / UNKNOWN | | -2 | ERROR | PARAM_OR_OPEN | | 1013 | ERROR_CODE_AUTH_FAILURE | AUTH_FAILURE | | 其它正整数(回传) | — | TRANSFER_BIZ | | throw | — | NOT_REGISTERED |
Result.msg 建议原样进入日志,UI 文案用领域码映射中文,避免把底层英文/内部文案直接甩给用户。 Result.data 仅在 ok: true 时下发,防止失败态误读空 fileUri 。
注册必须先于打开;Facade 用 ready 门闩双保险。
选择器 URI 先拷贝进 filesDir 再打开,减少 -2 。
默认只读;可编辑场景显式 enableEdit = true 。
监控按 kind 聚合,再下钻原始 code 。
Release 不打印 secret; msg 注意脱敏。
ResultCode.NONE ( -1 ) :表示默认/未赋值,不要当成功,也不要直接映射成 PARAM_OR_OPEN 。若回调尚未触发就读到 -1 ,说明时序仍停在注册前,应显示加载态而不是错误 Toast。
成功但无文件 :未开启关闭回传时, code === OK 且 data 为空是预期行为。Facade 的 ok: true 仍成立,页面若强依赖 fileUri ,应在调用参数里要求 transfer: true ,并在成功分支校验 data 。
单元测试怎么切 :为 mapResult 写表驱动测试即可覆盖 0 / -2 / 1013 / 正整数 / 缺省 code 。 openDocFacade 对 ready=false 与 catch 两条 NOT_REGISTERED 路径各测一次。不要在单测里真拉起 WPS;把 WPSApi.sendRequest 换成可注入的函数类型即可。
埋点维度 : kind 作告警主键, stage 作下钻维度,原始 code 作标签。这样回传业务码上涨时,不会误触发「凭据大面积失败」的值班规则。UI 文案按 kind 配置中文,避免把底层 msg 原文甩给终端用户。
与页面状态机配合 :建议页面只有 Idle / Registering / Ready / Opening / Transferring / Failed(kind) 有限状态。Facade 返回后只做状态迁移,不在按钮回调里再写一套 if (code === …) 。冷启动在 Ability 阶段调用 registerFacade ,首页打开按钮绑定 Ready 门闩,可减少竞态。
在鸿蒙 WPS 二开里,错误处理的质量往往决定联调效率。把 Result 与 throw 收进 Facade,页面只面对有限领域错误,1013、 -2 、回传正整数就不会再挤在同一个 else 。上述适配层可直接嵌进现有 TypeScript 工程:先落地 mapResult 与门闩,再逐步把散落的 result.code === 0 替换掉。当你需要扩展水印、修订或不落地等能力时,继续把失败收口到同一套 WpsDomainError ,比在每个页面复制错误码表更稳。
更多参数见官方对接文档: 365.kdocs.cn/l/clQl5cek2… 技术交流 QQ 群:628436767
转载声明:本文为转载整理,原文版权归原作者及原站点所有。
原文来源:Juejin HarmonyOS
原文作者:用户093407773514;如有侵权,请联系管理员删除。