Skip to content

[RNE Rewrite] Integrate resource fetcher (react-native-blob-util)#1328

Open
msluszniak wants to merge 4 commits into
rne-rewritefrom
@ms/resource-fetcher
Open

[RNE Rewrite] Integrate resource fetcher (react-native-blob-util)#1328
msluszniak wants to merge 4 commits into
rne-rewritefrom
@ms/resource-fetcher

Conversation

@msluszniak

@msluszniak msluszniak commented Jul 24, 2026

Copy link
Copy Markdown
Member

Description

Main change: Adds resource fetching to the rewrite as a single react-native-blob-util-backed fetcher inside react-native-executorch (no separate expo/bare packages). Replaces the temporary react-native-fs hook.

API Description: Public download(source | source[], { onProgress, signal }) returns local path(s); local paths pass through untouched. Every create<Task> factory now resolves remote model URLs internally, so create<Task>(models.X) works directly and the use<Task> hooks (which pre-download for progress) hit an instant no-op. HF download-counter + download-event telemetry are bundled and fired once per genuine fetch.

Important Note: Backend is split by platform: Android uses the system DownloadManager (reliable for files >2 GB, continues in the background, OS-managed resume), iOS streams via NSURLSession with .partial/HTTP-Range resume.

Introduces a breaking change?

  • Yes
  • No

Type of change

  • Bug fix (change which fixes an issue)
  • New feature (change which adds functionality)
  • Documentation update (improves or adds clarity to existing documentation)
  • Other (chores, tests, code style improvements etc.)

Tested on

  • iOS
  • Android

Testing instructions

  1. Run the computer-vision example app.
  2. Open Classification, pick an XNNPACK model — it downloads with progress, then loads and runs.
  3. Reopen the screen — the model is served from cache instantly (no re-download).
  4. Imperative: createClassifier(models.classification.EFFICIENTNET_V2_S.XNNPACK_FP32) resolves the URL to a cached path internally.

Screenshots

Related issues

Closes #1253

Checklist

  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have updated the documentation accordingly
  • My changes generate no new warnings

Additional notes

Replace the temporary react-native-fs download hook with a single
blob-util-backed fetcher living in react-native-executorch (no separate
expo/bare packages).

- src/fetcher: imperative `download(source | source[], { onProgress, signal })`
  returning local path(s); persistent DocumentDir cache keyed by URL hash.
- HTTP-Range auto-resume of interrupted downloads via a .partial file, with a
  safe fallback to a fresh full download if partial assembly fails.
- Byte-weighted unified progress across multiple files; AbortSignal cancel that
  preserves bytes for later resume.
- Bundled download telemetry (HF download counter + anonymous download event),
  fired once per genuine, non-cached fetch.
- Rewire useResourceDownload + inspectModel onto the new fetcher; swap the
  react-native-fs dependency for react-native-blob-util in the lib and example
  apps.

Closes #1253
…tories

Every create<Task> factory now runs its model/tokenizer path fields through
the fetcher's download() before loading, so remote URLs are transparently
downloaded and cached. Because download() passes local paths through
untouched, the use<Task> hooks (which still pre-download for progress) hit an
instant no-op — no double download, single telemetry event.

- Wrap each loadModel/loadTokenizer arg with download() across all 12 factories
  (single modelPath, plus tokenizerPath and nested vadModel for the multi-file
  tasks). Whisper delegates VAD resolution to the FSMN factory.
- Add a tuple-preserving download() overload so download([a, b]) resolves to
  [string, string] under noUncheckedIndexedAccess.
- Imperative create<Task>(models.X) now works without an explicit download().
…large downloads

On-device testing revealed react-native-blob-util's in-process streaming
download is broken on modern Android (a 0.24.10 regression, upstream #475):
it aborts after 8 KB with "Download interrupted", so every model download
failed. curl and the system DownloadManager fetch the same URLs fine.

Split the fetcher backend by platform:
- Android: route through blob-util's system DownloadManager. It reliably
  handles files >2 GB (the whole point — LLM .pte files exceed the OkHttp
  2 GB in-process limit), continues in the background / across app kill, and
  resumes transient network drops itself. Downloads stage in the app-private
  external files dir so DownloadManager can write there and the move into the
  cache stays on one volume (no multi-GB cross-filesystem copy).
- iOS: keep the NSURLSession streaming path with .partial/HTTP-Range resume
  (unaffected by the Android regression, no 2 GB limit).

Verified on a physical Android device: byte-weighted progress, cache-hit
short-circuit, and create<Task>(models.X) URL resolution all pass end to end.
@msluszniak
msluszniak marked this pull request as draft July 24, 2026 16:12
@msluszniak msluszniak self-assigned this Jul 25, 2026
@msluszniak msluszniak added refactoring feature PRs that implement a new feature labels Jul 25, 2026
@msluszniak msluszniak linked an issue Jul 25, 2026 that may be closed by this pull request
@msluszniak
msluszniak marked this pull request as ready for review July 25, 2026 09:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature PRs that implement a new feature refactoring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[RNE Rewrite] Integrate ResourceFetcher with refactor

1 participant