Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add documentation for migrating Android build files to declarative form #135392

Closed
bartekpacia opened this issue Sep 24, 2023 · 8 comments · Fixed by flutter/website#9857
Closed
Labels
d: api docs Issues with https://api.flutter.dev/ P2 Important issues not at the top of the work list platform-android Android applications specifically t: gradle "flutter build" and "flutter run" on Android team-tool Owned by Flutter Tool team tool Affects the "flutter" command-line tool. See also t: labels. triaged-tool Triaged by Flutter Tool team

Comments

@bartekpacia
Copy link
Member

bartekpacia commented Sep 24, 2023

Overview

Gradle files in the android directory of a Flutter app proejct were recently refactored. This work is discussed in much more detail in the following issues (and respective PRs that fixed them):

New flutter created apps will use the updated buildscript templates automatically. Existing apps aren't migrated though. Doing so automatically (using the tool's Migrator API) would be hard to do and error prone, and even then it would only work for projects that didn't substantially modify the buildscripts (which most apps do at some point).

This issue is about writing a migration guide where all these changes would be explained, so developers could easily update the native buildscripts.

Changes

Below is a summary of what default Gradle build files look like in a few latest Flutter versions. They're taken from the default app generated with flutter create example.

A migration guide should take into account that different apps were generated with different versions of Flutter.

Flutter 3.10

Released on May 10th, 2023.

Gradle build files didn't change much (at all) in previous Flutter versions.

android/settings.gradle
include ':app'

def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
def properties = new Properties()

assert localPropertiesFile.exists()
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }

def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
android/build.gradle
buildscript {
    ext.kotlin_version = '1.7.10'
    repositories {
        google()
        mavenCentral()
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:7.3.0'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

allprojects {
    repositories {
        google()
        mavenCentral()
    }
}

rootProject.buildDir = '../build'
subprojects {
    project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
    project.evaluationDependsOn(':app')
}

tasks.register("clean", Delete) {
    delete rootProject.buildDir
}
android/app/build.gradle
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
    localPropertiesFile.withReader('UTF-8') { reader ->
        localProperties.load(reader)
    }
}

def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
    throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}

def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
    flutterVersionCode = '1'
}

def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
    flutterVersionName = '1.0'
}

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"

android {
    compileSdkVersion flutter.compileSdkVersion
    ndkVersion flutter.ndkVersion

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    kotlinOptions {
        jvmTarget = '1.8'
    }

    sourceSets {
        main.java.srcDirs += 'src/main/kotlin'
    }

    defaultConfig {
        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
        applicationId "com.example.example"
        // You can update the following values to match your application needs.
        // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration.
        minSdkVersion flutter.minSdkVersion
        targetSdkVersion flutter.targetSdkVersion
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            // TODO: Add your own signing config for the release build.
            // Signing with the debug keys for now, so `flutter run --release` works.
            signingConfig signingConfigs.debug
        }
    }
}

flutter {
    source '../..'
}

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}

Flutter 3.13

Released on August 16th, 2023.

android/settings.gradle
pluginManagement {
    def flutterSdkPath = {
        def properties = new Properties()
        file("local.properties").withInputStream { properties.load(it) }
        def flutterSdkPath = properties.getProperty("flutter.sdk")
        assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
        return flutterSdkPath
    }
    settings.ext.flutterSdkPath = flutterSdkPath()

    includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")

    plugins {
        id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false
    }
}

include ":app"

apply from: "${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle/app_plugin_loader.gradle"
android/build.gradle
buildscript {
    ext.kotlin_version = '1.7.10'
    repositories {
        google()
        mavenCentral()
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:7.3.0'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

allprojects {
    repositories {
        google()
        mavenCentral()
    }
}

rootProject.buildDir = '../build'
subprojects {
    project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
    project.evaluationDependsOn(':app')
}

tasks.register("clean", Delete) {
    delete rootProject.buildDir
}
android/app/build.gradle
plugins {
    id "com.android.application"
    id "kotlin-android"
    id "dev.flutter.flutter-gradle-plugin"
}

def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
    localPropertiesFile.withReader('UTF-8') { reader ->
        localProperties.load(reader)
    }
}

def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
    flutterVersionCode = '1'
}

def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
    flutterVersionName = '1.0'
}

android {
    namespace "com.example.example"
    compileSdkVersion flutter.compileSdkVersion
    ndkVersion flutter.ndkVersion

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    kotlinOptions {
        jvmTarget = '1.8'
    }

    sourceSets {
        main.java.srcDirs += 'src/main/kotlin'
    }

    defaultConfig {
        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
        applicationId "com.example.example"
        // You can update the following values to match your application needs.
        // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
        minSdkVersion flutter.minSdkVersion
        targetSdkVersion flutter.targetSdkVersion
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }

    buildTypes {
        release {
            // TODO: Add your own signing config for the release build.
            // Signing with the debug keys for now, so `flutter run --release` works.
            signingConfig signingConfigs.debug
        }
    }
}

flutter {
    source '../..'
}

dependencies {}

Flutter 3.16

Released on November 15th, 2023.

android/settings.gradle
pluginManagement {
    def flutterSdkPath = {
        def properties = new Properties()
        file("local.properties").withInputStream { properties.load(it) }
        def flutterSdkPath = properties.getProperty("flutter.sdk")
        assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
        return flutterSdkPath
    }
    settings.ext.flutterSdkPath = flutterSdkPath()

    includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")

    repositories {
        google()
        mavenCentral()
        gradlePluginPortal()
    }

    plugins {
        id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false
    }
}

plugins {
    id "dev.flutter.flutter-plugin-loader" version "1.0.0"
    id "com.android.application" version "7.3.0" apply false
}

include ":app"
android/build.gradle
buildscript {
    ext.kotlin_version = '1.7.10'
    repositories {
        google()
        mavenCentral()
    }

    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

allprojects {
    repositories {
        google()
        mavenCentral()
    }
}

rootProject.buildDir = '../build'
subprojects {
    project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
    project.evaluationDependsOn(':app')
}

tasks.register("clean", Delete) {
    delete rootProject.buildDir
}
android/app/build.gradle
plugins {
    id "com.android.application"
    id "kotlin-android"
    id "dev.flutter.flutter-gradle-plugin"
}

def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
    localPropertiesFile.withReader('UTF-8') { reader ->
        localProperties.load(reader)
    }
}

def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
    flutterVersionCode = '1'
}

def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
    flutterVersionName = '1.0'
}

android {
    namespace "com.example.example"
    compileSdkVersion flutter.compileSdkVersion
    ndkVersion flutter.ndkVersion

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    kotlinOptions {
        jvmTarget = '1.8'
    }

    sourceSets {
        main.java.srcDirs += 'src/main/kotlin'
    }

    defaultConfig {
        applicationId "com.example.example"
        minSdkVersion flutter.minSdkVersion
        targetSdkVersion flutter.targetSdkVersion
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }

    buildTypes {
        release {
            signingConfig signingConfigs.debug
        }
    }
}

flutter {
    source '../..'
}

dependencies {}

Flutter 3.19

Released on February 15th, 2024.

android/settings.gradle
pluginManagement {
    def flutterSdkPath = {
        def properties = new Properties()
        file("local.properties").withInputStream { properties.load(it) }
        def flutterSdkPath = properties.getProperty("flutter.sdk")
        assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
        return flutterSdkPath
    }
    settings.ext.flutterSdkPath = flutterSdkPath()

    includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")

    repositories {
        google()
        mavenCentral()
        gradlePluginPortal()
    }
}

plugins {
    id "dev.flutter.flutter-plugin-loader" version "1.0.0"
    id "com.android.application" version "7.3.0" apply false
    id "org.jetbrains.kotlin.android" version "1.7.10" apply false
}

include ":app"
android/build.gradle
allprojects {
    repositories {
        google()
        mavenCentral()
    }
}

rootProject.buildDir = '../build'
subprojects {
    project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
    project.evaluationDependsOn(':app')
}

tasks.register("clean", Delete) {
    delete rootProject.buildDir
}
android/app/build.gradle
plugins {
    id "com.android.application"
    id "kotlin-android"
    id "dev.flutter.flutter-gradle-plugin"
}

def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
    localPropertiesFile.withReader('UTF-8') { reader ->
        localProperties.load(reader)
    }
}

def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
    flutterVersionCode = '1'
}

def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
    flutterVersionName = '1.0'
}

android {
    namespace "com.example.example"
    compileSdk flutter.compileSdkVersion
    ndkVersion flutter.ndkVersion

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    kotlinOptions {
        jvmTarget = '1.8'
    }

    sourceSets {
        main.java.srcDirs += 'src/main/kotlin'
    }

    defaultConfig {
        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
        applicationId "com.example.example"
        // You can update the following values to match your application needs.
        // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
        minSdkVersion flutter.minSdkVersion
        targetSdkVersion flutter.targetSdkVersion
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }

    buildTypes {
        release {
            // TODO: Add your own signing config for the release build.
            // Signing with the debug keys for now, so `flutter run --release` works.
            signingConfig signingConfigs.debug
        }
    }
}

flutter {
    source '../..'
}

dependencies {}

Future changes

I'll do my best to keep this issue updated.

@darshankawar darshankawar added in triage Presently being triaged by the triage team platform-android Android applications specifically tool Affects the "flutter" command-line tool. See also t: labels. d: api docs Issues with https://api.flutter.dev/ t: gradle "flutter build" and "flutter run" on Android team-tool Owned by Flutter Tool team and removed in triage Presently being triaged by the triage team labels Sep 25, 2023
@christopherfujino christopherfujino added P2 Important issues not at the top of the work list triaged-tool Triaged by Flutter Tool team labels Sep 26, 2023
@firephreek
Copy link

It might've been more helpful to have the docs outlining the migration or at least some guidance in the templates themselves prior to having this pushed out. I think it pre-dates this commit, but having the flutter gradle plugin identifer as flutter makes aspects of build.gradle confusing. In particular, a user has to know that even though a convention has been established of using the local.properties file (per docs) for configuring values like flutter.versionCode, (e.g. localProperties.getProperty('flutter.versionCode')), setting other similar properties like 'flutter.minSdkVersion=31' in that same file will have no effect despite that very property being referenced in app/build.gradle (ala minSdkVersion flutter.minSdkVersion). More, without knowing how or where that plugin is being loaded from and without digging into the source code itself, there's no way to know that the identifier is just flutter instead of, say flutterGradlePlugin which would make that much more self evident. The indirection, while simplifying on the face, means I've spent more time trying to understand what's going on because 'obvious' wasn't working.

@bartekpacia
Copy link
Member Author

I think it pre-dates this commit, but having the flutter gradle plugin identifer as flutter makes aspects of build.gradle confusing.

That's right.

In general, I think the topic you're talking about deserves a separate issue.

@Gustl22
Copy link
Contributor

Gustl22 commented Nov 10, 2023

Also pay attention to #54566 which still is used and needs migration for previous versions since v1.20.0.

@asaarnak
Copy link
Contributor

asaarnak commented Nov 24, 2023

@bartekpacia
Thank you for a very nice overview of differences between flutter versions!
We have migrated manually and are using these plugins:

plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id 'dev.flutter.flutter-gradle-plugin'
    id 'com.google.gms.google-services'
    id 'com.google.firebase.crashlytics'
    id 'com.google.firebase.firebase-perf'
}

@bartekpacia
Copy link
Member Author

bartekpacia commented Nov 24, 2023

@asaarnak Glad to hear that!

In settings.gradle you can also remove these lines (even if you're not on Flutter master):

plugins {
    id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false
}

It's not needed at all. Just saying in case you have it in your project:)

@asaarnak
Copy link
Contributor

asaarnak commented Nov 24, 2023

@bartekpacia
Thanks.
Yep, we already migrated to the Flutter master changes
and removed plugins block under pluginManagement
and it works on stable.

Our settings.gradle root plugins block looks like this:

plugins {
    id 'dev.flutter.flutter-plugin-loader' version '1.0.0'
    id 'com.android.application' version '8.3.0-alpha14' apply false
    id 'org.jetbrains.kotlin.android' version '1.9.21' apply false
    id 'com.google.gms.google-services' version '4.4.0' apply false
    id 'com.google.firebase.crashlytics' version '2.9.9' apply false
    id 'com.google.firebase.firebase-perf' version '1.4.2' apply false
}

sfshaza2 pushed a commit to flutter/website that referenced this issue Dec 8, 2023
This PR adds a guide explaining how to migrate from _imperative apply_
of Flutter's Gradle plugins to _declarative apply_.

Resolves flutter/flutter#135392

## Presubmit checklist

- [x] This PR doesn’t contain automatically generated corrections
(Grammarly or similar).
- [x] This PR follows the [Google Developer Documentation Style
Guidelines](https://developers.google.com/style) — for example, it
doesn’t use _i.e._ or _e.g._, and it avoids _I_ and _we_ (first person).
- [x] This PR uses [semantic line
breaks](https://github.com/dart-lang/site-shared/blob/main/doc/writing-for-dart-and-flutter-websites.md#semantic-line-breaks)
of 80 characters or fewer.


## Preview


[here](https://flutter-docs-prod--pr9857-migration-guide-gradle-plugi-vyllekcb.web.app/release/breaking-changes/flutter-gradle-plugin-apply)

---------

Co-authored-by: Anthony Sansone <atsansone@users.noreply.github.com>
Co-authored-by: Gustl22 <git@reb0.org>
atsansone added a commit to atsansone/website that referenced this issue Dec 11, 2023
This PR adds a guide explaining how to migrate from _imperative apply_
of Flutter's Gradle plugins to _declarative apply_.

Resolves flutter/flutter#135392

## Presubmit checklist

- [x] This PR doesn’t contain automatically generated corrections
(Grammarly or similar).
- [x] This PR follows the [Google Developer Documentation Style
Guidelines](https://developers.google.com/style) — for example, it
doesn’t use _i.e._ or _e.g._, and it avoids _I_ and _we_ (first person).
- [x] This PR uses [semantic line
breaks](https://github.com/dart-lang/site-shared/blob/main/doc/writing-for-dart-and-flutter-websites.md#semantic-line-breaks)
of 80 characters or fewer.


## Preview


[here](https://flutter-docs-prod--pr9857-migration-guide-gradle-plugi-vyllekcb.web.app/release/breaking-changes/flutter-gradle-plugin-apply)

---------

Co-authored-by: Anthony Sansone <atsansone@users.noreply.github.com>
Co-authored-by: Gustl22 <git@reb0.org>
auto-submit bot pushed a commit that referenced this issue Dec 13, 2023
…ethod" way (#139690)

This PR adds a deprecation message when Android build is using the legacy "apply script method" way of applying Flutter's Gradle plugins (that is: [`flutter.gradle`](https://github.com/flutter/flutter/blob/3.16.0/packages/flutter_tools/gradle/flutter.gradle) and [`app_plugin_loader.gradle`](https://github.com/flutter/flutter/blob/3.16.0/packages/flutter_tools/gradle/app_plugin_loader.gradle)).

See also:
- #121541
  - in particular #121541 (comment)
- #135392
  - and PR that add the migration guide: [#9857](flutter/website#9857)

- I think either `logger.error` or `logger.quiet` must be used, because all other error levels are not shown during `flutter build apk` (and that's what most people use).
auto-submit bot added a commit that referenced this issue Dec 13, 2023
… script method" way" (#140102)

Reverts #139690
Initiated by: hellohuanlin
This change reverts the following previous change:
Original Description:
This PR adds a deprecation message when Android build is using the legacy "apply script method" way of applying Flutter's Gradle plugins (that is: [`flutter.gradle`](https://github.com/flutter/flutter/blob/3.16.0/packages/flutter_tools/gradle/flutter.gradle) and [`app_plugin_loader.gradle`](https://github.com/flutter/flutter/blob/3.16.0/packages/flutter_tools/gradle/app_plugin_loader.gradle)).

See also:
- #121541
  - in particular #121541 (comment)
- #135392
  - and PR that add the migration guide: [#9857](flutter/website#9857)

- I think either `logger.error` or `logger.quiet` must be used, because all other error levels are not shown during `flutter build apk` (and that's what most people use).
bartekpacia added a commit to bartekpacia/flutter that referenced this issue Dec 14, 2023
…ethod" way (flutter#139690)

This PR adds a deprecation message when Android build is using the legacy "apply script method" way of applying Flutter's Gradle plugins (that is: [`flutter.gradle`](https://github.com/flutter/flutter/blob/3.16.0/packages/flutter_tools/gradle/flutter.gradle) and [`app_plugin_loader.gradle`](https://github.com/flutter/flutter/blob/3.16.0/packages/flutter_tools/gradle/app_plugin_loader.gradle)).

See also:
- flutter#121541
  - in particular flutter#121541 (comment)
- flutter#135392
  - and PR that add the migration guide: [flutter#9857](flutter/website#9857)

- I think either `logger.error` or `logger.quiet` must be used, because all other error levels are not shown during `flutter build apk` (and that's what most people use).
auto-submit bot pushed a commit that referenced this issue Dec 19, 2023
…cript method (#140103)

> This PR relands #139690 which was reverted in #140102

This PR adds a deprecation message when Android build is using the legacy "apply script method" way of applying Flutter's Gradle plugins (that is: [`flutter.gradle`](https://github.com/flutter/flutter/blob/3.16.0/packages/flutter_tools/gradle/flutter.gradle) and [`app_plugin_loader.gradle`](https://github.com/flutter/flutter/blob/3.16.0/packages/flutter_tools/gradle/app_plugin_loader.gradle)).

See also:
- #121541
  - in particular #121541 (comment)
- #135392
  - and PR that add the migration guide: [#9857](flutter/website#9857)

- I think either `logger.error` or `logger.quiet` must be used, because all other error levels are not shown during `flutter build apk` (and that's what most people use).
Copy link

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Dec 22, 2023
@bartekpacia
Copy link
Member Author

To whoever reads this issue in a future: if you encounter any problems while migrating, please create a new issue or ask on StackOverflow.

Thanks!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
d: api docs Issues with https://api.flutter.dev/ P2 Important issues not at the top of the work list platform-android Android applications specifically t: gradle "flutter build" and "flutter run" on Android team-tool Owned by Flutter Tool team tool Affects the "flutter" command-line tool. See also t: labels. triaged-tool Triaged by Flutter Tool team
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants