Capacitor Plugin Setup

Install the DeployYourApp Capacitor plugin, set up iOS and Android, and get a working update check.


How to add @deploy-your-app/capacitor-update-manager to a Capacitor app and get the first update check working.

Automated setup

The CLI does the whole installation interactively:

dya setup

dya setup logs you in, picks or creates the app, generates RSA keys, installs the plugin with your package manager, writes the plugins.DeployYourApp block into capacitor.config.json (or prints a snippet for .ts / .js configs), and runs npx cap sync. It requires a TTY, so it is not usable in CI. See dya setup.

The rest of this page covers the same steps by hand.

Requirements

Requirement Value
@capacitor/core >=6.0.0 (peer dependency)
iOS deployment target 13.0
Android minSdkVersion 22
Android compileSdkVersion 34
Android JDK / Kotlin Java 17, Kotlin 1.9.25

The Android minSdkVersion, compileSdkVersion, and targetSdkVersion are read from your root project's ext block when you define them, so the plugin follows your app's values.

Install

npm install @deploy-your-app/capacitor-update-manager
npx cap sync

npx cap sync registers the plugin with both native projects and pulls in the iOS ZIP dependency. No manual class registration is needed on either platform.

Configure

Add a DeployYourApp block under plugins in capacitor.config.json:

{
  "appId": "com.yourcompany.yourapp",
  "webDir": "dist",
  "plugins": {
    "DeployYourApp": {
      "appId": "com.yourcompany.yourapp",
      "channel": "production"
    }
  }
}

plugins.DeployYourApp.appId is the app ID from the DeployYourApp dashboard. It is separate from the top-level Capacitor appId, even when the two happen to match. When it is unset the plugin falls back to the platform's own identifier — the bundle identifier on iOS, the application package name on Android — and logs a warning to the Xcode console or logcat. Unless that identifier happens to be your dashboard app ID, every update check will return "no update". Set it explicitly.

That is the minimum. Every other option has a default — see Configuration for the full list.

Confirm each launch

The plugin rolls a newly served bundle back unless your app confirms it booted. Call notifyAppReady() once, as early as your app can honestly say it is working:

import { DeployYourApp } from '@deploy-your-app/capacitor-update-manager';

await DeployYourApp.notifyAppReady();

If a new bundle does not call this within appReadyTimeout (10 seconds by default), the plugin restores the previous bundle. See Update lifecycle.

With the default autoUpdate: true, that is the whole integration. The plugin checks for updates on launch and every checkInterval seconds, downloads new bundles, verifies them, and activates them on the next launch.

iOS

npx cap sync is the only step. Specifics worth knowing:

  • ZIP extraction uses ZIPFoundation ~> 0.9.19. CocoaPods installs it from the plugin's podspec; Swift Package Manager resolves it from Package.swift.
  • The plugin ships an Apple privacy manifest (PrivacyInfo.xcprivacy) as a resource bundle. It is included automatically in the CocoaPods integration.
  • Bundles are stored under Application Support/dya-bundles/<bundleId>/. Plugin state (device ID, channel, bundle metadata) lives in UserDefaults under dya_* keys.
  • The plugin writes Capacitor's own serverBasePath key in UserDefaults so a cold start serves the active bundle before plugins load.

Android

npx cap sync is the only step. Specifics worth knowing:

  • The plugin's AndroidManifest.xml is empty — it declares no permissions, activities, or services. Your app still needs the internet permission it already has for any network access.
  • ZIP extraction uses java.util.zip, so there is no extra Gradle dependency beyond capacitor-android, androidx.appcompat, and the Kotlin standard library.
  • Bundles are stored under the app's internal files/dya-bundles/<bundleId>/. Plugin state lives in the dya_prefs and dya_config SharedPreferences files.
  • The plugin writes Capacitor's serverBasePath key in the CapWebViewSettings preferences so a cold start serves the active bundle before plugins load.

Verify the installation

Build and run on a device or emulator, then confirm the plugin answers and reaches the server:

import { DeployYourApp, DYA_EVENTS } from '@deploy-your-app/capacitor-update-manager';

DeployYourApp.addListener(DYA_EVENTS.UPDATE_AVAILABLE, ({ version }) => {
  console.log('Update available:', version);
});

const { version } = await DeployYourApp.getPluginVersion();
console.log('Plugin version:', version);

const { deviceId } = await DeployYourApp.getDeviceId();
console.log('Device ID:', deviceId);

const result = await DeployYourApp.checkForUpdate();
console.log('Update available?', result.available);

A successful check registers the device against your app. The device then appears in the dashboard, which confirms appId and updateUrl are correct. available: false on a fresh app is expected until you deploy a bundle with dya deploy.

Pointing at another environment

Skip this. By default the plugin talks to deployyour.app and neither URL needs setting. These options exist for testing an app against a different DeployYourApp API, such as a local server during development.

Both are base URLs — the plugin appends /api/update and /api/stats itself. Because bundles are served from object storage rather than the API host, that host must also be listed in allowedDownloadHosts; downloads from anywhere else are refused, and https is required except from localhost:

{
  "plugins": {
    "DeployYourApp": {
      "appId": "com.yourcompany.yourapp",
      "updateUrl": "http://localhost:3000",
      "statsUrl": "http://localhost:3000",
      "allowedDownloadHosts": ["localhost"]
    }
  }
}

Troubleshooting

The plugin is not found at runtime. Run npx cap sync again. It must run after every install and after any change to capacitor.config.json.

Every check returns no update. Confirm plugins.DeployYourApp.appId matches the app ID in the dashboard, that the channel name exists on that app, and that you have deployed a bundle to it. An unset appId produces this exact symptom; look for the DeployYourApp warning in logcat or the Xcode console, which names the identifier that was substituted.

The device never appears in the dashboard. The device only registers once an update check reaches the server. Check that the device has network access to your updateUrl.

Next steps


Previous
CI/CD Integration
Next
Configuration