[Android 14 / 新架构] PDF下载在缓存目录的临时文件上因ENOENT错误而崩溃
环境
| 包名 | 版本 |
|---|---|
react-native-pdf |
7.0.4 |
react-native-blob-util |
0.23.2 |
react-native |
0.82.1 |
| Android | 14 (API 34) |
| 新架构 | enabled (newArchEnabled=true) |
minSdkVersion |
34 |
错误描述
在使用以下方式加载远程PDF时:
<Pdf
source={{
uri: 'https://example.com/doc.pdf',
cache: true,
}}
/>
在启用新架构时,应用在Android 14上崩溃。
该失败表现为未处理的Promise拒绝,并绕过绑定在 this.lastRNBFTask 上的 .catch() 处理程序。
该错误也从未传递给 onError 属性。
控制台错误
Uncaught (in promise, id: 0):
Error: /data/user/0/<package>/cache/<sha1>.pdf.tmp:
open failed: ENOENT (No such file or directory)
复现步骤
- 启用新架构:
newArchEnabled=true
- 目标Android 14(
API 34) - 渲染:
<Pdf
source={{
uri: 'https://example.com/doc.pdf',
cache: true,
}}
/>
-
在以下情形打开屏幕:
-
全新安装,或
- 清除Android设置中的应用缓存后
预期行为
- PDF能成功加载
- 如果加载失败,错误应通过
onError属性传递。
实际行为
在 CacheDir 中的 .pdf.tmp 文件上发生未处理的Promise拒绝,内容为 ENOENT。
该错误绕过了库的错误处理,表现为全局未处理拒绝。
onError 从未被调用。
额外背景信息
CacheDir能正确解析- 生成的临时文件路径看起来有效。
- 在执行打开/读取操作时,该文件不存在。
- 在启用新架构的Android 14上,该问题可稳定复现。
- 在Android 13及以下版本上不复现。
- 禁用新架构时不复现。
可能的根本原因
这似乎是在启用新架构的Android 14上缓存/临时文件流程中的一个竞态条件。
位于 CacheDir 内的 .pdf.tmp 文件在实际存在之前就被访问(或在重新创建/清理过程中),导致 react-native-blob-util 抛出 ENOENT。
该拒绝在 react-native-pdf 将其转发给 onError 之前就已从Promise链中传播出去。
相关问题
react-native-blob-utilAndroid 14ENOENT问题- RN 0.76+上的TurboModules / 新架构文件系统时序问题
解决方案
在Android 14上启用新架构时,这似乎是 react-native-pdf + react-native-blob-util 中的一个竞态条件。缓存目录本身似乎不是问题所在。.pdf.tmp文件在完全写入或生成完成之前就被打开了,尽管临时路径是可接受的。因此该拒绝在react-native-pdf将其传递给onError之前就已逃逸,Android会抛出ENOENT。
因此,在Android 14的新架构下,最好避免直接对远程PDF使用 cache: true。
你也可以改用以下做法:
source={{uri: localFilePath, cache: false}}
简要做法是:先手动将PDF下载到一个稳定的本地文件路径,然后把本地file:// 路径传递给react-native-pdf,并禁用缓存;再检查文件是否存在。这样就能对下载故障、重试和回退界面有完整控制,同时也避免内部临时文件时序问题。