docs: state the minimum Kotlin version - #1876
Draft
AlvaroBrey wants to merge 5 commits into
Draft
Conversation
AlvaroBrey
force-pushed
the
docs/kotlin-build-requirement
branch
from
August 27, 2026 09:25
99b7887 to
3f0c12f
Compare
This was referenced Aug 27, 2026
Merged
AlvaroBrey
added a commit
to RevenueCat/purchases-android
that referenced
this pull request
Aug 27, 2026
> [!NOTE] > This targets branch `11.0-dev` which will become the epic branch for the upcoming major release. Once this first PR is merged, I'll open a continuous one from that one to `main` until we are ready to release it altogether. - Moves the SDK's build toolchain to AGP 9: | Dependency | From | To | |---|---|---| | AGP | 8.13.2 | **9.2.1** | | Gradle | 8.14.5 | **9.4.1** | | Kotlin | 2.0.21 | **2.2.21** | | Poko | 0.17.2 | **0.20.2** | | Paparazzi | 2.0.0-alpha02 | **2.0.0-alpha05** | - No public API change and no `api*.txt` diff. - **Why this becomes a major**: this transitively raises the miminum kotlin version for consumers to 2.1.0. up from 1.8.0. - Kotlin lands on **2.2.21, the minimum required by AGP 9**, - AGP is capped at **9.2.1** rather than latest: AGP 9.3.x requires Gradle 9.5+, and Gradle 9.5+ embeds a Kotlin that a 2.2 compiler cannot read, bumping consumers to an even higher minimum Kotlin version. - Nothing downstream needs AGP 9 or Gradle 9, just the Kotlin bump. The published AAR metadata is unchanged (`minCompileSdk=1`, `minAndroidGradlePluginVersion=1.0.0`). Companion docs PR: RevenueCat/docs#1942 Companion PHC PR: RevenueCat/purchases-hybrid-common#1844 ### Checklist - [ ] If applicable, unit tests - [ ] If applicable, create follow-up issues for `purchases-ios` and hybrids <details><summary>Agent description</summary> ### Motivation AGP 8 is increasingly behind, and AGP 9 removes a number of DSL surfaces we still used. The prerequisite work already landed separately in #3931, #3961 and #3963. AGP 9 has a runtime dependency on Kotlin Gradle Plugin **2.2.10 or higher**, so a Kotlin bump is not optional here. Everything above that floor is a choice, and this PR deliberately takes the minimum. ### Why not Kotlin 2.3.x An earlier revision of this branch used Kotlin 2.3.21. Measuring the cost changed the decision: - **It breaks every React Native consumer.** We publish `kotlin-stdlib` at `compile` scope and Gradle resolves consumers onto it. A compiler reads metadata at most one minor ahead. Kotlin 2.3.x publishes metadata 2.3.0, and React Native's own Gradle plugin pins the compiler: 2.0.21 through RN 0.79, 2.1.20 through RN 0.86, with only RN `main` on 2.2.0. Reproduced on a real RN 0.86 app: `metadata version is 2.3.0 / compiler version 2.1.0 can read versions up to 2.2.0`. Every RN app would have needed an explicit `kotlin-gradle-plugin` version in `android/build.gradle`. - **It forces the K2 migration.** Kotlin 2.3.21 rejects `languageVersion 1.8` outright. 2.2.x still accepts it, so the frontend migration stays out of a version bump where it does not belong. - **It does not avoid a second bump anyway.** Kotlin 2.4 removes `languageVersion 1.8` regardless. At Kotlin 2.2.21 the published metadata is 2.2.0, which RN 0.81+ reads untouched. ### Why AGP 9.2.1 and Gradle 9.4.1 This is the non-obvious constraint, and CI found it rather than local builds. `:codegen` is a `java-gradle-plugin` module, so it compiles against the Kotlin that **Gradle itself embeds**. Embedded Kotlin by Gradle release: | Gradle | Embedded Kotlin | Readable by a 2.2 compiler (max 2.3.0) | |---|---|---| | 9.3.1 | 2.2.21 | yes | | 9.4.1 | 2.3.0 | yes, exactly at the limit | | 9.5.1 | 2.3.20 | no | | 9.7.0 | 2.4.0 | no | Gradle 9.7.0 therefore failed `prepare-tests` with `metadata version is 2.4.0, but the compiler version 2.2.0 can read versions up to 2.3.0`. AGP 9.3.x requires Gradle 9.5.0 or higher (`Minimum supported Gradle version is 9.5.0`), which is exactly the range we cannot read. **AGP 9.2.1 is the newest release that runs on Gradle 9.4.1**; 9.1.1 and 9.0.1 were also confirmed to work, 9.3.1 was confirmed not to. So the AGP ceiling here is a consequence of the Kotlin floor, not an independent preference. When the deferred Kotlin 2.3 bump happens, AGP and Gradle can move up with it. ### Also in this PR - Standalone sample apps (`CustomEntitlementComputationSample`, `MagicWeather`, `MagicWeatherCompose`) move to Kotlin 2.2.21 and gain the `compose-compiler` plugin alias. They consume our published artifacts, so they need a compiler that can read our metadata. - Unit tests are re-enabled on the release variant via `HasUnitTestBuilder.enableUnitTest`, because AGP 9 only creates unit tests for the `testBuildType` variant and the published variant is release. - The `androidDependencies` cache-warm CI step is dropped; AGP 9 removed that task. - `migrations/v11-MIGRATION.md` documents the new Kotlin floor, mirroring the v9 guide. - README `Requirements` now says Kotlin 2.1.0+. ### Deferred on purpose - **Kotlin 2.3 and the K1 to K2 migration**, until React Native ships the KGP 2.2 pin already on its `main` branch. Doing it sooner buys nothing and costs every RN app a migration step. - **AGP 9 built-in Kotlin** (previously #3965). Not breaking and not required; the `android.builtInKotlin=false` / `android.newDsl=false` opt-out only has to go at AGP 10. ### Testing - `assembleDebug` across all modules; release AARs for `:purchases` and `:ui:revenuecatui`. - `:purchases` unit tests, `:ui:debugview:verifyPaparazziDefaultsDebug`, `detektAll`. - `scripts/api-check.sh` with **zero** `api*.txt` diff. - Published contract checked directly: POM carries `kotlin-stdlib:2.2.21` at `compile` scope, the release AAR still reports `minCompileSdk=1` and `minAndroidGradlePluginVersion=1.0.0`, and our own classes carry metadata `mv = {1, 8, 0}`. - Consumer floor measured against the real release AAR plus the stdlib we publish: Kotlin 2.1.21 compiles; 2.0.21 and 1.9.24 fail. That is what the 2.1.0 claim in the README rests on. ### Downstream The Kotlin floor is what propagates, not AGP. Nothing downstream needs AGP 9 or Gradle 9. The only direct consumer is purchases-hybrid-common, which re-exposes us at compile scope via `api(libs.purchases)`. RevenueCat/purchases-hybrid-common#1844 raises its Kotlin accordingly, and the hybrid SDKs pick the floor up from there rather than from this repo. Documentation follows separately: - RevenueCat/docs#1942 adds the Kotlin minimum to the Android, Flutter and React Native installation pages, and adds the 9.x-to-10.x and 10.x-to-11.x migration guides the site was missing. - RevenueCat/purchases-flutter#1876 states the Kotlin minimum in that repo's README. Flutter applies the version from the app's `android/settings.gradle`, so the requirement lands on the consuming app and the Flutter version itself does not move. - RevenueCat/react-native-purchases#1925 raises the React Native floor to 0.80.0, the first release whose Gradle plugin pins a Kotlin that can read our metadata. </details> <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Major toolchain and minimum Kotlin version changes affect all consumers and CI, though public API and published AAR AGP/minSdk metadata are intentionally unchanged. > > **Overview** > This PR moves the SDK build to **AGP 9.2.1**, **Gradle 9.4.1**, and **Kotlin 2.2.21**, and bumps related tooling (Poko, Paparazzi, baseline profile plugin). **`gradle.properties`** opts out of AGP 9’s built-in Kotlin and new DSL for now. > > The **consumer-facing change** is a higher Kotlin floor: README and **`migrations/v11-MIGRATION.md`** document **Kotlin 2.1.0+** (up from 1.8.0), driven by published stdlib metadata—not a public API change. > > **Build-logic** re-enables unit tests on library variants under AGP 9 via **`enableUnitTest`**, and keeps **`aarMetadata.minCompileSdk = 1`** so published AAR requirements don’t tighten. > > Compose sample apps switch to the **Kotlin Compose compiler plugin** and drop **`composeOptions.kotlinCompilerExtensionVersion`**. Several modules replace deprecated **`kotlinOptions`** with **`kotlin.compilerOptions.jvmTarget`**. > > **CircleCI** drops the removed **`androidDependencies`** warmup and uses Gradle cache restore on standalone sample builds instead. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 1b6b4df. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
AlvaroBrey
added a commit
to RevenueCat/purchases-android
that referenced
this pull request
Aug 28, 2026
> [!NOTE] > This targets branch `11.0-dev` which will become the epic branch for the upcoming major release. Once this first PR is merged, I'll open a continuous one from that one to `main` until we are ready to release it altogether. - Moves the SDK's build toolchain to AGP 9: | Dependency | From | To | |---|---|---| | AGP | 8.13.2 | **9.2.1** | | Gradle | 8.14.5 | **9.4.1** | | Kotlin | 2.0.21 | **2.2.21** | | Poko | 0.17.2 | **0.20.2** | | Paparazzi | 2.0.0-alpha02 | **2.0.0-alpha05** | - No public API change and no `api*.txt` diff. - **Why this becomes a major**: this transitively raises the miminum kotlin version for consumers to 2.1.0. up from 1.8.0. - Kotlin lands on **2.2.21, the minimum required by AGP 9**, - AGP is capped at **9.2.1** rather than latest: AGP 9.3.x requires Gradle 9.5+, and Gradle 9.5+ embeds a Kotlin that a 2.2 compiler cannot read, bumping consumers to an even higher minimum Kotlin version. - Nothing downstream needs AGP 9 or Gradle 9, just the Kotlin bump. The published AAR metadata is unchanged (`minCompileSdk=1`, `minAndroidGradlePluginVersion=1.0.0`). Companion docs PR: RevenueCat/docs#1942 Companion PHC PR: RevenueCat/purchases-hybrid-common#1844 ### Checklist - [ ] If applicable, unit tests - [ ] If applicable, create follow-up issues for `purchases-ios` and hybrids <details><summary>Agent description</summary> ### Motivation AGP 8 is increasingly behind, and AGP 9 removes a number of DSL surfaces we still used. The prerequisite work already landed separately in #3931, #3961 and #3963. AGP 9 has a runtime dependency on Kotlin Gradle Plugin **2.2.10 or higher**, so a Kotlin bump is not optional here. Everything above that floor is a choice, and this PR deliberately takes the minimum. ### Why not Kotlin 2.3.x An earlier revision of this branch used Kotlin 2.3.21. Measuring the cost changed the decision: - **It breaks every React Native consumer.** We publish `kotlin-stdlib` at `compile` scope and Gradle resolves consumers onto it. A compiler reads metadata at most one minor ahead. Kotlin 2.3.x publishes metadata 2.3.0, and React Native's own Gradle plugin pins the compiler: 2.0.21 through RN 0.79, 2.1.20 through RN 0.86, with only RN `main` on 2.2.0. Reproduced on a real RN 0.86 app: `metadata version is 2.3.0 / compiler version 2.1.0 can read versions up to 2.2.0`. Every RN app would have needed an explicit `kotlin-gradle-plugin` version in `android/build.gradle`. - **It forces the K2 migration.** Kotlin 2.3.21 rejects `languageVersion 1.8` outright. 2.2.x still accepts it, so the frontend migration stays out of a version bump where it does not belong. - **It does not avoid a second bump anyway.** Kotlin 2.4 removes `languageVersion 1.8` regardless. At Kotlin 2.2.21 the published metadata is 2.2.0, which RN 0.81+ reads untouched. ### Why AGP 9.2.1 and Gradle 9.4.1 This is the non-obvious constraint, and CI found it rather than local builds. `:codegen` is a `java-gradle-plugin` module, so it compiles against the Kotlin that **Gradle itself embeds**. Embedded Kotlin by Gradle release: | Gradle | Embedded Kotlin | Readable by a 2.2 compiler (max 2.3.0) | |---|---|---| | 9.3.1 | 2.2.21 | yes | | 9.4.1 | 2.3.0 | yes, exactly at the limit | | 9.5.1 | 2.3.20 | no | | 9.7.0 | 2.4.0 | no | Gradle 9.7.0 therefore failed `prepare-tests` with `metadata version is 2.4.0, but the compiler version 2.2.0 can read versions up to 2.3.0`. AGP 9.3.x requires Gradle 9.5.0 or higher (`Minimum supported Gradle version is 9.5.0`), which is exactly the range we cannot read. **AGP 9.2.1 is the newest release that runs on Gradle 9.4.1**; 9.1.1 and 9.0.1 were also confirmed to work, 9.3.1 was confirmed not to. So the AGP ceiling here is a consequence of the Kotlin floor, not an independent preference. When the deferred Kotlin 2.3 bump happens, AGP and Gradle can move up with it. ### Also in this PR - Standalone sample apps (`CustomEntitlementComputationSample`, `MagicWeather`, `MagicWeatherCompose`) move to Kotlin 2.2.21 and gain the `compose-compiler` plugin alias. They consume our published artifacts, so they need a compiler that can read our metadata. - Unit tests are re-enabled on the release variant via `HasUnitTestBuilder.enableUnitTest`, because AGP 9 only creates unit tests for the `testBuildType` variant and the published variant is release. - The `androidDependencies` cache-warm CI step is dropped; AGP 9 removed that task. - `migrations/v11-MIGRATION.md` documents the new Kotlin floor, mirroring the v9 guide. - README `Requirements` now says Kotlin 2.1.0+. ### Deferred on purpose - **Kotlin 2.3 and the K1 to K2 migration**, until React Native ships the KGP 2.2 pin already on its `main` branch. Doing it sooner buys nothing and costs every RN app a migration step. - **AGP 9 built-in Kotlin** (previously #3965). Not breaking and not required; the `android.builtInKotlin=false` / `android.newDsl=false` opt-out only has to go at AGP 10. ### Testing - `assembleDebug` across all modules; release AARs for `:purchases` and `:ui:revenuecatui`. - `:purchases` unit tests, `:ui:debugview:verifyPaparazziDefaultsDebug`, `detektAll`. - `scripts/api-check.sh` with **zero** `api*.txt` diff. - Published contract checked directly: POM carries `kotlin-stdlib:2.2.21` at `compile` scope, the release AAR still reports `minCompileSdk=1` and `minAndroidGradlePluginVersion=1.0.0`, and our own classes carry metadata `mv = {1, 8, 0}`. - Consumer floor measured against the real release AAR plus the stdlib we publish: Kotlin 2.1.21 compiles; 2.0.21 and 1.9.24 fail. That is what the 2.1.0 claim in the README rests on. ### Downstream The Kotlin floor is what propagates, not AGP. Nothing downstream needs AGP 9 or Gradle 9. The only direct consumer is purchases-hybrid-common, which re-exposes us at compile scope via `api(libs.purchases)`. RevenueCat/purchases-hybrid-common#1844 raises its Kotlin accordingly, and the hybrid SDKs pick the floor up from there rather than from this repo. Documentation follows separately: - RevenueCat/docs#1942 adds the Kotlin minimum to the Android, Flutter and React Native installation pages, and adds the 9.x-to-10.x and 10.x-to-11.x migration guides the site was missing. - RevenueCat/purchases-flutter#1876 states the Kotlin minimum in that repo's README. Flutter applies the version from the app's `android/settings.gradle`, so the requirement lands on the consuming app and the Flutter version itself does not move. - RevenueCat/react-native-purchases#1925 raises the React Native floor to 0.80.0, the first release whose Gradle plugin pins a Kotlin that can read our metadata. </details> <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Major toolchain and minimum Kotlin version changes affect all consumers and CI, though public API and published AAR AGP/minSdk metadata are intentionally unchanged. > > **Overview** > This PR moves the SDK build to **AGP 9.2.1**, **Gradle 9.4.1**, and **Kotlin 2.2.21**, and bumps related tooling (Poko, Paparazzi, baseline profile plugin). **`gradle.properties`** opts out of AGP 9’s built-in Kotlin and new DSL for now. > > The **consumer-facing change** is a higher Kotlin floor: README and **`migrations/v11-MIGRATION.md`** document **Kotlin 2.1.0+** (up from 1.8.0), driven by published stdlib metadata—not a public API change. > > **Build-logic** re-enables unit tests on library variants under AGP 9 via **`enableUnitTest`**, and keeps **`aarMetadata.minCompileSdk = 1`** so published AAR requirements don’t tighten. > > Compose sample apps switch to the **Kotlin Compose compiler plugin** and drop **`composeOptions.kotlinCompilerExtensionVersion`**. Several modules replace deprecated **`kotlinOptions`** with **`kotlin.compilerOptions.jvmTarget`**. > > **CircleCI** drops the removed **`androidDependencies`** warmup and uses Gradle cache restore on standalone sample builds instead. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 1b6b4df. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
AlvaroBrey
added a commit
to RevenueCat/purchases-android
that referenced
this pull request
Aug 31, 2026
> [!NOTE] > This targets branch `11.0-dev` which will become the epic branch for the upcoming major release. Once this first PR is merged, I'll open a continuous one from that one to `main` until we are ready to release it altogether. - Moves the SDK's build toolchain to AGP 9: | Dependency | From | To | |---|---|---| | AGP | 8.13.2 | **9.2.1** | | Gradle | 8.14.5 | **9.4.1** | | Kotlin | 2.0.21 | **2.2.21** | | Poko | 0.17.2 | **0.20.2** | | Paparazzi | 2.0.0-alpha02 | **2.0.0-alpha05** | - No public API change and no `api*.txt` diff. - **Why this becomes a major**: this transitively raises the miminum kotlin version for consumers to 2.1.0. up from 1.8.0. - Kotlin lands on **2.2.21, the minimum required by AGP 9**, - AGP is capped at **9.2.1** rather than latest: AGP 9.3.x requires Gradle 9.5+, and Gradle 9.5+ embeds a Kotlin that a 2.2 compiler cannot read, bumping consumers to an even higher minimum Kotlin version. - Nothing downstream needs AGP 9 or Gradle 9, just the Kotlin bump. The published AAR metadata is unchanged (`minCompileSdk=1`, `minAndroidGradlePluginVersion=1.0.0`). Companion docs PR: RevenueCat/docs#1942 Companion PHC PR: RevenueCat/purchases-hybrid-common#1844 ### Checklist - [ ] If applicable, unit tests - [ ] If applicable, create follow-up issues for `purchases-ios` and hybrids <details><summary>Agent description</summary> ### Motivation AGP 8 is increasingly behind, and AGP 9 removes a number of DSL surfaces we still used. The prerequisite work already landed separately in #3931, #3961 and #3963. AGP 9 has a runtime dependency on Kotlin Gradle Plugin **2.2.10 or higher**, so a Kotlin bump is not optional here. Everything above that floor is a choice, and this PR deliberately takes the minimum. ### Why not Kotlin 2.3.x An earlier revision of this branch used Kotlin 2.3.21. Measuring the cost changed the decision: - **It breaks every React Native consumer.** We publish `kotlin-stdlib` at `compile` scope and Gradle resolves consumers onto it. A compiler reads metadata at most one minor ahead. Kotlin 2.3.x publishes metadata 2.3.0, and React Native's own Gradle plugin pins the compiler: 2.0.21 through RN 0.79, 2.1.20 through RN 0.86, with only RN `main` on 2.2.0. Reproduced on a real RN 0.86 app: `metadata version is 2.3.0 / compiler version 2.1.0 can read versions up to 2.2.0`. Every RN app would have needed an explicit `kotlin-gradle-plugin` version in `android/build.gradle`. - **It forces the K2 migration.** Kotlin 2.3.21 rejects `languageVersion 1.8` outright. 2.2.x still accepts it, so the frontend migration stays out of a version bump where it does not belong. - **It does not avoid a second bump anyway.** Kotlin 2.4 removes `languageVersion 1.8` regardless. At Kotlin 2.2.21 the published metadata is 2.2.0, which RN 0.81+ reads untouched. ### Why AGP 9.2.1 and Gradle 9.4.1 This is the non-obvious constraint, and CI found it rather than local builds. `:codegen` is a `java-gradle-plugin` module, so it compiles against the Kotlin that **Gradle itself embeds**. Embedded Kotlin by Gradle release: | Gradle | Embedded Kotlin | Readable by a 2.2 compiler (max 2.3.0) | |---|---|---| | 9.3.1 | 2.2.21 | yes | | 9.4.1 | 2.3.0 | yes, exactly at the limit | | 9.5.1 | 2.3.20 | no | | 9.7.0 | 2.4.0 | no | Gradle 9.7.0 therefore failed `prepare-tests` with `metadata version is 2.4.0, but the compiler version 2.2.0 can read versions up to 2.3.0`. AGP 9.3.x requires Gradle 9.5.0 or higher (`Minimum supported Gradle version is 9.5.0`), which is exactly the range we cannot read. **AGP 9.2.1 is the newest release that runs on Gradle 9.4.1**; 9.1.1 and 9.0.1 were also confirmed to work, 9.3.1 was confirmed not to. So the AGP ceiling here is a consequence of the Kotlin floor, not an independent preference. When the deferred Kotlin 2.3 bump happens, AGP and Gradle can move up with it. ### Also in this PR - Standalone sample apps (`CustomEntitlementComputationSample`, `MagicWeather`, `MagicWeatherCompose`) move to Kotlin 2.2.21 and gain the `compose-compiler` plugin alias. They consume our published artifacts, so they need a compiler that can read our metadata. - Unit tests are re-enabled on the release variant via `HasUnitTestBuilder.enableUnitTest`, because AGP 9 only creates unit tests for the `testBuildType` variant and the published variant is release. - The `androidDependencies` cache-warm CI step is dropped; AGP 9 removed that task. - `migrations/v11-MIGRATION.md` documents the new Kotlin floor, mirroring the v9 guide. - README `Requirements` now says Kotlin 2.1.0+. ### Deferred on purpose - **Kotlin 2.3 and the K1 to K2 migration**, until React Native ships the KGP 2.2 pin already on its `main` branch. Doing it sooner buys nothing and costs every RN app a migration step. - **AGP 9 built-in Kotlin** (previously #3965). Not breaking and not required; the `android.builtInKotlin=false` / `android.newDsl=false` opt-out only has to go at AGP 10. ### Testing - `assembleDebug` across all modules; release AARs for `:purchases` and `:ui:revenuecatui`. - `:purchases` unit tests, `:ui:debugview:verifyPaparazziDefaultsDebug`, `detektAll`. - `scripts/api-check.sh` with **zero** `api*.txt` diff. - Published contract checked directly: POM carries `kotlin-stdlib:2.2.21` at `compile` scope, the release AAR still reports `minCompileSdk=1` and `minAndroidGradlePluginVersion=1.0.0`, and our own classes carry metadata `mv = {1, 8, 0}`. - Consumer floor measured against the real release AAR plus the stdlib we publish: Kotlin 2.1.21 compiles; 2.0.21 and 1.9.24 fail. That is what the 2.1.0 claim in the README rests on. ### Downstream The Kotlin floor is what propagates, not AGP. Nothing downstream needs AGP 9 or Gradle 9. The only direct consumer is purchases-hybrid-common, which re-exposes us at compile scope via `api(libs.purchases)`. RevenueCat/purchases-hybrid-common#1844 raises its Kotlin accordingly, and the hybrid SDKs pick the floor up from there rather than from this repo. Documentation follows separately: - RevenueCat/docs#1942 adds the Kotlin minimum to the Android, Flutter and React Native installation pages, and adds the 9.x-to-10.x and 10.x-to-11.x migration guides the site was missing. - RevenueCat/purchases-flutter#1876 states the Kotlin minimum in that repo's README. Flutter applies the version from the app's `android/settings.gradle`, so the requirement lands on the consuming app and the Flutter version itself does not move. - RevenueCat/react-native-purchases#1925 raises the React Native floor to 0.80.0, the first release whose Gradle plugin pins a Kotlin that can read our metadata. </details> <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Major toolchain and minimum Kotlin version changes affect all consumers and CI, though public API and published AAR AGP/minSdk metadata are intentionally unchanged. > > **Overview** > This PR moves the SDK build to **AGP 9.2.1**, **Gradle 9.4.1**, and **Kotlin 2.2.21**, and bumps related tooling (Poko, Paparazzi, baseline profile plugin). **`gradle.properties`** opts out of AGP 9’s built-in Kotlin and new DSL for now. > > The **consumer-facing change** is a higher Kotlin floor: README and **`migrations/v11-MIGRATION.md`** document **Kotlin 2.1.0+** (up from 1.8.0), driven by published stdlib metadata—not a public API change. > > **Build-logic** re-enables unit tests on library variants under AGP 9 via **`enableUnitTest`**, and keeps **`aarMetadata.minCompileSdk = 1`** so published AAR requirements don’t tighten. > > Compose sample apps switch to the **Kotlin Compose compiler plugin** and drop **`composeOptions.kotlinCompilerExtensionVersion`**. Several modules replace deprecated **`kotlinOptions`** with **`kotlin.compilerOptions.jvmTarget`**. > > **CircleCI** drops the removed **`androidDependencies`** warmup and uses Gradle cache restore on standalone sample builds instead. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 1b6b4df. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
purchases-android v11 publishes kotlin-stdlib 2.2.21 at compile scope, so its metadata is 2.2.0 and a compiler older than 2.1 cannot read it. Flutter applies the app's own Kotlin Gradle Plugin version to plugin subprojects, so the requirement lands on the consuming app.
purchases-android v11 publishes stdlib metadata 2.2.0. Kotlin 1.9.20 rejects it with "The binary version of its metadata is 2.2.0, expected version is 1.9.0", so this module could not compile against v11 at all.
Scaffolding to prove the Kotlin bump against real v11 artifacts before release. Revert both the snapshot repository and the two pins before merging.
The apps compile their own MainActivity against purchases-android transitively, so a 1.8.22 compiler cannot read v11's metadata either.
Flutter builds the plugin as a subproject of the app, so the app's repositories decide resolution, not the plugin's. Revert with the pins in purchases_ui_flutter.
AlvaroBrey
force-pushed
the
docs/kotlin-build-requirement
branch
from
August 31, 2026 14:11
3f0c12f to
8c97408
Compare
AlvaroBrey
added a commit
to RevenueCat/purchases-android
that referenced
this pull request
Sep 7, 2026
> [!NOTE] > This targets branch `11.0-dev` which will become the epic branch for the upcoming major release. Once this first PR is merged, I'll open a continuous one from that one to `main` until we are ready to release it altogether. - Moves the SDK's build toolchain to AGP 9: | Dependency | From | To | |---|---|---| | AGP | 8.13.2 | **9.2.1** | | Gradle | 8.14.5 | **9.4.1** | | Kotlin | 2.0.21 | **2.2.21** | | Poko | 0.17.2 | **0.20.2** | | Paparazzi | 2.0.0-alpha02 | **2.0.0-alpha05** | - No public API change and no `api*.txt` diff. - **Why this becomes a major**: this transitively raises the miminum kotlin version for consumers to 2.1.0. up from 1.8.0. - Kotlin lands on **2.2.21, the minimum required by AGP 9**, - AGP is capped at **9.2.1** rather than latest: AGP 9.3.x requires Gradle 9.5+, and Gradle 9.5+ embeds a Kotlin that a 2.2 compiler cannot read, bumping consumers to an even higher minimum Kotlin version. - Nothing downstream needs AGP 9 or Gradle 9, just the Kotlin bump. The published AAR metadata is unchanged (`minCompileSdk=1`, `minAndroidGradlePluginVersion=1.0.0`). Companion docs PR: RevenueCat/docs#1942 Companion PHC PR: RevenueCat/purchases-hybrid-common#1844 - [ ] If applicable, unit tests - [ ] If applicable, create follow-up issues for `purchases-ios` and hybrids <details><summary>Agent description</summary> AGP 8 is increasingly behind, and AGP 9 removes a number of DSL surfaces we still used. The prerequisite work already landed separately in #3931, #3961 and #3963. AGP 9 has a runtime dependency on Kotlin Gradle Plugin **2.2.10 or higher**, so a Kotlin bump is not optional here. Everything above that floor is a choice, and this PR deliberately takes the minimum. An earlier revision of this branch used Kotlin 2.3.21. Measuring the cost changed the decision: - **It breaks every React Native consumer.** We publish `kotlin-stdlib` at `compile` scope and Gradle resolves consumers onto it. A compiler reads metadata at most one minor ahead. Kotlin 2.3.x publishes metadata 2.3.0, and React Native's own Gradle plugin pins the compiler: 2.0.21 through RN 0.79, 2.1.20 through RN 0.86, with only RN `main` on 2.2.0. Reproduced on a real RN 0.86 app: `metadata version is 2.3.0 / compiler version 2.1.0 can read versions up to 2.2.0`. Every RN app would have needed an explicit `kotlin-gradle-plugin` version in `android/build.gradle`. - **It forces the K2 migration.** Kotlin 2.3.21 rejects `languageVersion 1.8` outright. 2.2.x still accepts it, so the frontend migration stays out of a version bump where it does not belong. - **It does not avoid a second bump anyway.** Kotlin 2.4 removes `languageVersion 1.8` regardless. At Kotlin 2.2.21 the published metadata is 2.2.0, which RN 0.81+ reads untouched. This is the non-obvious constraint, and CI found it rather than local builds. `:codegen` is a `java-gradle-plugin` module, so it compiles against the Kotlin that **Gradle itself embeds**. Embedded Kotlin by Gradle release: | Gradle | Embedded Kotlin | Readable by a 2.2 compiler (max 2.3.0) | |---|---|---| | 9.3.1 | 2.2.21 | yes | | 9.4.1 | 2.3.0 | yes, exactly at the limit | | 9.5.1 | 2.3.20 | no | | 9.7.0 | 2.4.0 | no | Gradle 9.7.0 therefore failed `prepare-tests` with `metadata version is 2.4.0, but the compiler version 2.2.0 can read versions up to 2.3.0`. AGP 9.3.x requires Gradle 9.5.0 or higher (`Minimum supported Gradle version is 9.5.0`), which is exactly the range we cannot read. **AGP 9.2.1 is the newest release that runs on Gradle 9.4.1**; 9.1.1 and 9.0.1 were also confirmed to work, 9.3.1 was confirmed not to. So the AGP ceiling here is a consequence of the Kotlin floor, not an independent preference. When the deferred Kotlin 2.3 bump happens, AGP and Gradle can move up with it. - Standalone sample apps (`CustomEntitlementComputationSample`, `MagicWeather`, `MagicWeatherCompose`) move to Kotlin 2.2.21 and gain the `compose-compiler` plugin alias. They consume our published artifacts, so they need a compiler that can read our metadata. - Unit tests are re-enabled on the release variant via `HasUnitTestBuilder.enableUnitTest`, because AGP 9 only creates unit tests for the `testBuildType` variant and the published variant is release. - The `androidDependencies` cache-warm CI step is dropped; AGP 9 removed that task. - `migrations/v11-MIGRATION.md` documents the new Kotlin floor, mirroring the v9 guide. - README `Requirements` now says Kotlin 2.1.0+. - **Kotlin 2.3 and the K1 to K2 migration**, until React Native ships the KGP 2.2 pin already on its `main` branch. Doing it sooner buys nothing and costs every RN app a migration step. - **AGP 9 built-in Kotlin** (previously #3965). Not breaking and not required; the `android.builtInKotlin=false` / `android.newDsl=false` opt-out only has to go at AGP 10. - `assembleDebug` across all modules; release AARs for `:purchases` and `:ui:revenuecatui`. - `:purchases` unit tests, `:ui:debugview:verifyPaparazziDefaultsDebug`, `detektAll`. - `scripts/api-check.sh` with **zero** `api*.txt` diff. - Published contract checked directly: POM carries `kotlin-stdlib:2.2.21` at `compile` scope, the release AAR still reports `minCompileSdk=1` and `minAndroidGradlePluginVersion=1.0.0`, and our own classes carry metadata `mv = {1, 8, 0}`. - Consumer floor measured against the real release AAR plus the stdlib we publish: Kotlin 2.1.21 compiles; 2.0.21 and 1.9.24 fail. That is what the 2.1.0 claim in the README rests on. The Kotlin floor is what propagates, not AGP. Nothing downstream needs AGP 9 or Gradle 9. The only direct consumer is purchases-hybrid-common, which re-exposes us at compile scope via `api(libs.purchases)`. RevenueCat/purchases-hybrid-common#1844 raises its Kotlin accordingly, and the hybrid SDKs pick the floor up from there rather than from this repo. Documentation follows separately: - RevenueCat/docs#1942 adds the Kotlin minimum to the Android, Flutter and React Native installation pages, and adds the 9.x-to-10.x and 10.x-to-11.x migration guides the site was missing. - RevenueCat/purchases-flutter#1876 states the Kotlin minimum in that repo's README. Flutter applies the version from the app's `android/settings.gradle`, so the requirement lands on the consuming app and the Flutter version itself does not move. - RevenueCat/react-native-purchases#1925 raises the React Native floor to 0.80.0, the first release whose Gradle plugin pins a Kotlin that can read our metadata. </details> <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Major toolchain and minimum Kotlin version changes affect all consumers and CI, though public API and published AAR AGP/minSdk metadata are intentionally unchanged. > > **Overview** > This PR moves the SDK build to **AGP 9.2.1**, **Gradle 9.4.1**, and **Kotlin 2.2.21**, and bumps related tooling (Poko, Paparazzi, baseline profile plugin). **`gradle.properties`** opts out of AGP 9’s built-in Kotlin and new DSL for now. > > The **consumer-facing change** is a higher Kotlin floor: README and **`migrations/v11-MIGRATION.md`** document **Kotlin 2.1.0+** (up from 1.8.0), driven by published stdlib metadata—not a public API change. > > **Build-logic** re-enables unit tests on library variants under AGP 9 via **`enableUnitTest`**, and keeps **`aarMetadata.minCompileSdk = 1`** so published AAR requirements don’t tighten. > > Compose sample apps switch to the **Kotlin Compose compiler plugin** and drop **`composeOptions.kotlinCompilerExtensionVersion`**. Several modules replace deprecated **`kotlinOptions`** with **`kotlin.compilerOptions.jvmTarget`**. > > **CircleCI** drops the removed **`androidDependencies`** warmup and uses Gradle cache restore on standalone sample builds instead. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 1b6b4df. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
AlvaroBrey
added a commit
to RevenueCat/purchases-android
that referenced
this pull request
Sep 7, 2026
> [!NOTE] > This targets branch `11.0-dev` which will become the epic branch for the upcoming major release. Once this first PR is merged, I'll open a continuous one from that one to `main` until we are ready to release it altogether. - Moves the SDK's build toolchain to AGP 9: | Dependency | From | To | |---|---|---| | AGP | 8.13.2 | **9.2.1** | | Gradle | 8.14.5 | **9.4.1** | | Kotlin | 2.0.21 | **2.2.21** | | Poko | 0.17.2 | **0.20.2** | | Paparazzi | 2.0.0-alpha02 | **2.0.0-alpha05** | - No public API change and no `api*.txt` diff. - **Why this becomes a major**: this transitively raises the miminum kotlin version for consumers to 2.1.0. up from 1.8.0. - Kotlin lands on **2.2.21, the minimum required by AGP 9**, - AGP is capped at **9.2.1** rather than latest: AGP 9.3.x requires Gradle 9.5+, and Gradle 9.5+ embeds a Kotlin that a 2.2 compiler cannot read, bumping consumers to an even higher minimum Kotlin version. - Nothing downstream needs AGP 9 or Gradle 9, just the Kotlin bump. The published AAR metadata is unchanged (`minCompileSdk=1`, `minAndroidGradlePluginVersion=1.0.0`). Companion docs PR: RevenueCat/docs#1942 Companion PHC PR: RevenueCat/purchases-hybrid-common#1844 - [ ] If applicable, unit tests - [ ] If applicable, create follow-up issues for `purchases-ios` and hybrids <details><summary>Agent description</summary> AGP 8 is increasingly behind, and AGP 9 removes a number of DSL surfaces we still used. The prerequisite work already landed separately in #3931, #3961 and #3963. AGP 9 has a runtime dependency on Kotlin Gradle Plugin **2.2.10 or higher**, so a Kotlin bump is not optional here. Everything above that floor is a choice, and this PR deliberately takes the minimum. An earlier revision of this branch used Kotlin 2.3.21. Measuring the cost changed the decision: - **It breaks every React Native consumer.** We publish `kotlin-stdlib` at `compile` scope and Gradle resolves consumers onto it. A compiler reads metadata at most one minor ahead. Kotlin 2.3.x publishes metadata 2.3.0, and React Native's own Gradle plugin pins the compiler: 2.0.21 through RN 0.79, 2.1.20 through RN 0.86, with only RN `main` on 2.2.0. Reproduced on a real RN 0.86 app: `metadata version is 2.3.0 / compiler version 2.1.0 can read versions up to 2.2.0`. Every RN app would have needed an explicit `kotlin-gradle-plugin` version in `android/build.gradle`. - **It forces the K2 migration.** Kotlin 2.3.21 rejects `languageVersion 1.8` outright. 2.2.x still accepts it, so the frontend migration stays out of a version bump where it does not belong. - **It does not avoid a second bump anyway.** Kotlin 2.4 removes `languageVersion 1.8` regardless. At Kotlin 2.2.21 the published metadata is 2.2.0, which RN 0.81+ reads untouched. This is the non-obvious constraint, and CI found it rather than local builds. `:codegen` is a `java-gradle-plugin` module, so it compiles against the Kotlin that **Gradle itself embeds**. Embedded Kotlin by Gradle release: | Gradle | Embedded Kotlin | Readable by a 2.2 compiler (max 2.3.0) | |---|---|---| | 9.3.1 | 2.2.21 | yes | | 9.4.1 | 2.3.0 | yes, exactly at the limit | | 9.5.1 | 2.3.20 | no | | 9.7.0 | 2.4.0 | no | Gradle 9.7.0 therefore failed `prepare-tests` with `metadata version is 2.4.0, but the compiler version 2.2.0 can read versions up to 2.3.0`. AGP 9.3.x requires Gradle 9.5.0 or higher (`Minimum supported Gradle version is 9.5.0`), which is exactly the range we cannot read. **AGP 9.2.1 is the newest release that runs on Gradle 9.4.1**; 9.1.1 and 9.0.1 were also confirmed to work, 9.3.1 was confirmed not to. So the AGP ceiling here is a consequence of the Kotlin floor, not an independent preference. When the deferred Kotlin 2.3 bump happens, AGP and Gradle can move up with it. - Standalone sample apps (`CustomEntitlementComputationSample`, `MagicWeather`, `MagicWeatherCompose`) move to Kotlin 2.2.21 and gain the `compose-compiler` plugin alias. They consume our published artifacts, so they need a compiler that can read our metadata. - Unit tests are re-enabled on the release variant via `HasUnitTestBuilder.enableUnitTest`, because AGP 9 only creates unit tests for the `testBuildType` variant and the published variant is release. - The `androidDependencies` cache-warm CI step is dropped; AGP 9 removed that task. - `migrations/v11-MIGRATION.md` documents the new Kotlin floor, mirroring the v9 guide. - README `Requirements` now says Kotlin 2.1.0+. - **Kotlin 2.3 and the K1 to K2 migration**, until React Native ships the KGP 2.2 pin already on its `main` branch. Doing it sooner buys nothing and costs every RN app a migration step. - **AGP 9 built-in Kotlin** (previously #3965). Not breaking and not required; the `android.builtInKotlin=false` / `android.newDsl=false` opt-out only has to go at AGP 10. - `assembleDebug` across all modules; release AARs for `:purchases` and `:ui:revenuecatui`. - `:purchases` unit tests, `:ui:debugview:verifyPaparazziDefaultsDebug`, `detektAll`. - `scripts/api-check.sh` with **zero** `api*.txt` diff. - Published contract checked directly: POM carries `kotlin-stdlib:2.2.21` at `compile` scope, the release AAR still reports `minCompileSdk=1` and `minAndroidGradlePluginVersion=1.0.0`, and our own classes carry metadata `mv = {1, 8, 0}`. - Consumer floor measured against the real release AAR plus the stdlib we publish: Kotlin 2.1.21 compiles; 2.0.21 and 1.9.24 fail. That is what the 2.1.0 claim in the README rests on. The Kotlin floor is what propagates, not AGP. Nothing downstream needs AGP 9 or Gradle 9. The only direct consumer is purchases-hybrid-common, which re-exposes us at compile scope via `api(libs.purchases)`. RevenueCat/purchases-hybrid-common#1844 raises its Kotlin accordingly, and the hybrid SDKs pick the floor up from there rather than from this repo. Documentation follows separately: - RevenueCat/docs#1942 adds the Kotlin minimum to the Android, Flutter and React Native installation pages, and adds the 9.x-to-10.x and 10.x-to-11.x migration guides the site was missing. - RevenueCat/purchases-flutter#1876 states the Kotlin minimum in that repo's README. Flutter applies the version from the app's `android/settings.gradle`, so the requirement lands on the consuming app and the Flutter version itself does not move. - RevenueCat/react-native-purchases#1925 raises the React Native floor to 0.80.0, the first release whose Gradle plugin pins a Kotlin that can read our metadata. </details> <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Major toolchain and minimum Kotlin version changes affect all consumers and CI, though public API and published AAR AGP/minSdk metadata are intentionally unchanged. > > **Overview** > This PR moves the SDK build to **AGP 9.2.1**, **Gradle 9.4.1**, and **Kotlin 2.2.21**, and bumps related tooling (Poko, Paparazzi, baseline profile plugin). **`gradle.properties`** opts out of AGP 9’s built-in Kotlin and new DSL for now. > > The **consumer-facing change** is a higher Kotlin floor: README and **`migrations/v11-MIGRATION.md`** document **Kotlin 2.1.0+** (up from 1.8.0), driven by published stdlib metadata—not a public API change. > > **Build-logic** re-enables unit tests on library variants under AGP 9 via **`enableUnitTest`**, and keeps **`aarMetadata.minCompileSdk = 1`** so published AAR requirements don’t tighten. > > Compose sample apps switch to the **Kotlin Compose compiler plugin** and drop **`composeOptions.kotlinCompilerExtensionVersion`**. Several modules replace deprecated **`kotlinOptions`** with **`kotlin.compilerOptions.jvmTarget`**. > > **CircleCI** drops the removed **`androidDependencies`** warmup and uses Gradle cache restore on standalone sample builds instead. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 1b6b4df. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Docs only. Adds the minimum Kotlin version that arrives with the next purchases-hybrid-common major.
kotlin-stdlib2.2.21 at compile scope, so its metadata is 2.2.0. A Kotlin compiler reads metadata at most one minor ahead, so an app on a compiler older than 2.1 fails to build.android/settings.gradleto plugin subprojects, so the requirement lands on the consuming app. Verified: app at 1.8.22 fails, app at 2.1.21 builds, with the plugin's ownext.kotlin_versionunchanged in both.Depends on RevenueCat/purchases-hybrid-common#1844, which propagates the floor. Merge after the purchases-hybrid-common major that carries purchases-android v11.
Checklist