Flutter 1.17.2 cherrypicks (#58050)

* fix segment hit test behavior (#57461)

* Making DropdownButtonFormField to re-render if parent widget changes (#57037)

* Update DropdownButtonFormField's state if widget updates

Co-authored-by: Shi-Hao Hong <shihaohong@google.com>

* throw more specific toolexit when git fails during upgrade (#57162)

* [flutter_tools] Refresh VM state before executing hot reload (#53960)

* Update engine hash for 1.17.2

* Remove MaterialControls from examples/flutter_view (#57621)

Co-authored-by: Jenn Magder <magder@google.com>

* Prevent building non-android plugins in build aar (#58018)

* Allow FLUTTER_APPLICATION_PATH to be null for misconfigured Xcode projects (#57701)

* Don't import plugins that don't support android in settings.gradle (#54407)

Co-authored-by: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com>
Co-authored-by: Pedro Massango <pedromassango.developer@gmail.com>
Co-authored-by: Shi-Hao Hong <shihaohong@google.com>
Co-authored-by: Christopher Fujino <christopherfujino@gmail.com>
Co-authored-by: Jason Simmons <jason-simmons@users.noreply.github.com>
Co-authored-by: stuartmorgan <stuartmorgan@google.com>
Co-authored-by: Jenn Magder <magder@google.com>
Co-authored-by: Emmanuel Garcia <egarciad@google.com>
diff --git a/bin/internal/engine.version b/bin/internal/engine.version
index d9d42ce..ed199b1 100644
--- a/bin/internal/engine.version
+++ b/bin/internal/engine.version
@@ -1 +1 @@
-6bc433c6b6b5b98dcf4cc11aff31cdee90849f32
+b851c718295a896918dc93cb1ff14f2f895a1b90
diff --git a/dev/benchmarks/macrobenchmarks/android/settings.gradle b/dev/benchmarks/macrobenchmarks/android/settings.gradle
index bef552e..d3b6a40 100644
--- a/dev/benchmarks/macrobenchmarks/android/settings.gradle
+++ b/dev/benchmarks/macrobenchmarks/android/settings.gradle
@@ -4,16 +4,12 @@
 
 include ':app'
 
-def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
 
-def plugins = new Properties()
-def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
-if (pluginsFile.exists()) {
-    pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
-}
+assert localPropertiesFile.exists()
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
 
-plugins.each { name, path ->
-    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
-    include ":$name"
-    project(":$name").projectDir = pluginDirectory
-}
+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"
diff --git a/dev/benchmarks/test_apps/stocks/android/settings.gradle b/dev/benchmarks/test_apps/stocks/android/settings.gradle
index dbc3b58..d3b6a40 100644
--- a/dev/benchmarks/test_apps/stocks/android/settings.gradle
+++ b/dev/benchmarks/test_apps/stocks/android/settings.gradle
@@ -4,16 +4,12 @@
 
 include ':app'
 
-def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
 
-def plugins = new Properties()
-def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
-if (pluginsFile.exists()) {
-    pluginsFile.withInputStream { stream -> plugins.load(stream) }
-}
+assert localPropertiesFile.exists()
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
 
-plugins.each { name, path ->
-    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
-    include ":$name"
-    project(":$name").projectDir = pluginDirectory
-}
+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"
diff --git a/dev/bots/test.dart b/dev/bots/test.dart
index b6dea10..318244f 100644
--- a/dev/bots/test.dart
+++ b/dev/bots/test.dart
@@ -976,6 +976,7 @@
     // TODO(ianh): Fails on macOS looking for "dexdump", https://github.com/flutter/flutter/issues/42494
     if (!Platform.isMacOS) () => _runDevicelabTest('gradle_jetifier_test', environment: gradleEnvironment),
     () => _runDevicelabTest('gradle_non_android_plugin_test', environment: gradleEnvironment),
+    () => _runDevicelabTest('gradle_deprecated_settings_test', environment: gradleEnvironment),
     () => _runDevicelabTest('gradle_plugin_bundle_test', environment: gradleEnvironment),
     () => _runDevicelabTest('gradle_plugin_fat_apk_test', environment: gradleEnvironment),
     () => _runDevicelabTest('gradle_plugin_light_apk_test', environment: gradleEnvironment),
diff --git a/dev/devicelab/bin/tasks/build_aar_module_test.dart b/dev/devicelab/bin/tasks/build_aar_module_test.dart
index 199e2ae..7711509 100644
--- a/dev/devicelab/bin/tasks/build_aar_module_test.dart
+++ b/dev/devicelab/bin/tasks/build_aar_module_test.dart
@@ -24,11 +24,11 @@
       return TaskResult.failure('Could not find Java');
     print('\nUsing JAVA_HOME=$javaHome');
 
-    section('Create module project');
-
     final Directory tempDir = Directory.systemTemp.createTempSync('flutter_module_test.');
     final Directory projectDir = Directory(path.join(tempDir.path, 'hello'));
     try {
+      section('Create module project');
+
       await inDirectory(tempDir, () async {
         await flutter(
           'create',
@@ -36,15 +36,55 @@
         );
       });
 
-      section('Add plugins');
+      section('Create plugin that supports android platform');
 
-      final File pubspec = File(path.join(projectDir.path, 'pubspec.yaml'));
-      String content = pubspec.readAsStringSync();
+      await inDirectory(tempDir, () async {
+        await flutter(
+          'create',
+          options: <String>['--org', 'io.flutter.devicelab', '--template', 'plugin', 'plugin_with_android'],
+        );
+      });
+
+      section('Create plugin that doesn\'t support android project');
+
+      await inDirectory(tempDir, () async {
+        await flutter(
+          'create',
+          options: <String>['--org', 'io.flutter.devicelab', '--template', 'plugin', 'plugin_without_android'],
+        );
+      });
+
+      // Delete the android/ directory.
+      File(path.join(
+        tempDir.path,
+        'plugin_without_android',
+        'android'
+      )).deleteSync(recursive: true);
+
+      // Remove Android support from the plugin pubspec.yaml
+      final File pluginPubspec = File(path.join(tempDir.path, 'plugin_without_android', 'pubspec.yaml'));
+      pluginPubspec.writeAsStringSync(pluginPubspec.readAsStringSync().replaceFirst('''
+      android:
+        package: io.flutter.devicelab.plugin_without_android
+        pluginClass: PluginWithoutAndroidPlugin
+''', ''), flush: true);
+
+      section('Add plugins to pubspec.yaml');
+
+      final File modulePubspec = File(path.join(projectDir.path, 'pubspec.yaml'));
+      String content = modulePubspec.readAsStringSync();
       content = content.replaceFirst(
         '\ndependencies:\n',
-        '\ndependencies:\n  device_info: 0.4.1\n  package_info: 0.4.0+9\n',
+        '\ndependencies:\n'
+          '  plugin_with_android:\n'
+          '    path: ../plugin_with_android\n'
+          '  plugin_without_android:\n'
+          '    path: ../plugin_without_android\n',
       );
-      pubspec.writeAsStringSync(content, flush: true);
+      modulePubspec.writeAsStringSync(content, flush: true);
+
+      section('Run packages get in module project');
+
       await inDirectory(projectDir, () async {
         await flutter(
           'packages',
@@ -57,7 +97,7 @@
       await inDirectory(projectDir, () async {
         await flutter(
           'build',
-          options: <String>['aar', '--release', '--verbose'],
+          options: <String>['aar', '--verbose'],
         );
       });
 
@@ -99,44 +139,22 @@
         repoPath,
         'io',
         'flutter',
-        'plugins',
-        'deviceinfo',
-        'device_info_release',
+        'devicelab',
+        'plugin_with_android',
+        'plugin_with_android_release',
         '1.0',
-        'device_info_release-1.0.aar',
+        'plugin_with_android_release-1.0.aar',
       ));
 
       checkFileExists(path.join(
         repoPath,
         'io',
         'flutter',
-        'plugins',
-        'deviceinfo',
-        'device_info_release',
+        'devicelab',
+        'plugin_with_android',
+        'plugin_with_android_release',
         '1.0',
-        'device_info_release-1.0.pom',
-      ));
-
-      checkFileExists(path.join(
-        repoPath,
-        'io',
-        'flutter',
-        'plugins',
-        'packageinfo',
-        'package_info_release',
-        '1.0',
-        'package_info_release-1.0.aar',
-      ));
-
-      checkFileExists(path.join(
-        repoPath,
-        'io',
-        'flutter',
-        'plugins',
-        'packageinfo',
-        'package_info_release',
-        '1.0',
-        'package_info_release-1.0.pom',
+        'plugin_with_android_release-1.0.pom',
       ));
 
       section('Check AOT blobs in release POM');
@@ -146,8 +164,7 @@
         'armeabi_v7a_release',
         'arm64_v8a_release',
         'x86_64_release',
-        'package_info_release',
-        'device_info_release',
+        'plugin_with_android_release',
       ], releasePom);
 
       section('Check assets in release AAR');
@@ -174,15 +191,6 @@
         )
       );
 
-      section('Build debug AAR');
-
-      await inDirectory(projectDir, () async {
-        await flutter(
-          'build',
-          options: <String>['aar', '--verbose', '--debug'],
-        );
-      });
-
       section('Check debug Maven artifacts');
 
       checkFileExists(path.join(
@@ -213,44 +221,22 @@
         repoPath,
         'io',
         'flutter',
-        'plugins',
-        'deviceinfo',
-        'device_info_debug',
+        'devicelab',
+        'plugin_with_android',
+        'plugin_with_android_debug',
         '1.0',
-        'device_info_debug-1.0.aar',
+        'plugin_with_android_debug-1.0.aar',
       ));
 
       checkFileExists(path.join(
         repoPath,
         'io',
         'flutter',
-        'plugins',
-        'deviceinfo',
-        'device_info_debug',
+        'devicelab',
+        'plugin_with_android',
+        'plugin_with_android_debug',
         '1.0',
-        'device_info_debug-1.0.pom',
-      ));
-
-      checkFileExists(path.join(
-        repoPath,
-        'io',
-        'flutter',
-        'plugins',
-        'packageinfo',
-        'package_info_debug',
-        '1.0',
-        'package_info_debug-1.0.aar',
-      ));
-
-      checkFileExists(path.join(
-        repoPath,
-        'io',
-        'flutter',
-        'plugins',
-        'packageinfo',
-        'package_info_debug',
-        '1.0',
-        'package_info_debug-1.0.pom',
+        'plugin_with_android_debug-1.0.pom',
       ));
 
       section('Check AOT blobs in debug POM');
@@ -261,8 +247,7 @@
         'x86_64_debug',
         'armeabi_v7a_debug',
         'arm64_v8a_debug',
-        'package_info_debug',
-        'device_info_debug',
+        'plugin_with_android_debug',
       ], debugPom);
 
       section('Check assets in debug AAR');
diff --git a/dev/devicelab/bin/tasks/flutter_view_ios__start_up.dart b/dev/devicelab/bin/tasks/flutter_view_ios__start_up.dart
index 21ec1e4..d761626 100644
--- a/dev/devicelab/bin/tasks/flutter_view_ios__start_up.dart
+++ b/dev/devicelab/bin/tasks/flutter_view_ios__start_up.dart
@@ -3,30 +3,12 @@
 // found in the LICENSE file.
 
 import 'dart:async';
-import 'dart:io';
 
-import 'package:flutter_devicelab/framework/utils.dart';
 import 'package:flutter_devicelab/tasks/perf_tests.dart';
 import 'package:flutter_devicelab/framework/adb.dart';
 import 'package:flutter_devicelab/framework/framework.dart';
 
 Future<void> main() async {
   deviceOperatingSystem = DeviceOperatingSystem.ios;
-  await task(() async {
-    final Directory iosDirectory = dir(
-      '${flutterDirectory.path}/examples/flutter_view/ios',
-    );
-    await inDirectory(iosDirectory, () async {
-      await exec(
-        'pod',
-        <String>['install'],
-        environment: <String, String>{
-          'LANG': 'en_US.UTF-8',
-        },
-      );
-    });
-
-    final TaskFunction taskFunction = createFlutterViewStartupTest();
-    return await taskFunction();
-  });
+  await task(createFlutterViewStartupTest());
 }
diff --git a/dev/devicelab/bin/tasks/gradle_deprecated_settings_test.dart b/dev/devicelab/bin/tasks/gradle_deprecated_settings_test.dart
new file mode 100644
index 0000000..1465891
--- /dev/null
+++ b/dev/devicelab/bin/tasks/gradle_deprecated_settings_test.dart
@@ -0,0 +1,57 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:flutter_devicelab/framework/framework.dart';
+import 'package:flutter_devicelab/framework/utils.dart';
+import 'package:path/path.dart' as path;
+
+/// Tests that apps can be built using the deprecated `android/settings.gradle` file.
+/// This test should be removed once apps have been migrated to this new file.
+// TODO(egarciad): Migrate existing files, https://github.com/flutter/flutter/issues/54566
+Future<void> main() async {
+  await task(() async {
+
+    section('Find Java');
+
+    final String javaHome = await findJavaHome();
+    if (javaHome == null)
+      return TaskResult.failure('Could not find Java');
+    print('\nUsing JAVA_HOME=$javaHome');
+
+    final Directory projectDirectory =
+        dir('${flutterDirectory.path}/dev/integration_tests/gradle_deprecated_settings');
+    try {
+      section('Build debug APK using deprecated settings.gradle');
+      await inDirectory(projectDirectory, () async {
+        await flutter(
+          'build',
+          options: <String>[
+            'apk',
+            '--debug',
+            '--target-platform', 'android-arm',
+            '--no-shrink',
+            '--verbose',
+          ],
+        );
+      });
+      final File debugApk = File(path.join(
+        projectDirectory.path,
+        'build',
+        'app',
+        'outputs',
+        'flutter-apk',
+        'app-debug.apk',
+      ));
+      if (!exists(debugApk)) {
+        return TaskResult.failure('Failed to build debug APK.');
+      }
+      return TaskResult.success(null);
+    } catch (e) {
+      return TaskResult.failure(e.toString());
+    }
+  });
+}
diff --git a/dev/devicelab/bin/tasks/gradle_migrate_settings_test.dart b/dev/devicelab/bin/tasks/gradle_migrate_settings_test.dart
index a9d5fff..4117e75 100644
--- a/dev/devicelab/bin/tasks/gradle_migrate_settings_test.dart
+++ b/dev/devicelab/bin/tasks/gradle_migrate_settings_test.dart
@@ -117,7 +117,7 @@
 
       section('Override settings.gradle with custom logic');
 
-      const String customDeprecatedFileContent = '''
+      const String customDeprecatedFileContent = r'''
 include ':app'
 
 def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
@@ -130,8 +130,8 @@
 
 plugins.each { name, path ->
     def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
-    include ":\$name"
-    project(":\$name").projectDir = pluginDirectory
+    include ":$name"
+    project(":$name").projectDir = pluginDirectory
 }
 // some custom logic
 ''';
diff --git a/dev/devicelab/bin/tasks/ios_content_validation_test.dart b/dev/devicelab/bin/tasks/ios_content_validation_test.dart
index 2137618..2f12097 100644
--- a/dev/devicelab/bin/tasks/ios_content_validation_test.dart
+++ b/dev/devicelab/bin/tasks/ios_content_validation_test.dart
@@ -24,19 +24,32 @@
             '--release',
             '--obfuscate',
             '--split-debug-info=foo/',
+            '--no-codesign',
           ]);
         });
+        final String buildPath = path.join(
+          flutterProject.rootPath,
+          'build',
+          'ios',
+          'iphoneos',
+        );
         final String outputAppPath = path.join(
-          flutterProject.rootPath,
-          'build/ios/iphoneos/Runner.app',
+          buildPath,
+          'Runner.app',
         );
-        final String outputAppFramework = path.join(
-          flutterProject.rootPath,
+        final Directory outputAppFramework = Directory(path.join(
           outputAppPath,
-          'Frameworks/App.framework/App',
-        );
-        if (!File(outputAppFramework).existsSync()) {
-          fail('Failed to produce expected output at $outputAppFramework');
+          'Frameworks',
+          'App.framework',
+        ));
+
+        final File outputAppFrameworkBinary = File(path.join(
+          outputAppFramework.path,
+          'App',
+        ));
+
+        if (!outputAppFrameworkBinary.existsSync()) {
+          fail('Failed to produce expected output at ${outputAppFrameworkBinary.path}');
         }
 
         section('Validate obfuscation');
@@ -46,7 +59,7 @@
         await inDirectory(flutterProject.rootPath, () async {
           final String response = await eval(
             'grep',
-            <String>[flutterProject.name, outputAppFramework],
+            <String>[flutterProject.name, outputAppFrameworkBinary.path],
             canFail: true,
           );
           if (response.trim().contains('matches')) {
@@ -56,16 +69,63 @@
 
         section('Validate bitcode');
 
-        final String outputFlutterFramework = path.join(
+        final Directory outputFlutterFramework = Directory(path.join(
           flutterProject.rootPath,
           outputAppPath,
-          'Frameworks/Flutter.framework/Flutter',
+          'Frameworks',
+          'Flutter.framework',
+        ));
+        final File outputFlutterFrameworkBinary = File(path.join(
+          outputFlutterFramework.path,
+          'Flutter',
+        ));
+
+        if (!outputFlutterFrameworkBinary.existsSync()) {
+          fail('Failed to produce expected output at ${outputFlutterFrameworkBinary.path}');
+        }
+        bitcode = await containsBitcode(outputFlutterFrameworkBinary.path);
+
+        section('Xcode backend script');
+
+        outputFlutterFramework.deleteSync(recursive: true);
+        outputAppFramework.deleteSync(recursive: true);
+        if (outputFlutterFramework.existsSync() || outputAppFramework.existsSync()) {
+          fail('Failed to delete embedded frameworks');
+        }
+
+        final String xcodeBackendPath = path.join(
+          flutterDirectory.path,
+          'packages',
+          'flutter_tools',
+          'bin',
+          'xcode_backend.sh'
         );
 
-        if (!File(outputFlutterFramework).existsSync()) {
-          fail('Failed to produce expected output at $outputFlutterFramework');
+        // Simulate a commonly Xcode build setting misconfiguration
+        // where FLUTTER_APPLICATION_PATH is missing
+        final int result = await exec(
+          xcodeBackendPath,
+          <String>['embed_and_thin'],
+          environment: <String, String>{
+            'SOURCE_ROOT': flutterProject.iosPath,
+            'TARGET_BUILD_DIR': buildPath,
+            'FRAMEWORKS_FOLDER_PATH': 'Runner.app/Frameworks',
+            'VERBOSE_SCRIPT_LOGGING': '1',
+            'ACTION': 'install', // Skip bitcode stripping since we just checked that above.
+          },
+        );
+
+        if (result != 0) {
+          fail('xcode_backend embed_and_thin failed');
         }
-        bitcode = await containsBitcode(outputFlutterFramework);
+
+        if (!outputFlutterFrameworkBinary.existsSync()) {
+          fail('Failed to re-embed ${outputFlutterFrameworkBinary.path}');
+        }
+
+        if (!outputAppFrameworkBinary.existsSync()) {
+          fail('Failed to re-embed ${outputAppFrameworkBinary.path}');
+        }
       });
 
       if (foundProjectName) {
diff --git a/dev/devicelab/lib/framework/apk_utils.dart b/dev/devicelab/lib/framework/apk_utils.dart
index 1eb4955..961074d 100644
--- a/dev/devicelab/lib/framework/apk_utils.dart
+++ b/dev/devicelab/lib/framework/apk_utils.dart
@@ -214,6 +214,7 @@
 
   String get rootPath => path.join(parent.path, name);
   String get androidPath => path.join(rootPath, 'android');
+  String get iosPath => path.join(rootPath, 'ios');
 
   Future<void> addCustomBuildType(String name, {String initWith}) async {
     final File buildScript = File(
diff --git a/dev/integration_tests/abstract_method_smoke_test/android/settings.gradle b/dev/integration_tests/abstract_method_smoke_test/android/settings.gradle
index bef552e..d3b6a40 100644
--- a/dev/integration_tests/abstract_method_smoke_test/android/settings.gradle
+++ b/dev/integration_tests/abstract_method_smoke_test/android/settings.gradle
@@ -4,16 +4,12 @@
 
 include ':app'
 
-def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
 
-def plugins = new Properties()
-def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
-if (pluginsFile.exists()) {
-    pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
-}
+assert localPropertiesFile.exists()
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
 
-plugins.each { name, path ->
-    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
-    include ":$name"
-    project(":$name").projectDir = pluginDirectory
-}
+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"
diff --git a/dev/integration_tests/android_embedding_v2_smoke_test/android/settings.gradle b/dev/integration_tests/android_embedding_v2_smoke_test/android/settings.gradle
index bef552e..d3b6a40 100644
--- a/dev/integration_tests/android_embedding_v2_smoke_test/android/settings.gradle
+++ b/dev/integration_tests/android_embedding_v2_smoke_test/android/settings.gradle
@@ -4,16 +4,12 @@
 
 include ':app'
 
-def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
 
-def plugins = new Properties()
-def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
-if (pluginsFile.exists()) {
-    pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
-}
+assert localPropertiesFile.exists()
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
 
-plugins.each { name, path ->
-    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
-    include ":$name"
-    project(":$name").projectDir = pluginDirectory
-}
+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"
diff --git a/dev/integration_tests/android_semantics_testing/android/settings.gradle b/dev/integration_tests/android_semantics_testing/android/settings.gradle
index dbc3b58..d3b6a40 100644
--- a/dev/integration_tests/android_semantics_testing/android/settings.gradle
+++ b/dev/integration_tests/android_semantics_testing/android/settings.gradle
@@ -4,16 +4,12 @@
 
 include ':app'
 
-def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
 
-def plugins = new Properties()
-def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
-if (pluginsFile.exists()) {
-    pluginsFile.withInputStream { stream -> plugins.load(stream) }
-}
+assert localPropertiesFile.exists()
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
 
-plugins.each { name, path ->
-    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
-    include ":$name"
-    project(":$name").projectDir = pluginDirectory
-}
+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"
diff --git a/dev/integration_tests/android_splash_screens/splash_screen_kitchen_sink/android/settings.gradle b/dev/integration_tests/android_splash_screens/splash_screen_kitchen_sink/android/settings.gradle
index bef552e..d3b6a40 100644
--- a/dev/integration_tests/android_splash_screens/splash_screen_kitchen_sink/android/settings.gradle
+++ b/dev/integration_tests/android_splash_screens/splash_screen_kitchen_sink/android/settings.gradle
@@ -4,16 +4,12 @@
 
 include ':app'
 
-def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
 
-def plugins = new Properties()
-def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
-if (pluginsFile.exists()) {
-    pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
-}
+assert localPropertiesFile.exists()
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
 
-plugins.each { name, path ->
-    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
-    include ":$name"
-    project(":$name").projectDir = pluginDirectory
-}
+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"
diff --git a/dev/integration_tests/android_splash_screens/splash_screen_load_rotate/android/settings.gradle b/dev/integration_tests/android_splash_screens/splash_screen_load_rotate/android/settings.gradle
index bef552e..d3b6a40 100644
--- a/dev/integration_tests/android_splash_screens/splash_screen_load_rotate/android/settings.gradle
+++ b/dev/integration_tests/android_splash_screens/splash_screen_load_rotate/android/settings.gradle
@@ -4,16 +4,12 @@
 
 include ':app'
 
-def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
 
-def plugins = new Properties()
-def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
-if (pluginsFile.exists()) {
-    pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
-}
+assert localPropertiesFile.exists()
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
 
-plugins.each { name, path ->
-    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
-    include ":$name"
-    project(":$name").projectDir = pluginDirectory
-}
+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"
diff --git a/dev/integration_tests/android_splash_screens/splash_screen_trans_rotate/android/settings.gradle b/dev/integration_tests/android_splash_screens/splash_screen_trans_rotate/android/settings.gradle
index bef552e..d3b6a40 100644
--- a/dev/integration_tests/android_splash_screens/splash_screen_trans_rotate/android/settings.gradle
+++ b/dev/integration_tests/android_splash_screens/splash_screen_trans_rotate/android/settings.gradle
@@ -4,16 +4,12 @@
 
 include ':app'
 
-def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
 
-def plugins = new Properties()
-def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
-if (pluginsFile.exists()) {
-    pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
-}
+assert localPropertiesFile.exists()
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
 
-plugins.each { name, path ->
-    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
-    include ":$name"
-    project(":$name").projectDir = pluginDirectory
-}
+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"
diff --git a/dev/integration_tests/android_views/android/settings.gradle b/dev/integration_tests/android_views/android/settings.gradle
index bef552e..d3b6a40 100644
--- a/dev/integration_tests/android_views/android/settings.gradle
+++ b/dev/integration_tests/android_views/android/settings.gradle
@@ -4,16 +4,12 @@
 
 include ':app'
 
-def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
 
-def plugins = new Properties()
-def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
-if (pluginsFile.exists()) {
-    pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
-}
+assert localPropertiesFile.exists()
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
 
-plugins.each { name, path ->
-    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
-    include ":$name"
-    project(":$name").projectDir = pluginDirectory
-}
+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"
diff --git a/dev/integration_tests/channels/android/settings.gradle b/dev/integration_tests/channels/android/settings.gradle
index dbc3b58..d3b6a40 100644
--- a/dev/integration_tests/channels/android/settings.gradle
+++ b/dev/integration_tests/channels/android/settings.gradle
@@ -4,16 +4,12 @@
 
 include ':app'
 
-def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
 
-def plugins = new Properties()
-def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
-if (pluginsFile.exists()) {
-    pluginsFile.withInputStream { stream -> plugins.load(stream) }
-}
+assert localPropertiesFile.exists()
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
 
-plugins.each { name, path ->
-    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
-    include ":$name"
-    project(":$name").projectDir = pluginDirectory
-}
+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"
diff --git a/dev/integration_tests/codegen/android/settings.gradle b/dev/integration_tests/codegen/android/settings.gradle
index dbc3b58..d3b6a40 100644
--- a/dev/integration_tests/codegen/android/settings.gradle
+++ b/dev/integration_tests/codegen/android/settings.gradle
@@ -4,16 +4,12 @@
 
 include ':app'
 
-def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
 
-def plugins = new Properties()
-def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
-if (pluginsFile.exists()) {
-    pluginsFile.withInputStream { stream -> plugins.load(stream) }
-}
+assert localPropertiesFile.exists()
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
 
-plugins.each { name, path ->
-    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
-    include ":$name"
-    project(":$name").projectDir = pluginDirectory
-}
+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"
diff --git a/dev/integration_tests/external_ui/android/settings.gradle b/dev/integration_tests/external_ui/android/settings.gradle
index dbc3b58..d3b6a40 100644
--- a/dev/integration_tests/external_ui/android/settings.gradle
+++ b/dev/integration_tests/external_ui/android/settings.gradle
@@ -4,16 +4,12 @@
 
 include ':app'
 
-def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
 
-def plugins = new Properties()
-def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
-if (pluginsFile.exists()) {
-    pluginsFile.withInputStream { stream -> plugins.load(stream) }
-}
+assert localPropertiesFile.exists()
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
 
-plugins.each { name, path ->
-    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
-    include ":$name"
-    project(":$name").projectDir = pluginDirectory
-}
+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"
diff --git a/dev/integration_tests/flavors/android/settings.gradle b/dev/integration_tests/flavors/android/settings.gradle
index dbc3b58..d3b6a40 100644
--- a/dev/integration_tests/flavors/android/settings.gradle
+++ b/dev/integration_tests/flavors/android/settings.gradle
@@ -4,16 +4,12 @@
 
 include ':app'
 
-def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
 
-def plugins = new Properties()
-def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
-if (pluginsFile.exists()) {
-    pluginsFile.withInputStream { stream -> plugins.load(stream) }
-}
+assert localPropertiesFile.exists()
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
 
-plugins.each { name, path ->
-    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
-    include ":$name"
-    project(":$name").projectDir = pluginDirectory
-}
+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"
diff --git a/dev/integration_tests/flutter_driver_screenshot_test/android/settings.gradle b/dev/integration_tests/flutter_driver_screenshot_test/android/settings.gradle
index bef552e..d3b6a40 100644
--- a/dev/integration_tests/flutter_driver_screenshot_test/android/settings.gradle
+++ b/dev/integration_tests/flutter_driver_screenshot_test/android/settings.gradle
@@ -4,16 +4,12 @@
 
 include ':app'
 
-def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
 
-def plugins = new Properties()
-def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
-if (pluginsFile.exists()) {
-    pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
-}
+assert localPropertiesFile.exists()
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
 
-plugins.each { name, path ->
-    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
-    include ":$name"
-    project(":$name").projectDir = pluginDirectory
-}
+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"
diff --git a/dev/integration_tests/flutter_gallery/android/settings.gradle b/dev/integration_tests/flutter_gallery/android/settings.gradle
index dbc3b58..d3b6a40 100644
--- a/dev/integration_tests/flutter_gallery/android/settings.gradle
+++ b/dev/integration_tests/flutter_gallery/android/settings.gradle
@@ -4,16 +4,12 @@
 
 include ':app'
 
-def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
 
-def plugins = new Properties()
-def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
-if (pluginsFile.exists()) {
-    pluginsFile.withInputStream { stream -> plugins.load(stream) }
-}
+assert localPropertiesFile.exists()
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
 
-plugins.each { name, path ->
-    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
-    include ":$name"
-    project(":$name").projectDir = pluginDirectory
-}
+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"
diff --git a/dev/integration_tests/gradle_deprecated_settings/README.md b/dev/integration_tests/gradle_deprecated_settings/README.md
new file mode 100644
index 0000000..a4c6081
--- /dev/null
+++ b/dev/integration_tests/gradle_deprecated_settings/README.md
@@ -0,0 +1,7 @@
+# Deprecated settings.gradle
+
+This project is meant to test that apps using the current `android/settings.gradle`
+can still be built. This project can be removed once apps have been migrated to
+this new file.
+
+Issue: https://github.com/flutter/flutter/issues/54566
\ No newline at end of file
diff --git a/dev/integration_tests/gradle_deprecated_settings/android/app/build.gradle b/dev/integration_tests/gradle_deprecated_settings/android/app/build.gradle
new file mode 100644
index 0000000..be24d8d
--- /dev/null
+++ b/dev/integration_tests/gradle_deprecated_settings/android/app/build.gradle
@@ -0,0 +1,45 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+def localProperties = new Properties()
+def localPropertiesFile = rootProject.file('local.properties')
+if (localPropertiesFile.exists()) {
+    localPropertiesFile.withInputStream { stream ->
+        localProperties.load(stream)
+    }
+}
+
+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.")
+}
+
+apply plugin: 'com.android.application'
+apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
+
+android {
+    compileSdkVersion 28
+
+    lintOptions {
+        disable 'InvalidPackage'
+    }
+
+    defaultConfig {
+        applicationId "com.yourcompany.flavors"
+        minSdkVersion 21
+        targetSdkVersion 28
+        versionCode 1
+        versionName "1.0"
+    }
+
+    buildTypes {
+        release {
+            signingConfig signingConfigs.debug
+        }
+    }
+}
+
+flutter {
+    source '../..'
+}
diff --git a/dev/integration_tests/gradle_deprecated_settings/android/app/src/main/AndroidManifest.xml b/dev/integration_tests/gradle_deprecated_settings/android/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..e1a37c0
--- /dev/null
+++ b/dev/integration_tests/gradle_deprecated_settings/android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<!-- Copyright 2014 The Flutter Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file. -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.yourcompany.flavors">
+
+    <uses-permission android:name="android.permission.INTERNET"/>
+
+    <application
+        android:name="io.flutter.app.FlutterApplication"
+        android:label="flavors">
+        <activity
+            android:name=".MainActivity"
+            android:launchMode="singleTop"
+            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
+            android:hardwareAccelerated="true"
+            android:windowSoftInputMode="adjustResize">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/dev/integration_tests/gradle_deprecated_settings/android/app/src/main/java/com/yourcompany/flavors/MainActivity.java b/dev/integration_tests/gradle_deprecated_settings/android/app/src/main/java/com/yourcompany/flavors/MainActivity.java
new file mode 100644
index 0000000..7e6d4fe
--- /dev/null
+++ b/dev/integration_tests/gradle_deprecated_settings/android/app/src/main/java/com/yourcompany/flavors/MainActivity.java
@@ -0,0 +1,26 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package com.yourcompany.flavors;
+
+import android.os.Bundle;
+
+import io.flutter.app.FlutterActivity;
+import io.flutter.plugin.common.MethodCall;
+import io.flutter.plugin.common.MethodChannel;
+import io.flutter.plugins.GeneratedPluginRegistrant;
+
+public class MainActivity extends FlutterActivity {
+  @Override
+  protected void onCreate(Bundle savedInstanceState) {
+    super.onCreate(savedInstanceState);
+    GeneratedPluginRegistrant.registerWith(this);
+    new MethodChannel(getFlutterView(), "flavor").setMethodCallHandler(new MethodChannel.MethodCallHandler() {
+      @Override
+      public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
+        result.success(BuildConfig.FLAVOR);
+      }
+    });
+  }
+}
diff --git a/dev/integration_tests/gradle_deprecated_settings/android/build.gradle b/dev/integration_tests/gradle_deprecated_settings/android/build.gradle
new file mode 100644
index 0000000..5df71fc
--- /dev/null
+++ b/dev/integration_tests/gradle_deprecated_settings/android/build.gradle
@@ -0,0 +1,33 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+buildscript {
+    repositories {
+        google()
+        jcenter()
+    }
+
+    dependencies {
+        classpath 'com.android.tools.build:gradle:3.5.0'
+    }
+}
+
+allprojects {
+    repositories {
+        google()
+        jcenter()
+    }
+}
+
+rootProject.buildDir = '../build'
+subprojects {
+    project.buildDir = "${rootProject.buildDir}/${project.name}"
+}
+subprojects {
+    project.evaluationDependsOn(':app')
+}
+
+task clean(type: Delete) {
+    delete rootProject.buildDir
+}
diff --git a/dev/integration_tests/gradle_deprecated_settings/android/gradle.properties b/dev/integration_tests/gradle_deprecated_settings/android/gradle.properties
new file mode 100644
index 0000000..a673820
--- /dev/null
+++ b/dev/integration_tests/gradle_deprecated_settings/android/gradle.properties
@@ -0,0 +1,4 @@
+org.gradle.jvmargs=-Xmx1536M
+android.useAndroidX=true
+android.enableJetifier=true
+android.enableR8=true
diff --git a/dev/integration_tests/gradle_deprecated_settings/android/gradle/wrapper/gradle-wrapper.properties b/dev/integration_tests/gradle_deprecated_settings/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..296b146
--- /dev/null
+++ b/dev/integration_tests/gradle_deprecated_settings/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Fri Jun 23 08:50:38 CEST 2017
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
diff --git a/dev/integration_tests/gradle_deprecated_settings/android/settings.gradle b/dev/integration_tests/gradle_deprecated_settings/android/settings.gradle
new file mode 100644
index 0000000..2a07d76
--- /dev/null
+++ b/dev/integration_tests/gradle_deprecated_settings/android/settings.gradle
@@ -0,0 +1,24 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This is the `settings.gradle` file that apps currently use.
+// This file has changed, so it must be migrated in existing projects.
+
+include ':app'
+
+def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
+
+def plugins = new Properties()
+def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
+if (pluginsFile.exists()) {
+    pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
+}
+
+plugins.each { name, path ->
+    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
+    include ":$name"
+    project(":$name").projectDir = pluginDirectory
+}
diff --git a/dev/integration_tests/gradle_deprecated_settings/lib/main.dart b/dev/integration_tests/gradle_deprecated_settings/lib/main.dart
new file mode 100644
index 0000000..b0681fd
--- /dev/null
+++ b/dev/integration_tests/gradle_deprecated_settings/lib/main.dart
@@ -0,0 +1,9 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/material.dart';
+
+void main() {
+  runApp(const Text('Nothing to show'));
+}
diff --git a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml
new file mode 100644
index 0000000..dbe6b8d
--- /dev/null
+++ b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml
@@ -0,0 +1,21 @@
+name: gradle_deprecated_settings
+description: Integration test for the current settings.gradle.
+
+environment:
+  # The pub client defaults to an <2.0.0 sdk constraint which we need to explicitly overwrite.
+  sdk: ">=2.0.0-dev.68.0 <3.0.0"
+
+dependencies:
+  flutter:
+    sdk: flutter
+  camera: 0.5.7+4
+
+  collection: 1.14.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  meta: 1.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  typed_data: 1.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  vector_math: 2.0.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+
+flutter:
+  uses-material-design: true
+
+# PUBSPEC CHECKSUM: 185d
diff --git a/dev/integration_tests/image_loading/android/settings.gradle b/dev/integration_tests/image_loading/android/settings.gradle
index dbc3b58..d3b6a40 100644
--- a/dev/integration_tests/image_loading/android/settings.gradle
+++ b/dev/integration_tests/image_loading/android/settings.gradle
@@ -4,16 +4,12 @@
 
 include ':app'
 
-def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
 
-def plugins = new Properties()
-def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
-if (pluginsFile.exists()) {
-    pluginsFile.withInputStream { stream -> plugins.load(stream) }
-}
+assert localPropertiesFile.exists()
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
 
-plugins.each { name, path ->
-    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
-    include ":$name"
-    project(":$name").projectDir = pluginDirectory
-}
+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"
diff --git a/dev/integration_tests/named_isolates/android/settings.gradle b/dev/integration_tests/named_isolates/android/settings.gradle
index dbc3b58..d3b6a40 100644
--- a/dev/integration_tests/named_isolates/android/settings.gradle
+++ b/dev/integration_tests/named_isolates/android/settings.gradle
@@ -4,16 +4,12 @@
 
 include ':app'
 
-def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
 
-def plugins = new Properties()
-def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
-if (pluginsFile.exists()) {
-    pluginsFile.withInputStream { stream -> plugins.load(stream) }
-}
+assert localPropertiesFile.exists()
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
 
-plugins.each { name, path ->
-    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
-    include ":$name"
-    project(":$name").projectDir = pluginDirectory
-}
+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"
diff --git a/dev/integration_tests/platform_interaction/android/settings.gradle b/dev/integration_tests/platform_interaction/android/settings.gradle
index dbc3b58..d3b6a40 100644
--- a/dev/integration_tests/platform_interaction/android/settings.gradle
+++ b/dev/integration_tests/platform_interaction/android/settings.gradle
@@ -4,16 +4,12 @@
 
 include ':app'
 
-def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
 
-def plugins = new Properties()
-def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
-if (pluginsFile.exists()) {
-    pluginsFile.withInputStream { stream -> plugins.load(stream) }
-}
+assert localPropertiesFile.exists()
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
 
-plugins.each { name, path ->
-    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
-    include ":$name"
-    project(":$name").projectDir = pluginDirectory
-}
+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"
diff --git a/dev/integration_tests/release_smoke_test/android/settings.gradle b/dev/integration_tests/release_smoke_test/android/settings.gradle
index bef552e..d3b6a40 100644
--- a/dev/integration_tests/release_smoke_test/android/settings.gradle
+++ b/dev/integration_tests/release_smoke_test/android/settings.gradle
@@ -4,16 +4,12 @@
 
 include ':app'
 
-def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
 
-def plugins = new Properties()
-def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
-if (pluginsFile.exists()) {
-    pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
-}
+assert localPropertiesFile.exists()
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
 
-plugins.each { name, path ->
-    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
-    include ":$name"
-    project(":$name").projectDir = pluginDirectory
-}
+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"
diff --git a/dev/integration_tests/ui/android/settings.gradle b/dev/integration_tests/ui/android/settings.gradle
index dbc3b58..d3b6a40 100644
--- a/dev/integration_tests/ui/android/settings.gradle
+++ b/dev/integration_tests/ui/android/settings.gradle
@@ -4,16 +4,12 @@
 
 include ':app'
 
-def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
 
-def plugins = new Properties()
-def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
-if (pluginsFile.exists()) {
-    pluginsFile.withInputStream { stream -> plugins.load(stream) }
-}
+assert localPropertiesFile.exists()
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
 
-plugins.each { name, path ->
-    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
-    include ":$name"
-    project(":$name").projectDir = pluginDirectory
-}
+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"
diff --git a/dev/manual_tests/android/settings.gradle b/dev/manual_tests/android/settings.gradle
index bef552e..d3b6a40 100644
--- a/dev/manual_tests/android/settings.gradle
+++ b/dev/manual_tests/android/settings.gradle
@@ -4,16 +4,12 @@
 
 include ':app'
 
-def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
 
-def plugins = new Properties()
-def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
-if (pluginsFile.exists()) {
-    pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
-}
+assert localPropertiesFile.exists()
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
 
-plugins.each { name, path ->
-    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
-    include ":$name"
-    project(":$name").projectDir = pluginDirectory
-}
+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"
diff --git a/examples/catalog/android/settings.gradle b/examples/catalog/android/settings.gradle
index dbc3b58..d3b6a40 100644
--- a/examples/catalog/android/settings.gradle
+++ b/examples/catalog/android/settings.gradle
@@ -4,16 +4,12 @@
 
 include ':app'
 
-def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
 
-def plugins = new Properties()
-def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
-if (pluginsFile.exists()) {
-    pluginsFile.withInputStream { stream -> plugins.load(stream) }
-}
+assert localPropertiesFile.exists()
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
 
-plugins.each { name, path ->
-    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
-    include ":$name"
-    project(":$name").projectDir = pluginDirectory
-}
+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"
diff --git a/examples/flutter_view/README.md b/examples/flutter_view/README.md
index 6c84a2a..b6db10b 100644
--- a/examples/flutter_view/README.md
+++ b/examples/flutter_view/README.md
@@ -11,8 +11,7 @@
 ## iOS
 
 You can open `ios/Runner.xcworkspace` in Xcode and build the project as
-usual. For this sample you need to run `pod install` from the `ios` folder
-before building the first time.
+usual.
 
 ## Android
 
diff --git a/examples/flutter_view/android/settings.gradle b/examples/flutter_view/android/settings.gradle
index dbc3b58..d3b6a40 100644
--- a/examples/flutter_view/android/settings.gradle
+++ b/examples/flutter_view/android/settings.gradle
@@ -4,16 +4,12 @@
 
 include ':app'
 
-def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
 
-def plugins = new Properties()
-def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
-if (pluginsFile.exists()) {
-    pluginsFile.withInputStream { stream -> plugins.load(stream) }
-}
+assert localPropertiesFile.exists()
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
 
-plugins.each { name, path ->
-    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
-    include ":$name"
-    project(":$name").projectDir = pluginDirectory
-}
+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"
diff --git a/examples/flutter_view/ios/Flutter/Debug.xcconfig b/examples/flutter_view/ios/Flutter/Debug.xcconfig
index 9803018..592ceee 100644
--- a/examples/flutter_view/ios/Flutter/Debug.xcconfig
+++ b/examples/flutter_view/ios/Flutter/Debug.xcconfig
@@ -1,2 +1 @@
 #include "Generated.xcconfig"
-#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
diff --git a/examples/flutter_view/ios/Flutter/Release.xcconfig b/examples/flutter_view/ios/Flutter/Release.xcconfig
index a4a8c60..592ceee 100644
--- a/examples/flutter_view/ios/Flutter/Release.xcconfig
+++ b/examples/flutter_view/ios/Flutter/Release.xcconfig
@@ -1,2 +1 @@
 #include "Generated.xcconfig"
-#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
diff --git a/examples/flutter_view/ios/Podfile b/examples/flutter_view/ios/Podfile
deleted file mode 100644
index 827fe47..0000000
--- a/examples/flutter_view/ios/Podfile
+++ /dev/null
@@ -1,15 +0,0 @@
-# Uncomment this line to define a global platform for your project
-# platform :ios, '9.0'
-
-# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system.
-install! 'cocoapods', :disable_input_output_paths => true
-
-target 'Runner' do
-  # Uncomment this line if you're using Swift or would like to use dynamic frameworks
-   use_frameworks!
-   use_modular_headers!
-
-  # Pods for Runner
-  pod 'MaterialControls', '~> 1.2.2'
-
-end
diff --git a/examples/flutter_view/ios/Runner.xcodeproj/project.pbxproj b/examples/flutter_view/ios/Runner.xcodeproj/project.pbxproj
index c8b69db..a9d9e6b 100644
--- a/examples/flutter_view/ios/Runner.xcodeproj/project.pbxproj
+++ b/examples/flutter_view/ios/Runner.xcodeproj/project.pbxproj
@@ -16,7 +16,6 @@
 		97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
 		97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
 		97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
-		A10521F6BE294095B24A8A75 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 069A5C81CEBC82AF6693F60F /* Pods_Runner.framework */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXCopyFilesBuildPhase section */
@@ -33,14 +32,12 @@
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
-		069A5C81CEBC82AF6693F60F /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		2D4B11261E55A15A00FF14DB /* NativeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NativeViewController.m; sourceTree = "<group>"; };
 		2D4B11281E55A31800FF14DB /* NativeViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NativeViewController.h; sourceTree = "<group>"; };
 		2DD8945E1E5B87AF0010574F /* ic_add.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = ic_add.png; sourceTree = "<group>"; };
 		2DE332E61E55C6D800393FD5 /* MainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MainViewController.m; sourceTree = "<group>"; };
 		2DE332E81E55C6F100393FD5 /* MainViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MainViewController.h; sourceTree = "<group>"; };
 		3B3967041E83383D004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
-		63EC5EC13E843CD861057871 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
 		7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
 		7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
 		7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
@@ -52,8 +49,6 @@
 		97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
 		97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
 		97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
-		C50B4FE91C29B0DE9DD62DD3 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
-		EADA814501F2EF49C9E6C636 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -61,23 +56,12 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				A10521F6BE294095B24A8A75 /* Pods_Runner.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
-		840012C8B5EDBCF56B0E4AC1 /* Pods */ = {
-			isa = PBXGroup;
-			children = (
-				63EC5EC13E843CD861057871 /* Pods-Runner.debug.xcconfig */,
-				C50B4FE91C29B0DE9DD62DD3 /* Pods-Runner.release.xcconfig */,
-				EADA814501F2EF49C9E6C636 /* Pods-Runner.profile.xcconfig */,
-			);
-			name = Pods;
-			sourceTree = "<group>";
-		};
 		9740EEB11CF90186004384FC /* Flutter */ = {
 			isa = PBXGroup;
 			children = (
@@ -95,8 +79,6 @@
 				9740EEB11CF90186004384FC /* Flutter */,
 				97C146F01CF9000F007C117D /* Runner */,
 				97C146EF1CF9000F007C117D /* Products */,
-				840012C8B5EDBCF56B0E4AC1 /* Pods */,
-				CF3B75C9A7D2FA2A4C99F110 /* Frameworks */,
 			);
 			sourceTree = "<group>";
 		};
@@ -135,14 +117,6 @@
 			name = "Supporting Files";
 			sourceTree = "<group>";
 		};
-		CF3B75C9A7D2FA2A4C99F110 /* Frameworks */ = {
-			isa = PBXGroup;
-			children = (
-				069A5C81CEBC82AF6693F60F /* Pods_Runner.framework */,
-			);
-			name = Frameworks;
-			sourceTree = "<group>";
-		};
 /* End PBXGroup section */
 
 /* Begin PBXNativeTarget section */
@@ -150,14 +124,12 @@
 			isa = PBXNativeTarget;
 			buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
 			buildPhases = (
-				C15931CF7E2D081FE06790F0 /* [CP] Check Pods Manifest.lock */,
 				9740EEB61CF901F6004384FC /* Run Script */,
 				97C146EA1CF9000F007C117D /* Sources */,
 				97C146EB1CF9000F007C117D /* Frameworks */,
 				97C146EC1CF9000F007C117D /* Resources */,
 				9705A1C41CF9048500538489 /* Embed Frameworks */,
 				3B06AD1E1E4923F5004D2608 /* Thin Binary */,
-				D7EBAA0AD2D4385BA6FA83BA /* [CP] Embed Pods Frameworks */,
 			);
 			buildRules = (
 			);
@@ -245,39 +217,6 @@
 			shellPath = /bin/sh;
 			shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n";
 		};
-		C15931CF7E2D081FE06790F0 /* [CP] Check Pods Manifest.lock */ = {
-			isa = PBXShellScriptBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-			);
-			inputPaths = (
-				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
-				"${PODS_ROOT}/Manifest.lock",
-			);
-			name = "[CP] Check Pods Manifest.lock";
-			outputPaths = (
-				"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-			shellPath = /bin/sh;
-			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
-			showEnvVarsInLog = 0;
-		};
-		D7EBAA0AD2D4385BA6FA83BA /* [CP] Embed Pods Frameworks */ = {
-			isa = PBXShellScriptBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-			);
-			inputPaths = (
-			);
-			name = "[CP] Embed Pods Frameworks";
-			outputPaths = (
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-			shellPath = /bin/sh;
-			shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
-			showEnvVarsInLog = 0;
-		};
 /* End PBXShellScriptBuildPhase section */
 
 /* Begin PBXSourcesBuildPhase section */
diff --git a/examples/flutter_view/ios/Runner.xcworkspace/contents.xcworkspacedata b/examples/flutter_view/ios/Runner.xcworkspace/contents.xcworkspacedata
index 21a3cc1..1d526a1 100644
--- a/examples/flutter_view/ios/Runner.xcworkspace/contents.xcworkspacedata
+++ b/examples/flutter_view/ios/Runner.xcworkspace/contents.xcworkspacedata
@@ -4,7 +4,4 @@
    <FileRef
       location = "group:Runner.xcodeproj">
    </FileRef>
-   <FileRef
-      location = "group:Pods/Pods.xcodeproj">
-   </FileRef>
 </Workspace>
diff --git a/examples/flutter_view/ios/Runner/Base.lproj/Main.storyboard b/examples/flutter_view/ios/Runner/Base.lproj/Main.storyboard
index 380dd14..76c8ca3 100644
--- a/examples/flutter_view/ios/Runner/Base.lproj/Main.storyboard
+++ b/examples/flutter_view/ios/Runner/Base.lproj/Main.storyboard
@@ -1,10 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="FnB-1o-m6P">
-    <device id="retina4_7" orientation="portrait">
-        <adaptation id="fullscreen"/>
-    </device>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15705" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="FnB-1o-m6P">
+    <device id="retina4_7" orientation="portrait" appearance="light"/>
     <dependencies>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15706"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
     <scenes>
@@ -85,13 +84,13 @@
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <subviews>
                             <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="zVI-Xh-iNx">
-                                <rect key="frame" x="0.0" y="0.0" width="375" height="334"/>
+                                <rect key="frame" x="0.0" y="0.0" width="375" height="333.5"/>
                                 <subviews>
                                     <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="NLS-lx-anZ" userLabel="Top">
-                                        <rect key="frame" x="0.0" y="0.0" width="375" height="264"/>
+                                        <rect key="frame" x="0.0" y="0.0" width="375" height="263.5"/>
                                         <subviews>
                                             <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Flutter button tapped 0 times." textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="PJ2-AA-Riy" userLabel="IncrementLabel">
-                                                <rect key="frame" x="73" y="122" width="229" height="21"/>
+                                                <rect key="frame" x="73.5" y="121.5" width="228.5" height="20.5"/>
                                                 <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                                 <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                                                 <nil key="highlightedColor"/>
@@ -103,15 +102,15 @@
                                         </constraints>
                                     </view>
                                     <view contentMode="scaleToFill" restorationIdentifier="Bottom" translatesAutoresizingMaskIntoConstraints="NO" id="Qxj-hW-CeP" userLabel="Bottom">
-                                        <rect key="frame" x="0.0" y="264" width="375" height="70"/>
+                                        <rect key="frame" x="0.0" y="263.5" width="375" height="70"/>
                                         <subviews>
                                             <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="iOS" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="K0h-kv-J7E">
-                                                <rect key="frame" x="20" y="14" width="48" height="36"/>
+                                                <rect key="frame" x="20" y="14" width="47" height="36"/>
                                                 <fontDescription key="fontDescription" type="system" pointSize="30"/>
                                                 <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                                                 <nil key="highlightedColor"/>
                                             </label>
-                                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Jfa-Lk-nDI" customClass="MDButton">
+                                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Jfa-Lk-nDI">
                                                 <rect key="frame" x="300" y="-5" width="55" height="55"/>
                                                 <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                                                 <constraints>
@@ -119,15 +118,10 @@
                                                     <constraint firstAttribute="width" constant="55" id="zeJ-gS-6zj"/>
                                                 </constraints>
                                                 <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
-                                                <userDefinedRuntimeAttributes>
-                                                    <userDefinedRuntimeAttribute type="number" keyPath="type">
-                                                        <integer key="value" value="2"/>
-                                                    </userDefinedRuntimeAttribute>
-                                                    <userDefinedRuntimeAttribute type="image" keyPath="imageNormal" value="ic_add.png"/>
-                                                    <userDefinedRuntimeAttribute type="color" keyPath="rippleColor">
-                                                        <color key="value" red="0.82337594754841859" green="0.83186435937881464" blue="0.83186435937881464" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                                                    </userDefinedRuntimeAttribute>
-                                                </userDefinedRuntimeAttributes>
+                                                <state key="normal" image="ic_add.png"/>
+                                                <state key="disabled" image="ic_add.png"/>
+                                                <state key="selected" image="ic_add.png"/>
+                                                <state key="highlighted" image="ic_add.png"/>
                                                 <connections>
                                                     <action selector="handleIncrement:" destination="g6V-0q-Qmt" eventType="touchUpInside" id="3ie-8K-E0v"/>
                                                 </connections>
diff --git a/examples/flutter_view/ios/Runner/NativeViewController.m b/examples/flutter_view/ios/Runner/NativeViewController.m
index 17813e5..e82375a 100644
--- a/examples/flutter_view/ios/Runner/NativeViewController.m
+++ b/examples/flutter_view/ios/Runner/NativeViewController.m
@@ -5,7 +5,6 @@
 #import <Foundation/Foundation.h>
 
 #import "NativeViewController.h"
-#import "MDButton.h"
 
 @interface NativeViewController ()
 @property int counter;
@@ -19,7 +18,7 @@
   self.counter = 0;
 }
 
-- (IBAction)handleIncrement:(MDButton*)sender {
+- (IBAction)handleIncrement:(id)sender {
   [self.delegate didTapIncrementButton];
 }
 
diff --git a/examples/hello_world/android/settings.gradle b/examples/hello_world/android/settings.gradle
index dbc3b58..d3b6a40 100644
--- a/examples/hello_world/android/settings.gradle
+++ b/examples/hello_world/android/settings.gradle
@@ -4,16 +4,12 @@
 
 include ':app'
 
-def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
 
-def plugins = new Properties()
-def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
-if (pluginsFile.exists()) {
-    pluginsFile.withInputStream { stream -> plugins.load(stream) }
-}
+assert localPropertiesFile.exists()
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
 
-plugins.each { name, path ->
-    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
-    include ":$name"
-    project(":$name").projectDir = pluginDirectory
-}
+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"
diff --git a/examples/image_list/android/settings.gradle b/examples/image_list/android/settings.gradle
index bef552e..d3b6a40 100644
--- a/examples/image_list/android/settings.gradle
+++ b/examples/image_list/android/settings.gradle
@@ -4,16 +4,12 @@
 
 include ':app'
 
-def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
 
-def plugins = new Properties()
-def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
-if (pluginsFile.exists()) {
-    pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
-}
+assert localPropertiesFile.exists()
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
 
-plugins.each { name, path ->
-    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
-    include ":$name"
-    project(":$name").projectDir = pluginDirectory
-}
+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"
diff --git a/examples/layers/android/settings.gradle b/examples/layers/android/settings.gradle
index dbc3b58..d3b6a40 100644
--- a/examples/layers/android/settings.gradle
+++ b/examples/layers/android/settings.gradle
@@ -4,16 +4,12 @@
 
 include ':app'
 
-def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
 
-def plugins = new Properties()
-def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
-if (pluginsFile.exists()) {
-    pluginsFile.withInputStream { stream -> plugins.load(stream) }
-}
+assert localPropertiesFile.exists()
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
 
-plugins.each { name, path ->
-    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
-    include ":$name"
-    project(":$name").projectDir = pluginDirectory
-}
+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"
diff --git a/examples/platform_channel/android/settings.gradle b/examples/platform_channel/android/settings.gradle
index dbc3b58..d3b6a40 100644
--- a/examples/platform_channel/android/settings.gradle
+++ b/examples/platform_channel/android/settings.gradle
@@ -4,16 +4,12 @@
 
 include ':app'
 
-def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
 
-def plugins = new Properties()
-def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
-if (pluginsFile.exists()) {
-    pluginsFile.withInputStream { stream -> plugins.load(stream) }
-}
+assert localPropertiesFile.exists()
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
 
-plugins.each { name, path ->
-    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
-    include ":$name"
-    project(":$name").projectDir = pluginDirectory
-}
+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"
diff --git a/examples/platform_view/android/settings.gradle b/examples/platform_view/android/settings.gradle
index dbc3b58..d3b6a40 100644
--- a/examples/platform_view/android/settings.gradle
+++ b/examples/platform_view/android/settings.gradle
@@ -4,16 +4,12 @@
 
 include ':app'
 
-def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
 
-def plugins = new Properties()
-def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
-if (pluginsFile.exists()) {
-    pluginsFile.withInputStream { stream -> plugins.load(stream) }
-}
+assert localPropertiesFile.exists()
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
 
-plugins.each { name, path ->
-    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
-    include ":$name"
-    project(":$name").projectDir = pluginDirectory
-}
+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"
diff --git a/packages/flutter/lib/src/cupertino/segmented_control.dart b/packages/flutter/lib/src/cupertino/segmented_control.dart
index 3506c0a..82cb6db 100644
--- a/packages/flutter/lib/src/cupertino/segmented_control.dart
+++ b/packages/flutter/lib/src/cupertino/segmented_control.dart
@@ -382,6 +382,7 @@
       );
 
       child = GestureDetector(
+        behavior: HitTestBehavior.opaque,
         onTapDown: (TapDownDetails event) {
           _onTapDown(currentKey);
         },
diff --git a/packages/flutter/lib/src/material/dropdown.dart b/packages/flutter/lib/src/material/dropdown.dart
index fe22689..9775ea0 100644
--- a/packages/flutter/lib/src/material/dropdown.dart
+++ b/packages/flutter/lib/src/material/dropdown.dart
@@ -1539,4 +1539,12 @@
     assert(widget.onChanged != null);
     widget.onChanged(value);
   }
+
+  @override
+  void didUpdateWidget(DropdownButtonFormField<T> oldWidget) {
+    super.didUpdateWidget(oldWidget);
+    if (oldWidget.initialValue != widget.initialValue) {
+      setValue(widget.initialValue);
+    }
+  }
 }
diff --git a/packages/flutter/test/cupertino/segmented_control_test.dart b/packages/flutter/test/cupertino/segmented_control_test.dart
index 86384a1..bdf1927 100644
--- a/packages/flutter/test/cupertino/segmented_control_test.dart
+++ b/packages/flutter/test/cupertino/segmented_control_test.dart
@@ -926,6 +926,44 @@
     expect(sharedValue, 0);
   });
 
+  testWidgets(
+    'Segment still hittable with a child that has no hitbox',
+    (WidgetTester tester) async {
+      // Regression test for https://github.com/flutter/flutter/issues/57326.
+      final Map<int, Widget> children = <int, Widget>{};
+      children[0] = const Text('Child 1');
+      children[1] = const SizedBox();
+      int sharedValue = 0;
+
+      await tester.pumpWidget(
+        StatefulBuilder(
+          builder: (BuildContext context, StateSetter setState) {
+            return boilerplate(
+              child: CupertinoSegmentedControl<int>(
+                key: const ValueKey<String>('Segmented Control'),
+                children: children,
+                onValueChanged: (int newValue) {
+                  setState(() {
+                    sharedValue = newValue;
+                  });
+                },
+                groupValue: sharedValue,
+              ),
+            );
+          },
+        ),
+      );
+
+      expect(sharedValue, 0);
+
+      final Offset centerOfTwo = tester.getCenter(find.byWidget(children[1]));
+      // Tap within the bounds of children[1], but not at the center.
+      // children[1] is a SizedBox thus not hittable by itself.
+      await tester.tapAt(centerOfTwo + const Offset(10, 0));
+
+      expect(sharedValue, 1);
+  });
+
   testWidgets('Animation is correct when the selected segment changes', (WidgetTester tester) async {
     await tester.pumpWidget(setupSimpleSegmentedControl());
 
diff --git a/packages/flutter/test/cupertino/sliding_segmented_control_test.dart b/packages/flutter/test/cupertino/sliding_segmented_control_test.dart
index bd92bd2..1c13302 100644
--- a/packages/flutter/test/cupertino/sliding_segmented_control_test.dart
+++ b/packages/flutter/test/cupertino/sliding_segmented_control_test.dart
@@ -776,7 +776,8 @@
     expect(groupValue, 0);
 
     final Offset centerOfTwo = tester.getCenter(find.byWidget(children[1]));
-    // Tap just inside segment bounds
+    // Tap within the bounds of children[1], but not at the center.
+    // children[1] is a SizedBox thus not hittable by itself.
     await tester.tapAt(centerOfTwo + const Offset(10, 0));
 
     expect(groupValue, 1);
diff --git a/packages/flutter/test/material/dropdown_form_field_test.dart b/packages/flutter/test/material/dropdown_form_field_test.dart
index 224e07f..e5e7d6f 100644
--- a/packages/flutter/test/material/dropdown_form_field_test.dart
+++ b/packages/flutter/test/material/dropdown_form_field_test.dart
@@ -715,4 +715,50 @@
     expect(value, equals('two'));
     expect(dropdownButtonTapCounter, 2); // Should not change.
   });
+
+  testWidgets('DropdownButtonFormField should re-render if value param changes', (WidgetTester tester) async {
+    String currentValue = 'two';
+
+    await tester.pumpWidget(
+      StatefulBuilder(
+        builder: (BuildContext context, StateSetter setState) {
+          return MaterialApp(
+            home: Material(
+              child: DropdownButtonFormField<String>(
+                value: currentValue,
+                onChanged: onChanged,
+                items: menuItems.map((String value) {
+                  return DropdownMenuItem<String>(
+                    value: value,
+                    child: Text(value),
+                    onTap: () {
+                      setState(() {
+                        currentValue = value;
+                      });
+                    },
+                  );
+                }).toList(),
+              ),
+            ),
+          );
+        },
+      ),
+    );
+
+    // Make sure the rendered text value matches the initial state value.
+    expect(currentValue, equals('two'));
+    expect(find.text(currentValue), findsOneWidget);
+
+    // Tap the DropdownButtonFormField widget
+    await tester.tap(find.byType(dropdownButtonType));
+    await tester.pumpAndSettle();
+
+    // Tap the first dropdown menu item.
+    await tester.tap(find.text('one').last);
+    await tester.pumpAndSettle();
+
+    // Make sure the rendered text value matches the updated state value.
+    expect(currentValue, equals('one'));
+    expect(find.text(currentValue), findsOneWidget);
+  });
 }
diff --git a/packages/flutter_tools/bin/xcode_backend.sh b/packages/flutter_tools/bin/xcode_backend.sh
index 37806d5..f8c2795 100755
--- a/packages/flutter_tools/bin/xcode_backend.sh
+++ b/packages/flutter_tools/bin/xcode_backend.sh
@@ -277,15 +277,18 @@
 # Adds the App.framework as an embedded binary and the flutter_assets as
 # resources.
 EmbedFlutterFrameworks() {
-  AssertExists "${FLUTTER_APPLICATION_PATH}"
+  local project_path="${SOURCE_ROOT}/.."
+  if [[ -n "$FLUTTER_APPLICATION_PATH" ]]; then
+    project_path="${FLUTTER_APPLICATION_PATH}"
+  fi
 
   # Prefer the hidden .ios folder, but fallback to a visible ios folder if .ios
   # doesn't exist.
-  local flutter_ios_out_folder="${FLUTTER_APPLICATION_PATH}/.ios/Flutter"
-  local flutter_ios_engine_folder="${FLUTTER_APPLICATION_PATH}/.ios/Flutter/engine"
+  local flutter_ios_out_folder="${project_path}/.ios/Flutter"
+  local flutter_ios_engine_folder="${project_path}/.ios/Flutter/engine"
   if [[ ! -d ${flutter_ios_out_folder} ]]; then
-    flutter_ios_out_folder="${FLUTTER_APPLICATION_PATH}/ios/Flutter"
-    flutter_ios_engine_folder="${FLUTTER_APPLICATION_PATH}/ios/Flutter"
+    flutter_ios_out_folder="${project_path}/ios/Flutter"
+    flutter_ios_engine_folder="${project_path}/ios/Flutter"
   fi
 
   AssertExists "${flutter_ios_out_folder}"
diff --git a/packages/flutter_tools/gradle/aar_init_script.gradle b/packages/flutter_tools/gradle/aar_init_script.gradle
index 030d9b2..0175e99 100644
--- a/packages/flutter_tools/gradle/aar_init_script.gradle
+++ b/packages/flutter_tools/gradle/aar_init_script.gradle
@@ -72,6 +72,14 @@
     }
 }
 
+void configurePlugin(Project project, String outputDir) {
+    if (!project.hasProperty("android")) {
+        // A plugin doesn't support the Android platform when this property isn't defined in the plugin.
+        return
+    }
+    configureProject(project, outputDir)
+}
+
 String getFlutterRoot(Project project) {
     if (!project.hasProperty("flutter-root")) {
         throw new GradleException("The `-Pflutter-root` flag must be specified.")
@@ -157,7 +165,7 @@
     // This is due to the Android Gradle Plugin expecting all library subprojects to be published
     // as Maven artifacts.
     modulePlugins.each { pluginProject ->
-        configureProject(pluginProject, moduleProject.property("output-dir"))
+        configurePlugin(pluginProject, moduleProject.property("output-dir"))
         moduleProject.android.libraryVariants.all { variant ->
             // Configure the `assembleAar<variantName>` task for each plugin's projects and make
             // the module's equivalent task depend on the plugin's task.
diff --git a/packages/flutter_tools/gradle/app_plugin_loader.gradle b/packages/flutter_tools/gradle/app_plugin_loader.gradle
new file mode 100644
index 0000000..f722ea8
--- /dev/null
+++ b/packages/flutter_tools/gradle/app_plugin_loader.gradle
@@ -0,0 +1,30 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is included from `<app>/android/settings.gradle`,
+// so it can be versioned with the Flutter SDK.
+
+import groovy.json.JsonSlurper
+
+def flutterProjectRoot = rootProject.projectDir.parentFile
+
+// Note: if this logic is changed, also change the logic in module_plugin_loader.gradle.
+def pluginsFile = new File(flutterProjectRoot, '.flutter-plugins-dependencies')
+if (!pluginsFile.exists()) {
+  return
+}
+
+def object = new JsonSlurper().parseText(pluginsFile.text)
+assert object instanceof Map
+assert object.plugins instanceof Map
+assert object.plugins.android instanceof List
+// Includes the Flutter plugins that support the Android platform.
+object.plugins.android.each { androidPlugin ->
+  assert androidPlugin.name instanceof String
+  assert androidPlugin.path instanceof String
+  def pluginDirectory = new File(androidPlugin.path, 'android')
+  assert pluginDirectory.exists()
+  include ":${androidPlugin.name}"
+  project(":${androidPlugin.name}").projectDir = pluginDirectory
+}
diff --git a/packages/flutter_tools/gradle/deprecated_settings.gradle b/packages/flutter_tools/gradle/deprecated_settings.gradle
index 98e3600..c276a6f 100644
--- a/packages/flutter_tools/gradle/deprecated_settings.gradle
+++ b/packages/flutter_tools/gradle/deprecated_settings.gradle
@@ -29,3 +29,19 @@
     include ":$name"
     project(":$name").projectDir = pluginDirectory
 }
+;EOF
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+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"
diff --git a/packages/flutter_tools/gradle/manual_migration_settings.gradle.md b/packages/flutter_tools/gradle/manual_migration_settings.gradle.md
index f899531..b8e062f 100644
--- a/packages/flutter_tools/gradle/manual_migration_settings.gradle.md
+++ b/packages/flutter_tools/gradle/manual_migration_settings.gradle.md
@@ -3,17 +3,12 @@
     1. Copy `settings.gradle` as `settings_aar.gradle`
     2. Remove the following code from `settings_aar.gradle`:
 
-            def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+        def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+        def properties = new Properties()
 
-            def plugins = new Properties()
-            def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
-            if (pluginsFile.exists()) {
-                pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
-            }
+        assert localPropertiesFile.exists()
+        localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
 
-            plugins.each { name, path ->
-                def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
-                include ":$name"
-                project(":$name").projectDir = pluginDirectory
-            }
-
+        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"
diff --git a/packages/flutter_tools/gradle/module_plugin_loader.gradle b/packages/flutter_tools/gradle/module_plugin_loader.gradle
new file mode 100644
index 0000000..ebce109
--- /dev/null
+++ b/packages/flutter_tools/gradle/module_plugin_loader.gradle
@@ -0,0 +1,44 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is included from `<module>/.android/include_flutter.groovy`,
+// so it can be versioned with the Flutter SDK.
+
+import groovy.json.JsonSlurper
+
+def moduleProjectRoot = project(':flutter').projectDir.parentFile.parentFile
+
+// Note: if this logic is changed, also change the logic in app_plugin_loader.gradle.
+def pluginsFile = new File(moduleProjectRoot, '.flutter-plugins-dependencies')
+if (pluginsFile.exists()) {
+    def object = new JsonSlurper().parseText(pluginsFile.text)
+    assert object instanceof Map
+    assert object.plugins instanceof Map
+    assert object.plugins.android instanceof List
+    // Includes the Flutter plugins that support the Android platform.
+    object.plugins.android.each { androidPlugin ->
+        assert androidPlugin.name instanceof String
+        assert androidPlugin.path instanceof String
+        def pluginDirectory = new File(androidPlugin.path, 'android')
+        assert pluginDirectory.exists()
+        include ":${androidPlugin.name}"
+        project(":${androidPlugin.name}").projectDir = pluginDirectory
+    }
+}
+
+gradle.getGradle().projectsLoaded { g ->
+    g.rootProject.beforeEvaluate { p ->
+        def _mainModuleName = binding.variables['mainModuleName']
+        if (_mainModuleName != null && !_mainModuleName.empty) {
+            p.ext.mainModuleName = _mainModuleName
+        }
+    }
+    g.rootProject.afterEvaluate { p ->
+        p.subprojects { sp ->
+            if (sp.name != 'flutter') {
+                sp.evaluationDependsOn(':flutter')
+            }
+        }
+    }
+}
diff --git a/packages/flutter_tools/lib/src/commands/upgrade.dart b/packages/flutter_tools/lib/src/commands/upgrade.dart
index 21d1569..3c0b182 100644
--- a/packages/flutter_tools/lib/src/commands/upgrade.dart
+++ b/packages/flutter_tools/lib/src/commands/upgrade.dart
@@ -219,12 +219,23 @@
           workingDirectory: workingDirectory,
       );
       revision = result.stdout.trim();
-    } on Exception {
-      throwToolExit(
-        'Unable to upgrade Flutter: no origin repository configured. '
-        "Run 'git remote add origin "
-        "https://github.com/flutter/flutter' in $workingDirectory",
-      );
+    } on Exception catch (e) {
+      final String errorString = e.toString();
+      if (errorString.contains('fatal: HEAD does not point to a branch')) {
+        throwToolExit(
+          'You are not currently on a release branch. Use git to '
+          'check out an official branch (\'stable\', \'beta\', \'dev\', or \'master\') '
+          'and retry, for example:\n'
+          '  git checkout stable'
+        );
+      } else if (errorString.contains('fatal: no upstream configured for branch')) {
+        throwToolExit(
+          'Unable to upgrade Flutter: no origin repository configured. '
+          'Run \'git remote add origin '
+          'https://github.com/flutter/flutter\' in $workingDirectory');
+      } else {
+        throwToolExit(errorString);
+      }
     }
     return revision;
   }
diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart
index 7f013a4..636f52b 100644
--- a/packages/flutter_tools/lib/src/resident_runner.dart
+++ b/packages/flutter_tools/lib/src/resident_runner.dart
@@ -787,6 +787,13 @@
     await Future.wait(futures);
   }
 
+  Future<void> refreshVM() async {
+    final List<Future<void>> futures = <Future<void>>[
+      for (final FlutterDevice device in flutterDevices) device.getVMs(),
+    ];
+    await Future.wait(futures);
+  }
+
   Future<void> debugDumpApp() async {
     await refreshViews();
     for (final FlutterDevice device in flutterDevices) {
diff --git a/packages/flutter_tools/lib/src/run_hot.dart b/packages/flutter_tools/lib/src/run_hot.dart
index 727e062..3df2c5b 100644
--- a/packages/flutter_tools/lib/src/run_hot.dart
+++ b/packages/flutter_tools/lib/src/run_hot.dart
@@ -798,6 +798,7 @@
 
     if (!_isPaused()) {
       globals.printTrace('Refreshing active FlutterViews before reloading.');
+      await refreshVM();
       await refreshViews();
     }
 
diff --git a/packages/flutter_tools/templates/app/android.tmpl/settings.gradle b/packages/flutter_tools/templates/app/android.tmpl/settings.gradle
index 5a2f14f..d3b6a40 100644
--- a/packages/flutter_tools/templates/app/android.tmpl/settings.gradle
+++ b/packages/flutter_tools/templates/app/android.tmpl/settings.gradle
@@ -1,15 +1,15 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
 include ':app'
 
-def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
 
-def plugins = new Properties()
-def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
-if (pluginsFile.exists()) {
-    pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
-}
+assert localPropertiesFile.exists()
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
 
-plugins.each { name, path ->
-    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
-    include ":$name"
-    project(":$name").projectDir = pluginDirectory
-}
+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"
diff --git a/packages/flutter_tools/templates/module/android/library/include_flutter.groovy.copy.tmpl b/packages/flutter_tools/templates/module/android/library/include_flutter.groovy.copy.tmpl
index c6939be..ddec9ad 100644
--- a/packages/flutter_tools/templates/module/android/library/include_flutter.groovy.copy.tmpl
+++ b/packages/flutter_tools/templates/module/android/library/include_flutter.groovy.copy.tmpl
@@ -1,35 +1,20 @@
-// Generated file. Do not edit.
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
 
 def scriptFile = getClass().protectionDomain.codeSource.location.toURI()
 def flutterProjectRoot = new File(scriptFile).parentFile.parentFile
 
-gradle.include ':flutter'
-gradle.project(':flutter').projectDir = new File(flutterProjectRoot, '.android/Flutter')
+gradle.include ":flutter"
+gradle.project(":flutter").projectDir = new File(flutterProjectRoot, ".android/Flutter")
 
-def plugins = new Properties()
-def pluginsFile = new File(flutterProjectRoot, '.flutter-plugins')
-if (pluginsFile.exists()) {
-    pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
-}
+def localPropertiesFile = new File(flutterProjectRoot, ".android/local.properties")
+def properties = new Properties()
 
-plugins.each { name, path ->
-    def pluginDirectory = flutterProjectRoot.toPath().resolve(path).resolve('android').toFile()
-    gradle.include ":$name"
-    gradle.project(":$name").projectDir = pluginDirectory
-}
+assert localPropertiesFile.exists(), "❗️The Flutter module doesn't have a `$localPropertiesFile` file." +
+                                     "\nYou must run `flutter pub get` in `$flutterProjectRoot`."
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
 
-gradle.getGradle().projectsLoaded { g ->
-    g.rootProject.beforeEvaluate { p ->
-        _mainModuleName = binding.variables['mainModuleName']
-        if (_mainModuleName != null && !_mainModuleName.empty) {
-            p.ext.mainModuleName = _mainModuleName
-        }
-    }
-    g.rootProject.afterEvaluate { p ->
-        p.subprojects { sp ->
-            if (sp.name != 'flutter') {
-                sp.evaluationDependsOn(':flutter')
-            }
-        }
-    }
-}
+def flutterSdkPath = properties.getProperty("flutter.sdk")
+assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
+gradle.apply from: "$flutterSdkPath/packages/flutter_tools/gradle/module_plugin_loader.gradle"
diff --git a/packages/flutter_tools/templates/module/android/library_new_embedding/include_flutter.groovy.copy.tmpl b/packages/flutter_tools/templates/module/android/library_new_embedding/include_flutter.groovy.copy.tmpl
index c6939be..ddec9ad 100644
--- a/packages/flutter_tools/templates/module/android/library_new_embedding/include_flutter.groovy.copy.tmpl
+++ b/packages/flutter_tools/templates/module/android/library_new_embedding/include_flutter.groovy.copy.tmpl
@@ -1,35 +1,20 @@
-// Generated file. Do not edit.
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
 
 def scriptFile = getClass().protectionDomain.codeSource.location.toURI()
 def flutterProjectRoot = new File(scriptFile).parentFile.parentFile
 
-gradle.include ':flutter'
-gradle.project(':flutter').projectDir = new File(flutterProjectRoot, '.android/Flutter')
+gradle.include ":flutter"
+gradle.project(":flutter").projectDir = new File(flutterProjectRoot, ".android/Flutter")
 
-def plugins = new Properties()
-def pluginsFile = new File(flutterProjectRoot, '.flutter-plugins')
-if (pluginsFile.exists()) {
-    pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
-}
+def localPropertiesFile = new File(flutterProjectRoot, ".android/local.properties")
+def properties = new Properties()
 
-plugins.each { name, path ->
-    def pluginDirectory = flutterProjectRoot.toPath().resolve(path).resolve('android').toFile()
-    gradle.include ":$name"
-    gradle.project(":$name").projectDir = pluginDirectory
-}
+assert localPropertiesFile.exists(), "❗️The Flutter module doesn't have a `$localPropertiesFile` file." +
+                                     "\nYou must run `flutter pub get` in `$flutterProjectRoot`."
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
 
-gradle.getGradle().projectsLoaded { g ->
-    g.rootProject.beforeEvaluate { p ->
-        _mainModuleName = binding.variables['mainModuleName']
-        if (_mainModuleName != null && !_mainModuleName.empty) {
-            p.ext.mainModuleName = _mainModuleName
-        }
-    }
-    g.rootProject.afterEvaluate { p ->
-        p.subprojects { sp ->
-            if (sp.name != 'flutter') {
-                sp.evaluationDependsOn(':flutter')
-            }
-        }
-    }
-}
+def flutterSdkPath = properties.getProperty("flutter.sdk")
+assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
+gradle.apply from: "$flutterSdkPath/packages/flutter_tools/gradle/module_plugin_loader.gradle"
diff --git a/packages/flutter_tools/test/commands.shard/permeable/upgrade_test.dart b/packages/flutter_tools/test/commands.shard/permeable/upgrade_test.dart
index 633ff27..e85c6ea 100644
--- a/packages/flutter_tools/test/commands.shard/permeable/upgrade_test.dart
+++ b/packages/flutter_tools/test/commands.shard/permeable/upgrade_test.dart
@@ -161,7 +161,7 @@
       Platform: () => fakePlatform,
     });
 
-    testUsingContext('fetchRemoteRevision', () async {
+    testUsingContext('fetchRemoteRevision returns revision if git succeeds', () async {
       const String revision = 'abc123';
       when(processManager.run(
         <String>['git', 'fetch', '--tags'],
@@ -186,6 +186,60 @@
       Platform: () => fakePlatform,
     });
 
+    testUsingContext('fetchRemoteRevision throws toolExit if HEAD is detached', () async {
+      when(processManager.run(
+        <String>['git', 'fetch', '--tags'],
+        environment:anyNamed('environment'),
+        workingDirectory: anyNamed('workingDirectory')),
+      ).thenAnswer((Invocation invocation) async {
+        return FakeProcessResult()..exitCode = 0;
+      });
+      when(processManager.run(
+        <String>['git', 'rev-parse', '--verify', '@{u}'],
+        environment:anyNamed('environment'),
+        workingDirectory: anyNamed('workingDirectory')),
+      ).thenThrow(const ProcessException(
+        'git',
+        <String>['rev-parse', '--verify', '@{u}'],
+        'fatal: HEAD does not point to a branch',
+      ));
+      expect(
+        () async => await realCommandRunner.fetchRemoteRevision(),
+        throwsToolExit(message: 'You are not currently on a release branch.'),
+      );
+    }, overrides: <Type, Generator>{
+      ProcessManager: () => processManager,
+      Platform: () => fakePlatform,
+    });
+
+    testUsingContext('fetchRemoteRevision throws toolExit if no upstream configured', () async {
+      when(processManager.run(
+        <String>['git', 'fetch', '--tags'],
+        environment:anyNamed('environment'),
+        workingDirectory: anyNamed('workingDirectory')),
+      ).thenAnswer((Invocation invocation) async {
+        return FakeProcessResult()..exitCode = 0;
+      });
+      when(processManager.run(
+        <String>['git', 'rev-parse', '--verify', '@{u}'],
+        environment:anyNamed('environment'),
+        workingDirectory: anyNamed('workingDirectory')),
+      ).thenThrow(const ProcessException(
+        'git',
+        <String>['rev-parse', '--verify', '@{u}'],
+        'fatal: no upstream configured for branch',
+      ));
+      expect(
+        () async => await realCommandRunner.fetchRemoteRevision(),
+        throwsToolExit(
+          message: 'Unable to upgrade Flutter: no origin repository configured\.',
+        ),
+      );
+    }, overrides: <Type, Generator>{
+      ProcessManager: () => processManager,
+      Platform: () => fakePlatform,
+    });
+
     testUsingContext('git exception during attemptReset throwsToolExit', () async {
       const String revision = 'abc123';
       const String errorMessage = 'fatal: Could not parse object ´$revision´';
diff --git a/packages/flutter_tools/test/general.shard/android/gradle_test.dart b/packages/flutter_tools/test/general.shard/android/gradle_test.dart
index 4906b66..4d20f5d 100644
--- a/packages/flutter_tools/test/general.shard/android/gradle_test.dart
+++ b/packages/flutter_tools/test/general.shard/android/gradle_test.dart
@@ -470,8 +470,10 @@
 
 plugins.each { name, path ->
     def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
-    include ":$name"
-    project(":$name").projectDir = pluginDirectory
+    if (pluginDirectory.exists()) {
+        include ":$name"
+        project(":$name").projectDir = pluginDirectory
+    }
 }
 ''';
 
diff --git a/packages/flutter_tools/test/general.shard/resident_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_runner_test.dart
index bbf44b2..fe93619 100644
--- a/packages/flutter_tools/test/general.shard/resident_runner_test.dart
+++ b/packages/flutter_tools/test/general.shard/resident_runner_test.dart
@@ -110,6 +110,7 @@
       });
     when(mockFlutterDevice.vmService).thenReturn(mockVMService);
     when(mockFlutterDevice.refreshViews()).thenAnswer((Invocation invocation) async { });
+    when(mockFlutterDevice.getVMs()).thenAnswer((Invocation invocation) async { });
     when(mockFlutterDevice.reloadSources(any, pause: anyNamed('pause'))).thenReturn(<Future<Map<String, dynamic>>>[
       Future<Map<String, dynamic>>.value(<String, dynamic>{
         'type': 'ReloadReport',