分享面板关了,大文件还在准备:HarmonyOS 7 System Share 的取消、就绪与重复回调怎么收口
用户点击“分享视频”,应用先压缩并生成临时文件;分享面板刚弹出,用户又立刻关闭。几分钟后应用仍在后台压缩,临时文件越积越多,再次分享还收到上一次的迟到回调。官方systemShare提供分享数据创建、分享面板拉起、呈现与关闭,并支持文本、文件和扩展数据。工程上还需要把“内容准备”和“面板生命周期”拆开,否则一次取消会留下两条任务。
验证边界:本文的 HarmonyOS 7/API 26 能力与约束以文末当前官方资料为准;应用侧状态模型和断言已在本机 Node.js 环境执行。当前本机 SDK 为 API 24,且没有连接 HDC 真机,因此不声称完成 API 26 编译、真机拍摄、跨设备传输或 AppGallery 审核验证。
用慢文件准备和快速关闭制造迟到结果
选择一个需要 5 秒生成的 300MB 测试文件。点击分享后在 1 秒内关闭面板,随后马上再次分享另一个文件。记录 shareRequestId、prepareGeneration、fileUri、panelState、resultAction 和 tempLeaseId。若第一次压缩继续运行,或第一次回调改变第二次分享的 UI,问题就被复现。
案例一:文件尚未准备好,不应先把空 URI 交给面板
大文件需要转码或导出时,先进入 preparing 并展示可取消进度;文件 URI、大小和读取权限都准备完成后再构造 SharedRecord。为了“看起来快”而先拉起面板,目标端很可能拿到不存在或仍在写入的文件。
案例二:面板关闭不等于后台任务自然停止
用户关闭面板后,应用要根据 lease 决定取消文件准备、延迟删除临时文件或保留已完成缓存。旧请求的结果回调必须携带 requestId;如果不是当前请求,只做日志,不更新当前页面。
分享分成 prepare、present、settle 三个阶段
prepare 负责生成稳定内容与 URI;present 只管理分享面板和用户选择;settle 根据结果完成清理、保留或重试。三个阶段共用 requestId,却拥有独立超时和取消策略。这样才能知道“面板关了”应该取消哪一段工作。
临时文件使用租约而不是定时乱删
每个分享请求创建 tempLeaseId。目标端可能在面板选择后才开始读取,应用不能在收到选择结果瞬间删除文件。租约记录创建时间、最终状态和最晚清理时间;取消且未呈现的文件可立即删,已交给系统的文件按策略延迟回收。
文件 URI 和扩展数据都要可验证
官方参考列出 SharedRecord 和应用文件 URI 等支持方式,并允许extraData携带扩展内容。不要把沙箱路径直接当成跨应用可读地址,也不要在 extraData 放敏感明文。构造记录前检查 URI 类型、MIME、大小和可读性,失败就停在 prepare 阶段。
可直接复用的工程切片
import { systemShare } from '@kit.ShareKit' type ShareJob = { requestId: string state: 'preparing'|'presented'|'settled'|'cancelled' fileUri?: string tempLeaseId: string } // 文件稳定可读后再构造 SharedRecord 与 ShareController; // 分享面板结果只处理 requestId 仍为当前代际的任务。上面是围绕官方能力位置整理的 ArkTS/工程接入片段,仍需在 API 26 工具链和目标设备上编译验证。下面把最容易出错的应用侧判定抽成可执行断言,避免把接口示意写成“已经真机跑通”。
class ShareGate { current=''; state='idle'; begin(id){this.current=id;this.state='preparing';} settle(id){if(id!==this.current)return false;this.state='settled';return true;} } const g=new ShareGate(); g.begin('r1'); g.begin('r2'); if(g.settle('r1')) throw new Error('旧分享回调覆盖当前任务'); if(!g.settle('r2')||g.state!=='settled') throw new Error('当前分享无法结算');方案对比
| 方案 | 优点 | 风险或限制 |
| 先拉面板再准备文件 | 首屏反馈快 | 目标端可能拿到空或半成品 |
| 面板关闭后全部立即删除 | 清理简单 | 系统/目标端可能仍在读取 |
| 三阶段任务 + 临时文件租约 | 生命周期清晰 | 需要 requestId 和清理调度 |
采用三阶段任务和临时文件租约。用户取消时停止尚未交付的工作,已交给系统的内容按租约安全回收,迟到回调不能越权。
交付物与回归清单
一个ShareJob状态机、URI 预检表、临时文件租约和重复回调断言。它既适用于本机应用分享,也能约束跨设备分享入口的准备过程。
- 文件未稳定前不拉起分享面板。
- 面板关闭可取消尚未完成的准备任务。
- 旧 requestId 回调不改变新任务。
- 临时文件删除遵循租约而非固定短延时。
- URI、MIME、大小和权限在构造记录前验证。
分享接口负责把内容交给系统,应用仍要为内容准备和清理负责。把一次分享当成有代际、有租约的任务,取消才是真的取消。
官方资料
- systemShare API 参考
- 手机应用发起系统分享
- 多设备自适应应用
- 工程构建版本配置