Skip to content

Announcing the Capacitor Live Update Plugin

One of the biggest advantages of Capacitor over other runtimes is the ability to deliver updates in real-time without having to resubmit your app to the app stores, so-called Over-the-Air (OTA) updates. For this reason, we are very excited to introduce you today to our brand new Capacitor Live Update plugin. In this blog post, you will learn everything about the new plugin and how you can implement it in your Capacitor app.

How it works

Live updates are a powerful feature that allows you to deliver small bug fixes and updates to your Capacitor app in real-time. For this, it is important to understand the different layers of a Capacitor app and how they interact with each other.

Layers Layers

Capacitor App Layers

As you can see in the image above, a Capacitor app basically consists of a web layer and a native layer. The web layer consists of the HTML, CSS, and JavaScript files that are loaded into the web view. The native layer consists of the native code that is compiled into the app.

Limitation

Live updates only allow you to update the web layer of your app.

So as long as you only make changes to your web application, you can deploy live updates without having to resubmit your app to the app stores. As soon as you make a change to the native code, such as adding a plugin, you must resubmit your app to the app stores.

Installation

First you need to install the package and sync your Capacitor project:

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

Usage

To be able to distribute the live updates to your users, you need to host a service that at least provides the bundles for download. You can either self-host such a service or use the Capawesome Cloud. Let's take a look at the self-hosted option first.

Self-hosted

If you choose the self-hosted option, you have to make sure that your bundle is available for download somewhere.

To download a bundle, you need a public URL and a unique bundle ID. The bundle ID is only used to identify the bundle and can be chosen freely. Use the downloadBundle(...) method to download a bundle:

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

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

The plugin then downloads, extracts and moves the bundle to the correct location.

Binary Compatible Changes

Make sure that you implement a mechanism that ensures that only Binary Compatible Changes are delivered to the users to prevent incompatible updates. For example, the Capawesome Cloud offers the possibility to use Channels to restrict updates to specific versions of your app.

After downloading the bundle, you can set it as the next bundle (1) to use with the setBundle(...) method. This means that the next time the app is started, the new bundle will be used.

  1. The next bundle is the bundle that will be used the next time the web view is loaded. This allows you to download and prepare a new bundle without immediately applying it. This way you can ensure that the new bundle is only used after a restart of the app or a reload of the web view.
import { LiveUpdate } from '@capawesome/capacitor-live-update';

const setBundle = async () => {
    await LiveUpdate.setBundle({ bundleId: '1.0.0' });
};

If you want to apply the next bundle immediately, you can use the reload() method to reload the web view.

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

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

To make sure that your app does not break if you set an incompatible bundle, the plugin provides an automatic rollback mechanism. This rollback mechanism resets the bundle to the bundle with which the app was delivered. To prevent a rollback, you must call the ready() method as soon as the app is ready.

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

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

After calling the ready() method, the app is considered ready and the automatic rollback mechanism is disabled.

Cloud

If you don't want to host such a service yourself or if you want to use additional features such as Channels or Rollouts, you can use the Capawesome Cloud to upload, manage and distribute your bundles. To get started, you need to create an account on the Capawesome Cloud Console.

After you have created an account, we recommend that you install the Capawesome CLI to manage your apps and bundles from the command line.

npm install -g @capawesome/cli

First, you need to log in to Capawesome Cloud:

npx capawesome login

Then you can create a new app:

npx capawesome apps:create --name "My App"

After you have created an app, you need to configure the Capacitor Live Update plugin. To do this, simply add the ID of the app you have just created to the Capacitor configuration file:

capacitor.config.json
{
  "plugins": {
    "LiveUpdate": {
      "appId": "00000000-0000-0000-0000-000000000000"
    }
  }
}

Sync your Capacitor project to apply the changes:

npx cap sync

Next, you can upload a new bundle to the Capawesome Cloud. For this, you simply need to specify the path to the bundle (e.g. www or dist) and the ID of the app (see previous step):

npx capawesome apps:bundles:create --appId <app-id> --path www
Upload to a channel

We recommend that you also specify a Channel when uploading the bundle:

npx capawesome apps:bundles:create --appId <app-id> --path www --channel production-1.0.0

This way you can easily restrict live updates to native versions of your app and prevent incompatible updates.

The Capawesome CLI then automatically creates a zip archive of the bundle and uploads it to the Capawesome Cloud where it becomes immediately available for download.

All that's left to do is to call the sync() method in your app to check for new updates and apply them if necessary.

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

const sync = async () => {
    const result = await LiveUpdate.sync();
    if (result.nextBundleId) {
        await LiveUpdate.reload();
    }
};

The new bundle becomes available only after restarting the app. Therefore, if you want to apply the new bundle immediately, you should call the reload() method to reload the web view.

Again, make sure to call the ready() method as soon as the the app is ready to prevent a rollback:

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

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

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.

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

npx cap run android

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:

  1. Reset: Call the reset() method to reset the app to the default bundle.
  2. Reinstall: Reinstall the app to use the default bundle.
  3. Update: Increase the versionCode/CFBundleVersion so that the plugin automatically performs a reset (assuming the resetOnUpdate configuration option is active).

However, this is only a problem during development. It is not a problem in production as long as you have the resetOnUpdate configuration option enabled, as the versionCode/CFBundleVersion is always incremented during a native update and thus always resets to the default bundle.

Closing Thoughts

We hope you are as excited as we are about the new Capacitor Live Update plugin. We are already working on new features and improvements, such as automatic update modes and partial updates. Be sure to check out the API Reference to see what else you can do with this plugin. If you have any questions, just create a discussion in the GitHub repository. Make sure you follow us on X so you don't miss any future updates.