How-to: Troubleshoot updates
Work top-down: most "update not working" reports are a channel or app-id mismatch, not a bug.
Update not detected
-
Channel must match the upload. The device checks ONE channel; the build must be active in that same channel.
await NativeUpdate.setChannel('production'); // must equal the dashboard upload channelconst result = await NativeUpdate.sync();console.log(result.status); // 'UP_TO_DATE' | 'UPDATE_AVAILABLE' | 'UPDATE_INSTALLED' | 'ERROR' -
App id and API key must match the dashboard app. A key from a different app returns no updates (or 401).
-
The new bundle's version must be higher than the version the device reports. Same or lower versions are never offered.
-
Rollout percentage: with a staged rollout, a device outside the current percentage correctly sees
UP_TO_DATE. Raise the percentage in the dashboard to include it. -
Inspect the wire call directly — the SDK issues
GET {serverUrl}/v1/updates/check?channel=…withX-API-Key,X-Device-ID,X-Current-Version,X-Platformheaders:curl -H "X-API-Key: nu_app_…" -H "X-Device-ID: test" \-H "X-Current-Version: 1.0.0" -H "X-Platform: android" \"https://nativeupdatebe.aoneahsan.com/api/v1/updates/check?channel=production"{"available": false}here means the backend has nothing newer for that channel — fix the upload, not the app.
Download fails
-
Watch progress + state events (the only download-related events are these):
const progress = await NativeUpdate.addListener('downloadProgress', (p) => {console.log(`${p.percent}% of ${p.totalBytes} bytes (${p.bundleId})`);});const state = await NativeUpdate.addListener('updateStateChanged', (e) => {console.log('bundle state:', e.status, e.version);}); -
Checksum mismatch aborts the install by design. Re-create and re-upload the bundle rather than retrying the same artifact.
-
HTTPS is enforced in production — a plain-
httpdownloadUrlis rejected. Serve bundles over HTTPS. -
Unstable network: retry with backoff instead of hammering
sync():async function syncWithRetry(retries = 3) {for (let i = 0; i < retries; i++) {try {return await NativeUpdate.sync();} catch (error) {if (i === retries - 1) throw error;await new Promise((r) => setTimeout(r, 1000 * (i + 1)));}}}
Install fails or is rejected
-
Validate the bundle explicitly when debugging signature/checksum problems:
const validation = await NativeUpdate.validateUpdate({bundlePath: bundle.path,checksum: expectedChecksum,signature: expectedSignature, // when signing is enforced});console.log(validation.isValid, validation.details); -
Signature verification: the public key configured in
liveUpdate.publicKeymust pair with the private key that signed the bundle. Rotating keys? Follow Rotate signing keys. -
minNativeVersiongate: the backend refuses bundles that need a newer native binary than the device runs. Ship the store update first.
App crashes after an update (rollback)
-
Call
notifyAppReady()on every successful boot — without it the plugin treats the new bundle as broken and auto-rolls back:import { NativeUpdate } from 'native-update';// after your app has rendered its first stable frame:await NativeUpdate.notifyAppReady(); -
Manual recovery:
await NativeUpdate.reset()returns the device to the original shipped bundle;NativeUpdate.list()+NativeUpdate.set(bundle)re-activates a specific downloaded bundle. -
Full strategy (automatic + server-side + per-device): Roll back a bad bundle.
Dashboard-side checks
- Build stuck in "Processing": the upload has not finished staging — re-upload if it never turns "active".
- Build not reaching the device: confirm channel, app id, active status, and rollout percentage — in that order.
- Sign-in problems: the dashboard uses Google sign-in; clear cookies for the dashboard domain or try a private window.
Debug logging
Enable verbose SDK logs during development via the { config: … } overload:
await NativeUpdate.configure({
config: {
baseUrl: 'https://nativeupdatebe.aoneahsan.com/api',
apiKey: 'nu_app_…',
enableLogging: true, // verbose logs in dev builds
},
});
Then inspect the current state with the real inspection methods:
console.log('active bundle:', await NativeUpdate.current());
console.log('downloaded bundles:', await NativeUpdate.list());
console.log('latest on server:', await NativeUpdate.getLatest());
console.log('security info:', await NativeUpdate.getSecurityInfo());
Platform notes
- iOS review prompts are limited by Apple to ~3 per year per user, and never show in the Simulator — test
requestReview()on a device and treatresult.displayed === falseas normal. - Android Play in-app updates (
getAppUpdateInfo(),performImmediateUpdate(), …) require the app to be installed from the Play Store on a device with Play services. - iOS background updates need Background App Refresh enabled plus the background capability in Xcode.
Still stuck?
Gather the plugin version, platform + OS version, the sync() result status, and any updateStateChanged events, then email aoneahsan@gmail.com.