Commit 79de76a
authored
[android][breaking] compile with kotlin 2.x and raise api / language version (#75)
## Summary
Bumps the Kotlin compiler (and serialization plugin) from 1.9.23 to 2.3.21, and raises the consumer-floor pin (`apiVersion` / `languageVersion`) from Kotlin 1.9 to Kotlin 2.0.
**This is a breaking change for consumers.** Raising `apiVersion` / `languageVersion` makes Kotlin 2.0+ the required consumer floor — anyone still building against 1.9 can't consume the new AAR. Bundling this into the next major release is deliberate (see below).
First of a stack of PRs preparing the next major release.
> **If you consume this library and you're stuck on Kotlin 1.9.x for any reason — please reach out before this lands.** We chose the lowest pin we believe the consumer base can absorb, but the data on real-world consumer floors is limited; concrete blockers will help us calibrate.
## Why now
- **Kotlin 1.9 is deprecated by the 2.x compiler** and will be removed in a future minor. Holding the consumer pin at 1.9 forces us to stay on a 1.9.x compiler indefinitely, which is itself a dead-end path.
- **One forced consumer-floor break, not two.** Doing the compiler bump and the `apiVersion`/`languageVersion` bump together means consumers cross the breaking boundary once. If we bumped just the compiler now and the pin later, consumers would absorb two separate "minimum Kotlin" raises in successive releases.
- **Major-version cut is the cheapest moment to do it.** A consumer-floor raise is already a major-version event; bundling it into a planned major (alongside JVM 11) avoids spending a major version on this alone.
- **Compiler ahead of the pin** (compiler 2.3, pin 2.0) leaves room for future routine compiler bumps without re-breaking consumers.
## Why pin 2.0 and not 2.1
We considered raising the pin to Kotlin 2.1 — it would silence a compiler warning we now carry (see below) and buy more runway before the next forced break. Pin 2.0 was the deliberate choice for consumer reach:
- **React Native consumers**: the RN wrapper at `platforms/react-native/` claims `react-native: "*"` peer compatibility. RN templates ship Kotlin 1.9 on RN ≤ 0.76, Kotlin 2.0 on RN 0.77/0.78, Kotlin 2.1+ on RN 0.79+. Pin 2.0 keeps RN 0.77+ consumers reachable; pin 2.1 would cut off two RN minors that are still very common in production given how painful RN upgrades are.
- **Unknown consumer toolchains**: we don't have systematic visibility into top consumers' Kotlin/AGP floors. Pin 2.0 is the most conservative non-deprecated choice available.
## Accepted trade-off: LV 2.0 deprecation warning in our build
Kotlin 2.3's compiler now emits `Language version 2.0 is deprecated and its support will be removed in a future version of Kotlin. Update the version to 2.1.` on every `:lib:compile*Kotlin` invocation. We accept this warning rather than bump the pin to 2.1:
- The warning is **in our build only** — consumers don't see it. They consume the published AAR; Kotlin metadata is what they read, and the metadata is valid for any Kotlin 2.0+ compiler.
- It will become a hard error in some future Kotlin minor. When it does, we'll bump the pin in a minor release of the library, by which time the lagging RN/consumer cohort will have caught up and the cost will be lower.
- No `lib.api` impact from the 2.3 compiler bump (verified — `apiDump` produced zero diff vs the 2.1.20 dump).
## Changes
- `build.gradle`: Kotlin plugins (`org.jetbrains.kotlin.android`, `org.jetbrains.kotlin.plugin.serialization`) 1.9.23 → 2.3.21.
- `lib/build.gradle`: `apiVersion` / `languageVersion` pinned to `KotlinVersion.KOTLIN_2_0`; explanatory comment updated.
- `gradle.properties` (root + sample): AGP-opt-out comment block rewritten. `android.builtInKotlin=false` and `android.newDsl=false` remain, now documented as tooling-gap workarounds (BCV [#312](Kotlin/binary-compatibility-validator#312), [KT-71172](https://youtrack.jetbrains.com/issue/KT-71172)) rather than as Kotlin-version-specific.
- `lib/api/lib.api`: regenerated. 780 / 780 line diff, all inside auto-generated kotlinx-serialization `$$serializer` companion classes flipping to `synthetic` with `final` methods (a language-2.0 codegen change, not a human-authored API change).
- `CLAUDE.md`: references to the Kotlin pin updated 1.9 → 2.0.
## Why we're not on AGP 9's built-in Kotlin
AGP 9 ships a built-in Kotlin plugin that replaces `org.jetbrains.kotlin.android`, but neither of our API-validation paths works with it for Android libraries today:
- `binary-compatibility-validator` listens for the `kotlin-android` plugin id, which AGP's built-in path doesn't apply ([BCV #312](Kotlin/binary-compatibility-validator#312)) — `:lib:apiCheck`/`:lib:apiDump` silently never register, so our public-API gate disappears.
- KGP's experimental `abiValidation` DSL exists for JVM and Multiplatform but is not yet exposed on `KotlinAndroidProjectExtension` ([KT-71172](https://youtrack.jetbrains.com/issue/KT-71172)).
We stay on the explicit `org.jetbrains.kotlin.android` plugin so BCV keeps gating public API. The two AGP opt-outs (`builtInKotlin=false`, `newDsl=false`) are coupled to this decision — revisit when either upstream issue lands. Flipping them later is consumer-invisible: same `kotlinc` output, same `lib.api`.
## Consumer impact
- **Consumer floor (breaking)**: Kotlin 2.0+ now required to consume the AAR. Consumers on 1.9.x toolchains can't build against the new release. Needs a prominent release-notes entry.
- **React Native consumers**: RN 0.77+ apps (which ship Kotlin 2.0+) build fine. RN ≤ 0.76 (Kotlin 1.9) can't consume the new lib until they upgrade RN.
- **Java consumers**: effectively unaffected by the Kotlin pin itself — Java doesn't read Kotlin metadata. Only transitive impact is `kotlin-stdlib` floor on the classpath rising from 1.9.x → 2.0.x. JVM target / JDK floor changes live in the stacked `target-jvm-11` PR.
- **lib.api**: 780-line diff, all inside auto-generated kotlinx-serialization `$$serializer` companions — they flip to `synthetic` with `final` methods under language-2.0. No human-authored API moved.
- **Practical day-to-day**: zero for normal consumers already on Kotlin 2.0+. `Json.encodeToString(...)`, `Foo.serializer()` and friends behave identically. Only theoretically affected: anyone subclassing an auto-generated `$$serializer` (not a supported kotlinx-serialization pattern).
## Test plan
- [ ] `./gradlew :lib:clean :lib:test :lib:detekt :lib:lintRelease :lib:apiCheck :lib:assembleRelease` — green
- [ ] `InteropTest` (Java consumer test) — all cases pass
- [ ] Sample app `./gradlew assembleDebug` from `samples/MobileBuyIntegration/` — green
## Test plan
- [ ] `./gradlew :lib:clean :lib:test :lib:detekt :lib:lintRelease :lib:apiCheck :lib:assembleRelease` — green
- [ ] `InteropTest` (Java consumer test) — all cases pass
- [ ] Sample app `./gradlew assembleDebug` from `samples/MobileBuyIntegration/` — green
## Test plan
- [x] `./gradlew :lib:clean :lib:test :lib:detekt :lib:lintRelease :lib:apiCheck :lib:assembleRelease` passes locally.
- [x] Java `InteropTest` passes (consumer-facing Java interop intact).
- [x] `:lib:apiCheck` still gates public-API drift against `lib/api/lib.api`.
- [ ] CI green on the PR.
### Before you merge
> [!IMPORTANT]
>
> - [ ] I've added tests to support my implementation
> - [x] I have read and agree with the [Contribution Guidelines](./CONTRIBUTING.md)
> - [x] I have read and agree with the [Code of Conduct](./CODE_OF_CONDUCT.md)
> - [x] I've updated the relevant platform README (`platforms/swift/README.md` and/or `platforms/android/README.md`)
---
<details>
<summary>Releasing a new Swift version?</summary>
- [ ] I have bumped the version in `platforms/swift/ShopifyCheckoutKit.podspec`
- [ ] I have bumped the version in `platforms/swift/Sources/ShopifyCheckoutKit/ShopifyCheckoutKit.swift`
- [ ] I have updated `platforms/swift/CHANGELOG.md`
- [ ] I have updated the SwiftPM/CocoaPods version snippets in `platforms/swift/README.md` (major version only)
</details>
<details>
<summary>Releasing a new Android version?</summary>
- [ ] I have bumped the `versionName` in `platforms/android/lib/build.gradle`
- [ ] I have updated `platforms/android/CHANGELOG.md`
- [ ] I have updated the Gradle/Maven version snippets in `platforms/android/README.md`
</details>
> [!TIP]
> See the [Contributing documentation](./CONTRIBUTING.md) for the full release process per platform.1 parent ec7bc62 commit 79de76a
6 files changed
Lines changed: 585 additions & 568 deletions
File tree
- platforms/android
- lib
- api
- samples/MobileBuyIntegration
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
43 | 43 | | |
44 | 44 | | |
45 | 45 | | |
46 | | - | |
| 46 | + | |
47 | 47 | | |
48 | 48 | | |
49 | 49 | | |
| |||
91 | 91 | | |
92 | 92 | | |
93 | 93 | | |
94 | | - | |
| 94 | + | |
95 | 95 | | |
96 | 96 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
4 | | - | |
5 | | - | |
| 4 | + | |
| 5 | + | |
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
20 | 24 | | |
21 | 25 | | |
22 | 26 | | |
23 | 27 | | |
24 | 28 | | |
25 | 29 | | |
26 | | - | |
| 30 | + | |
27 | 31 | | |
28 | | - | |
29 | | - | |
30 | | - | |
| 32 | + | |
| 33 | + | |
31 | 34 | | |
32 | | - | |
33 | | - | |
34 | | - | |
35 | | - | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
36 | 45 | | |
37 | | - | |
38 | 46 | | |
39 | | - | |
| 47 | + | |
40 | 48 | | |
0 commit comments