From dea1cc1bb2b56327340928d5b95bf9f69b12e41b Mon Sep 17 00:00:00 2001 From: Gabriel Donadel Dall'Agnol Date: Wed, 2 Sep 2026 14:01:23 -0700 Subject: [PATCH 1/2] fix(android): skip explicit Kotlin plugin when AGP provides built-in Kotlin AGP 9 enables built-in Kotlin by default and applies the Kotlin plugin itself. Applying it again fails configuration with "Cannot add extension with name 'kotlin'". Guard the explicit apply so it only runs when AGP is not providing Kotlin: AGP 8 and older, or AGP 9 with android.builtInKotlin=false. AGP 10 removes that opt-out, so built-in Kotlin is always active there and the explicit apply must never run. --- packages/core/android/build.gradle | 23 ++++++++++++++++++- .../android/build.gradle | 23 ++++++++++++++++++- .../android/build.gradle | 23 ++++++++++++++++++- .../react-native-webview/android/build.gradle | 23 ++++++++++++++++++- 4 files changed, 88 insertions(+), 4 deletions(-) diff --git a/packages/core/android/build.gradle b/packages/core/android/build.gradle index 1b3238fa2..3c9016972 100644 --- a/packages/core/android/build.gradle +++ b/packages/core/android/build.gradle @@ -36,7 +36,28 @@ apply plugin: 'com.android.library' if (isNewArchitectureEnabled()) { apply plugin: 'com.facebook.react' } -apply plugin: 'kotlin-android' +// Android Gradle Plugin 9 ships built-in Kotlin support and applies the Kotlin +// plugin itself. Applying it a second time fails the configuration phase with +// "Cannot add extension with name 'kotlin'". Apply it only when AGP is not +// providing Kotlin: AGP 8 and older, or AGP 9 with android.builtInKotlin=false. +def shouldApplyKotlinPlugin() { + def agpMajor = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.')[0].toInteger() + if (agpMajor <= 8) { + return true + } + // AGP 10 removes the opt-out: built-in Kotlin is always active there. + if (agpMajor >= 10) { + return false + } + def propertyVal = providers.gradleProperty("android.builtInKotlin").orNull + def builtInKotlinEnabled = propertyVal != null ? propertyVal.toBoolean() : true + return !builtInKotlinEnabled +} + +if (shouldApplyKotlinPlugin()) { + apply plugin: 'kotlin-android' +} + apply plugin: 'org.jlleitschuh.gradle.ktlint' diff --git a/packages/internal-testing-tools/android/build.gradle b/packages/internal-testing-tools/android/build.gradle index 276d3e508..5ecc20b81 100644 --- a/packages/internal-testing-tools/android/build.gradle +++ b/packages/internal-testing-tools/android/build.gradle @@ -31,7 +31,28 @@ apply plugin: 'com.android.library' if (isNewArchitectureEnabled()) { apply plugin: 'com.facebook.react' } -apply plugin: 'kotlin-android' +// Android Gradle Plugin 9 ships built-in Kotlin support and applies the Kotlin +// plugin itself. Applying it a second time fails the configuration phase with +// "Cannot add extension with name 'kotlin'". Apply it only when AGP is not +// providing Kotlin: AGP 8 and older, or AGP 9 with android.builtInKotlin=false. +def shouldApplyKotlinPlugin() { + def agpMajor = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.')[0].toInteger() + if (agpMajor <= 8) { + return true + } + // AGP 10 removes the opt-out: built-in Kotlin is always active there. + if (agpMajor >= 10) { + return false + } + def propertyVal = providers.gradleProperty("android.builtInKotlin").orNull + def builtInKotlinEnabled = propertyVal != null ? propertyVal.toBoolean() : true + return !builtInKotlinEnabled +} + +if (shouldApplyKotlinPlugin()) { + apply plugin: 'kotlin-android' +} + apply plugin: 'org.jlleitschuh.gradle.ktlint' /** diff --git a/packages/react-native-session-replay/android/build.gradle b/packages/react-native-session-replay/android/build.gradle index f9f1b3da3..2bfa2056e 100644 --- a/packages/react-native-session-replay/android/build.gradle +++ b/packages/react-native-session-replay/android/build.gradle @@ -34,7 +34,28 @@ apply plugin: 'com.android.library' if (isNewArchitectureEnabled()) { apply plugin: 'com.facebook.react' } -apply plugin: 'kotlin-android' +// Android Gradle Plugin 9 ships built-in Kotlin support and applies the Kotlin +// plugin itself. Applying it a second time fails the configuration phase with +// "Cannot add extension with name 'kotlin'". Apply it only when AGP is not +// providing Kotlin: AGP 8 and older, or AGP 9 with android.builtInKotlin=false. +def shouldApplyKotlinPlugin() { + def agpMajor = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.')[0].toInteger() + if (agpMajor <= 8) { + return true + } + // AGP 10 removes the opt-out: built-in Kotlin is always active there. + if (agpMajor >= 10) { + return false + } + def propertyVal = providers.gradleProperty("android.builtInKotlin").orNull + def builtInKotlinEnabled = propertyVal != null ? propertyVal.toBoolean() : true + return !builtInKotlinEnabled +} + +if (shouldApplyKotlinPlugin()) { + apply plugin: 'kotlin-android' +} + apply plugin: 'org.jlleitschuh.gradle.ktlint' /** diff --git a/packages/react-native-webview/android/build.gradle b/packages/react-native-webview/android/build.gradle index e145fb2cd..2e38e5a98 100644 --- a/packages/react-native-webview/android/build.gradle +++ b/packages/react-native-webview/android/build.gradle @@ -32,7 +32,28 @@ apply plugin: 'com.android.library' if (isNewArchitectureEnabled()) { apply plugin: 'com.facebook.react' } -apply plugin: 'kotlin-android' +// Android Gradle Plugin 9 ships built-in Kotlin support and applies the Kotlin +// plugin itself. Applying it a second time fails the configuration phase with +// "Cannot add extension with name 'kotlin'". Apply it only when AGP is not +// providing Kotlin: AGP 8 and older, or AGP 9 with android.builtInKotlin=false. +def shouldApplyKotlinPlugin() { + def agpMajor = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.')[0].toInteger() + if (agpMajor <= 8) { + return true + } + // AGP 10 removes the opt-out: built-in Kotlin is always active there. + if (agpMajor >= 10) { + return false + } + def propertyVal = providers.gradleProperty("android.builtInKotlin").orNull + def builtInKotlinEnabled = propertyVal != null ? propertyVal.toBoolean() : true + return !builtInKotlinEnabled +} + +if (shouldApplyKotlinPlugin()) { + apply plugin: 'kotlin-android' +} + apply plugin: 'org.jlleitschuh.gradle.ktlint' apply plugin: "io.gitlab.arturbosch.detekt" From b1492ef22a94813d5c2a8565fdbc2873a84aea19 Mon Sep 17 00:00:00 2001 From: Gabriel Donadel Dall'Agnol Date: Mon, 7 Sep 2026 22:00:02 +0200 Subject: [PATCH 2/2] Apply batched suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- packages/core/android/build.gradle | 2 +- packages/internal-testing-tools/android/build.gradle | 2 +- packages/react-native-session-replay/android/build.gradle | 2 +- packages/react-native-webview/android/build.gradle | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/core/android/build.gradle b/packages/core/android/build.gradle index 3c9016972..93163231a 100644 --- a/packages/core/android/build.gradle +++ b/packages/core/android/build.gradle @@ -39,7 +39,7 @@ if (isNewArchitectureEnabled()) { // Android Gradle Plugin 9 ships built-in Kotlin support and applies the Kotlin // plugin itself. Applying it a second time fails the configuration phase with // "Cannot add extension with name 'kotlin'". Apply it only when AGP is not -// providing Kotlin: AGP 8 and older, or AGP 9 with android.builtInKotlin=false. +// providing Kotlin: AGP 8 and older; AGP 9 only when android.builtInKotlin=false (AGP 10 always provides Kotlin). def shouldApplyKotlinPlugin() { def agpMajor = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.')[0].toInteger() if (agpMajor <= 8) { diff --git a/packages/internal-testing-tools/android/build.gradle b/packages/internal-testing-tools/android/build.gradle index 5ecc20b81..f2b211975 100644 --- a/packages/internal-testing-tools/android/build.gradle +++ b/packages/internal-testing-tools/android/build.gradle @@ -34,7 +34,7 @@ if (isNewArchitectureEnabled()) { // Android Gradle Plugin 9 ships built-in Kotlin support and applies the Kotlin // plugin itself. Applying it a second time fails the configuration phase with // "Cannot add extension with name 'kotlin'". Apply it only when AGP is not -// providing Kotlin: AGP 8 and older, or AGP 9 with android.builtInKotlin=false. +// providing Kotlin: AGP 8 and older; AGP 9 only when android.builtInKotlin=false (AGP 10 always provides Kotlin). def shouldApplyKotlinPlugin() { def agpMajor = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.')[0].toInteger() if (agpMajor <= 8) { diff --git a/packages/react-native-session-replay/android/build.gradle b/packages/react-native-session-replay/android/build.gradle index 2bfa2056e..34a278072 100644 --- a/packages/react-native-session-replay/android/build.gradle +++ b/packages/react-native-session-replay/android/build.gradle @@ -37,7 +37,7 @@ if (isNewArchitectureEnabled()) { // Android Gradle Plugin 9 ships built-in Kotlin support and applies the Kotlin // plugin itself. Applying it a second time fails the configuration phase with // "Cannot add extension with name 'kotlin'". Apply it only when AGP is not -// providing Kotlin: AGP 8 and older, or AGP 9 with android.builtInKotlin=false. +// providing Kotlin: AGP 8 and older; AGP 9 only when android.builtInKotlin=false (AGP 10 always provides Kotlin). def shouldApplyKotlinPlugin() { def agpMajor = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.')[0].toInteger() if (agpMajor <= 8) { diff --git a/packages/react-native-webview/android/build.gradle b/packages/react-native-webview/android/build.gradle index 2e38e5a98..6f165cf20 100644 --- a/packages/react-native-webview/android/build.gradle +++ b/packages/react-native-webview/android/build.gradle @@ -35,7 +35,7 @@ if (isNewArchitectureEnabled()) { // Android Gradle Plugin 9 ships built-in Kotlin support and applies the Kotlin // plugin itself. Applying it a second time fails the configuration phase with // "Cannot add extension with name 'kotlin'". Apply it only when AGP is not -// providing Kotlin: AGP 8 and older, or AGP 9 with android.builtInKotlin=false. +// providing Kotlin: AGP 8 and older; AGP 9 only when android.builtInKotlin=false (AGP 10 always provides Kotlin). def shouldApplyKotlinPlugin() { def agpMajor = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.')[0].toInteger() if (agpMajor <= 8) {