From 04000798019e7d4f76709e041bb768392e3099ba Mon Sep 17 00:00:00 2001 From: Andre Destro Date: Wed, 12 Aug 2026 11:53:28 +0100 Subject: [PATCH 1/3] docs: add Capacitor 9 plugin upgrade guide Covers plugin-author changes (Cordova-optional implications for plugins, Android/iOS breaking changes, gradle plugin variable bumps, using the plugin-migration-v8-to-v9 tool). Cross-links with the app upgrade guide added in the previous commit. RMET-5321 --- docs/main/updating/9-0.md | 2 +- docs/main/updating/plugins/9-0.md | 225 ++++++++++++++++++++++++++++++ sidebars.js | 1 + 3 files changed, 227 insertions(+), 1 deletion(-) create mode 100644 docs/main/updating/plugins/9-0.md diff --git a/docs/main/updating/9-0.md b/docs/main/updating/9-0.md index 4e3013d5c..01e021514 100644 --- a/docs/main/updating/9-0.md +++ b/docs/main/updating/9-0.md @@ -9,7 +9,7 @@ slug: /updating/9-0 In this guide, you'll find steps to update your project to the current Capacitor 9 version as well as a list of breaking changes for our official plugins. :::note -This guide covers app-level changes. If you maintain a Capacitor plugin, see the "Updating plugins to 9.0" guide instead. +This guide covers app-level changes. If you maintain a Capacitor plugin, see [Updating plugins to 9.0](/main/updating/plugins/9-0.md) instead. ::: ## Cordova support is now optional diff --git a/docs/main/updating/plugins/9-0.md b/docs/main/updating/plugins/9-0.md new file mode 100644 index 000000000..aac04d00b --- /dev/null +++ b/docs/main/updating/plugins/9-0.md @@ -0,0 +1,225 @@ +--- +title: Updating plugins to 9.0 +description: Guide for updating Capacitor from v8 to v9 in your plugin +slug: /updating/plugins/9-0 +--- + +# Updating Capacitor to 9.0 in your plugin + +:::note +This guide covers plugin-author changes. If you're updating an app, see [Updating to 9.0](/main/updating/9-0.md) instead. +::: + +:::note +Capacitor 9 hasn't reached general availability yet. Dependency versions below point at the `next` dist-tag / current alpha; once 9.0.0 ships, use a normal `^9.0.0` range instead. +::: + +## Using @capacitor/plugin-migration-v8-to-v9 + +From the plugin folder, run `npx @capacitor/plugin-migration-v8-to-v9@latest` and it will perform most of the file changes automatically. + +## Updating the files manually + +### Updating Capacitor dependencies + +Update `@capacitor/cli`, `@capacitor/core`, `@capacitor/android` and `@capacitor/ios` in devDependencies to `next`. +Update `@capacitor/core` in peerDependencies to `>=9.0.0-alpha.1` (check npm for the current alpha, since it moves forward regularly). + +### Cordova support is now optional + +Capacitor's Cordova compatibility layer is now only wired into a consuming app when that app actually has a Cordova plugin installed, on both Android and iOS. If your plugin's own native code directly references symbols from Capacitor's Cordova compatibility layer (for example `com.getcapacitor.cordova.CordovaPlugin` on Android), be aware that layer may not be present in a consuming app that has no Cordova plugins. There is currently no configuration option to force it to be included. + +If your plugin is SPM compatible, also remove the unconditional `Cordova` product dependency from your `Package.swift` — it's no longer guaranteed to be present in every consumer: + +```diff + dependencies: [ + .product(name: "Capacitor", package: "capacitor-swift-pm"), +- .product(name: "Cordova", package: "capacitor-swift-pm"), + ] +``` + +### Update Android Plugin Variables + +In your `build.gradle` file, update the following package versions: + +```diff +ext { + // Note: Some of the following dependencies are optional - only add/update the ones your plugin actually uses. + // If you use any of these dependencies, update them to the versions shown below. + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' + androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.1' + androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.3.0' + androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.7.0' +- androidxActivityVersion = project.hasProperty('androidxActivityVersion') ? rootProject.ext.androidxActivityVersion : '1.11.0' ++ androidxActivityVersion = project.hasProperty('androidxActivityVersion') ? rootProject.ext.androidxActivityVersion : '1.13.0' + androidxCoordinatorLayoutVersion = project.hasProperty('androidxCoordinatorLayoutVersion') ? rootProject.ext.androidxCoordinatorLayoutVersion : '1.3.0' +- androidxCoreVersion = project.hasProperty('androidxCoreVersion') ? rootProject.ext.androidxCoreVersion : '1.17.0' ++ androidxCoreVersion = project.hasProperty('androidxCoreVersion') ? rootProject.ext.androidxCoreVersion : '1.19.0' + androidxFragmentVersion = project.hasProperty('androidxFragmentVersion') ? rootProject.ext.androidxFragmentVersion : '1.8.9' + firebaseMessagingVersion = project.hasProperty('firebaseMessagingVersion') ? rootProject.ext.firebaseMessagingVersion : '25.0.1' +- playServicesLocationVersion = project.hasProperty('playServicesLocationVersion') ? rootProject.ext.playServicesLocationVersion : '21.3.0' ++ playServicesLocationVersion = project.hasProperty('playServicesLocationVersion') ? rootProject.ext.playServicesLocationVersion : '21.4.0' +- androidxBrowserVersion = project.hasProperty('androidxBrowserVersion') ? rootProject.ext.androidxBrowserVersion : '1.9.0' ++ androidxBrowserVersion = project.hasProperty('androidxBrowserVersion') ? rootProject.ext.androidxBrowserVersion : '1.10.0' +- androidxMaterialVersion = project.hasProperty('androidxMaterialVersion') ? rootProject.ext.androidxMaterialVersion : '1.13.0' ++ androidxMaterialVersion = project.hasProperty('androidxMaterialVersion') ? rootProject.ext.androidxMaterialVersion : '1.14.0' +- androidxExifInterfaceVersion = project.hasProperty('androidxExifInterfaceVersion') ? rootProject.ext.androidxExifInterfaceVersion : '1.4.1' ++ androidxExifInterfaceVersion = project.hasProperty('androidxExifInterfaceVersion') ? rootProject.ext.androidxExifInterfaceVersion : '1.4.2' + coreSplashScreenVersion = project.hasProperty('coreSplashScreenVersion') ? rootProject.ext.coreSplashScreenVersion : '1.2.0' +- androidxWebkitVersion = project.hasProperty('androidxWebkitVersion') ? rootProject.ext.androidxWebkitVersion : '1.14.0' ++ androidxWebkitVersion = project.hasProperty('androidxWebkitVersion') ? rootProject.ext.androidxWebkitVersion : '1.16.0' +- googleMapsPlayServicesVersion = project.hasProperty('googleMapsPlayServicesVersion') ? rootProject.ext.googleMapsPlayServicesVersion : '19.2.0' ++ googleMapsPlayServicesVersion = project.hasProperty('googleMapsPlayServicesVersion') ? rootProject.ext.googleMapsPlayServicesVersion : '20.0.0' +- googleMapsUtilsVersion = project.hasProperty('googleMapsUtilsVersion') ? rootProject.ext.googleMapsUtilsVersion : '3.19.1' ++ googleMapsUtilsVersion = project.hasProperty('googleMapsUtilsVersion') ? rootProject.ext.googleMapsUtilsVersion : '5.0.0' +- googleMapsKtxVersion = project.hasProperty('googleMapsKtxVersion') ? rootProject.ext.googleMapsKtxVersion : '5.2.1' +- googleMapsUtilsKtxVersion = project.hasProperty('googleMapsUtilsKtxVersion') ? rootProject.ext.googleMapsUtilsKtxVersion : '5.2.1' ++ googleMapsKtxVersion = project.hasProperty('googleMapsKtxVersion') ? rootProject.ext.googleMapsKtxVersion : '6.0.1' ++ googleMapsUtilsKtxVersion = project.hasProperty('googleMapsUtilsKtxVersion') ? rootProject.ext.googleMapsUtilsKtxVersion : '6.0.1' +- kotlinxCoroutinesVersion = project.hasProperty('kotlinxCoroutinesVersion') ? rootProject.ext.kotlinxCoroutinesVersion : '1.10.2' ++ kotlinxCoroutinesVersion = project.hasProperty('kotlinxCoroutinesVersion') ? rootProject.ext.kotlinxCoroutinesVersion : '1.11.0' +} +``` + +`googleMapsUtilsVersion` 5.0.0 includes upstream breaking changes to the Google Maps Utils API; check your usage against the [Google Maps Android Utility Library release notes](https://github.com/googlemaps/android-maps-utils/releases) if your plugin depends on it directly. + +### Migrate core-ktx to core + +`androidx.core:core` 1.19.0 merges every extension function previously shipped in `core-ktx` into `core` itself, turning `core-ktx` into an empty compatibility artifact. Drop the separate `androidxCoreKTXVersion` variable (reuse `androidxCoreVersion` instead) and depend on `core` rather than `core-ktx`: + +```diff +dependencies { +- implementation "androidx.core:core-ktx:$androidxCoreVersion" ++ implementation "androidx.core:core:$androidxCoreVersion" +} +``` + +### Remove targetSdkVersion, update minSdk / compileSdk + +AGP 9 infers `targetSdkVersion` from `compileSdkVersion` when it isn't set, and on a library module (which is what your plugin's `android/build.gradle` is) `targetSdkVersion` has no runtime effect anyway, so drop it entirely: + +```diff +# build.gradle + +android { +- compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 36 ++ compileSdk = project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 37 + defaultConfig { +- minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 24 ++ minSdkVersion = project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 26 +- targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 36 + } +} +``` + +### Remove the standalone Kotlin plugin + +AGP 9 bundles the Kotlin Gradle Plugin natively (Kotlin `2.2.10`) instead of requiring it to be applied separately. If your plugin still applies `kotlin-android` (or `org.jetbrains.kotlin.android`) and declares its own `kotlin_version`/`kotlin-stdlib`/`kotlin-gradle-plugin`, remove them, otherwise you'll hit a duplicate-plugin build failure: + +```diff +buildscript { +- ext.kotlin_version = project.hasProperty("kotlin_version") ? rootProject.ext.kotlin_version : '2.2.20' + repositories { + google() + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:9.2.1' +- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} +-apply plugin: 'kotlin-android' + +dependencies { +- implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" +} +``` + +### Give your plugin a unique Android namespace + +AGP 9 defaults `android.uniquePackageNames` to `true`: if your plugin's Android `namespace` collides with another library module in the same app (most commonly a leftover scaffold default, or a fork that kept the original plugin's namespace), the build now fails instead of silently working. Make sure your `namespace` in `build.gradle` is unique to your plugin. + +### Remove jcenter() + +Gradle 9 fully removes the `jcenter()` repository helper (redirected to Maven Central since 2024). Any `build.gradle` that still calls it fails at Gradle configuration time: + +```diff +repositories { + google() +- jcenter() ++ mavenCentral() +} +``` + +### Update gradle plugin to 9.2.1 + +```diff + dependencies { +- classpath 'com.android.tools.build:gradle:8.13.0' ++ classpath 'com.android.tools.build:gradle:9.2.1' + } +``` + +### Update gradle wrapper to 9.5.1 + +```diff +# gradle-wrapper.properties + +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +- distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-all.zip ++ distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-all.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +``` + +### Update google services plugin + +```diff +# build.gradle + + dependencies { + classpath 'com.android.tools.build:gradle:9.2.1' +- classpath 'com.google.gms:google-services:4.4.4' ++ classpath 'com.google.gms:google-services:4.5.0' +``` + +### Raise iOS Deployment Target to 16 + +Update your plugin's `.podspec` file: + +```diff +- s.ios.deployment_target = '15.0' ++ s.ios.deployment_target = '16.0' +``` + +#### SPM compatible plugins + +Update `Package.swift` file: + +```diff +- platforms: [.iOS(.v15)], ++ platforms: [.iOS(.v16)], +``` + +#### Plugins with old structure + +Do the following for your Xcode project: select the **Project** within the project editor and open the **Build Settings** tab. Under the **Deployment** section, change **iOS Deployment Target** to **iOS 16.0**. Repeat the same steps for any app **Targets**. + +Then, open `ios/Podfile` and update the iOS version to 16.0: + +```diff +-platform :ios, '15.0' ++platform :ios, '16.0' +``` + +### Update Capacitor SPM dependency + +In SPM compatible plugins, update `Package.swift` file to point at the current Capacitor 9 alpha (Capacitor 9 hasn't shipped a stable release yet, so this isn't a plain `9.0.0` version): + +```diff + dependencies: [ +- .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "8.0.0") ++ .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "9.0.0-alpha.1") + ], +``` diff --git a/sidebars.js b/sidebars.js index 5030da0b8..086f9e3c7 100644 --- a/sidebars.js +++ b/sidebars.js @@ -33,6 +33,7 @@ module.exports = { collapsed: false, items: [ 'main/updating/9-0', + 'main/updating/plugins/9-0', 'main/updating/8-5', 'main/updating/8-0', 'main/updating/plugins/8-0', From 2acea2a227390950e244d106ebcf69378bc2ff2f Mon Sep 17 00:00:00 2001 From: Andre Destro Date: Fri, 14 Aug 2026 13:04:12 +0100 Subject: [PATCH 2/3] docs: address PR review feedback on Cap9 plugin upgrade guide - Pin capacitor-swift-pm and the peerDependencies example to the latest alpha (9.0.0-alpha.6); earlier alphas had Cordova Optionality crashes. Use "prerelease" instead of "alpha" in the general wording so it doesn't go stale once Capacitor 9 reaches beta. - Clarify the uniquePackageNames namespace collision wording - Add a "Rename the default ProGuard file" section, since community plugins/forks may still reference proguard-android.txt - Point to the 8.5 UIScene audit section from the iOS deployment target step Addresses review comments from @OS-pedrogustavobilro on PR #590. --- docs/main/updating/plugins/9-0.md | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/docs/main/updating/plugins/9-0.md b/docs/main/updating/plugins/9-0.md index aac04d00b..7ce0b2563 100644 --- a/docs/main/updating/plugins/9-0.md +++ b/docs/main/updating/plugins/9-0.md @@ -11,7 +11,7 @@ This guide covers plugin-author changes. If you're updating an app, see [Updatin ::: :::note -Capacitor 9 hasn't reached general availability yet. Dependency versions below point at the `next` dist-tag / current alpha; once 9.0.0 ships, use a normal `^9.0.0` range instead. +Capacitor 9 hasn't reached general availability yet. Dependency versions below point at the `next` dist-tag / current prerelease; once 9.0.0 ships, use a normal `^9.0.0` range instead. ::: ## Using @capacitor/plugin-migration-v8-to-v9 @@ -23,7 +23,7 @@ From the plugin folder, run `npx @capacitor/plugin-migration-v8-to-v9@latest` an ### Updating Capacitor dependencies Update `@capacitor/cli`, `@capacitor/core`, `@capacitor/android` and `@capacitor/ios` in devDependencies to `next`. -Update `@capacitor/core` in peerDependencies to `>=9.0.0-alpha.1` (check npm for the current alpha, since it moves forward regularly). +Update `@capacitor/core` in peerDependencies to `>=9.0.0-alpha.6` (check npm for the current prerelease, since it moves forward regularly). ### Cordova support is now optional @@ -112,6 +112,20 @@ android { } ``` +### Rename the default ProGuard file + +AGP 9 removed `proguard-android.txt` — any `build.gradle` that still references it fails at Gradle configuration time, even with `minifyEnabled false`. Most official plugins already switched to `proguard-android-optimize.txt` in Capacitor 8, but if yours (or a fork of one) hasn't yet: + +```diff +buildTypes { + release { + minifyEnabled false +- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' ++ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } +} +``` + ### Remove the standalone Kotlin plugin AGP 9 bundles the Kotlin Gradle Plugin natively (Kotlin `2.2.10`) instead of requiring it to be applied separately. If your plugin still applies `kotlin-android` (or `org.jetbrains.kotlin.android`) and declares its own `kotlin_version`/`kotlin-stdlib`/`kotlin-gradle-plugin`, remove them, otherwise you'll hit a duplicate-plugin build failure: @@ -137,7 +151,7 @@ dependencies { ### Give your plugin a unique Android namespace -AGP 9 defaults `android.uniquePackageNames` to `true`: if your plugin's Android `namespace` collides with another library module in the same app (most commonly a leftover scaffold default, or a fork that kept the original plugin's namespace), the build now fails instead of silently working. Make sure your `namespace` in `build.gradle` is unique to your plugin. +AGP 9 defaults `android.uniquePackageNames` to `true`: if your plugin's Android `namespace` collides with another library module in the same app, the build now fails instead of silently working. The most common cause is a leftover scaffold default (`create-capacitor-plugin` pre-fills the `namespace` prompt with `com.mycompany.plugins.example`, and pressing Enter accepts it). A fork that kept the original plugin's namespace unchanged can cause the same failure. Make sure your `namespace` in `build.gradle` is unique to your plugin. ### Remove jcenter() @@ -186,6 +200,8 @@ zipStorePath=wrapper/dists ### Raise iOS Deployment Target to 16 +If your plugin observes app lifecycle or URL-opening notifications, also check it against the iOS UIScene lifecycle adopted in Capacitor 8.5 — see [Audit your custom code and plugins](/main/updating/8-5.md#audit-your-custom-code-and-plugins). + Update your plugin's `.podspec` file: ```diff @@ -215,11 +231,11 @@ Then, open `ios/Podfile` and update the iOS version to 16.0: ### Update Capacitor SPM dependency -In SPM compatible plugins, update `Package.swift` file to point at the current Capacitor 9 alpha (Capacitor 9 hasn't shipped a stable release yet, so this isn't a plain `9.0.0` version): +In SPM compatible plugins, update `Package.swift` file to point at the current Capacitor 9 prerelease (Capacitor 9 hasn't shipped a stable release yet, so this isn't a plain `9.0.0` version). Use the latest alpha, since earlier ones had crashes related to Cordova Optionality: ```diff dependencies: [ - .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "8.0.0") -+ .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "9.0.0-alpha.1") ++ .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "9.0.0-alpha.6") ], ``` From 53beba16b51733d835116770fb47842a5a2a2903 Mon Sep 17 00:00:00 2001 From: Rui Mendes Date: Fri, 14 Aug 2026 15:56:07 +0100 Subject: [PATCH 3/3] added breaking changes in code header --- docs/main/updating/plugins/9-0.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/main/updating/plugins/9-0.md b/docs/main/updating/plugins/9-0.md index 7ce0b2563..97014325e 100644 --- a/docs/main/updating/plugins/9-0.md +++ b/docs/main/updating/plugins/9-0.md @@ -4,6 +4,8 @@ description: Guide for updating Capacitor from v8 to v9 in your plugin slug: /updating/plugins/9-0 --- +# Breaking changes in code + # Updating Capacitor to 9.0 in your plugin :::note