Skip to content

Refactor the way Android Plugins are included #29328

Closed

Description

@dnfield

Today, we include plugins directly as subprojects. This causes problems when there are dependency conflicts, and tools like Jetifier that should be able to help us resolve them aren't set up to run on subprojects (they assume the project will more or less internally consistent). In particular, this has caused problems for Android X (#23586 #27106). It's also meaningful for Add2App use cases, where we have customers who want to distribute Flutter in a more modular fashion (e.g. as AARs rather than as source code). The main concern right now is solving the Android X headaches though. The following dependencies in pubspec.yaml would cause an android project to fail to build because of such conflicts:

dependencies:
  shared_preferences: any
  flutter:
    sdk: flutter
  camera: 0.2.6
  firebase_auth: any

A quick POC resolves a lot of these problems:

  • Include plugins as includeBuild in settings.gradle rather than as a subproject.
  • Specify dependencies on plugins in the dependencies section of app/build.gradle.
  • For each plugin, make sure it has all of its dependencies specified correctly in its build.gradle (including a dependency on flutter.jar).

For example:

Change android/settings.gradle's plugins.each to:

plugins.each { name, path ->
    includeBuild "$path/android"
}

Remove the subprojects from android/build.gradle and align the gradle plugin with other plugins' requirements:

...
        classpath 'com.android.tools.build:gradle:3.3.1'
...
rootProject.buildDir = '../build'
// subprojects {
//     project.buildDir = "${rootProject.buildDir}/${project.name}"
// }
// subprojects {
//     project.evaluationDependsOn(':app')
// }
...

Add the right dependencies to android/app/build.gradle:

dependencies {
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    implementation 'io.flutter.plugins.sharedpreferences:shared_preferences:1.0.0'
    implementation 'io.flutter.plugins.firebase.core:firebase_core:1.0.0'
    implementation 'io.flutter.plugins.firebaseauth:firebase_auth:1.0.0'
    implementation 'io.flutter.plugins.camera:camera:1.0.0'
}

This also requires changes in each plugin's build.gradle, at a minimum:

dependencies {
    api files('/Path/to/flutter/bin/cache/artifacts/engine/android-arm/flutter.jar')
}

The includeBuild method will get Gradle to build all these projects with one command, but is not ideal because it requires that all projects use the same gradle plugin version.

To remedy this, we should teach the flutter tool and/or flutter.gradle how to build Android plugins directly. This may end up including updating the plugin's gradle configuration so that it more correctly specifies its dependencies, including a dependency on flutter.jar from the framework/engine. We need to figure out if we can do that purely through the DSL or whether we'd actually have to generate a new build.gradle file for these purposes.

/cc @mklim @amirh @matthew-carroll @csells

Activity

  1. added
    platform-androidAndroid applications specifically
    toolAffects the "flutter" command-line tool. See also t: labels.
    t: gradle"flutter build" and "flutter run" on Android
    a: existing-appsIntegration with existing apps via the add-to-app flow
    on Mar 13, 2019
  2. added this to the milestone on Mar 13, 2019
  3. dnfield commented on Mar 13, 2019

    @dnfield
    ContributorAuthor

    Depending on what the solution ends up looking like in the end, we may want to distribute some of this work independently from Flutter tool - perhaps as an independent gradle plugin or as Dart package - so that we could retroactively apply this to stable channel without requiring an upgrade.

  4. mklim commented on Mar 14, 2019

    @mklim
    Contributor

    I've had to tweak these steps slightly to get the proof of concept working on my machine.

    • Copied the android/local.properties from my app to the android dir of all the different plugin repos to get around a missing sdk error. I do have $ANDROID_HOME set in my environment correctly so this shouldn't theoretically be necessary, probably some strange things going on there.
    • Added the flutter jar dependency as a compileOnly instead of api to avoid a duplicate classpath conflict.
  5. mklim commented on Mar 15, 2019

    @mklim
    Contributor

    I put up a very rough WIP of building the plugins as AARs and then including them at runtime at #29460. It's not ready to merge yet though, mostly because it's still blocked on two larger problems:

    1. It requires apps to manually remove the subprojects declarations from android/build.gradle and the plugins.each loop from android/settings.gradle like mentioned in the first comment of this issue. I think arguably this shouldn't require manual intervention to work at all, but if it does we need to gate it behind a check for the changes and use the current logic still otherwise.
    2. Transitive gradle dependencies within our Flutter plugins cause crashes at runtime, since the inner deps aren't included. As it is the patch requires apps to manually include all jars depended on by their plugins at runtime
  6. rmtmckenzie commented on Mar 22, 2019

    @rmtmckenzie
    Contributor

    Since this is being worked on now, something to consider... some of the APIs from the compat/androidx libraries depend on FragmentActivity being passed to them rather than a Context or Activity. In any plugins in the current system that basically means trying to cast the activity that is passed into the plugin to FragmentActivity and failing if the activity isn't a compat/androidx library.

    A good example of this is the androidx biometric library's BiometricPrompt which takes a FragmentActivity.

    Also see issue #29819 which describes a problem with FlutterFragmentActivity when using the AndroidX libraries - I don't know if that's something that would be affected by this work or not.

  7. dnfield commented on Mar 25, 2019

    @dnfield
    ContributorAuthor

    @rmtmckenzie - @matthew-carroll is working on a larger project to make that possible AFAIK

  8. matthew-carroll commented on Mar 25, 2019

    @matthew-carroll
    Contributor

    FYI @dnfield @mklim I've got a thread going on over in #29819 that will probably resolve @rmtmckenzie's comment, but it's unclear what the solution is. We're facing an AndroidX vs support lib problem. Have either of your efforts treated that issue at-large?

  9. 14 remaining items

  10. added
    P1High-priority issues at the top of the work list
    on May 29, 2020
  11. modified the milestone: on Jun 1, 2020
  12. modified the milestone: on Jul 7, 2020
  13. removed this from the milestone on Jul 22, 2020
  14. added
    P2Important issues not at the top of the work list
    and removed
    P1High-priority issues at the top of the work list
    on Aug 4, 2020
  15. removed this from the milestone on Aug 17, 2020
  16. blasten commented on Oct 31, 2021

    @blasten

    Refactoring the way Android plugins are included in Flutter won't provide additional benefits at the moment.
    The task itself is expensive to implement. It will also increase build times, will require different code paths for local plugin development, and maintaining a service for hosting 3P maven packages.

    Due to the above, this feature is out-of-scope, and unlikely to be implemented.

  17. github-actions commented on Nov 14, 2021

    @github-actions

    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.

  18. locked as resolved and limited conversation to collaborators on Nov 14, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Important issues not at the top of the work lista: existing-appsIntegration with existing apps via the add-to-app flowpackageflutter/packages repository. See also p: labels.platform-androidAndroid applications specificallyt: gradle"flutter build" and "flutter run" on AndroidtoolAffects the "flutter" command-line tool. See also t: labels.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions