fix: resume Android APK download after network reconnect#11633
Merged
Conversation
When the Android app-update download lost the connection mid-transfer it
restarted from byte zero on every retry, throwing away the bytes already
on disk. Three things conspired:
1. native-side downloadAPK had no Range support and treated the only
possible cache hit as "fully-downloaded + ASC-verified or delete";
2. ASC fetch failures during a network outage were collapsed into
"existing APK invalid" so the partial got deleted by the verifier
before resume could ever kick in;
3. JS retry burned through 3 attempts in ~12s with no network awareness,
so the whole retry budget was usually consumed inside the outage
window.
Fix in three pieces:
- Patch @onekeyfe/react-native-app-update Android downloadAPK to mirror
react-native-bundle-update's resume model: .partial file +
Range header + 416/Content-Range recovery + ApkVerifyOutcome tri-state
so an unreachable ASC preserves the bytes instead of deleting them.
Source change committed upstream in app-modules; carried here via
patch-package until a new @onekeyfe release.
- Rework runDownloadWithRetry to be NetInfo-aware: while
globalNetInfo reports the device offline we camp on
addEventListener (capped at 5 min) and release on the first online
emission; otherwise we keep the exponential backoff (now capped at
60s) and raise MAX_ATTEMPTS from 3 to 5 so the budget survives a
real handover.
- Extend the useAppUpdate jest suite: bump the exhaustion test to 5
retries, add a 60s-cap test, and add a NetInfo "offline → online
resumes" test. Merge globalNetInfo into the components mock because
the root jest.config moduleNameMapper rewrites every @onekeyhq/components
subpath to the same shared mock file.
Contributor
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
originalix
reviewed
May 14, 2026
Retry log now distinguishes offline-wait (capped at 5min) from exp backoff, and waitForOnlineOrTimeout emits start/end markers with exit reason so appUpdate.log timestamps match actual wait duration. Also syncs the stale "3x retry" call-site comment to the current 5x reachability-aware policy.
…/app-monorepo into fix/android-apk-resume-download # Conflicts: # apps/mobile/package.json # package.json # packages/components/package.json
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
originalix
previously approved these changes
May 14, 2026
- Remove unreachable lastError/throw at the bottom of runDownloadWithRetry (the for-loop always exits via return or the attempt===MAX throw). - Collapse the redundant exitReason='timeout' inside setTimeout — default value already covers the path. - Add a jest case for the offline-wait cap: stays offline, advances 5min, expects the grace timer + retry to land successfully.
originalix
approved these changes
May 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Rangesupport, ASC fetch failures during the outage deleted the partial, and the JS retry layer wasn't network-aware.What changed
patches/@onekeyfe+react-native-app-update+3.0.33.patch— carries the AndroiddownloadAPKrewrite (.partial+Range+416recovery +ApkVerifyOutcometri-state). Upstream source change: fix(app-update): android downloadAPK Range/.partial resume app-modules#58 — patch will retire on the next@onekeyfe/react-native-app-updaterelease.updateRetry.ts—runDownloadWithRetryis now NetInfo-aware: whileglobalNetInforeports the device offline we camp onaddEventListener(capped at 5 min) and release on the first online emission; otherwise exponential backoff (now capped at 60s).MAX_ATTEMPTSraised 3→5 so the budget survives a real Wi-Fi/cellular handover.useAppUpdate.test.ts— bumps the exhaustion test to 5 retries, adds a 60s-cap test, and adds an "offline → online resumes" test.globalNetInfomerged into the components mock because the rootjest.configmoduleNameMapperrewrites every@onekeyhq/componentssubpath to the same shared mock file.iOS / desktop scope check: iOS
ReactNativeAppUpdate.swiftis a no-op stub (App Store handles updates); desktop useselectron-updaterwhich already supportsRange/resume. No changes needed there.Test plan
npx jest packages/kit/src/components/AppUpdate/useAppUpdate.test.ts→ 128/128 pass (verified locally).npx tsgo -p tsconfig.json --noEmit→ exit 0 (verified locally).yarn lint:staged→ 0 errors (verified locally).runDownloadWithRetryblocks on NetInfo until the link comes back, then resumes.runDownloadWithRetry): trigger a JS-bundle OTA download and confirm 5-retry / NetInfo behavior doesn't break it.