在 HarmonyOS 应用接入 @wps/wps_sdk 后,打开与编辑往往先跑通,下一步产品会要求「用户关文档后,把编辑结果拿回本应用」。对接文档把这类能力挂在 OpenFileRequest 的关闭回传参数上:enableTransferFile 与 wpsTransferType(TransferType.URI / TransferType.FD)。本文按调用链说明等待语义、结果字段、拷贝到本应用沙箱的写法与联调清单,细节以官方对接文档为准。
一、回传在打开链路中的位置
典型时序:registerApp 成功 → 文件进沙箱 → new OpenFileRequest → 写入 enableEdit →(可选)策略/管控 → 开启关闭回传 → sendRequest → 用户关闭 WPS → Promise 才带着 result.data 回来。
| 层级 | 能力 | 入口 |
|---|---|---|
| 接入 | 注册、可选序列号 | registerApp / setWpsFileToken |
| 打开 | 拉起、只读/可编辑 | enableEdit |
| 结果 | 关窗回传 | enableTransferFile / wpsTransferType |
未开启回传时,sendRequest 在拉起成功后即可返回 OK,且 data 常为空------这是正常行为,不要当成失败。开启回传后,Promise 会等到用户真正关闭文档。
二、字段语义与优先级
| 字段 | 作用 |
|---|---|
enableTransferFile = true |
以 URI 方式回传(便捷开关) |
wpsTransferType = TransferType.URI |
明确 URI 回传 |
wpsTransferType = TransferType.FD |
FD 回传,关注 ResultData.transferFd |
wpsTransferType 优先级高于 enableTransferFile。封装时建议只走 wpsTransferType,避免两套开关互相覆盖造成联调困惑。
typescript
import { TransferType, OpenFileRequest } from '@wps/wps_sdk';
function enableCloseTransfer(req: OpenFileRequest, mode: 'uri' | 'fd'): void {
req.wpsTransferType = mode === 'fd' ? TransferType.FD : TransferType.URI;
// 不必再写 enableTransferFile;类型字段已足够表达意图
}
三、Result 与 ResultData
sendRequest 返回的 Result 中,关闭回传相关数据在 data(ResultData):
| 字段 | URI 模式 | FD 模式 |
|---|---|---|
fileUri |
WPS 侧路径(须再拷贝) | 可能无 |
transferFd |
--- | 文件描述符 |
transferFileName / transferFileSize |
--- | 常在 parameters 或同级字段 |
关键点:URI 回传的路径位于 WPS 沙箱 ,不能直接当本应用持久路径用。须拷贝到本应用沙箱后,得到可供后续上传、归档的 filePath。
四、URI:拷贝到本应用沙箱
typescript
import fs from '@ohos.file.fs';
import fileuri from '@ohos.file.fileuri';
function copyWpsUriToSandbox(ctx: UIAbilityContext, wpsFileUri: string): string | undefined {
const file = fs.openSync(wpsFileUri, fs.OpenMode.READ_ONLY);
if (!file.path) {
return undefined;
}
const fileName = file.path.substring(file.path.lastIndexOf('/') + 1);
const dir = `${ctx.filesDir}/wps_callback/${Date.now()}/`;
if (!fs.accessSync(dir)) {
fs.mkdirSync(dir, true);
}
const backupPath = dir + fileName;
fs.copyFileSync(file.fd, backupPath);
return fileuri.getUriFromPath(backupPath);
}
拷贝成功后,若业务约定需要清理 WPS 侧临时文件,再按对接文档建议删除;清理失败应打日志,不要吞掉主流程结果。
五、FD:从描述符写入沙箱
typescript
function copyFdToSandbox(ctx: UIAbilityContext, parameters: Record<string, Object>): string | undefined {
const fdParam = parameters['transferFd'] as Record<string, Object> | undefined;
if (!fdParam || fdParam['type'] !== 'FD') {
return undefined;
}
const fd = fdParam['value'] as number;
const fileName = (parameters['transferFileName'] as string) || 'edited_file';
if (fd < 0) {
return undefined;
}
const localDir = `${ctx.filesDir}/fd_transfer/`;
if (fs.accessSync(localDir)) {
fs.rmdirSync(localDir);
}
fs.mkdirSync(localDir, true);
const localPath = localDir + fileName;
const localFile = fs.openSync(localPath, fs.OpenMode.CREATE | fs.OpenMode.WRITE_ONLY | fs.OpenMode.TRUNC);
const chunk = new ArrayBuffer(64 * 1024);
while (true) {
const len = fs.readSync(fd, chunk);
if (len <= 0) break;
fs.writeSync(localFile.fd, chunk, { length: len });
}
fs.closeSync(localFile.fd);
fs.closeSync(fd);
return fileuri.getUriFromPath(localPath);
}
FD 模式要记得关闭描述符,避免泄漏。文件名优先用回传参数里的名字,便于业务侧归档。
六、可复用打开封装
把是否回传、回传模式收进 Facade,页面不直接拼字段。
typescript
export async function openEditableWithTransfer(
ctx: UIAbilityContext,
src: string,
mode: 'uri' | 'fd' = 'uri'
): Promise<{ result: Result; localPath?: string }> {
await prepareWps(APP_KEY, APP_SECRET);
const path = copyToSandbox(ctx, src);
const req = new OpenFileRequest(ctx, path);
req.enableEdit = true;
req.wpsTransferType = mode === 'fd' ? TransferType.FD : TransferType.URI;
const result = await WPSApi.sendRequest(req);
if (result.code !== ResultCode.OK || !result.data) {
return { result };
}
let localPath: string | undefined;
if (mode === 'fd' && result.data.parameters) {
localPath = copyFdToSandbox(ctx, result.data.parameters);
} else if (result.data.fileUri) {
localPath = copyWpsUriToSandbox(ctx, result.data.fileUri);
}
return { result, localPath };
}
未开回传的预览路径,不要误用这套等待语义;否则用户不关文档,调用方会一直挂起。
七、联调表与小结
| 现象 | 优先查 |
|---|---|
| Promise 很久不返回 | 是否开了回传、用户是否已关文档 |
OK 但 data 空 |
是否未开回传(属正常) |
有 fileUri 但后续读失败 |
是否未拷贝到本应用沙箱 |
| FD 无效 | transferFd、parameters 结构、是否已 close |
抛异常 / 1013 |
注册、凭据、包名、clean |
日志固定:code / msg / 是否开回传 / 模式 / 是否已得到本应用路径。全仓 new OpenFileRequest 命中保持一处。换 HAR 后 clean;Release 不打印 secret。
HarmonyOS 上关闭回传是结果层能力:显式设置 wpsTransferType(或 enableTransferFile),等待关窗,再把 WPS 沙箱内容落到本应用沙箱。字段语义以官方对接文档为准。
接入评审确认:HAR、沙箱目录、回传模式是否统一走 Facade、正式包包名。缺一环易「本地绿、上架红」。真机验收:可编辑 + URI 回传拷贝成功;可选再验 FD。把「先打开绿,再开回传,再拷贝」写进联调清单,联调会从猜原因变成对表排查。周五用正式包包名再验注册与关窗回传各一次。注释写清「回传结果必须先拷贝再给业务」,比口头说「参考 Demo」更耐看。
从协作看,超时与取消策略要提前约定:用户长时间不关文档时,UI 是否提示、是否允许取消等待。拷贝目录建议按时间戳隔离,避免并发覆盖。FD 与 URI 不要在同一页面混用两套解析而无分支。路径拷贝失败要有独立错误提示,勿与「打开失败」混单。把上述约定坚持几周,回传相关反复提问通常会下降,接入节奏也会更稳。
再补验收与工程习惯。关文档后先确认日志里出现 fileUri 或有效 fd,再确认本应用沙箱目录生成了新文件,最后才走上传或归档。只断言「Promise 结束」不够接近真实闭环。并发打开两份文档时,两个时间戳目录都应存在且互不覆盖。FD 模式核对文件名、大小与可读性,并确认描述符已关闭。清理临时文件失败不应把用户带到失败页------本应用路径已经可用。联调反馈请带上:是否开回传、模式、是否已拷贝。周五再用正式包包名过一遍注册与 URI 回传用例,确认没有回退。预设名或封装函数名建议用业务语言(如 openAndCollect),方便产品与测试对齐「关窗拿结果」这条链路。
基于 WPS Open SDK 鸿蒙版对接实践整理,仅供开发者参考。