Skip to content

fix(android): skip explicit Kotlin plugin when AGP provides built-in Kotlin - #1056

Closed
gabrieldonadel wants to merge 0 commit into
react-native-datetimepicker:masterfrom
gabrieldonadel:fix/agp9-built-in-kotlin
Closed

fix(android): skip explicit Kotlin plugin when AGP provides built-in Kotlin#1056
gabrieldonadel wants to merge 0 commit into
react-native-datetimepicker:masterfrom
gabrieldonadel:fix/agp9-built-in-kotlin

Conversation

@gabrieldonadel

Copy link
Copy Markdown

Problem

Android Gradle Plugin 9 ships built-in Kotlin support and enables it by default, so
AGP applies the Kotlin plugin itself. When a library also applies kotlin-android
explicitly, the two collide and configuration fails before anything compiles:

> Failed to apply plugin 'kotlin-android'.
   > Cannot add extension with name 'kotlin', as there is an extension already registered with that name.

The apply is unconditional in this file, so on an AGP 9 project this library cannot be
built at all. There is no consumer-side workaround short of patching the file —
setting android.builtInKotlin=false project-wide to build one dependency is not a
reasonable ask, and that escape hatch is removed in AGP 10.

Change

Keep the explicit apply, but skip it when AGP is already providing Kotlin:

def shouldApplyKotlinPlugin() {
    def agpMajor = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.')[0].toInteger()
    if (agpMajor <= 8) {
        return true
    }
    def propertyVal = providers.gradleProperty("android.builtInKotlin").orNull
    def builtInKotlinEnabled = propertyVal != null ? propertyVal.toBoolean() : true
    return !builtInKotlinEnabled
}

if (shouldApplyKotlinPlugin()) {
    apply plugin: 'kotlin-android'
}

Files changed:

  • android/build.gradle

Why the condition has this shape

Both halves are needed:

  • AGP <= 8 always applies. Built-in Kotlin only exists from AGP 9.0. On older AGP
    nothing else applies the Kotlin plugin, so skipping would break the build the other way.
  • Absent is treated as enabled. android.builtInKotlin defaults to on in AGP 9, so
    only an explicit false means "AGP is not providing Kotlin, apply it yourself". This
    mirrors AGP's own default.

Behaviour matrix:

AGP android.builtInKotlin explicit apply
8.x unset / false yes (unchanged)
9.x unset no — AGP provides it
9.x true no — AGP provides it
9.x false yes — consumer opted out

com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION needs no new plugin resolution, and
the apply here already happens after com.android.library, so AGP is on the classpath.

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. Same
    guard, both matrices green.
  • Syntax-checked this file with Groovy's Phases.CONVERSION.
  • Not run: this repo's own CI or example app. The AGP <= 8 path is unchanged by
    construction (shouldApplyKotlinPlugin() short-circuits to true), but a CI run is
    the real confirmation and I could not do that from outside.

Found while sweeping 157 popular React Native libraries for AGP 9 new-DSL
compatibility. 34 of them failed with the new DSL enabled, and 29 of those failed on
exactly this — it is the single most common blocker by a wide margin.

@gabrieldonadel

Copy link
Copy Markdown
Author

Sorry for the noise — I force-updated the branch to fix the indentation so it matches this file's style, which auto-closed this PR. Superseded by #1057, same change. Please review that one instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant