NativeScript
Set up signed application-tree updates, runtime compatibility, assets, and file deltas.
Alpha integration
NativeScript support is experimental. Signed full-tree updates, images, and file deltas have been exercised on iOS and Android simulators/emulators. This is not a production certification: workers, power-loss recovery, native upgrades, and physical-device coverage remain release gates. Use a dedicated test environment.
Supported setup
Use @nitropush/nativescript, not @nitropush/react-native. This SDK shares NitroPush's native Swift/Kotlin engine but does not install React Native or Nitro Modules.
The validated Webpack templates are NativeScript CLI/core 9.1.1, Android 9.1.1, iOS 9.1.0, and @nativescript/webpack 5.0.38. The engine requires iOS 15+; the tested Android example uses minimum SDK 26. Vite, snapshots, and SwiftUI bootstrap are not supported by these hooks. Preparation stops if it cannot identify the supported startup location.
As checked on September 10, 2026, the public npm registry does not yet expose
@nitropush/nativescript. Use the local workspace package or build a tarball:
Then, from the consuming NativeScript app:
Replace that path with the tarball just created. The monorepo example already
uses workspace:*. If you maintain a private registry or an alpha is published
later, use the available version there. Verify SDK/CLI versions and
nitropush release upload --help before proceeding; source support alone does
not mean npm or the backend has been deployed.
1. Project, environment, and signing
Create a project with framework NativeScript, or reuse an existing NativeScript project. Frameworks cannot be switched after creation. Confirm its platform settings; publish platform-specific outputs separately.
The environment key is written once to a new 0600 file, never recovered from the server later. Store it in your private build configuration and ignore that file in Git. Do not log it.
Signing is required for NativeScript. Use an existing registered keypair where available. For a new trust root:
The private PEM stays in your release pipeline and must be gitignored. The public file contains the complete base64 DER SPKI public key, not its SHA-256 pin. Set NITROPUSH_DEPLOYMENT_KEY and NITROPUSH_BUNDLE_PUBLIC_KEY in the native build environment using your secret/config manager. Never embed the private key. Do not regenerate a key for each release: changing the trust root requires native rebuilds.
2. Install the prepare hook
Add hooks/after-prepare/nitropush.js to the application:
The hook injects client configuration, selects the app tree before native runtime startup, and writes platforms/<platform>/nitropush-runtime.json. Do not hand-edit generated native projects. A native release rebuild is required; a JS-only upload cannot add this bootstrap to an installed binary.
3. Configure once, confirm healthy rendering
Do not call notifyAppReady() during module initialization: it must represent a successfully rendered application. If confirmation is missing, the next launch may roll back.
Only ON_NEXT_RESTART is supported. UPDATE_INSTALLED means the signed tree is staged. Fully terminate the test process and reopen it to activate; navigating or backgrounding alone is not a cold restart. Debug builds keep the development loader.
NativeScript API (not the React Native API)
| API | Result |
|---|---|
configure() | Singleton client from native build configuration |
client.notifyAppReady() | Confirm the active update is healthy |
client.getCurrentPackage() | Active package or null for the binary bundle |
client.getPendingPackage() | Staged package or null |
client.clearPendingUpdate() | Remove only the staged update |
sync(client, options?, onStatus?) | Coalesced update check/download/stage |
Package metadata is { releaseId, label, appVersion, isPending }. Status values are CHECKING_FOR_UPDATE, UP_TO_DATE, UPDATE_INSTALLED, and UNKNOWN_ERROR. There is no public immediate restart, progress listener, configureWith, or resume/suspend installation API in this alpha.
4. Build and publish the complete app tree
Build a release-mode Webpack app using the same dependencies and native inputs as the installed binary. Use the emitted app directory with package.json, its main script, chunks, assets, CSS/XML, fonts, and workers—not the source app/ or the entire APK/IPA build directory.
Android's validated output is platforms/android/app/src/main/assets/app. For iOS, locate app/ inside the built .app for the exact release configuration (Xcode may use DerivedData). Do not assume an older platforms/ios/build directory is the installed build.
Read runtimeVersion from the matching platform's nitropush-runtime.json and pass it unchanged:
Repeat separately for iOS with its own runtime and built app/ directory. --runtime-version is the canonical flag; --app-version is a deprecated alias. NativeScript rejects *, unsigned releases, and incompatible project frameworks. --bundle runs RN/Expo bundling, not NativeScript.
Keep the emitted package.json and Android native class-registration file equal to the binary baseline. Changes to those, native plugins, permissions, or native configuration require a new binary. Use ~/assets/example.png for files included in the app tree; verify images after a cold OTA launch on both platforms.
5. Smaller file-delta updates
Add --delta to the same signed upload command after a compatible baseline release exists. The CLI compares the previous tree for the same project, environment, platform, runtime, and deployment-key generation:
- Unchanged files are referenced by content hash without re-uploading their bytes.
- Changed files use
npdiff1copy/insert patches when the patch is at least 20% smaller. - New/unrelated files are sent in full. Files deleted from the inventory disappear from the new tree.
- The server reconstructs and verifies the complete signed target before publishing and retains full-file fallbacks.
An updated NativeScript native binary applies these patches automatically; it does not use the React Native enableDeltaUpdates flag or Hermes bsdiff4 decoder. Each base, patch, and reconstructed file is checked. Missing/corrupt bases or patches fall back to full files; unchanged cached files can be reused. The active tree is never patched in place.
A new native fingerprint starts with a full baseline. If the fingerprint changes unexpectedly, check lockfile/native inputs rather than forcing the previous runtime value.
Version, runtime fingerprint, and bundle hash
| Value | Purpose |
|---|---|
Version 1, 2, 3, … | Server-assigned OTA sequence; starts at 1 per project/environment/runtime target. Upload reservations can leave gaps. |
| Label | Human-readable release note/name; not a compatibility gate |
| Runtime fingerprint | Native compatibility; includes platform, bootstrap ABI, packaged SDK native source, dependency versions, lockfile, config, and App_Resources |
| Bundle/file SHA-256 | Integrity and content-addressed caching for the actual OTA files |
Keep both hashes. A JS or image change alters content hashes but normally remains compatible with the same native runtime. A native dependency change can break compatibility even when a JS bundle is unchanged. Removing runtime matching would let an incompatible signed update reach a device.
The fingerprint is deliberately conservative: even a JS-only dependency/lockfile change may require a new binary. Native edits outside the tracked inputs are unsupported.
Verify and troubleshoot
Before rollout: install a release binary → render/confirm readiness → upload a signed full tree → sync → cold restart → verify UI/assets → publish a signed delta → repeat on iOS and Android. Also verify offline launch, missing/corrupt asset rejection, rollback after failed first render, wrong-key rejection, native upgrade, lazy imports/workers, and interrupted installation.
| Symptom | Check |
|---|---|
| Missing native bootstrap | Hook, build-time keys, supported template, then native rebuild |
| No eligible release | Project/environment, exact runtime, platform, deployment generation, and rollout |
| Update staged but UI unchanged | Cold restart; inspect current vs pending package |
| Image missing only after OTA | File exists in signed inventory and ~/ resolves to the selected tree |
| Reverts next launch | First-screen readiness confirmation and actual render failure |
| Delta savings absent | Same runtime/base active, changed-file similarity, native decoder present |
| Bandwidth says not metered | SDK activity and manifest authorizations are not verified CDN egress |
The dashboard's patch savings exclude unchanged cache hits, manifest/base64 overhead, and HTTP/TLS bytes. Installs include both full and delta paths. Native telemetry is already emitted by the SDK; do not add duplicate JavaScript analytics.