Repository navigation
fix(android): build under AGP 9 built-in Kotlin and new DSL - #669
Merged
Merged
Conversation
…in extension AGP 9 ships built-in Kotlin support and registers the kotlin extension itself. Applying the Kotlin plugin again fails configuration with "Cannot add extension with name 'kotlin'". Check for the extension directly, which needs no AGP version table and covers AGP 10, where the android.builtInKotlin opt-out is removed. (cherry picked from commit 278eba6) Co-authored-by: Gabriel Donadel Dall'Agnol <donadeldev@gmail.com>
KGP 2.2 deprecates `kotlinOptions` at error level, and AGP 9 with
android.newDsl=true is the default React Native will have to adopt (AGP 10
removes the opt-out). Under the new DSL the module still configured, but:
- replace the two identical `tasks.withType(KotlinCompile).all { kotlinOptions }`
blocks (which also added every flag twice) with one
`kotlin { compilerOptions { optIn.addAll(...) } }`. The `kotlin` extension
exists both with AGP's built-in Kotlin and with kotlin-android, and the
`-Xopt-in` flags it replaces are deprecated.
- `lintOptions` -> `lint { disable.add(...) }` (available since AGP 7).
- `buildConfig true` / `compose true` -> `=` assignments; Gradle 9 reports
the space-assignment form as deprecated, to be removed in Gradle 10.
Refs MBL-2258
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add scripts/build-android-template-host.sh. It generates a React Native template app, installs the packed SDK, runs a Gradle task (default :app:assembleDebug) and checks that the module's Kotlin classes were compiled. `agp9-defaults` turns on android.builtInKotlin and android.newDsl and drops the app's kotlin-android, as AGP 9 intends; `template-defaults` builds the template as generated. The new "Android build compatibility" workflow runs: - RN 0.77.3, module only. This is the oldest React Native the module compiles on (AGP 8.7, Kotlin 2.0.21). Its app as generated can't build with this SDK: AndroidX Core 1.17 from the native SDK needs compileSdk 36 and AGP 8.9.1. - RN 0.81.6, the oldest template whose app builds as generated. - RN 0.88.0 as generated (AGP 9 with both opt-outs), and with AGP 9 defaults. Refs MBL-2255 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Sample app builds 📱Below you will find the list of the latest versions of the sample apps. It's recommended to always download the latest builds of the sample apps to accurately test the pull request. Builds are in progress. This comment will be updated when they finish.
|
sydneycollins-cio
approved these changes
Oct 23, 2026
mrehan27
approved these changes
Oct 23, 2026
cio-mobile-release Bot
pushed a commit
that referenced
this pull request
Oct 23, 2026
## [6.16.1](6.16.0...6.16.1) (2026-10-23) ### Bug Fixes * **android:** build under AGP 9 built-in Kotlin and new DSL ([#669](#669)) ([1068ea0](1068ea0))
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.
Refs MBL-2258, MBL-2255
Stacked on #652 by @gabrieldonadel (Expo). Its commit is cherry-picked here with authorship kept and a
Co-authored-bytrailer, because the new CI job can't pass without it. Please review and merge #652 first. After it merges, rebase this branch ontomainto drop the duplicate cherry-picked commit (a5988faf). This PR then reduces to the two commits below. Thanks, Gabriel, for the fix and the 500-library sweep behind it.Why
React Native 0.87+ templates build on AGP 9 (RN 0.88.0: AGP 9.2.1, Gradle 9.4.1, Kotlin 2.2.0, which AGP resolves to 2.2.10). They still opt out of AGP 9's built-in Kotlin and new DSL (
android.builtInKotlin=false,android.newDsl=false). AGP 10 removes the opt-out. An app that drops it today can't build with this SDK.Changes
fix(android): skip explicit Kotlin plugin when AGP registers the kotlin extension #652 (cherry-picked): apply
kotlin-androidonly when AGP hasn't already registered thekotlinextension.android/build.gradle:tasks.withType(KotlinCompile).all { kotlinOptions { … } }blocks become onekotlin { compilerOptions { optIn.addAll(…) } }. The old blocks also passed every flag twice. KGP 2.2 deprecateskotlinOptionsat error level, and Kotlin warns that-Xopt-inis deprecated. Thekotlinextension exists with both built-in Kotlin andkotlin-android.optInis in KGP 2.0.21'sKotlinCommonCompilerOptions.lintOptions { disable … }→lint { disable.add('GradleCompatible') }(AGP 7+).buildConfig true/compose true→=. These are the only two lines Gradle 9's problems report flags in this file (space-assignment is removed in Gradle 10).CI:
scripts/build-android-template-host.sh+ Android build compatibility workflow. Each run generates a stock RN template with@react-native-community/cli init, installs thenpm packed SDK, runs:app:assembleDebug(x86_64) and asserts the module's Kotlin classes landed in itsclasses.jar. Matrix::customerio-reactnative:assembleDebug). This is the oldest React Native the module compiles on: AGP 8.7.2 / Gradle 8.10 / Kotlin 2.0.21. Its app as generated can't build with this SDK; see below.android.builtInKotlin=true,android.newDsl=true, and the app'sorg.jetbrains.kotlin.androidline removedThe script fails if a template stops generating the lines a mode depends on. The module-class check reads the module's compile classes jar after an app build, or its debug AAR after a module-only build. It installs the template's NDK up front if missing (ubuntu-24.04 ships 27.3, the templates want 27.1.12297006). It prints the resolved AGP/KGP. Gradle caching uses
setup-gradlewith the MITcache-provider: basic.Local verification (macOS arm64, JDK 17)
All runs build a freshly generated template app with the
npm packed SDK.mainFailed to apply plugin 'kotlin-android'›Cannot add extension with name 'kotlin'main:customerio-reactnative:compileDebugKotlinruns via built-in Kotlin; warns-Xopt-in is deprecatedkotlin { compilerOptions { optIn } }andlint {}configure and compilemaincheckDebugAarMetadata:androidx.core:core(-ktx):1.17.0needs compileSdk 36 and AGP ≥ 8.9.1. Pre-existing since 5.1.0 (native Android 4.13.0); not caused by this PR.mainmainCould not find org.jetbrains.kotlin:compose-compiler-gradle-plugin:1.9.25Gradle 9's problems report on this module flagged only
buildConfig true/compose true, now fixed.#652 assessment
Safe to merge as-is. Merge it before this PR.
android.builtInKotlin=false, nothing registerskotlinbefore the check, sokotlin-androidis applied exactly as today. Both RN 0.88 modes build with it, and its change is inside this PR's RN 0.77.3 and 0.81.6 builds.kotlinOptions/-Xopt-indeprecations. Those still work from Groovy on KGP 2.2, but this PR removes them.kotlinextension (e.g. a JVM/KMP plugin applied to every subproject) would make the module skipkotlin-android. That's an unsupported setup, and no worse than today's hard failure.Not changed here (follow-ups)
compileSdkVersion/minSdkVersion/targetSdkVersionmethods still configure under AGP 9.2.1's new DSL, and Gradle doesn't flag them. Moving tocompileSdk =/minSdk =, and deciding whether the library should keep atargetSdkat all, can be a separate cleanup.kotlin-gradle-pluginandcompose-compiler-gradle-pluginat the host's declaredkotlinVersionto its own buildscript classpath. Under AGP 9 the root resolves KGP 2.2.10 while this asks for 2.2.0. Both modes build, but the module could rely on the root classpath instead.Codex review
Approach consult (before writing):
kotlin { compilerOptions { optIn.addAll } }extension form;lint { disable.add() }; an oldest-RN job; a configurable CLI version; asserting template lines in both modes; absolute path normalization; installing the NDK up front; printing resolved AGP/KGP;setup-gradlewithcache-provider: basic; keeping the generated host and uploading reports on failure.targetSdkVersion. Codex said AGP 9's new DSL lacks it, but AGP 9.2.1 withnewDsl=trueconfigures it fine (table above), and Codex withdrew the claim in its review.compileSdk =/minSdk =assignments, and the buildscript KGP/Compose versions.Adversarial review of the diff:
src/postInstall.js(runs during both installs) andreact-native.config.*. Fixed. The app module's report directory was also added to the failure artifact.kotlin.RequiresOptInis redundant but harmless; Groovy validity on AGP 8.7 / KGP 2.0.21 (now also confirmed by the 0.77.3 module build); no consumer-visible AAR or manifest change intended;set -euo pipefailusage; BSD/GNUsed/grepportability; the ubuntu-24.04sdkmanagerpath; CLI 15/20initflags; the stacking approach.Re-review after the matrix changed (stock RN 0.77.3 apps can't build with this SDK, so the 0.77.3 job became module-only and RN 0.81.6 was added): no defect. Codex found the AAR fallback sound under
set -euo pipefail. It also confirmed the module-only job guards plugin configuration, codegen and module compilation on the oldest RN/Kotlin, but not app packaging; the matrix comment says so.🤖 Generated with Claude Code