Vue NativeVue Native
Guide
Components
Composables
Navigation
  • iOS
  • Android
  • macOS
GitHub
Guide
Components
Composables
Navigation
  • iOS
  • Android
  • macOS
GitHub
  • Device & System

    • useNetwork
    • useAppState
    • useColorScheme
    • useDeviceInfo
    • useDimensions
    • usePlatform
  • Storage & Files

    • useAsyncStorage
    • useSecureStorage
    • useFileSystem
    • useDatabase
  • Sensors & Hardware

    • useGeolocation
    • useBiometry
    • useHaptics
    • useSensors
    • useBluetooth
  • Media

    • useCamera
    • useAudio
    • useCalendar
    • useContacts
  • Networking

    • useHttp
    • useWebSocket
  • Permissions

    • usePermissions
  • Navigation

    • useBackHandler
    • useSharedElementTransition
  • UI

    • useKeyboard
    • useClipboard
    • useShare
    • useLinking
    • useAnimation
    • useGesture
    • useNotifications
    • useI18n
    • usePerformance
  • Authentication

    • useAppleSignIn
    • useGoogleSignIn
  • Monetization & Updates

    • useIAP
    • useOTAUpdate
    • useBackgroundTask
  • Desktop (macOS)

    • useWindow
    • useMenu
    • useFileDialog
    • useDragDrop

useOTAUpdate

Over-The-Air (OTA) bundle updates for deploying new JavaScript bundles without going through app store review. Downloads new bundles from your server, verifies integrity with SHA-256, and applies them on the next app launch.

Usage

<script setup>
import { useOTAUpdate } from '@thelacanians/vue-native-runtime'

const {
  checkForUpdate, downloadUpdate, applyUpdate, rollback,
  currentVersion, availableVersion, downloadProgress,
  isChecking, isDownloading, status, error,
} = useOTAUpdate('https://updates.myapp.com/api/check')
</script>

API

useOTAUpdate(serverUrl: string): {
  checkForUpdate: () => Promise<UpdateInfo>
  downloadUpdate: (url?: string, hash?: string) => Promise<void>
  applyUpdate: () => Promise<void>
  rollback: () => Promise<void>
  getCurrentVersion: () => Promise<VersionInfo>
  currentVersion: Ref<string>
  availableVersion: Ref<string | null>
  downloadProgress: Ref<number>
  isChecking: Ref<boolean>
  isDownloading: Ref<boolean>
  status: Ref<UpdateStatus>
  error: Ref<string | null>
}

Methods

checkForUpdate()

Check the update server for a new bundle version. Returns the update info.

Returns: Promise<UpdateInfo>

UpdateInfo:

PropertyTypeDescription
updateAvailablebooleanWhether a new version is available.
versionstringVersion string of the available update.
downloadUrlstringURL to download the new bundle.
hashstringSHA-256 hash for integrity verification.
sizenumberBundle size in bytes.
releaseNotesstringRelease notes for this version.

downloadUpdate(url?, hash?)

Download a new bundle. If url and hash are omitted, uses values from the last checkForUpdate() call.

ParameterTypeDescription
urlstring?Download URL. Defaults to lastUpdateInfo.downloadUrl.
hashstring?Expected SHA-256 hash. Defaults to lastUpdateInfo.hash.

applyUpdate()

Apply the downloaded bundle. The new bundle will be loaded on the next app launch.

rollback()

Revert to the previous bundle version. If no previous OTA bundle exists, reverts to the embedded (app store) bundle.

getCurrentVersion()

Get the current bundle version info.

Returns: Promise<VersionInfo>

VersionInfo:

PropertyTypeDescription
versionstringCurrent bundle version identifier.
isUsingOTAbooleanWhether the app is running an OTA bundle.
bundlePathstringPath to the active OTA bundle, or empty if using embedded.

Reactive State

PropertyTypeDescription
currentVersionRef<string>Current bundle version (initialized on composable creation).
availableVersionRef<string | null>Available update version (set after checkForUpdate).
downloadProgressRef<number>Download progress from 0 to 1.
isCheckingRef<boolean>true while checking for updates.
isDownloadingRef<boolean>true while downloading a bundle.
statusRef<UpdateStatus>Current status: 'idle', 'checking', 'downloading', 'ready', or 'error'.
errorRef<string | null>Error message if something went wrong.

Update Server Requirements

Your update server must expose an endpoint that responds to GET requests with the following:

Request Headers

The native module sends these headers with each check:

HeaderDescription
X-Current-VersionThe currently installed bundle version.
X-Platform'ios' or 'android'.
X-App-IdThe app's bundle identifier / package name.

Response Format

The server should return JSON:

{
  "updateAvailable": true,
  "version": "2.1.0",
  "downloadUrl": "https://cdn.myapp.com/bundles/2.1.0/bundle.js",
  "hash": "a1b2c3d4e5f6...sha256hash",
  "size": 245760,
  "releaseNotes": "Bug fixes and performance improvements"
}

When no update is available:

{
  "updateAvailable": false
}

Bundle Hosting

The downloadUrl should point to a JS bundle file. The bundle is the IIFE output of your Vite build. You can host it on any CDN or static file server.

Platform Details

AspectiOSAndroid
Storage locationDocuments/VueNativeOTA/bundle.jsfilesDir/VueNativeOTA/bundle.js
Version trackingUserDefaultsSharedPreferences
Hash verificationCommonCrypto SHA-256java.security.MessageDigest SHA-256
HTTP clientURLSessionOkHttp
Progress eventsURLSessionDownloadDelegateManual byte tracking

Example

<script setup>
import { useOTAUpdate, createStyleSheet } from '@thelacanians/vue-native-runtime'

const {
  checkForUpdate, downloadUpdate, applyUpdate, rollback,
  currentVersion, availableVersion, downloadProgress,
  isChecking, isDownloading, status, error,
} = useOTAUpdate('https://updates.myapp.com/api/check')

async function handleCheckForUpdate() {
  const info = await checkForUpdate()
  if (info.updateAvailable) {
    console.log(`Update ${info.version} available (${info.size} bytes)`)
  }
}

async function handleUpdate() {
  await downloadUpdate()
  await applyUpdate()
  // The new bundle loads on next app launch
}

const styles = createStyleSheet({
  container: { flex: 1, padding: 20, justifyContent: 'center' },
  progress: { height: 4, backgroundColor: '#e0e0e0', borderRadius: 2, marginVertical: 12 },
  progressFill: { height: 4, backgroundColor: '#4FC08D', borderRadius: 2 },
  error: { color: '#e74c3c', marginTop: 8 },
})
</script>

<template>
  <VView :style="styles.container">
    <VText>Current version: {{ currentVersion }}</VText>
    <VText v-if="availableVersion">Update available: {{ availableVersion }}</VText>

    <VButton :onPress="handleCheckForUpdate" :disabled="isChecking">
      <VText>{{ isChecking ? 'Checking...' : 'Check for Update' }}</VText>
    </VButton>

    <VView v-if="isDownloading" :style="styles.progress">
      <VView :style="[styles.progressFill, { width: `${downloadProgress * 100}%` }]" />
    </VView>

    <VButton v-if="availableVersion" :onPress="handleUpdate" :disabled="isDownloading">
      <VText>{{ isDownloading ? `Downloading ${Math.round(downloadProgress * 100)}%` : 'Download & Apply' }}</VText>
    </VButton>

    <VButton :onPress="rollback">
      <VText>Rollback</VText>
    </VButton>

    <VText v-if="error" :style="styles.error">{{ error }}</VText>
  </VView>
</template>

Security Considerations

  • Always provide a SHA-256 hash with your bundles. The native module verifies the hash before saving the bundle, preventing tampered downloads from being applied.
  • Use HTTPS for both the update check endpoint and the bundle download URL.
  • Sign your bundles on the server side and verify signatures if your app handles sensitive data.
  • The rollback mechanism ensures you can always revert to a known-good bundle if an OTA update causes issues.

Notes

  • OTA updates only change the JavaScript bundle. Native code changes still require an app store update.
  • The new bundle is loaded on the next app launch after applyUpdate() is called. To force an immediate reload, you would need to restart the app.
  • Bundle storage uses the app's Documents directory (iOS) or internal files directory (Android), so bundles persist across app restarts.
  • The rollback() function keeps one previous version. If you need to roll back further, you roll back to the embedded (original app store) bundle.
  • Download progress events fire via ota:downloadProgress global events, which the composable listens to automatically.
Edit this page
Last Updated: 2/28/26, 11:24 PM
Contributors: Abdul Hamid, Claude Opus 4.6
Prev
useIAP
Next
useBackgroundTask