[multi-package]Fix packages issue builtinkotlin AGP 9#11733
Conversation
Pull last changes from master
## Summary
Updates the example app's `build.gradle.kts` to conditionally apply the Kotlin Android plugin based on the Android Gradle Plugin (AGP) version. AGP 9.0 introduces built-in Kotlin support, making the explicit application of the `kotlin-android` plugin redundant when enabled.
## Changes
- **Conditional Plugin Application**: Replaced the static `id("kotlin-android")` with logic that checks `ANDROID_GRADLE_PLUGIN_VERSION`. The `org.jetbrains.kotlin.android` plugin is now only applied if the AGP version is below 9 or if the `android.builtInKotlin` property is explicitly set to false.
- **Dynamic Kotlin Configuration**: Wrapped the `kotlinOptions` block in a conditional check. When built-in Kotlin is disabled, it uses `withGroovyBuilder` to set the `jvmTarget` to `VERSION_17`, preventing build script evaluation errors when the Kotlin plugin is not present.
- **AGP Property Support**: Added a check for the `android.builtInKotlin` Gradle property to allow developers to opt-out of the built-in behavior on AGP 9+.
## Test plan
This change ensures compatibility across different AGP versions used by consumers of the plugin's example application.
## Summary
Updates `build.gradle.kts` files across multiple Flutter plugin examples and Android library modules to conditionally apply the Kotlin Android plugin. AGP 9.0 introduces built-in Kotlin support, making explicit application of the `kotlin-android` plugin redundant unless specifically disabled.
## Changes
- **Conditional Plugin Application**: Removed the static `id("kotlin-android")` and added logic to check the `ANDROID_GRADLE_PLUGIN_VERSION`. The `org.jetbrains.kotlin.android` plugin is now applied programmatically only if the AGP version is below 9 or if the `android.builtInKotlin` Gradle property is set to false.
- **Safe Kotlin Configuration**: Wrapped `kotlinOptions` in a conditional block. When built-in Kotlin is active (AGP 9+), the explicit `kotlinOptions` block is skipped. When inactive, it uses `withGroovyBuilder` to set `jvmTarget` to `VERSION_17`, ensuring compatibility without causing build script evaluation errors when the plugin is absent.
- **Broad Impact**: Applied these changes across a wide range of packages, including `camera`, `google_maps_flutter`, `image_picker`, `video_player`, `webview_flutter`, `shared_preferences`, and `pigeon`.
## Test plan
These changes ensure that plugin examples and libraries remain compatible across a range of AGP versions, specifically handling the transition to built-in Kotlin support in AGP 9.0 while maintaining backward compatibility for older environments.
…iles ## Summary Removes redundant blank lines within the conditional `isBuiltInKotlinEnabled` block across numerous package example applications. This change standardizes the formatting of the Gradle build scripts across the repository. ## Changes - **Formatting Cleanup**: Removed extra vertical whitespace inside the `if (!isBuiltInKotlinEnabled)` check and its nested `withGroovyBuilder` block. - **Improved Consistency**: Applied these formatting fixes to `build.gradle.kts` files in multiple packages, including `camera`, `google_maps_flutter`, `google_sign_in`, `in_app_purchase`, `video_player`, `webview_flutter`, and others.
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
# Conflicts: # packages/animations/CHANGELOG.md # packages/camera/camera/CHANGELOG.md # packages/camera/camera_android_camerax/CHANGELOG.md # packages/espresso/CHANGELOG.md # packages/extension_google_sign_in_as_googleapis_auth/CHANGELOG.md # packages/file_selector/file_selector/CHANGELOG.md # packages/file_selector/file_selector_android/CHANGELOG.md # packages/flutter_plugin_android_lifecycle/CHANGELOG.md # packages/google_fonts/CHANGELOG.md # packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md # packages/google_sign_in/google_sign_in/CHANGELOG.md # packages/image_picker/image_picker/CHANGELOG.md # packages/image_picker/image_picker_android/CHANGELOG.md # packages/in_app_purchase/in_app_purchase/CHANGELOG.md # packages/in_app_purchase/in_app_purchase_android/CHANGELOG.md # packages/interactive_media_ads/CHANGELOG.md # packages/local_auth/local_auth/CHANGELOG.md # packages/local_auth/local_auth_android/CHANGELOG.md # packages/path_provider/path_provider/CHANGELOG.md # packages/pigeon/CHANGELOG.md # packages/quick_actions/quick_actions/CHANGELOG.md # packages/quick_actions/quick_actions_android/CHANGELOG.md # packages/rfw/CHANGELOG.md # packages/shared_preferences/shared_preferences/CHANGELOG.md # packages/shared_preferences/shared_preferences_android/CHANGELOG.md # packages/two_dimensional_scrollables/CHANGELOG.md # packages/url_launcher/url_launcher/CHANGELOG.md # packages/url_launcher/url_launcher_android/CHANGELOG.md # packages/video_player/video_player/CHANGELOG.md # packages/video_player/video_player_android/CHANGELOG.md # packages/webview_flutter/webview_flutter/CHANGELOG.md # packages/webview_flutter/webview_flutter_android/CHANGELOG.md
I propose adding a CI workflow that verifies every Android-capable package in the repository builds successfully with both Android Gradle Plugin (AGP) 8.x and 9.x like: name: Android AGP compatibility
on:
push:
branches: [master, main]
pull_request:
branches: [master, main]
workflow_dispatch:
permissions:
contents: read
jobs:
discover-examples:
runs-on: ubuntu-latest
outputs:
examples: ${{ steps.find.outputs.examples }}
steps:
- uses: actions/checkout@v6
- name: Discover Android examples
id: find
run: |
# Find all example/android/settings.gradle.kts across packages/ and third_party/packages/
examples=$(find packages third_party/packages -path "*/example/android/settings.gradle.kts" \
-not -path "*/build/*" \
2>/dev/null \
| sed 's|/android/settings.gradle.kts||' \
| sort \
| jq -R -s -c 'split("\n") | map(select(length > 0))')
echo "examples=$examples" >> "$GITHUB_OUTPUT"
echo "Found examples:"
echo "$examples" | jq .
android-agp-matrix:
needs: discover-examples
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
example: ${{ fromJson(needs.discover-examples.outputs.examples) }}
agp:
- lane: agp-8.x
agp_version: "8.9.1"
gradle_version: "8.14.3"
kotlin_version: "2.2.20"
built_in_kotlin: ""
- lane: agp-9.x
agp_version: "9.2.1"
gradle_version: "9.5.0"
kotlin_version: "2.3.21"
built_in_kotlin: "false"
name: "${{ matrix.example }} — ${{ matrix.agp.lane }}"
steps:
- uses: actions/checkout@v6
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '17'
- uses: subosito/flutter-action@v2
with:
flutter-version: 3.32.8
cache: true
- name: Show toolchain versions
run: |
flutter --version
java -version
- name: Patch Android config for ${{ matrix.agp.lane }}
shell: bash
env:
AGP_VERSION: ${{ matrix.agp.agp_version }}
GRADLE_VERSION: ${{ matrix.agp.gradle_version }}
KOTLIN_VERSION: ${{ matrix.agp.kotlin_version }}
BUILT_IN_KOTLIN: ${{ matrix.agp.built_in_kotlin }}
EXAMPLE_DIR: ${{ matrix.example }}
run: |
python3 <<'PY'
from pathlib import Path
import os
import re
import sys
agp_version = os.environ['AGP_VERSION']
gradle_version = os.environ['GRADLE_VERSION']
kotlin_version = os.environ['KOTLIN_VERSION']
built_in_kotlin = os.environ['BUILT_IN_KOTLIN']
example_dir = Path(os.environ['EXAMPLE_DIR'])
def patch_settings(settings_file):
"""Patch AGP and Kotlin versions in a settings.gradle.kts file."""
if not settings_file.exists():
return
settings = settings_file.read_text()
# Patch AGP (com.android.application or com.android.library)
settings, n = re.subn(
r'id\("com\.android\.(application|library)"\) version "[^"]+" apply false',
lambda m: f'id("com.android.{m.group(1)}") version "{agp_version}" apply false',
settings,
)
if n == 0:
print(f"⚠️ No AGP plugin found in {settings_file}, skipping AGP patch.")
# Patch Kotlin version
settings, n = re.subn(
r'id\("org\.jetbrains\.kotlin\.android"\) version "[^"]+" apply false',
f'id("org.jetbrains.kotlin.android") version "{kotlin_version}" apply false',
settings,
)
if n == 0:
print(f"⚠️ No Kotlin plugin found in {settings_file}, skipping Kotlin patch.")
settings_file.write_text(settings)
print(f"✅ Patched {settings_file}")
def patch_wrapper(wrapper_file):
"""Patch Gradle distribution version."""
if not wrapper_file.exists():
return
wrapper = wrapper_file.read_text()
wrapper, n = re.subn(
r'gradle-[^-]+-all\.zip',
f'gradle-{gradle_version}-all.zip',
wrapper, count=1,
)
if n != 1:
print(f"⚠️ Could not patch Gradle wrapper in {wrapper_file}")
sys.exit(1)
wrapper_file.write_text(wrapper)
print(f"✅ Patched {wrapper_file}")
def patch_gradle_properties(props_file):
"""Patch builtInKotlin flag."""
if not props_file.exists():
return
filtered_lines = []
for line in props_file.read_text().splitlines():
if line.startswith('android.builtInKotlin='):
continue
if line.strip() == '# This builtInKotlin flag was added automatically by Flutter migrator':
continue
filtered_lines.append(line)
if built_in_kotlin:
filtered_lines.append(f'android.builtInKotlin={built_in_kotlin}')
props_file.write_text('\n'.join(filtered_lines) + '\n')
print(f"✅ Patched {props_file}")
# 1. Patch the example's android/ directory
example_android = example_dir / 'android'
if not (example_android / 'settings.gradle.kts').exists():
print(f"⚠️ {example_android / 'settings.gradle.kts'} not found, skipping.")
sys.exit(0)
patch_settings(example_android / 'settings.gradle.kts')
patch_wrapper(example_android / 'gradle' / 'wrapper' / 'gradle-wrapper.properties')
patch_gradle_properties(example_android / 'gradle.properties')
# 2. Patch the parent package's android/ directory (plugin library project)
# The package root is the parent of the example/ directory.
package_android = example_dir.parent / 'android'
if (package_android / 'settings.gradle.kts').exists():
print(f"📦 Also patching plugin package at {package_android}")
patch_settings(package_android / 'settings.gradle.kts')
patch_wrapper(package_android / 'gradle' / 'wrapper' / 'gradle-wrapper.properties')
patch_gradle_properties(package_android / 'gradle.properties')
print("🎉 All patching complete.")
PY
- name: Show Android diff
run: |
# Show diff for the example's android dir
git --no-pager diff -- "${{ matrix.example }}/android" | cat
# Show diff for the parent package's android dir (if it exists)
PACKAGE_ANDROID="$(dirname "${{ matrix.example }}")/android"
if [ -d "$PACKAGE_ANDROID" ]; then
git --no-pager diff -- "$PACKAGE_ANDROID" | cat
fi
- name: Install dependencies
working-directory: ${{ matrix.example }}
run: flutter pub get
- name: Build Android APK (debug)
working-directory: ${{ matrix.example }}
run: flutter build apk --debug
What do you think? I appreciate your opinion. @reidbaker @jesswrd |
Fixes flutter/flutter#186795
Pre-Review Checklist
[shared_preferences]///).Explanation:
Updates
build.gradle.ktsfiles across multiple Flutter plugin examples and Android library modules to conditionally apply the Kotlin Android plugin. AGP 9.0 introduces built-in Kotlin support, making explicit application of thekotlin-androidplugin redundant unless specifically disabled.Changes
id("kotlin-android")and added logic to check theANDROID_GRADLE_PLUGIN_VERSION. Theorg.jetbrains.kotlin.androidplugin is now applied programmatically only if the AGP version is below 9 or if theandroid.builtInKotlinGradle property is set to false.kotlinOptionsin a conditional block. When built-in Kotlin is active (AGP 9+), the explicitkotlinOptionsblock is skipped. When inactive, it useswithGroovyBuilderto setjvmTargettoVERSION_17, ensuring compatibility without causing build script evaluation errors when the plugin is absent.camera,google_maps_flutter,image_picker,video_player,webview_flutter,shared_preferences, andpigeon.Test plan
These changes ensure that plugin examples and libraries remain compatible across a range of AGP versions, specifically handling the transition to built-in Kotlin support in AGP 9.0 while maintaining backward compatibility for older environments.
based into: #11692