Commit 5a733d4
fix(android): skip explicit Kotlin plugin when AGP registers the kotlin extension (#787)
## Problem
Android Gradle Plugin 9 ships built-in Kotlin support and enables it by
default, so
AGP registers the `kotlin` extension itself. When a library *also*
applies `kotlin-android`
explicitly, the two collide and configuration fails before anything
compiles. AGP
words it two ways, both the same problem:
```
> Failed to apply plugin 'kotlin-android'.
> Cannot add extension with name 'kotlin', as there is an extension already registered with that name.
```
```
> The 'kotlin-android' plugin is no longer required for Kotlin support since AGP 9.0.
```
The apply is unconditional in this module, so on an AGP 9 project this
cannot be built
at all. There is no consumer-side workaround short of patching the file
— setting
`android.builtInKotlin=false` project-wide just to build one dependency
is not a
reasonable ask, and that escape hatch is removed in AGP 10.
## Change
Apply the plugin only when nothing has registered the `kotlin` extension
yet:
```groovy
if (project.extensions.findByName('kotlin') == null) {
apply plugin: 'kotlin-android'
}
```
Files changed:
- `android/build.gradle`
This tests the condition that actually fails, so there is no AGP version
table to
keep in sync, and it covers AGP 10 — where the `android.builtInKotlin`
opt-out is
removed — without a special case.
| AGP | `android.builtInKotlin` | `kotlin` extension | explicit apply |
|---|---|---|---|
| 8.x | unset or `false` | absent | yes (unchanged) |
| 9.x | unset or `true` | registered by AGP | no |
| 9.x | `false` | absent | yes |
| 10+ | n/a (removed) | registered by AGP | no |
The guard sits after `apply plugin: 'com.android.library'` in every file
it touches,
so AGP has already registered its extensions by the time it runs. I
checked that
ordering per file rather than assuming it.
## What I verified, and what I did not
- **Verified end to end** on a real Expo SDK 58 / React Native 0.87
project with AGP
9.2.1 and Gradle 9.4.1: `:app:assembleDebug` succeeds both with
`-Pandroid.newDsl=true -Pandroid.builtInKotlin=true` and with both flags
off.
- Confirmed both branches actually execute rather than one path always
winning: with
the flags off, `compileDebugKotlin` runs from the explicitly applied
plugin; with
them on the build completes without it.
- Every changed file passes a Groovy `Phases.CONVERSION` syntax check.
- **Not run:** this repo's own CI or example app.
## Where this came from
A sweep of 500 popular React Native libraries against the AGP 9
defaults. 152 failed
with the new DSL enabled, and **144 of those failed on exactly this
collision** — by
far the most common blocker. Affects `react-native-enriched`,
`react-native-enriched-html` here.
The same guard shape was accepted in
[RevenueCat/react-native-purchases#1934](RevenueCat/react-native-purchases#1934),
at that maintainer's suggestion.
---------
Co-authored-by: Krystian Sienkiewicz <krystian.sienkiewicz@swmansion.com>1 parent 237c889 commit 5a733d4
1 file changed
Lines changed: 7 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
23 | | - | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
24 | 30 | | |
25 | 31 | | |
26 | 32 | | |
| |||
0 commit comments