[url_launcher] Support new desktop implementation versions (#4779)
diff --git a/packages/url_launcher/url_launcher/CHANGELOG.md b/packages/url_launcher/url_launcher/CHANGELOG.md
index 5eb5b4a..1634dcd 100644
--- a/packages/url_launcher/url_launcher/CHANGELOG.md
+++ b/packages/url_launcher/url_launcher/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 6.0.20
+
+* Fixes a typo in `default_package` registration for Windows, macOS, and Linux.
+
## 6.0.19
* Updates README:
diff --git a/packages/url_launcher/url_launcher/pubspec.yaml b/packages/url_launcher/url_launcher/pubspec.yaml
index 5d6548a..feb0a2c 100644
--- a/packages/url_launcher/url_launcher/pubspec.yaml
+++ b/packages/url_launcher/url_launcher/pubspec.yaml
@@ -3,7 +3,7 @@
web, phone, SMS, and email schemes.
repository: https://github.com/flutter/plugins/tree/main/packages/url_launcher/url_launcher
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+url_launcher%22
-version: 6.0.19
+version: 6.0.20
environment:
sdk: ">=2.14.0 <3.0.0"
@@ -17,24 +17,26 @@
ios:
default_package: url_launcher_ios
linux:
- default_package: url_laucher_linux
+ default_package: url_launcher_linux
macos:
- default_package: url_laucher_macos
+ default_package: url_launcher_macos
web:
default_package: url_launcher_web
windows:
- default_package: url_laucher_windows
+ default_package: url_launcher_windows
dependencies:
flutter:
sdk: flutter
url_launcher_android: ^6.0.13
url_launcher_ios: ^6.0.13
- url_launcher_linux: ^2.0.0
- url_launcher_macos: ^2.0.0
+ # Allow either the pure-native or Dart/native hybrid versions of the desktop
+ # implementations, as both are compatible.
+ url_launcher_linux: ">=2.0.0 <4.0.0"
+ url_launcher_macos: ">=2.0.0 <4.0.0"
url_launcher_platform_interface: ^2.0.3
url_launcher_web: ^2.0.0
- url_launcher_windows: ^2.0.0
+ url_launcher_windows: ">=2.0.0 <4.0.0"
dev_dependencies:
flutter_test:
diff --git a/script/tool/CHANGELOG.md b/script/tool/CHANGELOG.md
index 101bfac..fbf7610 100644
--- a/script/tool/CHANGELOG.md
+++ b/script/tool/CHANGELOG.md
@@ -17,6 +17,7 @@
for flake issues.
- Adds support for `CHROME_EXECUTABLE` in `drive-examples` to match similar
`flutter` behavior.
+- Validates `default_package` entries in plugins.
## 0.7.3
diff --git a/script/tool/lib/src/pubspec_check_command.dart b/script/tool/lib/src/pubspec_check_command.dart
index 4f2b208..2c27c91 100644
--- a/script/tool/lib/src/pubspec_check_command.dart
+++ b/script/tool/lib/src/pubspec_check_command.dart
@@ -6,6 +6,7 @@
import 'package:git/git.dart';
import 'package:platform/platform.dart';
import 'package:pubspec_parse/pubspec_parse.dart';
+import 'package:yaml/yaml.dart';
import 'common/core.dart';
import 'common/package_looping_command.dart';
@@ -100,9 +101,17 @@
}
if (isPlugin) {
- final String? error = _checkForImplementsError(pubspec, package: package);
- if (error != null) {
- printError('$indentation$error');
+ final String? implementsError =
+ _checkForImplementsError(pubspec, package: package);
+ if (implementsError != null) {
+ printError('$indentation$implementsError');
+ passing = false;
+ }
+
+ final String? defaultPackageError =
+ _checkForDefaultPackageError(pubspec, package: package);
+ if (defaultPackageError != null) {
+ printError('$indentation$defaultPackageError');
passing = false;
}
}
@@ -243,6 +252,49 @@
return null;
}
+ // Validates any "default_package" entries a plugin, returning an error
+ // string if there are any issues.
+ //
+ // Should only be called on plugin packages.
+ String? _checkForDefaultPackageError(
+ Pubspec pubspec, {
+ required RepositoryPackage package,
+ }) {
+ final dynamic platformsEntry = pubspec.flutter!['plugin']!['platforms'];
+ if (platformsEntry == null) {
+ logWarning('Does not implement any platforms');
+ return null;
+ }
+ final YamlMap platforms = platformsEntry as YamlMap;
+ final String packageName = package.directory.basename;
+
+ // Validate that the default_package entries look correct (e.g., no typos).
+ final Set<String> defaultPackages = <String>{};
+ for (final MapEntry<dynamic, dynamic> platformEntry in platforms.entries) {
+ final String? defaultPackage =
+ platformEntry.value['default_package'] as String?;
+ if (defaultPackage != null) {
+ defaultPackages.add(defaultPackage);
+ if (!defaultPackage.startsWith('${packageName}_')) {
+ return '"$defaultPackage" is not an expected implementation name '
+ 'for "$packageName"';
+ }
+ }
+ }
+
+ // Validate that all default_packages are also dependencies.
+ final Iterable<String> dependencies = pubspec.dependencies.keys;
+ final Iterable<String> missingPackages = defaultPackages
+ .where((String package) => !dependencies.contains(package));
+ if (missingPackages.isNotEmpty) {
+ return 'The following default_packages are missing '
+ 'corresponding dependencies:\n ' +
+ missingPackages.join('\n ');
+ }
+
+ return null;
+ }
+
// Returns true if [packageName] appears to be an implementation package
// according to repository conventions.
bool _isImplementationPackage(RepositoryPackage package) {
diff --git a/script/tool/test/pubspec_check_command_test.dart b/script/tool/test/pubspec_check_command_test.dart
index 9ad1eaa..42d2024 100644
--- a/script/tool/test/pubspec_check_command_test.dart
+++ b/script/tool/test/pubspec_check_command_test.dart
@@ -70,12 +70,27 @@
String _flutterSection({
bool isPlugin = false,
String? implementedPackage,
+ Map<String, Map<String, String>> pluginPlatformDetails =
+ const <String, Map<String, String>>{},
}) {
- final String pluginEntry = '''
+ String pluginEntry = '''
plugin:
${implementedPackage == null ? '' : ' implements: $implementedPackage'}
platforms:
''';
+
+ for (final MapEntry<String, Map<String, String>> platform
+ in pluginPlatformDetails.entries) {
+ pluginEntry += '''
+ ${platform.key}:
+''';
+ for (final MapEntry<String, String> detail in platform.value.entries) {
+ pluginEntry += '''
+ ${detail.key}: ${detail.value}
+''';
+ }
+ }
+
return '''
flutter:
${isPlugin ? pluginEntry : ''}
@@ -647,6 +662,82 @@
);
});
+ test('fails when a "default_package" looks incorrect', () async {
+ final Directory pluginDirectory =
+ createFakePlugin('plugin_a', packagesDir.childDirectory('plugin_a'));
+
+ pluginDirectory.childFile('pubspec.yaml').writeAsStringSync('''
+${_headerSection(
+ 'plugin_a',
+ isPlugin: true,
+ repositoryPackagesDirRelativePath: 'plugin_a/plugin_a',
+ )}
+${_environmentSection()}
+${_flutterSection(
+ isPlugin: true,
+ pluginPlatformDetails: <String, Map<String, String>>{
+ 'android': <String, String>{'default_package': 'plugin_b_android'}
+ },
+ )}
+${_dependenciesSection()}
+${_devDependenciesSection()}
+''');
+
+ Error? commandError;
+ final List<String> output = await runCapturingPrint(
+ runner, <String>['pubspec-check'], errorHandler: (Error e) {
+ commandError = e;
+ });
+
+ expect(commandError, isA<ToolExit>());
+ expect(
+ output,
+ containsAllInOrder(<Matcher>[
+ contains(
+ '"plugin_b_android" is not an expected implementation name for "plugin_a"'),
+ ]),
+ );
+ });
+
+ test(
+ 'fails when a "default_package" does not have a corresponding dependency',
+ () async {
+ final Directory pluginDirectory =
+ createFakePlugin('plugin_a', packagesDir.childDirectory('plugin_a'));
+
+ pluginDirectory.childFile('pubspec.yaml').writeAsStringSync('''
+${_headerSection(
+ 'plugin_a',
+ isPlugin: true,
+ repositoryPackagesDirRelativePath: 'plugin_a/plugin_a',
+ )}
+${_environmentSection()}
+${_flutterSection(
+ isPlugin: true,
+ pluginPlatformDetails: <String, Map<String, String>>{
+ 'android': <String, String>{'default_package': 'plugin_a_android'}
+ },
+ )}
+${_dependenciesSection()}
+${_devDependenciesSection()}
+''');
+
+ Error? commandError;
+ final List<String> output = await runCapturingPrint(
+ runner, <String>['pubspec-check'], errorHandler: (Error e) {
+ commandError = e;
+ });
+
+ expect(commandError, isA<ToolExit>());
+ expect(
+ output,
+ containsAllInOrder(<Matcher>[
+ contains('The following default_packages are missing corresponding '
+ 'dependencies:\n plugin_a_android'),
+ ]),
+ );
+ });
+
test('passes for an app-facing package without "implements"', () async {
final Directory pluginDirectory =
createFakePlugin('plugin_a', packagesDir.childDirectory('plugin_a'));