diff --git a/packages/flutter_tools/lib/src/flutter_plugins.dart b/packages/flutter_tools/lib/src/flutter_plugins.dart index 3d11a0cf4b..5ae90d9d17 100644 --- a/packages/flutter_tools/lib/src/flutter_plugins.dart +++ b/packages/flutter_tools/lib/src/flutter_plugins.dart @@ -244,9 +244,8 @@ bool _writeFlutterPluginsList( final String? oldPluginsFileStringContent = _readFileContent(pluginsFile); bool pluginsChanged = true; if (oldPluginsFileStringContent != null) { - Object? decodedJson; try { - decodedJson = jsonDecode(oldPluginsFileStringContent); + final Object? decodedJson = jsonDecode(oldPluginsFileStringContent); if (decodedJson is Map) { final String jsonOfNewPluginsMap = jsonEncode(pluginsMap); final String jsonOfOldPluginsMap = jsonEncode(decodedJson[_kFlutterPluginsPluginListKey]); @@ -1100,12 +1099,17 @@ void _createPlatformPluginSymlinks( /// dependencies declared in `pubspec.yaml`. /// /// Assumes `pub get` has been executed since last change to `pubspec.yaml`. +/// +/// Unless explicitly specified, [determineDevDependencies] is disabled by +/// default; if set to `true`, plugins that are development-only dependencies +/// may be labeled or, depending on the platform, omitted from metadata or +/// platform-specific artifacts. Future refreshPluginsList( FlutterProject project, { bool iosPlatform = false, bool macOSPlatform = false, bool forceCocoaPodsOnly = false, - bool? determineDevDependencies, + bool determineDevDependencies = false, bool? generateLegacyPlugins, }) async { final List plugins = await findPlugins( diff --git a/packages/flutter_tools/lib/src/project.dart b/packages/flutter_tools/lib/src/project.dart index cfa7b18e63..1f95962dcf 100644 --- a/packages/flutter_tools/lib/src/project.dart +++ b/packages/flutter_tools/lib/src/project.dart @@ -358,7 +358,12 @@ class FlutterProject { if (!directory.existsSync() || isPlugin) { return; } - await refreshPluginsList(this, iosPlatform: iosPlatform, macOSPlatform: macOSPlatform); + await refreshPluginsList( + this, + iosPlatform: iosPlatform, + macOSPlatform: macOSPlatform, + determineDevDependencies: releaseMode ?? false, + ); if (androidPlatform) { await android.ensureReadyForPlatformSpecificTooling(deprecationBehavior: deprecationBehavior); } diff --git a/packages/flutter_tools/test/general.shard/project_test.dart b/packages/flutter_tools/test/general.shard/project_test.dart index f1ceca8d9d..6dc8c6c68d 100644 --- a/packages/flutter_tools/test/general.shard/project_test.dart +++ b/packages/flutter_tools/test/general.shard/project_test.dart @@ -31,6 +31,12 @@ import '../src/fake_pub_deps.dart'; import '../src/fakes.dart'; void main() { + // TODO(matanlurey): Remove after `explicit-package-dependencies` is enabled by default. + // See https://github.com/flutter/flutter/issues/160257 for details. + FeatureFlags enableExplicitPackageDependencies() { + return TestFeatureFlags(isExplicitPackageDependenciesEnabled: true); + } + // TODO(zanderso): remove once FlutterProject is fully refactored. // this is safe since no tests have expectations on the test logger. final BufferLogger logger = BufferLogger.test(); @@ -272,6 +278,59 @@ void main() { await project.regeneratePlatformSpecificTooling(); expectExists(project.android.hostAppGradleRoot.childFile('local.properties')); }); + + testUsingContext( + 'omitted release mode does not determine dev dependencies', + () async { + // Create a plugin. + await aPluginProject(); + // Create a project that depends on that plugin. + final FlutterProject project = await projectWithPluginDependency(); + // Don't bother with Android, we just want the manifest. + project.directory.childDirectory('android').deleteSync(recursive: true); + + await project.regeneratePlatformSpecificTooling(); + expect( + project.flutterPluginsDependenciesFile.readAsStringSync(), + isNot(contains('"dev_dependency":true')), + ); + }, + overrides: { + FeatureFlags: enableExplicitPackageDependencies, + FileSystem: () => MemoryFileSystem.test(), + ProcessManager: () => FakeProcessManager.any(), + Pub: () => FakePubWithPrimedDeps(devDependencies: {'my_plugin'}), + FlutterProjectFactory: + () => FlutterProjectFactory(logger: logger, fileSystem: globals.fs), + }, + ); + + testUsingContext( + 'specified release mode determines dev dependencies', + () async { + // Create a plugin. + await aPluginProject(); + // Create a project that depends on that plugin. + final FlutterProject project = await projectWithPluginDependency(); + // Don't bother with Android, we just want the manifest. + project.directory.childDirectory('android').deleteSync(recursive: true); + + await project.regeneratePlatformSpecificTooling(releaseMode: true); + expect( + project.flutterPluginsDependenciesFile.readAsStringSync(), + contains('"dev_dependency":true'), + ); + }, + overrides: { + FeatureFlags: enableExplicitPackageDependencies, + FileSystem: () => MemoryFileSystem.test(), + ProcessManager: () => FakeProcessManager.any(), + Pub: () => FakePubWithPrimedDeps(devDependencies: {'my_plugin'}), + FlutterProjectFactory: + () => FlutterProjectFactory(logger: logger, fileSystem: globals.fs), + }, + ); + testUsingContext( 'injects plugins for macOS', () async { @@ -1730,6 +1789,40 @@ Future someProject({ return FlutterProject.fromDirectory(directory); } +Future projectWithPluginDependency() async { + final Directory directory = globals.fs.directory('some_project'); + directory.childDirectory('.dart_tool').childFile('package_config.json') + ..createSync(recursive: true) + ..writeAsStringSync(''' +{ + "configVersion": 2, + "packages": [ + { + "name": "my_plugin", + "rootUri": "/plugin_project", + "packageUri": "lib/", + "languageVersion": "2.12" + } + ] +} +'''); + directory.childFile('pubspec.yaml') + ..createSync(recursive: true) + ..writeAsStringSync(''' +name: app_name +flutter: + +dependencies: + my_plugin: + sdk: flutter +'''); + directory.childDirectory('ios').createSync(recursive: true); + final Directory androidDirectory = directory.childDirectory('android') + ..createSync(recursive: true); + androidDirectory.childFile('AndroidManifest.xml').writeAsStringSync(''); + return FlutterProject.fromDirectory(directory); +} + Future aPluginProject({bool legacy = true}) async { final Directory directory = globals.fs.directory('plugin_project'); directory.childDirectory('ios').createSync(recursive: true); diff --git a/packages/flutter_tools/test/host_cross_arch.shard/macos_content_validation_test.dart b/packages/flutter_tools/test/host_cross_arch.shard/macos_content_validation_test.dart index 7f7dd82f05..da967be5c1 100644 --- a/packages/flutter_tools/test/host_cross_arch.shard/macos_content_validation_test.dart +++ b/packages/flutter_tools/test/host_cross_arch.shard/macos_content_validation_test.dart @@ -5,6 +5,7 @@ import 'package:file_testing/file_testing.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/io.dart'; +import 'package:flutter_tools/src/features.dart'; import '../integration.shard/test_utils.dart'; import '../src/common.dart'; @@ -14,6 +15,20 @@ void main() { setUpAll(() { processManager.runSync([flutterBin, 'config', '--enable-macos-desktop']); + + // TODO(matanlurey): Remove after `explicit-package-dependencies` is enabled by default. + // See https://github.com/flutter/flutter/issues/160257 for details. + if (!explicitPackageDependencies.master.enabledByDefault) { + processManager.runSync([flutterBin, 'config', '--explicit-package-dependencies']); + } + }); + + tearDownAll(() { + // TODO(matanlurey): Remove after `explicit-package-dependencies` is enabled by default. + // See https://github.com/flutter/flutter/issues/160257 for details. + if (!explicitPackageDependencies.master.enabledByDefault) { + processManager.runSync([flutterBin, 'config', '--no-explicit-package-dependencies']); + } }); for (final String buildMode in ['Debug', 'Release']) {