Skip to content

Best Practices

Here are some best practices to follow when using the Live Update SDK to ensure a smooth user experience:

Automatic Rollbacks

The Live Update SDK supports automatic rollbacks in case an invalid bundle is provided. To enable this feature, configure the readyTimeout option and optionally enable autoBlockRolledBackBundles to prevent rollback loops:

capacitor.config.ts
import { CapacitorConfig } from "@capacitor/cli";

const config: CapacitorConfig = {
  plugins: {
    LiveUpdate: {
      readyTimeout: 10000,
      autoBlockRolledBackBundles: true // optional
    }
  }
};

export default config;
capacitor.config.json
{
  "plugins": {
    "LiveUpdate": {
      "readyTimeout": 10000,
      "autoBlockRolledBackBundles": true
    }
  }
}

The readyTimeout option specifies the maximum time (in milliseconds) to wait for your app to signal it's ready before rolling back to the built-in bundle. The autoBlockRolledBackBundles option automatically blocks bundles that caused a rollback and skips them in future sync operations, preventing your app from getting stuck in a rollback loop.

Your app must call the ready() method directly at app startup before the timeout expires, otherwise the SDK will roll back to the built-in bundle. Call this method as early as possible in your app's lifecycle—for example, in the ngOnInit or created hooks (Angular/Vue) or in the useEffect hook (React) of your root component:

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

const initializeApp = async () => {
  await LiveUpdate.ready();
  // Continue with app initialization...
};

Automatic Storage Cleanup

Since each billing plan includes a fixed quota of storage space, it is important to implement a strategy for automatically cleaning up unused or outdated bundles to avoid exceeding this limit. There are two main approaches to achieve this:

Both approaches can be used either individually or in combination.

Bundle Expiration Dates

The first approach is to set expiration dates for your bundles. This ensures that outdated bundles are automatically removed after a certain period of time. For example, you can use the following Capawesome CLI command to create a bundle that expires after 365 days:

npx @capawesome/cli apps:bundles:create --expires-in-days 365

In most cases, such a long expiration period is enough to ensure that users have ample time to update their apps before the bundles are removed.

Channel Bundle Limits

The second approach is to set limits on the number of bundles that can be stored for each channel. This ensures that older bundles are automatically removed when the limit is reached. For example, you can use the following Capawesome CLI command to create a channel with a bundle limit of 3:

npx @capawesome/cli apps:channels:create --bundle-limit 3

As soon as the limit of 3 bundles is reached, the oldest bundle will be automatically removed to make room for the new one.

Binary Compatible Changes

It is important to make sure that only Binary Compatible Changes are delivered to your users to prevent incompatible updates.

Capawesome Cloud offers two different ways to restrict live updates to specific native versions:

Versioned Bundles

Versioned bundles allow you to restrict live updates to specific native versions by defining a range of version codes for each platform.

Version Code

The version code (named versionCode on Android and CFBundleVersion on iOS) is the internal version number of your app. It is used to determine whether one version is more recent than another and must be incremented each time you release a new version of your app.

To create a versioned bundle, you only need to specify the minimum and maximum version codes for each platform:

  • Minimum Version: The native binary must have at least this version code to be compatible with the bundle.
  • Maximum Version: The native binary must have at most this version code to be compatible with the bundle.
  • Equivalent: If the native binary has this exact version code, do NOT download the bundle, because they are equal.

For this, you can use the following Capawesome CLI command:

npx @capawesome/cli apps:bundles:create --android-min 10 --android-max 12 --android-eq 11 --ios-min 10 --ios-max 12 --ios-eq 11

Versioned Channels

Versioned channels allow you to restrict live updates to specific native versions by creating a channel for each version code. This is the recommended approach, as it leaves less room for mistakes and makes bundles easier to manage. Channels also offer advanced features such as bundle limits.

To create a versioned channel, you can use the following Capawesome CLI command:

npx @capawesome/cli apps:channels:create --name production-10

In this example, we created a channel named production-10 for the version code 10.

To upload a bundle to a specific channel, you can use the following Capawesome CLI command:

npx @capawesome/cli apps:bundles:create --channel production-10

Finally, we just need to set the correct channel in the app to ensure that only compatible bundles are downloaded:

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

const sync = async () => {
  // Get the version code of the native app
  const { versionCode } = await LiveUpdate.getVersionCode();
  // Automatically download and set the latest compatible bundle
  await LiveUpdate.sync({ channel: `production-${versionCode}` });
};

Code Signing

We strongly recommend signing your app bundles to ensure their integrity and authenticity. This way, you can be sure that the bundles have not been tampered with and are coming from a trusted source. For more information, check out the Code Signing guide.

Reasonable Update Checks

While it's important to keep your app up-to-date, checking for updates too frequently can lead to a poor user experience. Not only does the device get rate-limited after a certain number of requests, but these requests also use up a lot of the device's resources like battery and data.

The simplest and most effective way to handle update checks is to use the autoUpdateStrategy configuration option. This automatically checks for updates at app startup and when the app resumes (with a minimum 15-minute interval between checks), which provides a perfect balance between keeping your app up-to-date and preserving device resources.

If you choose to implement manual update checks, you should definitely NOT check for updates in fixed intervals:

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

// Do NOT do this!!!
setTimeout(() => {
  LiveUpdate.checkForUpdate();
}, 60000);

For manual implementation examples, check out the Update Strategies guide.