Skip to main content

Native setup

Native setup

Add @codemagic/capacitor-patch to a Capacitor app (including Ionic and Cordova-on-Capacitor apps) so release builds can check for, download, and apply OTA updates. Configuration lives in capacitor.config.ts, and npx cap sync installs the native plugin. No changes to AppDelegate or MainApplication are needed.

Capacitor apps use their own CLI, cmpatch-capacitor, for sign-in, apps, deployment keys, releases, and release operations.

Requirements:

  • A running Patch server (local quickstart or Install)
  • Node.js 20.19+ or 22.12+ for cmpatch-capacitor
  • Capacitor 7.x or 8.x. The two latest Capacitor major versions are supported.
  • Android: minSdkVersion 24 or later, with CMake and the NDK available
  • iOS: Swift Package Manager or CocoaPods, with mixed Swift / Objective-C++ compilation

Install the CLI and the SDK​

note

@codemagic/capacitor-patch and @codemagic/capacitor-patch-cli are 0.x releases. Their API and flags may still change.

Install the CLI:

npm install -g @codemagic/capacitor-patch-cli

Install the SDK in your Capacitor app:

npm install @codemagic/capacitor-patch
npx cap sync

npx cap sync copies the plugin into both native projects and updates their dependency manifests (the CocoaPods Podfile or SPM package list on iOS, and the Gradle module list on Android). You do not need to run pod install separately.

Create apps and deployments​

Sign in and create one app per platform. Each new app has Staging and Production deployments.

export CODEMAGIC_PATCH_SERVER_URL=https://updates.example.com
cmpatch-capacitor login

cmpatch-capacitor app create --name MyApp-iOS
cmpatch-capacitor app create --name MyApp-Android

List the deployment keys:

cmpatch-capacitor deployment list --app MyApp-iOS
cmpatch-capacitor deployment list --app MyApp-Android

Use a separate deployment key for each platform. The manifest path has no platform segment, so a shared key causes iOS and Android releases to overwrite each other.

To set the server, use CODEMAGIC_PATCH_SERVER_URL, the --server-url flag, or a stored default (cmpatch-capacitor config set --server-url <url>). login does not set a default server.

You can also create apps in the web dashboard. Set the framework to Capacitor, then copy the deployment key and SDK URLs from the deployment's SDK configuration panel.

note

cmpatch-capacitor looks up apps by name only among Capacitor apps. Apps created as React Native (for example, with cmpatch init) do not appear in cmpatch-capacitor app list and cannot be selected with --app <name>.

Configure capacitor.config.ts​

Set deploymentKey, apiUrl, and downloadBaseUrl for each platform. Get the API and download URLs from Install, or from the local quickstart for a local server.

import type { CapacitorConfig } from "@capacitor/cli";

const config: CapacitorConfig = {
appId: "com.example.app",
appName: "Example",
webDir: "www",
plugins: {
CodemagicPatch: {
ios: {
deploymentKey: "ios-staging-deployment-key",
apiUrl: "https://updates.example.com",
downloadBaseUrl: "https://storage-updates.example.com/codemagic-patch",
// publicKey: "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----",
},
android: {
deploymentKey: "android-staging-deployment-key",
apiUrl: "https://updates.example.com",
downloadBaseUrl: "https://storage-updates.example.com/codemagic-patch",
},
},
},
};

export default config;
KeyRequiredValue
deploymentKeyYesDeployment key from cmpatch-capacitor deployment list. Use a different key for iOS and Android
apiUrlYesPatch API origin (server SERVER_URL). The SDK calls /v1/... on this host
downloadBaseUrlYesArtifact origin (server PUBLIC_BASE_URL). The bundled-storage default ends with /codemagic-patch
publicKeyNoPEM public key for release signature verification. If omitted, signatures are not checked
maxLaunchAttemptsNoNumber of launches a new update can run without calling notifyAppReady() before it is rolled back. Positive integer, default 3. Invalid values log a warning and fall back to the default

Configure at least one platform. Each platform block you add must include deploymentKey, apiUrl, and downloadBaseUrl.

Sync the native projects:

npx cap sync

Then rebuild the iOS and Android apps. An OTA update cannot add the plugin to a binary that was built without it.

Validate the config in CI​

npx codemagic-patch-check-config path/to/capacitor.config.json

The check fails if both platforms use the same deploymentKey or if maxLaunchAttempts is not a positive integer. It reads JSON only. If you use capacitor.config.ts, run it after npx cap sync against the generated copy, such as android/app/src/main/assets/capacitor.config.json.

Native resource overrides​

To set values per environment in CI without editing capacitor.config.ts, define them as native resources in iOS Info.plist or Android strings.xml. The keys match the React Native SDK:

  • CodemagicPatchDeploymentKey
  • CodemagicPatchApiUrl
  • CodemagicPatchDownloadBaseUrl
  • CodemagicPatchPublicKey
  • CodemagicPatchMaxLaunchAttempts

Native resources take precedence over capacitor.config.ts.

Bundle selection needs no extra wiring. The plugin selects the package in its native load() method and points the WebView at it.

Build for different deployments​

Select the deployment key at build time to produce Staging and Production binaries from the same project. If both deployments use the same server, the API and download URLs stay the same. Changing any of these values requires a new binary.

Read the keys from environment variables in capacitor.config.ts, and run npx cap sync before the native build:

ios: {
deploymentKey: process.env.PATCH_IOS_DEPLOYMENT_KEY,
apiUrl: "https://updates.example.com",
downloadBaseUrl: "https://storage-updates.example.com/codemagic-patch",
},
android: {
deploymentKey: process.env.PATCH_ANDROID_DEPLOYMENT_KEY,
apiUrl: "https://updates.example.com",
downloadBaseUrl: "https://storage-updates.example.com/codemagic-patch",
},

Alternatively, set the Production keys as native resource overrides in the store build job.

Before distributing a binary, check that the packaged config (or the Info.plist / strings.xml override) contains the intended deployment key.

note

Live reload (ionic serve, npx cap run --live-reload) loads the app from the dev server, so OTA updates have no effect. Test updates with a native build that does not use live reload.

Next steps​