Unverified Commit 25b2edbd authored by stuartmorgan's avatar stuartmorgan Committed by GitHub

Enable inline Dart plugin implementation on Desktop (#96610)

parent 6477d3ee
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:package_config/package_config.dart'; import 'package:package_config/package_config.dart';
import 'package:path/path.dart' as path; // flutter_ignore: package_path_import import 'package:path/path.dart' as path; // flutter_ignore: package_path_import
import 'package:pub_semver/pub_semver.dart' as semver;
import 'package:yaml/yaml.dart'; import 'package:yaml/yaml.dart';
import 'android/gradle.dart'; import 'android/gradle.dart';
...@@ -53,6 +54,9 @@ Plugin? _pluginFromPackage(String name, Uri packageRoot, Set<String> appDependen ...@@ -53,6 +54,9 @@ Plugin? _pluginFromPackage(String name, Uri packageRoot, Set<String> appDependen
if (flutterConfig == null || flutterConfig is! YamlMap || !flutterConfig.containsKey('plugin')) { if (flutterConfig == null || flutterConfig is! YamlMap || !flutterConfig.containsKey('plugin')) {
return null; return null;
} }
final String? flutterConstraintText = (pubspec['environment'] as YamlMap?)?['flutter'] as String?;
final semver.VersionConstraint? flutterConstraint = flutterConstraintText == null ?
null : semver.VersionConstraint.parse(flutterConstraintText);
final String packageRootPath = fs.path.fromUri(packageRoot); final String packageRootPath = fs.path.fromUri(packageRoot);
final YamlMap? dependencies = pubspec['dependencies'] as YamlMap?; final YamlMap? dependencies = pubspec['dependencies'] as YamlMap?;
globals.printTrace('Found plugin $name at $packageRootPath'); globals.printTrace('Found plugin $name at $packageRootPath');
...@@ -60,6 +64,7 @@ Plugin? _pluginFromPackage(String name, Uri packageRoot, Set<String> appDependen ...@@ -60,6 +64,7 @@ Plugin? _pluginFromPackage(String name, Uri packageRoot, Set<String> appDependen
name, name,
packageRootPath, packageRootPath,
flutterConfig['plugin'] as YamlMap?, flutterConfig['plugin'] as YamlMap?,
flutterConstraint,
dependencies == null ? <String>[] : <String>[...dependencies.keys.cast<String>()], dependencies == null ? <String>[] : <String>[...dependencies.keys.cast<String>()],
fileSystem: fs, fileSystem: fs,
appDependencies: appDependencies, appDependencies: appDependencies,
...@@ -1204,14 +1209,26 @@ List<PluginInterfaceResolution> resolvePlatformImplementation( ...@@ -1204,14 +1209,26 @@ List<PluginInterfaceResolution> resolvePlatformImplementation(
if (defaultImplementation != null) { if (defaultImplementation != null) {
defaultImplementations['$platform/${plugin.name}'] = defaultImplementation; defaultImplementations['$platform/${plugin.name}'] = defaultImplementation;
continue; continue;
} else if (platform != 'linux' && platform != 'macos' && platform != 'windows') { } else {
// An interface package (i.e., one with no 'implements') with an // An app-facing package (i.e., one with no 'implements') with an
// inline implementation is its own default implementation. // inline implementation should be its own default implementation.
// TODO(stuartmorgan): This should be true on desktop as well, but // Desktop platforms originally did not work that way, and enabling
// enabling that would be a breaking change for most existing // it unconditionally would break existing published plugins, so
// Dart-only plugins. See https://github.com/flutter/flutter/issues/87862 // only treat it as such if either:
implementsPackage = plugin.name; // - the platform is not desktop, or
defaultImplementations['$platform/${plugin.name}'] = plugin.name; // - the plugin requires at least Flutter 2.11 (when this opt-in logic
// was added), so that existing plugins continue to work.
// See https://github.com/flutter/flutter/issues/87862 for details.
final bool isDesktop = platform == 'linux' || platform == 'macos' || platform == 'windows';
final semver.VersionConstraint? flutterConstraint = plugin.flutterConstraint;
final semver.Version? minFlutterVersion = flutterConstraint != null &&
flutterConstraint is semver.VersionRange ? flutterConstraint.min : null;
final bool hasMinVersionForImplementsRequirement = minFlutterVersion != null &&
minFlutterVersion.compareTo(semver.Version(2, 11, 0)) >= 0;
if (!isDesktop || hasMinVersionForImplementsRequirement) {
implementsPackage = plugin.name;
defaultImplementations['$platform/${plugin.name}'] = plugin.name;
}
} }
} }
if (plugin.pluginDartClassPlatforms[platform] == null || if (plugin.pluginDartClassPlatforms[platform] == null ||
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'package:pub_semver/pub_semver.dart';
import 'package:yaml/yaml.dart'; import 'package:yaml/yaml.dart';
import 'base/common.dart'; import 'base/common.dart';
...@@ -15,6 +16,7 @@ class Plugin { ...@@ -15,6 +16,7 @@ class Plugin {
required this.platforms, required this.platforms,
required this.defaultPackagePlatforms, required this.defaultPackagePlatforms,
required this.pluginDartClassPlatforms, required this.pluginDartClassPlatforms,
this.flutterConstraint,
required this.dependencies, required this.dependencies,
required this.isDirectDependency, required this.isDirectDependency,
this.implementsPackage, this.implementsPackage,
...@@ -58,6 +60,7 @@ class Plugin { ...@@ -58,6 +60,7 @@ class Plugin {
String name, String name,
String path, String path,
YamlMap? pluginYaml, YamlMap? pluginYaml,
VersionConstraint? flutterConstraint,
List<String> dependencies, { List<String> dependencies, {
required FileSystem fileSystem, required FileSystem fileSystem,
Set<String>? appDependencies, Set<String>? appDependencies,
...@@ -71,6 +74,7 @@ class Plugin { ...@@ -71,6 +74,7 @@ class Plugin {
name, name,
path, path,
pluginYaml, pluginYaml,
flutterConstraint,
dependencies, dependencies,
fileSystem, fileSystem,
appDependencies != null && appDependencies.contains(name), appDependencies != null && appDependencies.contains(name),
...@@ -80,6 +84,7 @@ class Plugin { ...@@ -80,6 +84,7 @@ class Plugin {
name, name,
path, path,
pluginYaml, pluginYaml,
flutterConstraint,
dependencies, dependencies,
fileSystem, fileSystem,
appDependencies != null && appDependencies.contains(name), appDependencies != null && appDependencies.contains(name),
...@@ -90,6 +95,7 @@ class Plugin { ...@@ -90,6 +95,7 @@ class Plugin {
String name, String name,
String path, String path,
YamlMap pluginYaml, YamlMap pluginYaml,
VersionConstraint? flutterConstraint,
List<String> dependencies, List<String> dependencies,
FileSystem fileSystem, FileSystem fileSystem,
bool isDirectDependency, bool isDirectDependency,
...@@ -165,6 +171,7 @@ class Plugin { ...@@ -165,6 +171,7 @@ class Plugin {
platforms: platforms, platforms: platforms,
defaultPackagePlatforms: defaultPackages, defaultPackagePlatforms: defaultPackages,
pluginDartClassPlatforms: dartPluginClasses, pluginDartClassPlatforms: dartPluginClasses,
flutterConstraint: flutterConstraint,
dependencies: dependencies, dependencies: dependencies,
isDirectDependency: isDirectDependency, isDirectDependency: isDirectDependency,
implementsPackage: pluginYaml['implements'] != null ? pluginYaml['implements'] as String : '', implementsPackage: pluginYaml['implements'] != null ? pluginYaml['implements'] as String : '',
...@@ -175,6 +182,7 @@ class Plugin { ...@@ -175,6 +182,7 @@ class Plugin {
String name, String name,
String path, String path,
dynamic pluginYaml, dynamic pluginYaml,
VersionConstraint? flutterConstraint,
List<String> dependencies, List<String> dependencies,
FileSystem fileSystem, FileSystem fileSystem,
bool isDirectDependency, bool isDirectDependency,
...@@ -207,6 +215,7 @@ class Plugin { ...@@ -207,6 +215,7 @@ class Plugin {
platforms: platforms, platforms: platforms,
defaultPackagePlatforms: <String, String>{}, defaultPackagePlatforms: <String, String>{},
pluginDartClassPlatforms: <String, String>{}, pluginDartClassPlatforms: <String, String>{},
flutterConstraint: flutterConstraint,
dependencies: dependencies, dependencies: dependencies,
isDirectDependency: isDirectDependency, isDirectDependency: isDirectDependency,
); );
...@@ -371,6 +380,9 @@ class Plugin { ...@@ -371,6 +380,9 @@ class Plugin {
/// If [null], this plugin doesn't implement an interface. /// If [null], this plugin doesn't implement an interface.
final String? implementsPackage; final String? implementsPackage;
/// The required version of Flutter, if specified.
final VersionConstraint? flutterConstraint;
/// The name of the packages this plugin depends on. /// The name of the packages this plugin depends on.
final List<String> dependencies; final List<String> dependencies;
......
...@@ -13,6 +13,7 @@ import 'package:flutter_tools/src/globals.dart' as globals; ...@@ -13,6 +13,7 @@ import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/plugins.dart'; import 'package:flutter_tools/src/plugins.dart';
import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/project.dart';
import 'package:package_config/package_config.dart'; import 'package:package_config/package_config.dart';
import 'package:pub_semver/pub_semver.dart';
import 'package:test/fake.dart'; import 'package:test/fake.dart';
import 'package:yaml/yaml.dart'; import 'package:yaml/yaml.dart';
...@@ -56,6 +57,7 @@ void main() { ...@@ -56,6 +57,7 @@ void main() {
}, },
}, },
}), }),
null,
<String>[], <String>[],
fileSystem: fs, fileSystem: fs,
appDependencies: directDependencies, appDependencies: directDependencies,
...@@ -71,6 +73,7 @@ void main() { ...@@ -71,6 +73,7 @@ void main() {
}, },
}, },
}), }),
null,
<String>[], <String>[],
fileSystem: fs, fileSystem: fs,
appDependencies: directDependencies, appDependencies: directDependencies,
...@@ -86,6 +89,7 @@ void main() { ...@@ -86,6 +89,7 @@ void main() {
}, },
}, },
}), }),
null,
<String>[], <String>[],
fileSystem: fs, fileSystem: fs,
appDependencies: directDependencies, appDependencies: directDependencies,
...@@ -104,6 +108,7 @@ void main() { ...@@ -104,6 +108,7 @@ void main() {
}, },
}, },
}), }),
null,
<String>[], <String>[],
fileSystem: fs, fileSystem: fs,
appDependencies: directDependencies, appDependencies: directDependencies,
...@@ -144,6 +149,7 @@ void main() { ...@@ -144,6 +149,7 @@ void main() {
}, },
}, },
}), }),
null,
<String>[], <String>[],
fileSystem: fs, fileSystem: fs,
appDependencies: directDependencies, appDependencies: directDependencies,
...@@ -166,9 +172,9 @@ void main() { ...@@ -166,9 +172,9 @@ void main() {
); );
}); });
// See https://github.com/flutter/flutter/issues/87862 for why this is // See https://github.com/flutter/flutter/issues/87862 for details.
// currently asserted even though it's not the desired behavior long term. testWithoutContext('does not select inline implementation on desktop for '
testWithoutContext('does not select inline implementation on desktop', () async { 'missing min Flutter SDK constraint', () async {
final Set<String> directDependencies = <String>{}; final Set<String> directDependencies = <String>{};
final List<PluginInterfaceResolution> resolutions = resolvePlatformImplementation(<Plugin>[ final List<PluginInterfaceResolution> resolutions = resolvePlatformImplementation(<Plugin>[
...@@ -188,6 +194,7 @@ void main() { ...@@ -188,6 +194,7 @@ void main() {
}, },
}, },
}), }),
null,
<String>[], <String>[],
fileSystem: fs, fileSystem: fs,
appDependencies: directDependencies, appDependencies: directDependencies,
...@@ -196,6 +203,87 @@ void main() { ...@@ -196,6 +203,87 @@ void main() {
expect(resolutions.length, equals(0)); expect(resolutions.length, equals(0));
}); });
// See https://github.com/flutter/flutter/issues/87862 for details.
testWithoutContext('does not select inline implementation on desktop for '
'min Flutter SDK constraint < 2.11', () async {
final Set<String> directDependencies = <String>{};
final List<PluginInterfaceResolution> resolutions = resolvePlatformImplementation(<Plugin>[
Plugin.fromYaml(
'url_launcher',
'',
YamlMap.wrap(<String, dynamic>{
'platforms': <String, dynamic>{
'linux': <String, dynamic>{
'dartPluginClass': 'UrlLauncherLinux',
},
'macos': <String, dynamic>{
'dartPluginClass': 'UrlLauncherMacOS',
},
'windows': <String, dynamic>{
'dartPluginClass': 'UrlLauncherWindows',
},
},
}),
VersionConstraint.parse('>=2.10.0'),
<String>[],
fileSystem: fs,
appDependencies: directDependencies,
),
]);
expect(resolutions.length, equals(0));
});
testWithoutContext('selects inline implementation on desktop for '
'min Flutter SDK requirement of at least 2.11', () async {
final Set<String> directDependencies = <String>{};
final List<PluginInterfaceResolution> resolutions = resolvePlatformImplementation(<Plugin>[
Plugin.fromYaml(
'url_launcher',
'',
YamlMap.wrap(<String, dynamic>{
'platforms': <String, dynamic>{
'linux': <String, dynamic>{
'dartPluginClass': 'UrlLauncherLinux',
},
'macos': <String, dynamic>{
'dartPluginClass': 'UrlLauncherMacOS',
},
'windows': <String, dynamic>{
'dartPluginClass': 'UrlLauncherWindows',
},
},
}),
VersionConstraint.parse('>=2.11.0'),
<String>[],
fileSystem: fs,
appDependencies: directDependencies,
),
]);
expect(resolutions.length, equals(3));
expect(
resolutions.map((PluginInterfaceResolution resolution) => resolution.toMap()),
containsAll(<Map<String, String>>[
<String, String>{
'pluginName': 'url_launcher',
'dartClass': 'UrlLauncherLinux',
'platform': 'linux',
},
<String, String>{
'pluginName': 'url_launcher',
'dartClass': 'UrlLauncherMacOS',
'platform': 'macos',
},
<String, String>{
'pluginName': 'url_launcher',
'dartClass': 'UrlLauncherWindows',
'platform': 'windows',
},
])
);
});
testWithoutContext('selects default implementation', () async { testWithoutContext('selects default implementation', () async {
final Set<String> directDependencies = <String>{}; final Set<String> directDependencies = <String>{};
...@@ -210,6 +298,7 @@ void main() { ...@@ -210,6 +298,7 @@ void main() {
}, },
}, },
}), }),
null,
<String>[], <String>[],
fileSystem: fs, fileSystem: fs,
appDependencies: directDependencies, appDependencies: directDependencies,
...@@ -225,6 +314,7 @@ void main() { ...@@ -225,6 +314,7 @@ void main() {
}, },
}, },
}), }),
null,
<String>[], <String>[],
fileSystem: fs, fileSystem: fs,
appDependencies: directDependencies, appDependencies: directDependencies,
...@@ -254,6 +344,7 @@ void main() { ...@@ -254,6 +344,7 @@ void main() {
}, },
}, },
}), }),
null,
<String>[], <String>[],
fileSystem: fs, fileSystem: fs,
appDependencies: directDependencies, appDependencies: directDependencies,
...@@ -269,6 +360,7 @@ void main() { ...@@ -269,6 +360,7 @@ void main() {
}, },
}, },
}), }),
null,
<String>[], <String>[],
fileSystem: fs, fileSystem: fs,
appDependencies: directDependencies, appDependencies: directDependencies,
...@@ -301,6 +393,7 @@ void main() { ...@@ -301,6 +393,7 @@ void main() {
}, },
}, },
}), }),
null,
<String>[], <String>[],
fileSystem: fs, fileSystem: fs,
appDependencies: directDependencies, appDependencies: directDependencies,
...@@ -316,6 +409,7 @@ void main() { ...@@ -316,6 +409,7 @@ void main() {
}, },
}, },
}), }),
null,
<String>[], <String>[],
fileSystem: fs, fileSystem: fs,
appDependencies: directDependencies, appDependencies: directDependencies,
...@@ -331,6 +425,7 @@ void main() { ...@@ -331,6 +425,7 @@ void main() {
}, },
}, },
}), }),
null,
<String>[], <String>[],
fileSystem: fs, fileSystem: fs,
appDependencies: directDependencies, appDependencies: directDependencies,
...@@ -363,6 +458,7 @@ void main() { ...@@ -363,6 +458,7 @@ void main() {
}, },
}, },
}), }),
null,
<String>[], <String>[],
fileSystem: fs, fileSystem: fs,
appDependencies: directDependencies, appDependencies: directDependencies,
...@@ -378,6 +474,7 @@ void main() { ...@@ -378,6 +474,7 @@ void main() {
}, },
}, },
}), }),
null,
<String>[], <String>[],
fileSystem: fs, fileSystem: fs,
appDependencies: directDependencies, appDependencies: directDependencies,
...@@ -393,6 +490,7 @@ void main() { ...@@ -393,6 +490,7 @@ void main() {
}, },
}, },
}), }),
null,
<String>[], <String>[],
fileSystem: fs, fileSystem: fs,
appDependencies: directDependencies, appDependencies: directDependencies,
...@@ -426,6 +524,7 @@ void main() { ...@@ -426,6 +524,7 @@ void main() {
}, },
}, },
}), }),
null,
<String>[], <String>[],
fileSystem: fs, fileSystem: fs,
appDependencies: directDependencies, appDependencies: directDependencies,
...@@ -441,6 +540,7 @@ void main() { ...@@ -441,6 +540,7 @@ void main() {
}, },
}, },
}), }),
null,
<String>[], <String>[],
fileSystem: fs, fileSystem: fs,
appDependencies: directDependencies, appDependencies: directDependencies,
...@@ -477,6 +577,7 @@ void main() { ...@@ -477,6 +577,7 @@ void main() {
}, },
}, },
}), }),
null,
<String>[], <String>[],
fileSystem: fs, fileSystem: fs,
appDependencies: directDependencies, appDependencies: directDependencies,
...@@ -492,6 +593,7 @@ void main() { ...@@ -492,6 +593,7 @@ void main() {
}, },
}, },
}), }),
null,
<String>[], <String>[],
fileSystem: fs, fileSystem: fs,
appDependencies: directDependencies, appDependencies: directDependencies,
...@@ -1001,6 +1103,7 @@ void dreamWithFlags() => run(interactive: false); ...@@ -1001,6 +1103,7 @@ void dreamWithFlags() => run(interactive: false);
}, },
}, },
}), }),
null,
<String>[], <String>[],
fileSystem: fs, fileSystem: fs,
appDependencies: directDependencies, appDependencies: directDependencies,
......
...@@ -25,6 +25,7 @@ void main() { ...@@ -25,6 +25,7 @@ void main() {
_kTestPluginName, _kTestPluginName,
_kTestPluginPath, _kTestPluginPath,
pluginYaml, pluginYaml,
null,
const <String>[], const <String>[],
fileSystem: fileSystem, fileSystem: fileSystem,
); );
...@@ -61,6 +62,7 @@ void main() { ...@@ -61,6 +62,7 @@ void main() {
_kTestPluginName, _kTestPluginName,
_kTestPluginPath, _kTestPluginPath,
pluginYaml, pluginYaml,
null,
const <String>[], const <String>[],
fileSystem: fileSystem, fileSystem: fileSystem,
); );
...@@ -108,6 +110,7 @@ void main() { ...@@ -108,6 +110,7 @@ void main() {
_kTestPluginName, _kTestPluginName,
_kTestPluginPath, _kTestPluginPath,
pluginYaml, pluginYaml,
null,
const <String>[], const <String>[],
fileSystem: fileSystem, fileSystem: fileSystem,
); );
...@@ -150,6 +153,7 @@ void main() { ...@@ -150,6 +153,7 @@ void main() {
_kTestPluginName, _kTestPluginName,
_kTestPluginPath, _kTestPluginPath,
pluginYaml, pluginYaml,
null,
const <String>[], const <String>[],
fileSystem: fileSystem, fileSystem: fileSystem,
); );
...@@ -187,6 +191,7 @@ void main() { ...@@ -187,6 +191,7 @@ void main() {
_kTestPluginName, _kTestPluginName,
_kTestPluginPath, _kTestPluginPath,
pluginYaml, pluginYaml,
null,
const <String>[], const <String>[],
fileSystem: fileSystem, fileSystem: fileSystem,
), ),
...@@ -216,6 +221,7 @@ void main() { ...@@ -216,6 +221,7 @@ void main() {
_kTestPluginName, _kTestPluginName,
_kTestPluginPath, _kTestPluginPath,
pluginYaml, pluginYaml,
null,
const <String>[], const <String>[],
fileSystem: fileSystem, fileSystem: fileSystem,
); );
...@@ -247,6 +253,7 @@ void main() { ...@@ -247,6 +253,7 @@ void main() {
_kTestPluginName, _kTestPluginName,
_kTestPluginPath, _kTestPluginPath,
pluginYaml, pluginYaml,
null,
const <String>[], const <String>[],
fileSystem: fileSystem, fileSystem: fileSystem,
); );
...@@ -273,6 +280,7 @@ void main() { ...@@ -273,6 +280,7 @@ void main() {
_kTestPluginName, _kTestPluginName,
_kTestPluginPath, _kTestPluginPath,
pluginYaml, pluginYaml,
null,
const <String>[], const <String>[],
fileSystem: fileSystem, fileSystem: fileSystem,
); );
...@@ -296,6 +304,7 @@ void main() { ...@@ -296,6 +304,7 @@ void main() {
_kTestPluginName, _kTestPluginName,
_kTestPluginPath, _kTestPluginPath,
pluginYaml, pluginYaml,
null,
const <String>[], const <String>[],
fileSystem: fileSystem, fileSystem: fileSystem,
); );
...@@ -321,6 +330,7 @@ void main() { ...@@ -321,6 +330,7 @@ void main() {
_kTestPluginName, _kTestPluginName,
_kTestPluginPath, _kTestPluginPath,
pluginYaml, pluginYaml,
null,
const <String>[], const <String>[],
fileSystem: fileSystem, fileSystem: fileSystem,
); );
...@@ -340,6 +350,7 @@ void main() { ...@@ -340,6 +350,7 @@ void main() {
_kTestPluginName, _kTestPluginName,
_kTestPluginPath, _kTestPluginPath,
pluginYaml, pluginYaml,
null,
const <String>[], const <String>[],
fileSystem: fileSystem, fileSystem: fileSystem,
), ),
...@@ -357,6 +368,7 @@ void main() { ...@@ -357,6 +368,7 @@ void main() {
_kTestPluginName, _kTestPluginName,
_kTestPluginPath, _kTestPluginPath,
pluginYaml, pluginYaml,
null,
const <String>[], const <String>[],
fileSystem: fileSystem, fileSystem: fileSystem,
), ),
...@@ -376,6 +388,7 @@ void main() { ...@@ -376,6 +388,7 @@ void main() {
_kTestPluginName, _kTestPluginName,
_kTestPluginPath, _kTestPluginPath,
pluginYaml, pluginYaml,
null,
const <String>[], const <String>[],
fileSystem: fileSystem, fileSystem: fileSystem,
), ),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment