🚀 DAY 5 OF LAUNCH WEEK: Introducing Socket Firewall Enterprise.Learn more
Socket
Book a DemoInstallSign in
Socket

@capawesome/capacitor-live-update

Package Overview
Dependencies
Maintainers
1
Versions
33
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@capawesome/capacitor-live-update

Capacitor plugin to update your app remotely in real-time.

latest
Source
npmnpm
Version
7.2.2
Version published
Weekly downloads
6.2K
-11.83%
Maintainers
1
Weekly downloads
 
Created
Source

@capawesome/capacitor-live-update

Capacitor plugin that allows you to update your app remotely in real-time without requiring users to download a new version from the app store, known as Over-the-Air (OTA) updates.

Deliver Live Updates to your Capacitor app with Capawesome Cloud

Features

We are proud to offer one of the most complete and feature-rich Capacitor plugins for Over-the-Air (OTA) updates. Here are some of the key features:

  • 🔋 Supports Android and iOS
  • ⚡️ Capacitor 7 support
  • 📦 Bundle Management: Download, set, and delete bundles.
  • ☁️ Cloud Support: Use the Capawesome Cloud to manage your app updates.
  • 📺 Channel Support: Set a channel for the app to manage different versions.
  • 🔄 Auto Update: Automatically download and set the latest bundle for the app.
  • 🛟 Rollback: Reset the app to the default bundle if an incompatible bundle has been set.
  • 🚀 Rollout: Gradually roll out new bundles to gather valuable feedback.
  • 🔁 Delta Updates: Make your updates faster by only downloading changed files.
  • 🔒 Security: Verify the authenticity and integrity of the bundle using a public key.
  • ⚔️ Battle-Tested: Used in more than 500 projects to update apps on more than 10,000,000 devices.
  • 🌐 Open Source: Licensed under the MIT License.

Missing a feature? Just open an issue and we'll take a look!

Guides

Installation

npm install @capawesome/capacitor-live-update
npx cap sync

Android

Variables

If needed, you can define the following project variable in your app’s variables.gradle file to change the default version of the dependency:

  • $okhttp3Version version of com.squareup.okhttp3:okhttp (default: 22.3.1)
  • $zip4jVersion version of net.lingala.zip4j:zip4j (default: 2.11.5)

This can be useful if you encounter dependency conflicts with other plugins in your project.

iOS

Privacy manifest

Add the NSPrivacyAccessedAPICategoryUserDefaults dictionary key to your Privacy Manifest (usually ios/App/PrivacyInfo.xcprivacy):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>NSPrivacyAccessedAPITypes</key>
    <array>
      <!-- Add this dict entry to the array if the file already exists. -->
      <dict>
        <key>NSPrivacyAccessedAPIType</key>
        <string>NSPrivacyAccessedAPICategoryUserDefaults</string>
        <key>NSPrivacyAccessedAPITypeReasons</key>
        <array>
          <string>CA92.1</string>
        </array>
      </dict>
    </array>
  </dict>
</plist>

We recommend to declare CA92.1 as the reason for accessing the UserDefaults API.

Configuration

PropTypeDescriptionDefaultSince
appIdstringThe app ID is used to identify the app when using Capawesome Cloud. This is NOT the same as the app identifier (e.g. com.example.app). This is a unique identifier generated by Capawesome Cloud (e.g. 6e351b4f-69a7-415e-a057-4567df7ffe94).5.0.0
autoDeleteBundlesbooleanWhether or not to automatically delete unused bundles. When enabled, the plugin will automatically delete unused bundles after calling ready().false5.0.0
defaultChannelstringThe default channel of the app.6.3.0
httpTimeoutnumberThe timeout in milliseconds for HTTP requests.600006.4.0
publicKeystringThe public key to verify the integrity of the bundle. The public key must be a PEM-encoded RSA public key.6.1.0
readyTimeoutnumberThe timeout in milliseconds to wait for the app to be ready before resetting to the default bundle. It is strongly recommended to configure this option so that the plugin can roll back to the default bundle in case of problems. If configured, the plugin will wait for the app to call the ready() method before resetting to the default bundle. Set to 0 to disable the timeout.05.0.0
serverDomainstringThe API domain of the Capawesome Cloud server without scheme or path.'api.cloud.capawesome.io'7.0.0

Examples

In capacitor.config.json:

{
  "plugins": {
    "LiveUpdate": {
      "appId": '6e351b4f-69a7-415e-a057-4567df7ffe94',
      "autoDeleteBundles": undefined,
      "defaultChannel": 'production',
      "httpTimeout": undefined,
      "publicKey": '-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDodf1SD0OOn6hIlDuKBza0Ed0OqtwyVJwiyjmE9BJaZ7y8ZUfcF+SKmd0l2cDPM45XIg2tAFux5n29uoKyHwSt+6tCi5CJA5Z1/1eZruRRqABLonV77KS3HUtvOgqRLDnKSV89dYZkM++NwmzOPgIF422mvc+VukcVOBfc8/AHQIDAQAB-----END PUBLIC KEY-----',
      "readyTimeout": 10000,
      "serverDomain": 'api.cloud.capawesome.eu'
    }
  }
}

In capacitor.config.ts:

/// <reference types="@capawesome/capacitor-live-update" />

import { CapacitorConfig } from '@capacitor/cli';

const config: CapacitorConfig = {
  plugins: {
    LiveUpdate: {
      appId: '6e351b4f-69a7-415e-a057-4567df7ffe94',
      autoDeleteBundles: undefined,
      defaultChannel: 'production',
      httpTimeout: undefined,
      publicKey: '-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDodf1SD0OOn6hIlDuKBza0Ed0OqtwyVJwiyjmE9BJaZ7y8ZUfcF+SKmd0l2cDPM45XIg2tAFux5n29uoKyHwSt+6tCi5CJA5Z1/1eZruRRqABLonV77KS3HUtvOgqRLDnKSV89dYZkM++NwmzOPgIF422mvc+VukcVOBfc8/AHQIDAQAB-----END PUBLIC KEY-----',
      readyTimeout: 10000,
      serverDomain: 'api.cloud.capawesome.eu',
    },
  },
};

export default config;

Starter templates

The following starter templates are available:

Guides

Usage

import { LiveUpdate } from '@capawesome/capacitor-live-update';

const deleteBundle = async () => {
  await LiveUpdate.deleteBundle({ bundleId: 'my-bundle' });
};

const downloadBundle = async () => {
  await LiveUpdate.downloadBundle({ url: 'https://example.com/1.0.0.zip', bundleId: '1.0.0' });
};

const fetchLatestBundle = async () => {
  await LiveUpdate.fetchLatestBundle();
};

const getBundles = async () => {
  const result = await LiveUpdate.getBundles();
  return result.bundleIds;
};

const getChannel = async () => {
  const result = await LiveUpdate.getChannel();
  return result.channel;
};

const getCurrentBundle = async () => {
  const result = await LiveUpdate.getCurrentBundle();
  return result.bundleId;
};

const getCustomId = async () => {
  const result = await LiveUpdate.getCustomId();
  return result.customId;
};

const getDeviceId = async () => {
  const result = await LiveUpdate.getDeviceId();
  return result.deviceId;
};

const getNextBundle = async () => {
  const result = await LiveUpdate.getNextBundle();
  return result.bundleId;
};

const getVersionCode = async () => {
  const result = await LiveUpdate.getVersionCode();
  return result.versionCode;
};

const getVersionName = async () => {
  const result = await LiveUpdate.getVersionName();
  return result.versionName;
};

const ready = async () => {
  const result = await LiveUpdate.ready();
  if (result.currentBundleId) {
    console.log(`The app is now using the bundle with the identifier ${result.currentBundleId}.`);
  }
  if (result.previousBundleId) {
    console.log(`The app was using the bundle with the identifier ${result.previousBundleId}.`);
  }
  if (result.rollback) {
    console.log('The app was reset to the default bundle.');
  }
};

const reload = async () => {
  await LiveUpdate.reload();
};

const reset = async () => {
  await LiveUpdate.reset();
};

const setChannel = async () => {
  await LiveUpdate.setChannel({ channel: 'production-5' });
};

const setCustomId = async () => {
  await LiveUpdate.setCustomId({ customId: 'my-custom-id' });
};

const setNextBundle = async () => {
  await LiveUpdate.setNextBundle({ bundleId: '7f0b9bf2-dff6-4be2-bcac-b068cc5ea756' });
};

const sync = async () => {
  const result = await LiveUpdate.sync({
    channel: 'production-5',
  });
  return result.nextBundleId;
};

const isNewBundleAvailable = async () => {
  const { bundleId: latestBundleId } = await LiveUpdate.fetchLatestBundle({
    channel: 'production-5',
  });
  if (latestBundleId) {
    const { bundleId: currentBundleId } = await LiveUpdate.getCurrentBundle();
    return latestBundleId !== currentBundleId;
  } else {
    return false;
  }
};

API

deleteBundle(...)

deleteBundle(options: DeleteBundleOptions) => Promise<void>

Delete a bundle from the app.

Only available on Android and iOS.

ParamType
optionsDeleteBundleOptions

Since: 5.0.0

downloadBundle(...)

downloadBundle(options: DownloadBundleOptions) => Promise<void>

Download a bundle.

Only available on Android and iOS.

ParamType
optionsDownloadBundleOptions

Since: 5.0.0

fetchLatestBundle(...)

fetchLatestBundle(options?: FetchLatestBundleOptions | undefined) => Promise<FetchLatestBundleResult>

Fetch the latest bundle using the Capawesome Cloud.

Only available on Android and iOS.

ParamType
optionsFetchLatestBundleOptions

Returns: Promise<FetchLatestBundleResult>

Since: 6.6.0

getBundles()

getBundles() => Promise<GetBundlesResult>

Get all identifiers of bundles that have been downloaded.

Only available on Android and iOS.

Returns: Promise<GetBundlesResult>

Since: 5.0.0

getChannel()

getChannel() => Promise<GetChannelResult>

Get the channel that is used for the update.

Only available on Android and iOS.

Returns: Promise<GetChannelResult>

Since: 5.0.0

getCurrentBundle()

getCurrentBundle() => Promise<GetCurrentBundleResult>

Get the bundle identifier of the current bundle. The current bundle is the bundle that is currently used by the app.

Only available on Android and iOS.

Returns: Promise<GetCurrentBundleResult>

Since: 6.7.0

getCustomId()

getCustomId() => Promise<GetCustomIdResult>

Get the custom identifier of the device.

Only available on Android and iOS.

Returns: Promise<GetCustomIdResult>

Since: 5.0.0

getDeviceId()

getDeviceId() => Promise<GetDeviceIdResult>

Get the unique device identifier.

Only available on Android and iOS.

Returns: Promise<GetDeviceIdResult>

Since: 5.0.0

getNextBundle()

getNextBundle() => Promise<GetNextBundleResult>

Get the bundle identifier of the next bundle. The next bundle is the bundle that will be used after calling reload() or restarting the app.

Only available on Android and iOS.

Returns: Promise<GetNextBundleResult>

Since: 6.7.0

getVersionCode()

getVersionCode() => Promise<GetVersionCodeResult>

Get the version code of the app.

On Android, this is the versionCode from the android/app/build.gradle file. On iOS, this is the CFBundleVersion from the Info.plist file.

Only available on Android and iOS.

Returns: Promise<GetVersionCodeResult>

Since: 5.0.0

getVersionName()

getVersionName() => Promise<GetVersionNameResult>

Get the version name of the app.

On Android, this is the versionName from the android/app/build.gradle file. On iOS, this is the CFBundleShortVersionString from the Info.plist file.

Only available on Android and iOS.

Returns: Promise<GetVersionNameResult>

Since: 5.0.0

ready()

ready() => Promise<ReadyResult>

Notify the plugin that the app is ready to use and no rollback is needed.

Attention: This method should be called as soon as the app is ready to use to prevent the app from being reset to the default bundle.

Only available on Android and iOS.

Returns: Promise<ReadyResult>

Since: 5.0.0

reload()

reload() => Promise<void>

Reload the app to apply the new bundle.

Only available on Android and iOS.

Since: 5.0.0

reset()

reset() => Promise<void>

Reset the app to the default bundle.

Call reload() or restart the app to apply the changes.

Only available on Android and iOS.

Since: 5.0.0

setChannel(...)

setChannel(options: SetChannelOptions) => Promise<void>

Set the channel to use for the update.

Only available on Android and iOS.

ParamType
optionsSetChannelOptions

Since: 5.0.0

setCustomId(...)

setCustomId(options: SetCustomIdOptions) => Promise<void>

Set the custom identifier of the device.

Only available on Android and iOS.

ParamType
optionsSetCustomIdOptions

Since: 5.0.0

setNextBundle(...)

setNextBundle(options: SetNextBundleOptions) => Promise<void>

Set the next bundle to use for the app.

Call reload() or restart the app to apply the changes.

Only available on Android and iOS.

ParamType
optionsSetNextBundleOptions

Since: 6.7.0

sync(...)

sync(options?: SyncOptions | undefined) => Promise<SyncResult>

Automatically download and set the latest bundle for the app using the Capawesome Cloud.

Call reload() or restart the app to apply the changes.

Only available on Android and iOS.

ParamType
optionsSyncOptions

Returns: Promise<SyncResult>

Since: 5.0.0

addListener('downloadBundleProgress', ...)

addListener(eventName: 'downloadBundleProgress', listenerFunc: DownloadBundleProgressListener) => Promise<PluginListenerHandle>

Listen for the download progress of a bundle.

Only available on Android and iOS.

ParamType
eventName'downloadBundleProgress'
listenerFuncDownloadBundleProgressListener

Returns: Promise<PluginListenerHandle>

Since: 7.0.0

removeAllListeners()

removeAllListeners() => Promise<void>

Remove all listeners for this plugin.

Since: 7.2.0

Interfaces

DeleteBundleOptions

PropTypeDescriptionSince
bundleIdstringThe unique identifier of the bundle to delete.5.0.0

DownloadBundleOptions

PropTypeDescriptionDefaultSince
artifactType'manifest' | 'zip'The artifact type of the bundle.'zip'6.6.0
bundleIdstringThe unique identifier of the bundle. Attention: The value public is reserved and cannot be used as a bundle identifier.5.0.0
checksumstringThe checksum of the self-hosted bundle as a SHA-256 hash in base64 format to verify the integrity of the bundle. Attention: Only supported for the zip artifact type.7.1.0
signaturestringThe signature of the self-hosted bundle as a signed SHA-256 hash in base64 format to verify the integrity of the bundle. Attention: Only supported for the zip artifact type.7.1.0
urlstringThe URL of the bundle to download. For the zip artifact type, the URL must point to a ZIP file. For the manifest artifact type, the URL serves as the base URL to download the individual files. For example, if the URL is https://example.com/download, the plugin will download the file with the href index.html from https://example.com/download?href=index.html. To verify the integrity of the file, the server should return a X-Checksum header with the SHA-256 hash in base64 format. To verify the signature of the file, the server should return a X-Signature header with the signed SHA-256 hash in base64 format.5.0.0

FetchLatestBundleResult

PropTypeDescriptionSince
artifactType'manifest' | 'zip'The artifact type of the bundle.6.7.0
bundleIdstring | nullThe unique identifier of the latest bundle. If null, no bundle is available.6.6.0
checksumstringThe checksum of the latest bundle if the bundle is self-hosted. If the bundle is hosted on Capawesome Cloud, the checksum will be returned as response header when downloading the bundle.7.1.0
customProperties{ [key: string]: string; }Custom properties that are associated with the latest bundle.7.0.0
downloadUrlstringThe URL of the latest bundle to download. Pass this URL to the downloadBundle(...) method to download the bundle.6.7.0
signaturestringThe signature of the latest bundle if the bundle is self-hosted. If the bundle is hosted on Capawesome Cloud, the signature will be returned as response header when downloading the bundle.7.1.0

FetchLatestBundleOptions

PropTypeDescriptionSince
channelstringThe name of the channel where the latest bundle is fetched from.6.7.0

GetBundlesResult

PropTypeDescriptionSince
bundleIdsstring[]An array of unique identifiers of all available bundles.5.0.0

GetChannelResult

PropTypeDescriptionSince
channelstring | nullThe channel name. If null, the app is using the default channel.5.0.0

GetCurrentBundleResult

PropTypeDescriptionSince
bundleIdstring | nullThe unique identifier of the current bundle. If null, the default bundle is being used.6.7.0

GetCustomIdResult

PropTypeDescriptionSince
customIdstring | nullThe custom identifier of the device. If null, no custom identifier is set.5.0.0

GetDeviceIdResult

PropTypeDescriptionSince
deviceIdstringThe unique identifier of the device. On iOS, identifierForVendor is used. The value of this property is the same for apps that come from the same vendor running on the same device.5.0.0

GetNextBundleResult

PropTypeDescriptionSince
bundleIdstring | nullThe unique identifier of the next bundle. If null, the default bundle is being used.6.7.0

GetVersionCodeResult

PropTypeDescriptionSince
versionCodestringThe version code of the app. On Android, this is the versionCode from the android/app/build.gradle file. On iOS, this is the CFBundleVersion from the Info.plist file.5.0.0

GetVersionNameResult

PropTypeDescriptionSince
versionNamestringThe version name of the app. On Android, this is the versionName from the android/app/build.gradle file. On iOS, this is the CFBundleShortVersionString from the Info.plist file.5.0.0

ReadyResult

PropTypeDescriptionSince
previousBundleIdstring | nullThe identifier of the previous bundle used. If null, the default bundle was used.7.0.0
currentBundleIdstring | nullThe identifier of the current bundle used. If null, the default bundle is being used.7.0.0
rollbackbooleanWhether or not the app was reset to the default bundle.7.0.0

SetChannelOptions

PropTypeDescriptionSince
channelstring | nullThe channel name. Set null to remove the channel.5.0.0

SetCustomIdOptions

PropTypeDescriptionSince
customIdstring | nullThe custom identifier of the device. Set null to remove the custom identifier.5.0.0

SetNextBundleOptions

PropTypeDescriptionSince
bundleIdstring | nullThe unique identifier of the bundle to use. Set null to use the default bundle (same as calling reset()).6.7.0

SyncResult

PropTypeDescriptionSince
nextBundleIdstring | nullThe identifier of the next bundle to use. If null, the app is up-to-date and no new bundle is available.5.0.0

SyncOptions

PropTypeDescriptionSince
channelstringThe name of the channel where the latest bundle is fetched from.6.7.0

PluginListenerHandle

PropType
remove() => Promise<void>

DownloadBundleProgressEvent

Event that is triggered when the download progress of a bundle changes.

PropTypeDescriptionSince
bundleIdstringThe unique identifier of the bundle that is being downloaded.7.0.0
downloadedBytesnumberThe number of bytes that have been downloaded.7.0.0
progressnumberThe progress of the download in percent as a value between 0 and 1.7.0.0
totalBytesnumberThe total number of bytes to download.7.0.0

Type Aliases

DownloadBundleProgressListener

Listener for the download progress of a bundle.

(event: DownloadBundleProgressEvent): void

Testing

When testing the plugin, you must make sure that you do not use the Live Reload option, as in this case a development server is used to load the bundle and not the local file system.

Therefore, simply start your app without the live reload option, for example with the following command:

npx ionic cap run android --open

If you want to not receive live updates to test other parts of your app, you can simply set a non-existent channel, for example:

import { LiveUpdate } from '@capawesome/capacitor-live-update';

const sync = async () => {
  await LiveUpdate.sync({ channel: 'non-existent-channel' });
};

This way, the app will check for updates, but no updates will be found.

Limitations

Live updates are only supported for binary-compatible changes (e.g. HTML, CSS, JavaScript). If you change native code, such as adding a new plugin, you need to resubmit your app to the app stores. For this reason, you must be careful to restrict live updates to compatible native versions of your app.

FAQ

Why can't I see my changes during development?

As soon as you have installed a live update, the app will use the live update bundle and no longer the default bundle. So if you make local changes to your app and execute npx cap run, for example, these changes will apply to the default bundle, which is not currently in use. You then have three options to get back to the default bundle:

  • Reset: Call the reset() method to reset the app to the default bundle.
  • Reinstall: Reinstall the app to remove the live update bundle.
  • Update: Increase the native version code of your app so that Capacitor automatically resets to the default bundle.

However, this is only a problem during development. It is not a problem in production, as Capacitor automatically resets to the default bundle after a native update.

Changelog

See CHANGELOG.md.

License

See LICENSE.

Keywords

capacitor

FAQs

Package last updated on 09 Sep 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts