如何获取expo-sharing下载状态 检测PDF文件是否下载完成
Expo-Sharing实现PDF下载状态同步方案
问题核心原因
expo-sharing本身只负责调起系统级的分享/文件保存弹窗,如果你直接把远程PDF URL传入分享方法,整个下载流程是由系统服务接管的,前端层拿不到下载进度、操作结果的回调,自然无法判断是否下载完成、用户是否取消操作。
实现思路
别直接把远程地址丢给分享组件,先用expo-file-system自主管控PDF的全量下载流程,等文件完整下载到本地临时目录后,再把本地文件路径传给expo-sharing调起操作,三类状态全程自己维护,完全可控。
具体实现步骤
- 安装必需依赖
执行以下命令安装配套的文件系统库:npx expo install expo-file-system expo-sharing - 定义统一状态标识
先在业务代码里固定三类状态值,方便UI层同步对应提示:const PDF_STATUS = { DOWNLOADING: 'downloading', // 下载中 CANCELED: 'canceled', // 已取消 COMPLETED: 'completed' // 已完成 } - 编写带状态管控的下载分享逻辑
核心逻辑分为三段:创建可控下载任务标记下载中状态、监听下载完成事件、调起分享后根据返回结果标记取消/完成状态,参考代码如下:import * as FileSystem from 'expo-file-system'; import * as Sharing from 'expo-sharing'; const downloadAndSharePDF = async (remotePdfUrl, fileName) => { // 初始化状态为下载中,UI可同步展示加载提示、进度条 let currentStatus = PDF_STATUS.DOWNLOADING; // 生成本地临时文件存储路径 const localUri = `${FileSystem.cacheDirectory}${fileName}.pdf`; try { // 创建可中断的下载任务,可自行监听下载进度做进度展示 const downloadResumable = FileSystem.createDownloadResumable( remotePdfUrl, localUri, {}, (downloadProgress) => { const progress = downloadProgress.totalBytesWritten / downloadProgress.totalBytesExpectedToWrite; // 这里可以同步更新下载进度到UI console.log(`下载进度:${(progress * 100).toFixed(0)}%`); } ); // 要支持下载中途用户点取消,就把downloadResumable存在ref里 // 用户点取消按钮时调用 downloadResumable.cancelAsync() 即可中断下载,同时把状态置为CANCELED // 等待文件下载完成 const downloadResult = await downloadResumable.downloadAsync(); if (!downloadResult?.uri) throw new Error('文件下载失败'); // 校验本地文件是否存在、大小是否正常,避免下载到损坏文件 const fileInfo = await FileSystem.getInfoAsync(downloadResult.uri); if (!fileInfo.exists || fileInfo.size === 0) throw new Error('文件校验失败'); // 下载完成后调起系统分享弹窗 await Sharing.shareAsync(downloadResult.uri, { mimeType: 'application/pdf', dialogTitle: '保存或分享PDF', UTI: 'com.adobe.pdf' }); // 没有抛出错误就说明用户完成了保存/分享操作,标记为已完成 currentStatus = PDF_STATUS.COMPLETED; // 操作完成后可按需删除临时文件,避免占用存储空间 await FileSystem.deleteAsync(downloadResult.uri, { idempotent: true }); } catch (error) { // 判断错误类型:如果是用户主动关闭分享弹窗、取消下载,标记为已取消 if (error.message.includes('User did not share') || error.message.includes('cancelled')) { currentStatus = PDF_STATUS.CANCELED; } else { // 其他网络、权限类错误可以单独做失败提示,不属于三类状态范畴可自行处理 console.error('PDF操作失败:', error); } } // 最终把currentStatus返回给UI层,同步展示对应提示即可 return currentStatus; }
避坑说明
- 绝对不要直接传远程URL给
Sharing.shareAsync,这是之前拿不到下载完成状态的核心原因,这种模式下整个下载流程对前端是黑盒,没有任何回调可以监听。 - 安卓10及以上版本不需要额外申请存储权限即可完成文件保存,安卓9及以下版本需要先申请存储权限再调用上述逻辑,否则会保存失败。
- 如果不需要调起分享弹窗、只需要直接把PDF下载到用户设备存储目录,可以直接用
expo-file-system的下载方法把文件存到系统文档目录,不需要调用expo-sharing,下载完成的回调可以直接标记为已完成状态。
内容的提问来源于stack exchange,提问作者Lewis
相关产品推荐
相关产品推荐

