RN Fetch Blob在Android 14上异常:应用崩溃且文件无法打开
问题解决:React Native 0.73 + Android 14 下 RNFetchBlob 下载崩溃与文件无法打开
一、崩溃问题(receiver_exported/receiver_not_exported 报错)
Android 14(API 34)强制要求所有广播接收器必须显式声明android:exported属性,RNFetchBlob 旧版本未适配该规则,导致下载完成后触发广播时崩溃。
解决方法:
升级 RNFetchBlob 到最新适配版本
执行升级命令:npm install rn-fetch-blob@latest # 或 yarn add rn-fetch-blob@latest手动修改 AndroidManifest.xml
如果暂时无法升级,在项目的android/app/src/main/AndroidManifest.xml中添加广播接收器的exported属性:<receiver android:name="com.RNFetchBlob.RNFetchBlobDownloadCompleteReceiver" android:exported="false"> <intent-filter> <action android:name="android.intent.action.DOWNLOAD_COMPLETE"/> </intent-filter> </receiver>注:若接收器需接收系统全局广播,设为
android:exported="true",否则设为false即可。
二、文件无法打开(提示“Can't open file”)
该问题通常由权限不足、MIME类型未指定或文件路径访问限制导致,可按以下步骤修复:
解决方法:
添加 MIME 类型配置
在addAndroidDownloads配置中指定文件的MIME类型,让系统识别文件格式:addAndroidDownloads: { useDownloadManager: true, notification: true, path: `${dirToSave}/ows-booking-invoice-${invoiceResponse.variables?.orderId}.pdf`, mime: 'application/pdf', // 新增PDF的MIME类型 mediaScannable: true, // 让系统媒体库扫描到该文件 }检查文件权限与路径
- Android 10+ 访问公共下载目录(
DownloadDir)无需申请WRITE_EXTERNAL_STORAGE权限,但需确保路径正确,mediaScannable: true可触发系统扫描更新文件索引。 - 若仍无法访问,可尝试切换到应用私有目录:
android: RNFetchBlob.fs.dirs.CacheDir // 或 RNFetchBlob.fs.dirs.DCIMDir
- Android 10+ 访问公共下载目录(
优化文件打开逻辑
Android下打开文件需确保路径被系统认可,可修改下载完成后的打开逻辑:} else { console.log("File downloaded "); // 直接调用系统应用打开PDF RNFetchBlob.android.actionViewIntent( res.path(), 'application/pdf' ); Snackbar.show({ text: 'File Downloaded.', duration: Snackbar.LENGTH_SHORT, }); }
完整修改后的代码示例
useEffect(() => { setIsInvoiceDownloading(true); if (invoiceResponse.error && invoiceResponse.called) { console.log("Error in invoiceResponse") setIsInvoiceDownloading(false); firebase .analytics() .logEvent('ApiErrorMessage', { API: 'INVOICE_DOWNLOAD' }); Snackbar.show({ text: 'Could not fetch invoice. Please try again.', duration: Snackbar.LENGTH_SHORT, }); } else if (invoiceResponse.data) { console.log("Success in invoiceResponse ", invoiceResponse) const dirToSave = Platform.select({ ios: RNFetchBlob.fs.dirs.DocumentDir, android: RNFetchBlob.fs.dirs.DownloadDir, }); console.log("dirToSave invoiceResponse", dirToSave); RNFetchBlob.config({ fileCache: true, path: `${dirToSave}/ows-booking-invoice-${invoiceResponse.variables?.orderId}.pdf`, addAndroidDownloads: { useDownloadManager: true, notification: true, path: `${dirToSave}/ows-booking-invoice-${invoiceResponse.variables?.orderId}.pdf`, mime: 'application/pdf', mediaScannable: true, }, }) .fetch('GET', invoiceResponse.data.getInvoicePdfByBookingId) .then((res) => { console.log("Fetch successful, response ", res); setIsInvoiceDownloading(false); if (Platform.OS === 'ios') { RNFetchBlob.ios.openDocument(res.data); } else { console.log("File downloaded "); RNFetchBlob.android.actionViewIntent(res.path(), 'application/pdf'); Snackbar.show({ text: 'File Downloaded.', duration: Snackbar.LENGTH_SHORT, }); } }) .catch((err) => { console.log("Fetch failed, error: ", err); firebase .analytics() .logEvent('ApiErrorMessage', { API: 'INVOICE_DOWNLOAD' }); setIsInvoiceDownloading(false); Snackbar.show({ text: 'Could not download invoice. Please try again.', duration: Snackbar.LENGTH_SHORT, }); }); } }, [invoiceResponse]);
内容的提问来源于stack exchange,提问作者Saumya Chirania
相关产品推荐
相关产品推荐

