Unverified Commit 23cea267 authored by stuartmorgan's avatar stuartmorgan Committed by GitHub

Add dartPluginClass support for Android and iOS (#87991)

parent 0b38b9cb
......@@ -61,17 +61,14 @@ class DartPluginRegistrantTarget extends Target {
return true;
}
final String? platformName = environment.defines[kTargetPlatform];
if (platformName == null) {
return true;
}
final TargetPlatform? targetPlatform = getTargetPlatformForName(platformName);
// TODO(egarciad): Support Android and iOS.
// https://github.com/flutter/flutter/issues/52267
return targetPlatform != TargetPlatform.darwin &&
targetPlatform != TargetPlatform.linux_x64 &&
targetPlatform != TargetPlatform.linux_arm64 &&
targetPlatform != TargetPlatform.windows_x64 &&
targetPlatform != TargetPlatform.windows_uwp_x64;
final TargetPlatform? targetPlatform = platformName == null ? null
: getTargetPlatformForName(platformName);
// TODO(stuartmorgan): Investigate removing this check entirely; ideally the
// source generation step shouldn't be platform dependent, and the generated
// code should just do the right thing on every platform.
return targetPlatform == TargetPlatform.fuchsia_arm64 ||
targetPlatform == TargetPlatform.fuchsia_x64 ||
targetPlatform == TargetPlatform.web_javascript;
}
@override
......
......@@ -353,8 +353,9 @@ AndroidEmbeddingVersion _getAndroidEmbeddingVersion(FlutterProject project) {
}
Future<void> _writeAndroidPluginRegistrant(FlutterProject project, List<Plugin> plugins) async {
final List<Plugin> nativePlugins = _filterNativePlugins(plugins, AndroidPlugin.kConfigKey);
final List<Map<String, Object?>> androidPlugins =
_extractPlatformMaps(plugins, AndroidPlugin.kConfigKey);
_extractPlatformMaps(nativePlugins, AndroidPlugin.kConfigKey);
final Map<String, Object> templateContext = <String, Object>{
'plugins': androidPlugins,
......@@ -676,9 +677,9 @@ const String _dartPluginRegisterWith = r'''
}
''';
// TODO(egarciad): Evaluate merging the web and desktop plugin registry templates.
// TODO(egarciad): Evaluate merging the web and non-web plugin registry templates.
// https://github.com/flutter/flutter/issues/80406
const String _dartPluginRegistryForDesktopTemplate = '''
const String _dartPluginRegistryForNonWebTemplate = '''
//
// Generated file. Do not edit.
// This file is generated from template in file `flutter_tools/lib/src/flutter_plugins.dart`.
......@@ -688,6 +689,12 @@ const String _dartPluginRegistryForDesktopTemplate = '''
import '{{mainEntrypoint}}' as entrypoint;
import 'dart:io'; // flutter_ignore: dart_io_import.
{{#android}}
import 'package:{{pluginName}}/{{pluginName}}.dart';
{{/android}}
{{#ios}}
import 'package:{{pluginName}}/{{pluginName}}.dart';
{{/ios}}
{{#linux}}
import 'package:{{pluginName}}/{{pluginName}}.dart';
{{/linux}}
......@@ -703,7 +710,15 @@ class _PluginRegistrant {
@pragma('vm:entry-point')
static void register() {
if (Platform.isLinux) {
if (Platform.isAndroid) {
{{#android}}
$_dartPluginRegisterWith
{{/android}}
} else if (Platform.isIOS) {
{{#ios}}
$_dartPluginRegisterWith
{{/ios}}
} else if (Platform.isLinux) {
{{#linux}}
$_dartPluginRegisterWith
{{/linux}}
......@@ -733,7 +748,8 @@ void main(List<String> args) {
''';
Future<void> _writeIOSPluginRegistrant(FlutterProject project, List<Plugin> plugins) async {
final List<Map<String, Object?>> iosPlugins = _extractPlatformMaps(plugins, IOSPlugin.kConfigKey);
final List<Plugin> nativePlugins = _filterNativePlugins(plugins, IOSPlugin.kConfigKey);
final List<Map<String, Object?>> iosPlugins = _extractPlatformMaps(nativePlugins, IOSPlugin.kConfigKey);
final Map<String, Object> context = <String, Object>{
'os': 'ios',
'deploymentTarget': '9.0',
......@@ -1119,11 +1135,15 @@ bool hasPlugins(FlutterProject project) {
/// * Else fail.
///
/// For more details, https://flutter.dev/go/federated-plugins.
// TODO(stuartmorgan): Expand implementation to apply to all implementations,
// not just Dart-only, per the federated plugin spec.
List<PluginInterfaceResolution> resolvePlatformImplementation(
List<Plugin> plugins, {
bool throwOnPluginPubspecError = true,
}) {
final List<String> platforms = <String>[
AndroidPlugin.kConfigKey,
IOSPlugin.kConfigKey,
LinuxPlugin.kConfigKey,
MacOSPlugin.kConfigKey,
WindowsPlugin.kConfigKey,
......@@ -1135,20 +1155,28 @@ List<PluginInterfaceResolution> resolvePlatformImplementation(
for (final Plugin plugin in plugins) {
for (final String platform in platforms) {
// The plugin doesn't implement this platform.
if (plugin.platforms[platform] == null &&
plugin.defaultPackagePlatforms[platform] == null) {
// The plugin doesn't implement this platform.
continue;
}
// The plugin doesn't implement an interface, verify that it has a default implementation.
final String? implementsPackage = plugin.implementsPackage;
String? implementsPackage = plugin.implementsPackage;
if (implementsPackage == null || implementsPackage.isEmpty) {
final String? defaultImplementation = plugin.defaultPackagePlatforms[platform];
if (defaultImplementation == null) {
final bool hasInlineDartImplementation =
plugin.pluginDartClassPlatforms[platform] != null;
if (defaultImplementation == null && !hasInlineDartImplementation) {
if (throwOnPluginPubspecError) {
globals.printError(
"Plugin `${plugin.name}` doesn't implement a plugin interface, nor sets "
'a default implementation in pubspec.yaml.\n\n'
"Plugin `${plugin.name}` doesn't implement a plugin interface, nor does "
'it specify an implementation in pubspec.yaml.\n\n'
'To set an inline implementation, use:\n'
'flutter:\n'
' plugin:\n'
' platforms:\n'
' $platform:\n'
' $kDartPluginClass: <plugin-class>\n'
'\n'
'To set a default implementation, use:\n'
'flutter:\n'
' plugin:\n'
......@@ -1166,8 +1194,18 @@ List<PluginInterfaceResolution> resolvePlatformImplementation(
didFindError = true;
continue;
}
defaultImplementations['$platform/${plugin.name}'] = defaultImplementation;
continue;
if (defaultImplementation != null) {
defaultImplementations['$platform/${plugin.name}'] = defaultImplementation;
continue;
} else if (platform != 'linux' && platform != 'macos' && platform != 'windows') {
// An interface package (i.e., one with no 'implements') with an
// inline implementation is its own default implementation.
// TODO(stuartmorgan): This should be true on desktop as well, but
// enabling that would be a breaking change for most existing
// Dart-only plugins. See https://github.com/flutter/flutter/issues/87862
implementsPackage = plugin.name;
defaultImplementations['$platform/${plugin.name}'] = plugin.name;
}
}
if (plugin.pluginDartClassPlatforms[platform] == null ||
plugin.pluginDartClassPlatforms[platform] == 'none') {
......@@ -1249,6 +1287,8 @@ Future<void> generateMainDartWithPluginRegistrant(
final Map<String, Object> templateContext = <String, Object>{
'mainEntrypoint': currentMainUri,
'dartLanguageVersion': entrypointVersion.toString(),
AndroidPlugin.kConfigKey: <Object?>[],
IOSPlugin.kConfigKey: <Object?>[],
LinuxPlugin.kConfigKey: <Object?>[],
MacOSPlugin.kConfigKey: <Object?>[],
WindowsPlugin.kConfigKey: <Object?>[],
......@@ -1274,7 +1314,7 @@ Future<void> generateMainDartWithPluginRegistrant(
}
try {
_renderTemplateToFile(
_dartPluginRegistryForDesktopTemplate,
_dartPluginRegistryForNonWebTemplate,
templateContext,
newMainDart,
globals.templateRenderer,
......
......@@ -49,14 +49,22 @@ abstract class NativeOrDartPlugin {
/// Contains parameters to template an Android plugin.
///
/// The required fields include: [name] of the plugin, [package] of the plugin and
/// the [pluginClass] that will be the entry point to the plugin's native code.
class AndroidPlugin extends PluginPlatform {
/// The [name] of the plugin is required. Additionally, either:
/// - [defaultPackage], or
/// - an implementation consisting of:
/// - the [package] and [pluginClass] that will be the entry point to the
/// plugin's native code, and/or
/// - the [dartPluginClass] that will be the entry point for the plugin's
/// Dart code
/// is required.
class AndroidPlugin extends PluginPlatform implements NativeOrDartPlugin {
AndroidPlugin({
required this.name,
required this.package,
required this.pluginClass,
required this.pluginPath,
this.package,
this.pluginClass,
this.dartPluginClass,
this.defaultPackage,
required FileSystem fileSystem,
}) : _fileSystem = fileSystem;
......@@ -64,8 +72,10 @@ class AndroidPlugin extends PluginPlatform {
assert(validate(yaml));
return AndroidPlugin(
name: name,
package: yaml['package'] as String,
pluginClass: yaml['pluginClass'] as String,
package: yaml['package'] as String?,
pluginClass: yaml[kPluginClass] as String?,
dartPluginClass: yaml[kDartPluginClass] as String?,
defaultPackage: yaml[kDefaultPackage] as String?,
pluginPath: pluginPath,
fileSystem: fileSystem,
);
......@@ -73,11 +83,16 @@ class AndroidPlugin extends PluginPlatform {
final FileSystem _fileSystem;
@override
bool isNative() => pluginClass != null;
static bool validate(YamlMap yaml) {
if (yaml == null) {
return false;
}
return yaml['package'] is String && yaml['pluginClass'] is String;
return (yaml['package'] is String && yaml['pluginClass'] is String)||
yaml[kDartPluginClass] is String ||
yaml[kDefaultPackage] is String;
}
static const String kConfigKey = 'android';
......@@ -86,10 +101,16 @@ class AndroidPlugin extends PluginPlatform {
final String name;
/// The plugin package name defined in pubspec.yaml.
final String package;
final String? package;
/// The plugin main class defined in pubspec.yaml.
final String pluginClass;
/// The native plugin main class defined in pubspec.yaml, if any.
final String? pluginClass;
/// The Dart plugin main class defined in pubspec.yaml, if any.
final String? dartPluginClass;
/// The default implementation package defined in pubspec.yaml, if any.
final String? defaultPackage;
/// The absolute path to the plugin in the pub cache.
final String pluginPath;
......@@ -98,8 +119,10 @@ class AndroidPlugin extends PluginPlatform {
Map<String, dynamic> toMap() {
return <String, dynamic>{
'name': name,
'package': package,
'class': pluginClass,
if (package != null) 'package': package,
if (pluginClass != null) 'class': pluginClass,
if (dartPluginClass != null) kDartPluginClass : dartPluginClass,
if (defaultPackage != null) kDefaultPackage : defaultPackage,
// Mustache doesn't support complex types.
'supportsEmbeddingV1': _supportedEmbeddings.contains('1'),
'supportsEmbeddingV2': _supportedEmbeddings.contains('2'),
......@@ -119,6 +142,13 @@ class AndroidPlugin extends PluginPlatform {
'main',
);
final String? package = this.package;
// Don't attempt to validate the native code if there isn't supposed to
// be any.
if (package == null) {
return supportedEmbeddings;
}
final List<String> mainClassCandidates = <String>[
_fileSystem.path.join(
baseMainPath,
......@@ -170,13 +200,21 @@ class AndroidPlugin extends PluginPlatform {
/// Contains the parameters to template an iOS plugin.
///
/// The required fields include: [name] of the plugin, the [pluginClass] that
/// will be the entry point to the plugin's native code.
class IOSPlugin extends PluginPlatform {
/// The [name] of the plugin is required. Additionally, either:
/// - [defaultPackage], or
/// - an implementation consisting of:
/// - the [pluginClass] (with optional [classPrefix]) that will be the entry
/// point to the plugin's native code, and/or
/// - the [dartPluginClass] that will be the entry point for the plugin's
/// Dart code
/// is required.
class IOSPlugin extends PluginPlatform implements NativeOrDartPlugin {
const IOSPlugin({
required this.name,
required this.classPrefix,
required this.pluginClass,
this.pluginClass,
this.dartPluginClass,
this.defaultPackage,
});
factory IOSPlugin.fromYaml(String name, YamlMap yaml) {
......@@ -184,7 +222,9 @@ class IOSPlugin extends PluginPlatform {
return IOSPlugin(
name: name,
classPrefix: '',
pluginClass: yaml['pluginClass'] as String,
pluginClass: yaml[kPluginClass] as String?,
dartPluginClass: yaml[kDartPluginClass] as String?,
defaultPackage: yaml[kDefaultPackage] as String?,
);
}
......@@ -192,7 +232,9 @@ class IOSPlugin extends PluginPlatform {
if (yaml == null) {
return false;
}
return yaml['pluginClass'] is String;
return yaml[kPluginClass] is String ||
yaml[kDartPluginClass] is String ||
yaml[kDefaultPackage] is String;
}
static const String kConfigKey = 'ios';
......@@ -202,14 +244,21 @@ class IOSPlugin extends PluginPlatform {
/// Note, this is here only for legacy reasons. Multi-platform format
/// always sets it to empty String.
final String classPrefix;
final String pluginClass;
final String? pluginClass;
final String? dartPluginClass;
final String? defaultPackage;
@override
bool isNative() => pluginClass != null;
@override
Map<String, dynamic> toMap() {
return <String, dynamic>{
'name': name,
'prefix': classPrefix,
'class': pluginClass,
if (pluginClass != null) 'class': pluginClass,
if (dartPluginClass != null) kDartPluginClass : dartPluginClass,
if (defaultPackage != null) kDefaultPackage : defaultPackage,
};
}
}
......
......@@ -136,44 +136,35 @@ class Plugin {
WindowsPlugin.fromYaml(name, platformsYaml[WindowsPlugin.kConfigKey] as YamlMap);
}
final String? defaultPackageForLinux =
_getDefaultPackageForPlatform(platformsYaml, LinuxPlugin.kConfigKey);
final String? defaultPackageForMacOS =
_getDefaultPackageForPlatform(platformsYaml, MacOSPlugin.kConfigKey);
final String? defaultPackageForWindows =
_getDefaultPackageForPlatform(platformsYaml, WindowsPlugin.kConfigKey);
final String? defaultPluginDartClassForLinux =
_getPluginDartClassForPlatform(platformsYaml, LinuxPlugin.kConfigKey);
final String? defaultPluginDartClassForMacOS =
_getPluginDartClassForPlatform(platformsYaml, MacOSPlugin.kConfigKey);
final String? defaultPluginDartClassForWindows =
_getPluginDartClassForPlatform(platformsYaml, WindowsPlugin.kConfigKey);
// TODO(stuartmorgan): Consider merging web into this common handling; the
// fact that its implementation of Dart-only plugins and default packages
// are separate is legacy.
final List<String> sharedHandlingPlatforms = <String>[
AndroidPlugin.kConfigKey,
IOSPlugin.kConfigKey,
LinuxPlugin.kConfigKey,
MacOSPlugin.kConfigKey,
WindowsPlugin.kConfigKey,
];
final Map<String, String> defaultPackages = <String, String>{};
final Map<String, String> dartPluginClasses = <String, String>{};
for (final String platform in sharedHandlingPlatforms) {
final String? defaultPackage = _getDefaultPackageForPlatform(platformsYaml, platform);
if (defaultPackage != null) {
defaultPackages[platform] = defaultPackage;
}
final String? dartClass = _getPluginDartClassForPlatform(platformsYaml, platform);
if (dartClass != null) {
dartPluginClasses[platform] = dartClass;
}
}
return Plugin(
name: name,
path: path,
platforms: platforms,
defaultPackagePlatforms: <String, String>{
if (defaultPackageForLinux != null)
LinuxPlugin.kConfigKey : defaultPackageForLinux,
if (defaultPackageForMacOS != null)
MacOSPlugin.kConfigKey : defaultPackageForMacOS,
if (defaultPackageForWindows != null)
WindowsPlugin.kConfigKey : defaultPackageForWindows,
},
pluginDartClassPlatforms: <String, String>{
if (defaultPluginDartClassForLinux != null)
LinuxPlugin.kConfigKey : defaultPluginDartClassForLinux,
if (defaultPluginDartClassForMacOS != null)
MacOSPlugin.kConfigKey : defaultPluginDartClassForMacOS,
if (defaultPluginDartClassForWindows != null)
WindowsPlugin.kConfigKey : defaultPluginDartClassForWindows,
},
defaultPackagePlatforms: defaultPackages,
pluginDartClassPlatforms: dartPluginClasses,
dependencies: dependencies,
isDirectDependency: isDirectDependency,
implementsPackage: pluginYaml['implements'] != null ? pluginYaml['implements'] as String : '',
......
......@@ -26,6 +26,40 @@ void main() {
));
});
testWithoutContext('AndroidPlugin does not validate the main class for Dart-only plugins', () {
final FileSystem fileSystem = MemoryFileSystem.test();
final AndroidPlugin androidPlugin = AndroidPlugin(
name: 'pluginA',
dartPluginClass: 'PluginA',
pluginPath: '.pub_cache/plugin_a',
fileSystem: fileSystem,
);
expect(androidPlugin.toMap(), <String, Object>{
'name': 'pluginA',
'dartPluginClass': 'PluginA',
'supportsEmbeddingV1': false,
'supportsEmbeddingV2': false,
});
});
testWithoutContext('AndroidPlugin does not validate the main class for default_package', () {
final FileSystem fileSystem = MemoryFileSystem.test();
final AndroidPlugin androidPlugin = AndroidPlugin(
name: 'pluginA',
defaultPackage: 'plugin_a_android',
pluginPath: '.pub_cache/plugin_a',
fileSystem: fileSystem,
);
expect(androidPlugin.toMap(), <String, Object>{
'name': 'pluginA',
'default_package': 'plugin_a_android',
'supportsEmbeddingV1': false,
'supportsEmbeddingV2': false,
});
});
testWithoutContext('AndroidPlugin parses embedding version 2 from the Java search path', () {
final FileSystem fileSystem = MemoryFileSystem.test();
final AndroidPlugin androidPlugin = AndroidPlugin(
......
......@@ -110,10 +110,7 @@ void main() {
fileSystem: fileSystem,
logger: BufferLogger.test(),
processManager: FakeProcessManager.any(),
generateDartPluginRegistry: false,
defines: <String, String>{
kTargetPlatform: 'darwin-x64',
});
generateDartPluginRegistry: false);
expect(const DartPluginRegistrantTarget().canSkip(environment), isTrue);
......@@ -123,14 +120,10 @@ void main() {
fileSystem: fileSystem,
logger: BufferLogger.test(),
processManager: FakeProcessManager.any(),
generateDartPluginRegistry: true,
defines: <String, String>{
kTargetPlatform: 'darwin-x64',
});
generateDartPluginRegistry: true);
expect(const DartPluginRegistrantTarget().canSkip(environment2), isFalse);
});
testWithoutContext('skipped based on platform', () async {
const Map<String, bool> canSkip = <String, bool>{
'darwin-x64': false,
......@@ -139,8 +132,8 @@ void main() {
'windows-x64': false,
'windows-uwp-x64': false,
'web-javascript': true,
'ios': true,
'android': true,
'ios': false,
'android': false,
'fuchsia-arm64': true,
'fuchsia-x64': true,
};
......@@ -258,7 +251,9 @@ void main() {
'\n'
" @pragma('vm:entry-point')\n"
' static void register() {\n'
' if (Platform.isLinux) {\n'
' if (Platform.isAndroid) {\n'
' } else if (Platform.isIOS) {\n'
' } else if (Platform.isLinux) {\n'
' try {\n'
' PathProviderLinux.registerWith();\n'
' } catch (err) {\n'
......@@ -395,7 +390,9 @@ void main() {
'\n'
" @pragma('vm:entry-point')\n"
' static void register() {\n'
' if (Platform.isLinux) {\n'
' if (Platform.isAndroid) {\n'
' } else if (Platform.isIOS) {\n'
' } else if (Platform.isLinux) {\n'
' try {\n'
' PathProviderLinux.registerWith();\n'
' } catch (err) {\n'
......
......@@ -31,12 +31,10 @@ void main() {
final AndroidPlugin androidPlugin = plugin.platforms[AndroidPlugin.kConfigKey]! as AndroidPlugin;
final IOSPlugin iosPlugin = plugin.platforms[IOSPlugin.kConfigKey]! as IOSPlugin;
final String androidPluginClass = androidPlugin.pluginClass;
final String iosPluginClass = iosPlugin.pluginClass;
expect(iosPluginClass, 'SamplePlugin');
expect(androidPluginClass, 'SamplePlugin');
expect(iosPlugin.pluginClass, 'SamplePlugin');
expect(iosPlugin.classPrefix, 'FLT');
expect(androidPlugin.pluginClass, 'SamplePlugin');
expect(androidPlugin.package, 'com.flutter.dev');
});
......@@ -73,12 +71,10 @@ void main() {
final MacOSPlugin macOSPlugin = plugin.platforms[MacOSPlugin.kConfigKey]! as MacOSPlugin;
final WebPlugin webPlugin = plugin.platforms[WebPlugin.kConfigKey]! as WebPlugin;
final WindowsPlugin windowsPlugin = plugin.platforms[WindowsPlugin.kConfigKey]! as WindowsPlugin;
final String androidPluginClass = androidPlugin.pluginClass;
final String iosPluginClass = iosPlugin.pluginClass;
expect(iosPluginClass, 'ISamplePlugin');
expect(androidPluginClass, 'ASamplePlugin');
expect(iosPlugin.pluginClass, 'ISamplePlugin');
expect(iosPlugin.classPrefix, '');
expect(androidPlugin.pluginClass, 'ASamplePlugin');
expect(androidPlugin.package, 'com.flutter.dev');
expect(linuxPlugin.pluginClass, 'LSamplePlugin');
expect(macOSPlugin.pluginClass, 'MSamplePlugin');
......@@ -122,12 +118,10 @@ void main() {
final MacOSPlugin macOSPlugin = plugin.platforms[MacOSPlugin.kConfigKey]! as MacOSPlugin;
final WebPlugin webPlugin = plugin.platforms[WebPlugin.kConfigKey]! as WebPlugin;
final WindowsPlugin windowsPlugin = plugin.platforms[WindowsPlugin.kConfigKey]! as WindowsPlugin;
final String androidPluginClass = androidPlugin.pluginClass;
final String iosPluginClass = iosPlugin.pluginClass;
expect(iosPluginClass, 'ISamplePlugin');
expect(androidPluginClass, 'ASamplePlugin');
expect(iosPlugin.pluginClass, 'ISamplePlugin');
expect(iosPlugin.classPrefix, '');
expect(androidPlugin.pluginClass, 'ASamplePlugin');
expect(androidPlugin.package, 'com.flutter.dev');
expect(linuxPlugin.pluginClass, 'LSamplePlugin');
expect(macOSPlugin.pluginClass, 'MSamplePlugin');
......@@ -138,9 +132,12 @@ void main() {
testWithoutContext('Plugin parsing allows for Dart-only plugins without a pluginClass', () {
final FileSystem fileSystem = MemoryFileSystem.test();
/// This is currently supported only on macOS, linux, Windows.
const String pluginYamlRaw = 'implements: same_plugin\n' // this should be ignored by the tool
'platforms:\n'
' android:\n'
' dartPluginClass: ASamplePlugin\n'
' ios:\n'
' dartPluginClass: ISamplePlugin\n'
' linux:\n'
' dartPluginClass: LSamplePlugin\n'
' macos:\n'
......@@ -157,13 +154,19 @@ void main() {
fileSystem: fileSystem,
);
final AndroidPlugin androidPlugin = plugin.platforms[AndroidPlugin.kConfigKey]! as AndroidPlugin;
final IOSPlugin iOSPlugin = plugin.platforms[IOSPlugin.kConfigKey]! as IOSPlugin;
final LinuxPlugin linuxPlugin = plugin.platforms[LinuxPlugin.kConfigKey]! as LinuxPlugin;
final MacOSPlugin macOSPlugin = plugin.platforms[MacOSPlugin.kConfigKey]! as MacOSPlugin;
final WindowsPlugin windowsPlugin = plugin.platforms[WindowsPlugin.kConfigKey]! as WindowsPlugin;
expect(androidPlugin.pluginClass, isNull);
expect(iOSPlugin.pluginClass, isNull);
expect(linuxPlugin.pluginClass, isNull);
expect(macOSPlugin.pluginClass, isNull);
expect(windowsPlugin.pluginClass, isNull);
expect(androidPlugin.dartPluginClass, 'ASamplePlugin');
expect(iOSPlugin.dartPluginClass, 'ISamplePlugin');
expect(linuxPlugin.dartPluginClass, 'LSamplePlugin');
expect(macOSPlugin.dartPluginClass, 'MSamplePlugin');
expect(windowsPlugin.dartPluginClass, 'WinSamplePlugin');
......@@ -219,6 +222,8 @@ void main() {
expect(plugin.platforms, <String, PluginPlatform>{});
expect(plugin.defaultPackagePlatforms, <String, String>{
'android': 'sample_package_android',
'ios': 'sample_package_ios',
'linux': 'sample_package_linux',
'macos': 'sample_package_macos',
'windows': 'sample_package_windows',
......
......@@ -966,6 +966,53 @@ web_plugin_with_nested:${webPluginWithNestedFile.childDirectory('lib').uri.toStr
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('Injecting creates generated Android registrant, but does not include Dart-only plugins', () async {
// Create a plugin without a pluginClass.
final Directory pluginDirectory = createFakePlugin(fs);
pluginDirectory.childFile('pubspec.yaml').writeAsStringSync('''
flutter:
plugin:
platforms:
android:
dartPluginClass: SomePlugin
''');
await injectPlugins(flutterProject, androidPlatform: true);
final File registrantFile = androidProject.pluginRegistrantHost
.childDirectory(fs.path.join('src', 'main', 'java', 'io', 'flutter', 'plugins'))
.childFile('GeneratedPluginRegistrant.java');
expect(registrantFile, exists);
expect(registrantFile, isNot(contains('SomePlugin')));
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('Injecting creates generated iOS registrant, but does not include Dart-only plugins', () async {
flutterProject.isModule = true;
// Create a plugin without a pluginClass.
final Directory pluginDirectory = createFakePlugin(fs);
pluginDirectory.childFile('pubspec.yaml').writeAsStringSync('''
flutter:
plugin:
platforms:
ios:
dartPluginClass: SomePlugin
''');
await injectPlugins(flutterProject, iosPlatform: true);
final File registrantFile = iosProject.pluginRegistrantImplementation;
expect(registrantFile, exists);
expect(registrantFile, isNot(contains('SomePlugin')));
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('Injecting creates generated macos registrant, but does not include Dart-only plugins', () async {
flutterProject.isModule = true;
// Create a plugin without a pluginClass.
......@@ -1548,6 +1595,12 @@ class FakeIosProject extends Fake implements IosProject {
@override
Directory pluginRegistrantHost;
@override
File get pluginRegistrantHeader => pluginRegistrantHost.childFile('GeneratedPluginRegistrant.h');
@override
File get pluginRegistrantImplementation => pluginRegistrantHost.childFile('GeneratedPluginRegistrant.m');
@override
File podfile;
......
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