@norrix/client-sdk
v3.0.0
Published
Client SDK for Over-The-Air (OTA) updates with NativeScript using Norrix.
Readme
@norrix/client-sdk
Client SDK for Over-The-Air (OTA) updates with NativeScript using Norrix.
Installation
npm install --save @norrix/client-sdkUsage
Import @norrix/client-sdk at the top of your app entry file (main.ts or app.ts) and call initNorrix synchronously during bootstrap, before you start the app:
import { initNorrix } from '@norrix/client-sdk';
initNorrix({
updateUrl: `https://norrix.net`,
checkForUpdatesOnLaunch: true,
installUpdatesAutomatically: true,
downloadProgressCallback: (progress) => {
console.log(`Download progress: ${progress}%`);
},
statusCallback(status, data) {
console.log(`Status: ${status}`, data);
},
});The SDK arms its launch monitor when the module is evaluated, so the import position matters more than the initNorrix call. Initializing late (on a timer, after login, behind a lazy route) only delays telemetry and the first update check; it does not put the running update at risk.
Launch safety
Every launch decision is a function of a state file (norrix_ota/state.json) that the native loader and the SDK share. An update is launchable when it has succeeded at least once, or has never failed.
- Success is the first content displayed. The monitor listens on the classic, UIScene, and NativeScript 9.1 multi-window lifecycles (
displayed, and each window'scontentLoaded). - Failure is an uncaught JS error before first display, a bootstrap that never reaches
UIApplicationMainon iOS, or an uncaught native exception (NSExceptionon iOS, a JavaThrowableon Android). - A process that ends any other way — force quit, jetsam, watchdog, a background launch, an iOS prewarm — records nothing. The next launch selects the same update again.
A failed update is quarantined for the current store binary: it is never launched again, never reinstalled, and its id is sent as excludeIds on the next check. Recovery relaunches into a newer update if one is available, otherwise into the previous known-good update, otherwise into the store bundle; in-process when the runtime exposes NativeScriptRuntime.reloadApplication, by process restart otherwise (including @nativescript/ios 9.1.0; a 9.1.x patch adds the API). Quarantine is cleared when the binary changes.
Which version is running
const running = norrix.getRunningUpdate();
// { source: 'update' | 'embedded', updateId?, version, buildNumber, confirmed }
const next = norrix.getInstalledUpdate();
// the update the next launch will run, or null for the store bundleBuild version labels from getRunningUpdate(). Norrix_OTA_Version and Norrix_OTA_BuildNumber in ApplicationSettings describe the installed update — what runs next — not what is executing now. They are still written for backward compatibility only.
What can be updated?
- Anything inside your
/srcor/appfolder (except the App_Resources folder) - Anything inside your
/node_modulesfolder
What cannot be updated?
- NativeScript platform updates (e.g., bumping @nativescript/ios, @nativescript/android, @nativescript/visionos)
- Plugin updates that require a different version of native libraries
- Contents of the App_Resources folder (these are part of the native binary)
Upgrading to 3.0
3.0 requires a new store binary. The native loader (NorrixOTA.xcframework, NorrixAndroidOTA.aar) reads and writes the new state file, and the iOS after-prepare hook adds a second call to the boot file: [NorrixOTA runMainApplicationDidReturn] after runMainApplication, which reports a JS bootstrap that never reached UIApplicationMain. The hook applies this automatically on ns prepare. Ship a store build with 3.0 before publishing OTA updates for it; devices on an older binary keep using the loader they shipped with.
| Before | After |
| ------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Norrix_OTA_Launch_Sentinel, Norrix_OTA_Crash_Recovery* in ApplicationSettings | norrix_ota/state.json; the sentinel and recovery keys are gone |
| trackAppLaunch(otaFingerprint, configuration), reading the OTA version from ApplicationSettings | trackAppLaunch(running, configuration), where running is the running update ({ updateId, version, buildNumber }) or undefined for the store bundle |
| ota_crash_recovery telemetry | ota_launch_failed and ota_recovered (plus ota_launch_confirmed, ota_update_skipped_quarantined) |
| OTA package unzipped in place | unzipped to norrix_ota/.tmp-<id>-<platform>, then renamed to norrix_ota/<id>-<platform> with a norrix-install.json marker; directories without the marker are ignored |
| A rollback landed on the store binary | Recovery relaunches into the previous known-good update, and only falls back to the store bundle |
Also new in 3.0:
SyncStatus.ROLLED_BACKis reported tostatusCallbackwhen the running update failed to launch and the app is being relaunched.retryFailedUpdates(defaultfalse) lets the server offer a quarantined update again.getRunningUpdate(),getInstalledUpdate(),getQuarantinedUpdateIds(), andisUpdateQuarantined(id).UpdateInfo.updateIdcarries the server update id.
Compatibility with 2.x binaries
The 3.x SDK and its native loader ship together in a store binary. The Norrix server withholds any update bundle built with 3.x from a binary running 2.x (the binary is told a store update is required), and a 3.x SDK that finds itself on a 2.x loader pauses all update activity and reports SyncStatus.ERROR. Upgrade the package, cut a new binary, and only then publish updates from the upgraded project.
