Pre-download PDFs to file:// URI to avoid stale blob: URIs on iOS#260
Conversation
Fixes GUMROAD-MOBILE-1V On iOS with Hermes, blob: URIs created by react-native-blob-util become unresolvable after JS runtime resets because the native blob store is cleared but URI references persist. This caused 'Unable to resolve data for blob: UUID' errors when reopening the app with cached PDF state. Pre-download PDFs using expo-file-system before passing to the Pdf component, so react-native-pdf receives a local file:// path and never creates blob: URIs internally. Changes: - Add download state (cachedUri, downloadError, isDownloading) to PdfViewerScreen with a useEffect that downloads the PDF on mount - Show LoadingSpinner while downloading instead of the Pdf component - Pass the local file:// cachedUri to the Pdf component source - Pass cachedUri to PdfNavigationSheet to reuse the downloaded file - Filter stale-blob errors from Sentry captures in onError callback - Update tests to handle async download lifecycle
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 25ffff1. Configure here.
Greptile SummaryThis PR pre-downloads PDFs to a local
Confidence Score: 5/5Safe to merge — change is scoped to PDF loading and does not touch auth, payments, or any shared infrastructure. All state transitions (download → loading → render, download failure → retry, stale retry cancellation) are correctly guarded by the cancelled-flag pattern. The PdfNavigationSheet re-download regression from the previous review is fixed with the isLocalFile guard. The share handler correctly prefers the already-cached URI. New tests cover every new code path including the deferred-promise race. No files require special attention. Important Files Changed
Reviews (3): Last reviewed commit: "Use cached PDF for sharing" | Re-trigger Greptile |
|
Fixed the bot review findings in d0e811d: retry downloads now cancel prior attempts, PdfNavigationSheet uses file:// URIs directly instead of re-downloading them, and the PDF viewer tests cover loading, scoped download failures, stale retry races, and local/remote thumbnail download behavior.\n\nVerification:\n- yarn test --runInBand\n- yarn typecheck\n- yarn lint\n- yarn prettier --check app/pdf-viewer.tsx components/pdf-navigation-sheet.tsx tests/app/pdf-viewer.test.tsx tests/components/pdf-navigation-sheet.test.tsx |
|
Follow-up fixed the remaining Greptile summary P1 in cf676f1: the share button now uses the already-cached file:// PDF when available instead of re-downloading the original remote URL, with regression coverage that sharing only performs the initial cache download.\n\nVerification after cf676f1:\n- yarn test --runInBand (201 tests passed)\n- yarn typecheck\n- yarn lint\n- yarn prettier --check app/pdf-viewer.tsx tests/app/pdf-viewer.test.tsx\n- GitHub checks: test + Cursor Bugbot passing |
|
Assigning @nyomanjyotisa per Gianfranco. |

What
Pre-download PDFs to a local
file://URI usingexpo-file-systembefore passing to thePdfcomponent, preventingreact-native-pdffrom creatingblob:URIs internally on iOS.Changes to
app/pdf-viewer.tsx:cachedUri,downloadError,isDownloading) with auseEffectthat callsFile.downloadFileAsyncon mount, mirroring the existing pattern inpdf-navigation-sheet.tsxLoadingSpinnerwhile the download is in progressfile://cachedUrito thePdfcomponent'ssourcepropcachedUri ?? uritoPdfNavigationSheetso it reuses the already-downloaded file instead of downloading redundantly'Unable to resolve data for blob:') fromSentry.captureExceptionin theonErrorcallbackChanges to
tests/app/pdf-viewer.test.tsx:await waitForfor the async download to complete before assertingWhy
On iOS with Hermes,
blob:URIs created byreact-native-blob-util(used internally byreact-native-pdf) become unresolvable after JS runtime resets. The nativeRCTBlobManagerblob store is cleared on restart, butblob:URI references can persist in TanStack Query cache, navigation state, or background tab mounts via Expo Router. This causes'Unable to resolve data for blob: UUID'crashes when the app is reopened.By pre-downloading to a
file://path,react-native-pdfreceives a local file and never invokesreact-native-blob-utilto create ablob:URI, eliminating the stale reference entirely.Test results
All 28 test suites pass (197 tests), including 2 new tests for the download lifecycle:
TypeScript compiles cleanly (
tsc --noEmit— no errors).Built with Claude Sonnet 4. Prompted with the root cause analysis and proposed solution from the issue description.
Need help on this PR? Tag
/codesmithwith what you need. Autofix is disabled.Note
Low Risk
Scoped to PDF viewing and caching; no auth or payment changes, with added tests for download and retry edge cases.
Overview
The PDF viewer now downloads remote PDFs to cache with
expo-file-systembefore mountingreact-native-pdf, shows a loading spinner until the localfile://path is ready, and feeds that path into both the main viewer and the navigation sheet (cachedUri ?? uri) so thumbnails do not re-fetch the same remote URL.Error handling treats download failures like render failures (shared retry UI), cancels in-flight downloads on unmount/retry so late failures do not overwrite a successful retry, and suppresses Sentry for known stale
blob:resolution errors while still surfacing other PDF errors.PdfNavigationSheetskipsdownloadFileAsyncwhen the URI is alreadyfile://, matching the viewer’s cached file. Tests cover the async download lifecycle, retry races, and navigation-sheet download vs local behavior.Reviewed by Cursor Bugbot for commit d0e811d. Bugbot is set up for automated code reviews on this repo. Configure here.