Add --platforms
to flutter create -t plugin
command (#59507)
This commit is contained in:
parent
14992c5951
commit
2e63b7d4f8
@ -41,7 +41,7 @@ Future<void> main() async {
|
|||||||
await inDirectory(tempDir, () async {
|
await inDirectory(tempDir, () async {
|
||||||
await flutter(
|
await flutter(
|
||||||
'create',
|
'create',
|
||||||
options: <String>['--org', 'io.flutter.devicelab', '--template', 'plugin', 'plugin_with_android'],
|
options: <String>['--org', 'io.flutter.devicelab', '--template', 'plugin', '--platforms=android', 'plugin_with_android'],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -50,25 +50,10 @@ Future<void> main() async {
|
|||||||
await inDirectory(tempDir, () async {
|
await inDirectory(tempDir, () async {
|
||||||
await flutter(
|
await flutter(
|
||||||
'create',
|
'create',
|
||||||
options: <String>['--org', 'io.flutter.devicelab', '--template', 'plugin', 'plugin_without_android'],
|
options: <String>['--org', 'io.flutter.devicelab', '--template', 'plugin', '--platforms=ios', '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');
|
section('Add plugins to pubspec.yaml');
|
||||||
|
|
||||||
final File modulePubspec = File(path.join(projectDir.path, 'pubspec.yaml'));
|
final File modulePubspec = File(path.join(projectDir.path, 'pubspec.yaml'));
|
||||||
|
@ -32,6 +32,7 @@ Future<void> main() async {
|
|||||||
options: <String>[
|
options: <String>[
|
||||||
'--org', 'io.flutter.devicelab',
|
'--org', 'io.flutter.devicelab',
|
||||||
'-t', 'plugin',
|
'-t', 'plugin',
|
||||||
|
'--platforms=ios,android',
|
||||||
'ios_only',
|
'ios_only',
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
@ -40,6 +40,7 @@ Future<void> main() async {
|
|||||||
'--org',
|
'--org',
|
||||||
'io.flutter.devicelab.plugin_a',
|
'io.flutter.devicelab.plugin_a',
|
||||||
'--template=plugin',
|
'--template=plugin',
|
||||||
|
'--platforms=android,ios',
|
||||||
pluginADirectory.path,
|
pluginADirectory.path,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@ -55,6 +56,7 @@ Future<void> main() async {
|
|||||||
'--org',
|
'--org',
|
||||||
'io.flutter.devicelab.plugin_b',
|
'io.flutter.devicelab.plugin_b',
|
||||||
'--template=plugin',
|
'--template=plugin',
|
||||||
|
'--platforms=android,ios',
|
||||||
pluginBDirectory.path,
|
pluginBDirectory.path,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@ -70,6 +72,7 @@ Future<void> main() async {
|
|||||||
'--org',
|
'--org',
|
||||||
'io.flutter.devicelab.plugin_c',
|
'io.flutter.devicelab.plugin_c',
|
||||||
'--template=plugin',
|
'--template=plugin',
|
||||||
|
'--platforms=ios',
|
||||||
pluginCDirectory.path,
|
pluginCDirectory.path,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
@ -26,6 +26,7 @@ Future<void> main() async {
|
|||||||
'--org',
|
'--org',
|
||||||
'io.flutter.devicelab',
|
'io.flutter.devicelab',
|
||||||
'--template=plugin',
|
'--template=plugin',
|
||||||
|
'--platforms=ios,android',
|
||||||
'--ios-language=objc',
|
'--ios-language=objc',
|
||||||
objcPluginName,
|
objcPluginName,
|
||||||
],
|
],
|
||||||
@ -79,6 +80,7 @@ Future<void> main() async {
|
|||||||
'--org',
|
'--org',
|
||||||
'io.flutter.devicelab',
|
'io.flutter.devicelab',
|
||||||
'--template=plugin',
|
'--template=plugin',
|
||||||
|
'--platforms=ios,android',
|
||||||
'--ios-language=swift',
|
'--ios-language=swift',
|
||||||
swiftPluginName,
|
swiftPluginName,
|
||||||
],
|
],
|
||||||
|
@ -9,14 +9,14 @@ import 'package:flutter_devicelab/framework/framework.dart';
|
|||||||
|
|
||||||
Future<void> main() async {
|
Future<void> main() async {
|
||||||
await task(combine(<TaskFunction>[
|
await task(combine(<TaskFunction>[
|
||||||
PluginTest('apk', <String>['-a', 'java']),
|
PluginTest('apk', <String>['-a', 'java', '--platforms=android']),
|
||||||
PluginTest('apk', <String>['-a', 'kotlin']),
|
PluginTest('apk', <String>['-a', 'kotlin', '--platforms=android']),
|
||||||
// These create the plugins using the new v2 plugin templates but create the
|
// These create the plugins using the new v2 plugin templates but create the
|
||||||
// apps using the old v1 embedding app templates to make sure new plugins
|
// apps using the old v1 embedding app templates to make sure new plugins
|
||||||
// are by default backward compatible.
|
// are by default backward compatible.
|
||||||
PluginTest('apk', <String>['-a', 'java'], pluginCreateEnvironment:
|
PluginTest('apk', <String>['-a', 'java', '--platforms=android'], pluginCreateEnvironment:
|
||||||
<String, String>{'ENABLE_ANDROID_EMBEDDING_V2': 'true'}),
|
<String, String>{'ENABLE_ANDROID_EMBEDDING_V2': 'true'}),
|
||||||
PluginTest('apk', <String>['-a', 'kotlin'], pluginCreateEnvironment:
|
PluginTest('apk', <String>['-a', 'kotlin', '--platforms=android'], pluginCreateEnvironment:
|
||||||
<String, String>{'ENABLE_ANDROID_EMBEDDING_V2': 'true'}),
|
<String, String>{'ENABLE_ANDROID_EMBEDDING_V2': 'true'}),
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import 'package:flutter_devicelab/framework/framework.dart';
|
|||||||
|
|
||||||
Future<void> main() async {
|
Future<void> main() async {
|
||||||
await task(combine(<TaskFunction>[
|
await task(combine(<TaskFunction>[
|
||||||
PluginTest('ios', <String>['-i', 'objc']),
|
PluginTest('ios', <String>['-i', 'objc', '--platforms=ios']),
|
||||||
PluginTest('ios', <String>['-i', 'swift']),
|
PluginTest('ios', <String>['-i', 'swift', '--platforms=ios']),
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import 'package:flutter_devicelab/framework/framework.dart';
|
|||||||
|
|
||||||
Future<void> main() async {
|
Future<void> main() async {
|
||||||
await task(combine(<TaskFunction>[
|
await task(combine(<TaskFunction>[
|
||||||
PluginTest('apk', <String>['-a', 'java']),
|
PluginTest('apk', <String>['-a', 'java', '--platforms=android']),
|
||||||
PluginTest('apk', <String>['-a', 'kotlin']),
|
PluginTest('apk', <String>['-a', 'kotlin', '--platforms=android']),
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
@ -351,7 +351,7 @@ class FlutterPluginProject {
|
|||||||
|
|
||||||
static Future<FlutterPluginProject> create(Directory directory, String name) async {
|
static Future<FlutterPluginProject> create(Directory directory, String name) async {
|
||||||
await inDirectory(directory, () async {
|
await inDirectory(directory, () async {
|
||||||
await flutter('create', options: <String>['--template=plugin', name]);
|
await flutter('create', options: <String>['--template=plugin', '--platforms=ios,android', name]);
|
||||||
});
|
});
|
||||||
return FlutterPluginProject(directory, name);
|
return FlutterPluginProject(directory, name);
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,9 @@ import 'dart:async';
|
|||||||
|
|
||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
|
import 'package:yaml/yaml.dart';
|
||||||
|
|
||||||
import '../android/android.dart' as android;
|
import '../android/android.dart' as android_common;
|
||||||
import '../android/android_sdk.dart' as android_sdk;
|
import '../android/android_sdk.dart' as android_sdk;
|
||||||
import '../android/gradle_utils.dart' as gradle;
|
import '../android/gradle_utils.dart' as gradle;
|
||||||
import '../base/common.dart';
|
import '../base/common.dart';
|
||||||
@ -15,20 +16,39 @@ import '../base/context.dart';
|
|||||||
import '../base/file_system.dart';
|
import '../base/file_system.dart';
|
||||||
import '../base/io.dart';
|
import '../base/io.dart';
|
||||||
import '../base/net.dart';
|
import '../base/net.dart';
|
||||||
|
import '../base/terminal.dart';
|
||||||
import '../base/utils.dart';
|
import '../base/utils.dart';
|
||||||
import '../cache.dart';
|
import '../cache.dart';
|
||||||
import '../convert.dart';
|
import '../convert.dart';
|
||||||
import '../dart/pub.dart';
|
import '../dart/pub.dart';
|
||||||
import '../features.dart';
|
import '../features.dart';
|
||||||
|
import '../flutter_manifest.dart';
|
||||||
import '../flutter_project_metadata.dart';
|
import '../flutter_project_metadata.dart';
|
||||||
import '../globals.dart' as globals;
|
import '../globals.dart' as globals;
|
||||||
|
import '../plugins.dart';
|
||||||
import '../project.dart';
|
import '../project.dart';
|
||||||
import '../reporting/reporting.dart';
|
import '../reporting/reporting.dart';
|
||||||
import '../runner/flutter_command.dart';
|
import '../runner/flutter_command.dart';
|
||||||
import '../template.dart';
|
import '../template.dart';
|
||||||
|
|
||||||
|
const List<String> _kAvailablePlatforms = <String>[
|
||||||
|
'ios',
|
||||||
|
'android',
|
||||||
|
'windows',
|
||||||
|
'linux',
|
||||||
|
'macos',
|
||||||
|
'web',
|
||||||
|
];
|
||||||
|
|
||||||
|
const String _kNoPlatformsErrorMessage = '''
|
||||||
|
The plugin project was generated without specifying the `--platforms` flag, no platforms are currently supported.
|
||||||
|
To add platforms, run `flutter create -t plugin --platforms <platforms> .` under the same
|
||||||
|
directory. You can also find detailed instructions on how to add platforms in the `pubspec.yaml` at https://flutter.dev/docs/development/packages-and-plugins/developing-packages#plugin-platforms.
|
||||||
|
''';
|
||||||
|
|
||||||
class CreateCommand extends FlutterCommand {
|
class CreateCommand extends FlutterCommand {
|
||||||
CreateCommand() {
|
CreateCommand() {
|
||||||
|
_addPlatformsOptions();
|
||||||
argParser.addFlag('pub',
|
argParser.addFlag('pub',
|
||||||
defaultsTo: true,
|
defaultsTo: true,
|
||||||
help: 'Whether to run "flutter pub get" after the project has been created.',
|
help: 'Whether to run "flutter pub get" after the project has been created.',
|
||||||
@ -318,6 +338,19 @@ class CreateCommand extends FlutterCommand {
|
|||||||
final bool generatePlugin = template == FlutterProjectType.plugin;
|
final bool generatePlugin = template == FlutterProjectType.plugin;
|
||||||
final bool generatePackage = template == FlutterProjectType.package;
|
final bool generatePackage = template == FlutterProjectType.package;
|
||||||
|
|
||||||
|
final List<String> platforms = stringsArg('platforms');
|
||||||
|
// `--platforms` does not support module or package.
|
||||||
|
if (argResults.wasParsed('platforms') && (generateModule || generatePackage)) {
|
||||||
|
final String template = generateModule ? 'module' : 'package';
|
||||||
|
throwToolExit(
|
||||||
|
'The "--platforms" argument is not supported in $template template.',
|
||||||
|
exitCode: 2
|
||||||
|
);
|
||||||
|
} else if (platforms == null || platforms.isEmpty) {
|
||||||
|
throwToolExit('Must specify at least one platform using --platforms',
|
||||||
|
exitCode: 2);
|
||||||
|
}
|
||||||
|
|
||||||
String organization = stringArg('org');
|
String organization = stringArg('org');
|
||||||
if (!argResults.wasParsed('org')) {
|
if (!argResults.wasParsed('org')) {
|
||||||
final FlutterProject project = FlutterProject.fromDirectory(projectDir);
|
final FlutterProject project = FlutterProject.fromDirectory(projectDir);
|
||||||
@ -344,7 +377,7 @@ class CreateCommand extends FlutterCommand {
|
|||||||
throwToolExit(error);
|
throwToolExit(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
final Map<String, dynamic> templateContext = _templateContext(
|
final Map<String, dynamic> templateContext = _createTemplateContext(
|
||||||
organization: organization,
|
organization: organization,
|
||||||
projectName: projectName,
|
projectName: projectName,
|
||||||
projectDescription: stringArg('description'),
|
projectDescription: stringArg('description'),
|
||||||
@ -353,10 +386,12 @@ class CreateCommand extends FlutterCommand {
|
|||||||
withPluginHook: generatePlugin,
|
withPluginHook: generatePlugin,
|
||||||
androidLanguage: stringArg('android-language'),
|
androidLanguage: stringArg('android-language'),
|
||||||
iosLanguage: stringArg('ios-language'),
|
iosLanguage: stringArg('ios-language'),
|
||||||
web: featureFlags.isWebEnabled,
|
ios: platforms.contains('ios'),
|
||||||
linux: featureFlags.isLinuxEnabled,
|
android: platforms.contains('android'),
|
||||||
macos: featureFlags.isMacOSEnabled,
|
web: featureFlags.isWebEnabled && platforms.contains('web'),
|
||||||
windows: featureFlags.isWindowsEnabled,
|
linux: featureFlags.isLinuxEnabled && platforms.contains('linux'),
|
||||||
|
macos: featureFlags.isMacOSEnabled && platforms.contains('macos'),
|
||||||
|
windows: featureFlags.isWindowsEnabled && platforms.contains('windows'),
|
||||||
);
|
);
|
||||||
|
|
||||||
final String relativeDirPath = globals.fs.path.relative(projectDirPath);
|
final String relativeDirPath = globals.fs.path.relative(projectDirPath);
|
||||||
@ -417,7 +452,8 @@ class CreateCommand extends FlutterCommand {
|
|||||||
if (globals.doctor.canLaunchAnything) {
|
if (globals.doctor.canLaunchAnything) {
|
||||||
// Let them know a summary of the state of their tooling.
|
// Let them know a summary of the state of their tooling.
|
||||||
await globals.doctor.summary();
|
await globals.doctor.summary();
|
||||||
|
final List<String> platforms = _getSupportedPlatformsFromTemplateContext(templateContext);
|
||||||
|
final String platformsString = platforms.join(', ');
|
||||||
globals.printStatus('''
|
globals.printStatus('''
|
||||||
In order to run your $application, type:
|
In order to run your $application, type:
|
||||||
|
|
||||||
@ -430,7 +466,7 @@ Your $application code is in $relativeAppMain.
|
|||||||
globals.printStatus('''
|
globals.printStatus('''
|
||||||
Your plugin code is in $relativePluginMain.
|
Your plugin code is in $relativePluginMain.
|
||||||
|
|
||||||
Host platform code is in the "android" and "ios" directories under $relativePluginPath.
|
Host platform code is in the $platformsString directories under $relativePluginPath.
|
||||||
To edit platform code in an IDE see https://flutter.dev/developing-packages/#edit-plugin-package.
|
To edit platform code in an IDE see https://flutter.dev/developing-packages/#edit-plugin-package.
|
||||||
''');
|
''');
|
||||||
}
|
}
|
||||||
@ -467,6 +503,17 @@ To edit platform code in an IDE see https://flutter.dev/developing-packages/#edi
|
|||||||
return FlutterCommandResult.success();
|
return FlutterCommandResult.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _addPlatformsOptions() {
|
||||||
|
argParser.addMultiOption('platforms',
|
||||||
|
help: 'the platforms supported by this project.'
|
||||||
|
'This argument only works when the --template is set to app or plugin.'
|
||||||
|
'Platform folders (e.g. android/) will be generated in the target project.'
|
||||||
|
'When adding platforms to a plugin project, the pubspec.yaml will be updated with the requested platform.'
|
||||||
|
'Adding desktop platforms requires the corresponding desktop config setting to be enabled.',
|
||||||
|
defaultsTo: _kAvailablePlatforms,
|
||||||
|
allowed: _kAvailablePlatforms);
|
||||||
|
}
|
||||||
|
|
||||||
Future<int> _generateModule(Directory directory, Map<String, dynamic> templateContext, { bool overwrite = false }) async {
|
Future<int> _generateModule(Directory directory, Map<String, dynamic> templateContext, { bool overwrite = false }) async {
|
||||||
int generatedCount = 0;
|
int generatedCount = 0;
|
||||||
final String description = argResults.wasParsed('description')
|
final String description = argResults.wasParsed('description')
|
||||||
@ -504,12 +551,27 @@ To edit platform code in an IDE see https://flutter.dev/developing-packages/#edi
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<int> _generatePlugin(Directory directory, Map<String, dynamic> templateContext, { bool overwrite = false }) async {
|
Future<int> _generatePlugin(Directory directory, Map<String, dynamic> templateContext, { bool overwrite = false }) async {
|
||||||
|
// Plugin doesn't create any platform by default
|
||||||
|
if (!argResults.wasParsed('platforms')) {
|
||||||
|
// If the user didn't explicitly declare the platforms, we don't generate any platforms.
|
||||||
|
templateContext['ios'] = false;
|
||||||
|
templateContext['android'] = false;
|
||||||
|
templateContext['web'] = false;
|
||||||
|
templateContext['linux'] = false;
|
||||||
|
templateContext['macos'] = false;
|
||||||
|
templateContext['windows'] = false;
|
||||||
|
globals.printError(_kNoPlatformsErrorMessage);
|
||||||
|
}
|
||||||
|
final List<String> platforms = _getSupportedPlatformsFromTemplateContext(templateContext);
|
||||||
|
final bool willAddPlatforms = platforms.isNotEmpty;
|
||||||
|
templateContext['no_platforms'] = !willAddPlatforms;
|
||||||
int generatedCount = 0;
|
int generatedCount = 0;
|
||||||
final String description = argResults.wasParsed('description')
|
final String description = argResults.wasParsed('description')
|
||||||
? stringArg('description')
|
? stringArg('description')
|
||||||
: 'A new flutter plugin project.';
|
: 'A new flutter plugin project.';
|
||||||
templateContext['description'] = description;
|
templateContext['description'] = description;
|
||||||
generatedCount += await _renderTemplate('plugin', directory, templateContext, overwrite: overwrite);
|
generatedCount += await _renderTemplate('plugin', directory, templateContext, overwrite: overwrite);
|
||||||
|
|
||||||
if (boolArg('pub')) {
|
if (boolArg('pub')) {
|
||||||
await pub.get(
|
await pub.get(
|
||||||
context: PubContext.createPlugin,
|
context: PubContext.createPlugin,
|
||||||
@ -517,8 +579,45 @@ To edit platform code in an IDE see https://flutter.dev/developing-packages/#edi
|
|||||||
offline: boolArg('offline'),
|
offline: boolArg('offline'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (willAddPlatforms) {
|
||||||
|
// If adding new platforms to an existing plugin project, prints
|
||||||
|
// a help message containing the platforms maps need to be added to the `platforms` key in the pubspec.
|
||||||
|
final String pubspecPath = globals.fs.path.join(directory.absolute.path, 'pubspec.yaml');
|
||||||
|
final List<String> platformsToAdd = List<String>.from(platforms);
|
||||||
|
final FlutterManifest manifest = FlutterManifest.createFromPath(pubspecPath, fileSystem: globals.fs, logger: globals.logger);
|
||||||
|
final List<String> existingPlatforms = manifest.supportedPlatforms.keys.toList();
|
||||||
|
platformsToAdd.removeWhere(existingPlatforms.contains);
|
||||||
|
final YamlMap platformsMapToPrint = Plugin.createPlatformsYamlMap(platformsToAdd, templateContext['pluginClass'] as String, templateContext['androidIdentifier'] as String);
|
||||||
|
if (platformsMapToPrint.isNotEmpty) {
|
||||||
|
String prettyYaml = '';
|
||||||
|
for (final String platform in platformsMapToPrint.keys.toList().cast<String>()) {
|
||||||
|
prettyYaml += '$platform:\n';
|
||||||
|
for (final String key in (platformsMapToPrint[platform] as YamlMap).keys.toList().cast<String>()) {
|
||||||
|
prettyYaml += ' $key: ${platformsMapToPrint[platform][key] as String}\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
globals.printStatus('''
|
||||||
|
The `pubspec.yaml` under the project directory must be updated to support ${platformsToAdd.join(', ')},
|
||||||
|
Add below lines to under the `platform:` key:
|
||||||
|
''', emphasis: true);
|
||||||
|
globals.printStatus(prettyYaml, emphasis: true, color: TerminalColor.blue);
|
||||||
|
globals.printStatus('''
|
||||||
|
If the `platforms` key does not exist in the `pubspec.yaml`, it might because that the plugin project does not
|
||||||
|
use the multi-platforms plugin format. We highly recommend a migration to the multi-platforms plugin format.
|
||||||
|
For detailed instructions on how to format the pubspec.yaml to support platforms using the multi-platforms format, see:
|
||||||
|
https://flutter.dev/docs/development/packages-and-plugins/developing-packages#plugin-platforms
|
||||||
|
''', emphasis: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
final FlutterProject project = FlutterProject.fromDirectory(directory);
|
final FlutterProject project = FlutterProject.fromDirectory(directory);
|
||||||
gradle.updateLocalProperties(project: project, requireAndroidSdk: false);
|
final bool generateAndroid = templateContext['android'] == true;
|
||||||
|
if (generateAndroid) {
|
||||||
|
gradle.updateLocalProperties(
|
||||||
|
project: project, requireAndroidSdk: false);
|
||||||
|
}
|
||||||
|
|
||||||
final String projectName = templateContext['projectName'] as String;
|
final String projectName = templateContext['projectName'] as String;
|
||||||
final String organization = templateContext['organization'] as String;
|
final String organization = templateContext['organization'] as String;
|
||||||
@ -527,19 +626,22 @@ To edit platform code in an IDE see https://flutter.dev/developing-packages/#edi
|
|||||||
templateContext['projectName'] = exampleProjectName;
|
templateContext['projectName'] = exampleProjectName;
|
||||||
templateContext['androidIdentifier'] = _createAndroidIdentifier(organization, exampleProjectName);
|
templateContext['androidIdentifier'] = _createAndroidIdentifier(organization, exampleProjectName);
|
||||||
templateContext['iosIdentifier'] = _createUTIIdentifier(organization, exampleProjectName);
|
templateContext['iosIdentifier'] = _createUTIIdentifier(organization, exampleProjectName);
|
||||||
|
templateContext['macosIdentifier'] = _createUTIIdentifier(organization, exampleProjectName);
|
||||||
templateContext['description'] = 'Demonstrates how to use the $projectName plugin.';
|
templateContext['description'] = 'Demonstrates how to use the $projectName plugin.';
|
||||||
templateContext['pluginProjectName'] = projectName;
|
templateContext['pluginProjectName'] = projectName;
|
||||||
templateContext['androidPluginIdentifier'] = androidPluginIdentifier;
|
templateContext['androidPluginIdentifier'] = androidPluginIdentifier;
|
||||||
|
|
||||||
generatedCount += await _generateApp(project.example.directory, templateContext, overwrite: overwrite);
|
generatedCount += await _generateApp(project.example.directory, templateContext, overwrite: overwrite, pluginExampleApp: true);
|
||||||
return generatedCount;
|
return generatedCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<int> _generateApp(Directory directory, Map<String, dynamic> templateContext, { bool overwrite = false }) async {
|
Future<int> _generateApp(Directory directory, Map<String, dynamic> templateContext, { bool overwrite = false, bool pluginExampleApp = false}) async {
|
||||||
int generatedCount = 0;
|
int generatedCount = 0;
|
||||||
generatedCount += await _renderTemplate('app', directory, templateContext, overwrite: overwrite);
|
generatedCount += await _renderTemplate('app', directory, templateContext, overwrite: overwrite);
|
||||||
final FlutterProject project = FlutterProject.fromDirectory(directory);
|
final FlutterProject project = FlutterProject.fromDirectory(directory);
|
||||||
generatedCount += _injectGradleWrapper(project);
|
if (templateContext['android'] == true) {
|
||||||
|
generatedCount += _injectGradleWrapper(project);
|
||||||
|
}
|
||||||
|
|
||||||
if (boolArg('with-driver-test')) {
|
if (boolArg('with-driver-test')) {
|
||||||
final Directory testDirectory = directory.childDirectory('test_driver');
|
final Directory testDirectory = directory.childDirectory('test_driver');
|
||||||
@ -548,11 +650,11 @@ To edit platform code in an IDE see https://flutter.dev/developing-packages/#edi
|
|||||||
|
|
||||||
if (boolArg('pub')) {
|
if (boolArg('pub')) {
|
||||||
await pub.get(context: PubContext.create, directory: directory.path, offline: boolArg('offline'));
|
await pub.get(context: PubContext.create, directory: directory.path, offline: boolArg('offline'));
|
||||||
await project.ensureReadyForPlatformSpecificTooling(checkProjects: false);
|
await project.ensureReadyForPlatformSpecificTooling(checkProjects: pluginExampleApp);
|
||||||
|
}
|
||||||
|
if (templateContext['android'] == true) {
|
||||||
|
gradle.updateLocalProperties(project: project, requireAndroidSdk: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
gradle.updateLocalProperties(project: project, requireAndroidSdk: false);
|
|
||||||
|
|
||||||
return generatedCount;
|
return generatedCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -570,7 +672,24 @@ To edit platform code in an IDE see https://flutter.dev/developing-packages/#edi
|
|||||||
return -files.length;
|
return -files.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> _templateContext({
|
List<String> _getSupportedPlatformsFromTemplateContext(Map<String, dynamic> templateContext) {
|
||||||
|
return <String>[
|
||||||
|
if (templateContext['ios'] == true)
|
||||||
|
'ios',
|
||||||
|
if (templateContext['android'] == true)
|
||||||
|
'android',
|
||||||
|
if (templateContext['web'] == true)
|
||||||
|
'web',
|
||||||
|
if (templateContext['linux'] == true)
|
||||||
|
'linux',
|
||||||
|
if (templateContext['windows'] == true)
|
||||||
|
'windows',
|
||||||
|
if (templateContext['macos'] == true)
|
||||||
|
'macos',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> _createTemplateContext({
|
||||||
String organization,
|
String organization,
|
||||||
String projectName,
|
String projectName,
|
||||||
String projectDescription,
|
String projectDescription,
|
||||||
@ -579,6 +698,8 @@ To edit platform code in an IDE see https://flutter.dev/developing-packages/#edi
|
|||||||
String flutterRoot,
|
String flutterRoot,
|
||||||
bool renderDriverTest = false,
|
bool renderDriverTest = false,
|
||||||
bool withPluginHook = false,
|
bool withPluginHook = false,
|
||||||
|
bool ios = false,
|
||||||
|
bool android = false,
|
||||||
bool web = false,
|
bool web = false,
|
||||||
bool linux = false,
|
bool linux = false,
|
||||||
bool macos = false,
|
bool macos = false,
|
||||||
@ -603,7 +724,7 @@ To edit platform code in an IDE see https://flutter.dev/developing-packages/#edi
|
|||||||
'description': projectDescription,
|
'description': projectDescription,
|
||||||
'dartSdk': '$flutterRoot/bin/cache/dart-sdk',
|
'dartSdk': '$flutterRoot/bin/cache/dart-sdk',
|
||||||
'useAndroidEmbeddingV2': featureFlags.isAndroidEmbeddingV2Enabled,
|
'useAndroidEmbeddingV2': featureFlags.isAndroidEmbeddingV2Enabled,
|
||||||
'androidMinApiLevel': android.minApiLevel,
|
'androidMinApiLevel': android_common.minApiLevel,
|
||||||
'androidSdkVersion': android_sdk.minimumAndroidSdkVersion,
|
'androidSdkVersion': android_sdk.minimumAndroidSdkVersion,
|
||||||
'withDriverTest': renderDriverTest,
|
'withDriverTest': renderDriverTest,
|
||||||
'pluginClass': pluginClass,
|
'pluginClass': pluginClass,
|
||||||
@ -616,6 +737,8 @@ To edit platform code in an IDE see https://flutter.dev/developing-packages/#edi
|
|||||||
'iosLanguage': iosLanguage,
|
'iosLanguage': iosLanguage,
|
||||||
'flutterRevision': globals.flutterVersion.frameworkRevision,
|
'flutterRevision': globals.flutterVersion.frameworkRevision,
|
||||||
'flutterChannel': globals.flutterVersion.channel,
|
'flutterChannel': globals.flutterVersion.channel,
|
||||||
|
'ios': ios,
|
||||||
|
'android': android,
|
||||||
'web': web,
|
'web': web,
|
||||||
'linux': linux,
|
'linux': linux,
|
||||||
'macos': macos,
|
'macos': macos,
|
||||||
|
@ -163,17 +163,16 @@ class FlutterManifest {
|
|||||||
if (isModule) {
|
if (isModule) {
|
||||||
return _flutterDescriptor['module']['androidPackage'] as String;
|
return _flutterDescriptor['module']['androidPackage'] as String;
|
||||||
}
|
}
|
||||||
if (isPlugin) {
|
if (supportedPlatforms == null) {
|
||||||
final YamlMap plugin = _flutterDescriptor['plugin'] as YamlMap;
|
// Pre-multi-platform plugin format
|
||||||
if (plugin.containsKey('platforms')) {
|
if (isPlugin) {
|
||||||
final YamlMap platforms = plugin['platforms'] as YamlMap;
|
final YamlMap plugin = _flutterDescriptor['plugin'] as YamlMap;
|
||||||
|
|
||||||
if (platforms.containsKey('android')) {
|
|
||||||
return platforms['android']['package'] as String;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return plugin['androidPackage'] as String;
|
return plugin['androidPackage'] as String;
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (supportedPlatforms.containsKey('android')) {
|
||||||
|
return supportedPlatforms['android']['package'] as String;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -187,6 +186,20 @@ class FlutterManifest {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the supported platforms. This only supports the new `platforms` format.
|
||||||
|
///
|
||||||
|
/// If the plugin uses the legacy pubspec format, this method returns null.
|
||||||
|
Map<String, dynamic> get supportedPlatforms {
|
||||||
|
if (isPlugin) {
|
||||||
|
final YamlMap plugin = _flutterDescriptor['plugin'] as YamlMap;
|
||||||
|
if (plugin.containsKey('platforms')) {
|
||||||
|
final YamlMap platformsMap = plugin['platforms'] as YamlMap;
|
||||||
|
return platformsMap.value.cast<String, dynamic>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
List<Map<String, dynamic>> get fontsDescriptor {
|
List<Map<String, dynamic>> get fontsDescriptor {
|
||||||
return fonts.map((Font font) => font.descriptor).toList();
|
return fonts.map((Font font) => font.descriptor).toList();
|
||||||
}
|
}
|
||||||
|
@ -174,6 +174,25 @@ class Plugin {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a YamlMap that represents the supported platforms.
|
||||||
|
///
|
||||||
|
/// For example, if the `platforms` contains 'ios' and 'android', the return map looks like:
|
||||||
|
/// android:
|
||||||
|
/// package: io.flutter.plugins.sample
|
||||||
|
/// pluginClass: SamplePlugin
|
||||||
|
/// ios:
|
||||||
|
/// pluginClass: SamplePlugin
|
||||||
|
static YamlMap createPlatformsYamlMap(List<String> platforms, String pluginClass, String androidPackage) {
|
||||||
|
final Map<String, dynamic> map = <String, dynamic>{};
|
||||||
|
for (final String platform in platforms) {
|
||||||
|
map[platform] = <String, String>{
|
||||||
|
'pluginClass': pluginClass,
|
||||||
|
...platform == 'android' ? <String, String>{'package': androidPackage} : <String, String>{},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return YamlMap.wrap(map);
|
||||||
|
}
|
||||||
|
|
||||||
static List<String> validatePluginYaml(YamlMap yaml) {
|
static List<String> validatePluginYaml(YamlMap yaml) {
|
||||||
if (yaml == null) {
|
if (yaml == null) {
|
||||||
return <String>['Invalid "plugin" specification.'];
|
return <String>['Invalid "plugin" specification.'];
|
||||||
|
@ -225,6 +225,9 @@ class FlutterProject {
|
|||||||
|
|
||||||
/// Generates project files necessary to make Gradle builds work on Android
|
/// Generates project files necessary to make Gradle builds work on Android
|
||||||
/// and CocoaPods+Xcode work on iOS, for app and module projects only.
|
/// and CocoaPods+Xcode work on iOS, for app and module projects only.
|
||||||
|
// TODO(cyanglaz): The param `checkProjects` is confusing. We should give it a better name
|
||||||
|
// or add some documentation explaining what it does, or both.
|
||||||
|
// https://github.com/flutter/flutter/issues/60023
|
||||||
Future<void> ensureReadyForPlatformSpecificTooling({bool checkProjects = false}) async {
|
Future<void> ensureReadyForPlatformSpecificTooling({bool checkProjects = false}) async {
|
||||||
if (!directory.existsSync() || hasExampleApp) {
|
if (!directory.existsSync() || hasExampleApp) {
|
||||||
return;
|
return;
|
||||||
@ -648,6 +651,7 @@ class IosProject extends FlutterProjectPlatform implements XcodeBasedProject {
|
|||||||
template.render(
|
template.render(
|
||||||
target,
|
target,
|
||||||
<String, dynamic>{
|
<String, dynamic>{
|
||||||
|
'ios': true,
|
||||||
'projectName': parent.manifest.appName,
|
'projectName': parent.manifest.appName,
|
||||||
'iosIdentifier': parent.manifest.iosBundleIdentifier,
|
'iosIdentifier': parent.manifest.iosBundleIdentifier,
|
||||||
},
|
},
|
||||||
@ -797,6 +801,7 @@ class AndroidProject extends FlutterProjectPlatform {
|
|||||||
template.render(
|
template.render(
|
||||||
target,
|
target,
|
||||||
<String, dynamic>{
|
<String, dynamic>{
|
||||||
|
'android': true,
|
||||||
'projectName': parent.manifest.appName,
|
'projectName': parent.manifest.appName,
|
||||||
'androidIdentifier': parent.manifest.androidPackage,
|
'androidIdentifier': parent.manifest.androidPackage,
|
||||||
'androidX': usesAndroidX,
|
'androidX': usesAndroidX,
|
||||||
|
@ -108,6 +108,16 @@ class Template {
|
|||||||
}
|
}
|
||||||
relativeDestinationPath = relativeDestinationPath.replaceAll('$platform-$language.tmpl', platform);
|
relativeDestinationPath = relativeDestinationPath.replaceAll('$platform-$language.tmpl', platform);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final bool android = context['android'] as bool;
|
||||||
|
if (relativeDestinationPath.contains('android') && !android) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(cyanglaz): do not add iOS folder by default when 1.20.0 is released.
|
||||||
|
// Also need to update the flutter SDK min constraint in the pubspec.yaml to 1.20.0.
|
||||||
|
// https://github.com/flutter/flutter/issues/59787
|
||||||
|
|
||||||
// Only build a web project if explicitly asked.
|
// Only build a web project if explicitly asked.
|
||||||
final bool web = context['web'] as bool;
|
final bool web = context['web'] as bool;
|
||||||
if (relativeDestinationPath.contains('web') && !web) {
|
if (relativeDestinationPath.contains('web') && !web) {
|
||||||
@ -128,6 +138,7 @@ class Template {
|
|||||||
if (relativeDestinationPath.startsWith('windows.tmpl') && !windows) {
|
if (relativeDestinationPath.startsWith('windows.tmpl') && !windows) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final String projectName = context['projectName'] as String;
|
final String projectName = context['projectName'] as String;
|
||||||
final String androidIdentifier = context['androidIdentifier'] as String;
|
final String androidIdentifier = context['androidIdentifier'] as String;
|
||||||
final String pluginClass = context['pluginClass'] as String;
|
final String pluginClass = context['pluginClass'] as String;
|
||||||
@ -139,7 +150,7 @@ class Template {
|
|||||||
.replaceAll(imageTemplateExtension, '')
|
.replaceAll(imageTemplateExtension, '')
|
||||||
.replaceAll(templateExtension, '');
|
.replaceAll(templateExtension, '');
|
||||||
|
|
||||||
if (androidIdentifier != null) {
|
if (android != null && android && androidIdentifier != null) {
|
||||||
finalDestinationPath = finalDestinationPath
|
finalDestinationPath = finalDestinationPath
|
||||||
.replaceAll('androidIdentifier', androidIdentifier.replaceAll('.', pathSeparator));
|
.replaceAll('androidIdentifier', androidIdentifier.replaceAll('.', pathSeparator));
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,12 @@ This project is a starting point for a Flutter
|
|||||||
a specialized package that includes platform-specific implementation code for
|
a specialized package that includes platform-specific implementation code for
|
||||||
Android and/or iOS.
|
Android and/or iOS.
|
||||||
|
|
||||||
For help getting started with Flutter, view our
|
For help getting started with Flutter, view our
|
||||||
[online documentation](https://flutter.dev/docs), which offers tutorials,
|
[online documentation](https://flutter.dev/docs), which offers tutorials,
|
||||||
samples, guidance on mobile development, and a full API reference.
|
samples, guidance on mobile development, and a full API reference.
|
||||||
|
|
||||||
|
{{#no_platforms}}
|
||||||
|
The plugin project was generated without specifying the `--platforms` flag, no platforms are currently supported.
|
||||||
|
To add platforms, run `flutter create -t plugin --platforms <platforms> .` under the same
|
||||||
|
directory. You can also find a detailed instruction on how to add platforms in the `pubspec.yaml` at https://flutter.dev/docs/development/packages-and-plugins/developing-packages#plugin-platforms.
|
||||||
|
{{/no_platforms}}
|
||||||
|
@ -1,3 +1,10 @@
|
|||||||
|
{{#no_platforms}}
|
||||||
|
// You have generated a new plugin project without
|
||||||
|
// specifying the `--platforms` flag. A plugin project supports no platforms is generated.
|
||||||
|
// To add platforms, run `flutter create -t plugin --platforms <platforms> .` under the same
|
||||||
|
// directory. You can also find a detailed instruction on how to add platforms in the `pubspec.yaml` at https://flutter.dev/docs/development/packages-and-plugins/developing-packages#plugin-platforms.
|
||||||
|
{{/no_platforms}}
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
@ -31,11 +31,25 @@ flutter:
|
|||||||
# adding or updating assets for this project.
|
# adding or updating assets for this project.
|
||||||
plugin:
|
plugin:
|
||||||
platforms:
|
platforms:
|
||||||
|
{{#no_platforms}}
|
||||||
|
# This plugin project was generated without specifying any
|
||||||
|
# platforms with the `--platform` argument. If you see the `fake_platform` map below, remove it and
|
||||||
|
# then add platforms following the instruction here:
|
||||||
|
# https://flutter.dev/docs/development/packages-and-plugins/developing-packages#plugin-platforms
|
||||||
|
# -------------------
|
||||||
|
some_platform:
|
||||||
|
pluginClass: somePluginClass
|
||||||
|
# -------------------
|
||||||
|
{{/no_platforms}}
|
||||||
|
{{#android}}
|
||||||
android:
|
android:
|
||||||
package: {{androidIdentifier}}
|
package: {{androidIdentifier}}
|
||||||
pluginClass: {{pluginClass}}
|
pluginClass: {{pluginClass}}
|
||||||
|
{{/android}}
|
||||||
|
{{#ios}}
|
||||||
ios:
|
ios:
|
||||||
pluginClass: {{pluginClass}}
|
pluginClass: {{pluginClass}}
|
||||||
|
{{/ios}}
|
||||||
{{#linux}}
|
{{#linux}}
|
||||||
linux:
|
linux:
|
||||||
pluginClass: {{pluginClass}}
|
pluginClass: {{pluginClass}}
|
||||||
@ -44,6 +58,10 @@ flutter:
|
|||||||
macos:
|
macos:
|
||||||
pluginClass: {{pluginClass}}
|
pluginClass: {{pluginClass}}
|
||||||
{{/macos}}
|
{{/macos}}
|
||||||
|
{{#windows}}
|
||||||
|
windows:
|
||||||
|
pluginClass: {{pluginClass}}
|
||||||
|
{{/windows}}
|
||||||
{{#web}}
|
{{#web}}
|
||||||
web:
|
web:
|
||||||
pluginClass: {{pluginDartClass}}Web
|
pluginClass: {{pluginDartClass}}Web
|
||||||
|
@ -26,6 +26,7 @@ import 'package:pubspec_parse/pubspec_parse.dart';
|
|||||||
|
|
||||||
import '../../src/common.dart';
|
import '../../src/common.dart';
|
||||||
import '../../src/context.dart';
|
import '../../src/context.dart';
|
||||||
|
import '../../src/pubspec_schema.dart';
|
||||||
import '../../src/testbed.dart';
|
import '../../src/testbed.dart';
|
||||||
|
|
||||||
const String frameworkRevision = '12345678';
|
const String frameworkRevision = '12345678';
|
||||||
@ -242,23 +243,18 @@ void main() {
|
|||||||
testUsingContext('detects and recreates a plugin project correctly', () async {
|
testUsingContext('detects and recreates a plugin project correctly', () async {
|
||||||
await projectDir.create(recursive: true);
|
await projectDir.create(recursive: true);
|
||||||
await projectDir.absolute.childFile('.metadata').writeAsString('project_type: plugin\n');
|
await projectDir.absolute.childFile('.metadata').writeAsString('project_type: plugin\n');
|
||||||
return _createAndAnalyzeProject(
|
await _createAndAnalyzeProject(
|
||||||
projectDir,
|
projectDir,
|
||||||
|
<String>[],
|
||||||
<String>[
|
<String>[
|
||||||
'-i', 'objc', '-a', 'java',
|
|
||||||
],
|
|
||||||
<String>[
|
|
||||||
'android/src/main/java/com/example/flutter_project/FlutterProjectPlugin.java',
|
|
||||||
'example/android/app/src/main/java/com/example/flutter_project_example/MainActivity.java',
|
|
||||||
'example/ios/Runner/AppDelegate.h',
|
|
||||||
'example/ios/Runner/AppDelegate.m',
|
|
||||||
'example/ios/Runner/main.m',
|
|
||||||
'example/lib/main.dart',
|
'example/lib/main.dart',
|
||||||
'flutter_project.iml',
|
'flutter_project.iml',
|
||||||
'ios/Classes/FlutterProjectPlugin.h',
|
|
||||||
'ios/Classes/FlutterProjectPlugin.m',
|
|
||||||
'lib/flutter_project.dart',
|
'lib/flutter_project.dart',
|
||||||
],
|
],
|
||||||
|
unexpectedPaths: <String>[
|
||||||
|
'android/app/src/main/java/com/example/flutter_project/MainActivity.java',
|
||||||
|
'android/src/main/java/com/example/flutter_project/FlutterProjectPlugin.java',
|
||||||
|
'example/android/app/src/main/java/com/example/flutter_project_example/MainActivity.java',]
|
||||||
);
|
);
|
||||||
}, overrides: <Type, Generator>{
|
}, overrides: <Type, Generator>{
|
||||||
Pub: () => Pub(
|
Pub: () => Pub(
|
||||||
@ -380,19 +376,16 @@ void main() {
|
|||||||
projectDir,
|
projectDir,
|
||||||
<String>['--template=plugin', '-i', 'objc', '-a', 'java'],
|
<String>['--template=plugin', '-i', 'objc', '-a', 'java'],
|
||||||
<String>[
|
<String>[
|
||||||
'android/src/main/java/com/example/flutter_project/FlutterProjectPlugin.java',
|
|
||||||
'example/android/app/src/main/java/com/example/flutter_project_example/MainActivity.java',
|
|
||||||
'example/ios/Runner/AppDelegate.h',
|
|
||||||
'example/ios/Runner/AppDelegate.m',
|
|
||||||
'example/ios/Runner/main.m',
|
|
||||||
'example/lib/main.dart',
|
'example/lib/main.dart',
|
||||||
'flutter_project.iml',
|
'flutter_project.iml',
|
||||||
'ios/Classes/FlutterProjectPlugin.h',
|
|
||||||
'ios/Classes/FlutterProjectPlugin.m',
|
|
||||||
'lib/flutter_project.dart',
|
'lib/flutter_project.dart',
|
||||||
],
|
],
|
||||||
unexpectedPaths: <String>[
|
unexpectedPaths: <String>[
|
||||||
|
'android/src/main/java/com/example/flutter_project/FlutterProjectPlugin.java',
|
||||||
|
'example/android/app/src/main/java/com/example/flutter_project_example/MainActivity.java',
|
||||||
'lib/flutter_project_web.dart',
|
'lib/flutter_project_web.dart',
|
||||||
|
// TODO(cyanglaz): no-op iOS folder should be removed after 1.20.0 release
|
||||||
|
// https://github.com/flutter/flutter/issues/59787
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
return _runFlutterTest(projectDir.childDirectory('example'));
|
return _runFlutterTest(projectDir.childDirectory('example'));
|
||||||
@ -410,7 +403,7 @@ void main() {
|
|||||||
testUsingContext('plugin project supports web', () async {
|
testUsingContext('plugin project supports web', () async {
|
||||||
await _createAndAnalyzeProject(
|
await _createAndAnalyzeProject(
|
||||||
projectDir,
|
projectDir,
|
||||||
<String>['--template=plugin'],
|
<String>['--template=plugin', '--platforms=web'],
|
||||||
<String>[
|
<String>[
|
||||||
'lib/flutter_project.dart',
|
'lib/flutter_project.dart',
|
||||||
'lib/flutter_project_web.dart',
|
'lib/flutter_project_web.dart',
|
||||||
@ -464,7 +457,7 @@ void main() {
|
|||||||
testUsingContext('kotlin/swift plugin project', () async {
|
testUsingContext('kotlin/swift plugin project', () async {
|
||||||
return _createProject(
|
return _createProject(
|
||||||
projectDir,
|
projectDir,
|
||||||
<String>['--no-pub', '--template=plugin', '-a', 'kotlin', '--ios-language', 'swift'],
|
<String>['--no-pub', '--template=plugin', '-a', 'kotlin', '--ios-language', 'swift', '--platforms', 'ios,android'],
|
||||||
<String>[
|
<String>[
|
||||||
'android/src/main/kotlin/com/example/flutter_project/FlutterProjectPlugin.kt',
|
'android/src/main/kotlin/com/example/flutter_project/FlutterProjectPlugin.kt',
|
||||||
'example/android/app/src/main/kotlin/com/example/flutter_project_example/MainActivity.kt',
|
'example/android/app/src/main/kotlin/com/example/flutter_project_example/MainActivity.kt',
|
||||||
@ -495,6 +488,7 @@ void main() {
|
|||||||
'--org', 'com.bar.foo',
|
'--org', 'com.bar.foo',
|
||||||
'-i', 'objc',
|
'-i', 'objc',
|
||||||
'-a', 'java',
|
'-a', 'java',
|
||||||
|
'--platforms', 'android',
|
||||||
], <String>[
|
], <String>[
|
||||||
'android/src/main/java/com/bar/foo/flutter_project/FlutterProjectPlugin.java',
|
'android/src/main/java/com/bar/foo/flutter_project/FlutterProjectPlugin.java',
|
||||||
'example/android/app/src/main/java/com/bar/foo/flutter_project_example/MainActivity.java',
|
'example/android/app/src/main/java/com/bar/foo/flutter_project_example/MainActivity.java',
|
||||||
@ -515,6 +509,7 @@ void main() {
|
|||||||
'--project-name', 'xyz',
|
'--project-name', 'xyz',
|
||||||
'-i', 'objc',
|
'-i', 'objc',
|
||||||
'-a', 'java',
|
'-a', 'java',
|
||||||
|
'--platforms', 'android,ios',
|
||||||
], <String>[
|
], <String>[
|
||||||
'android/src/main/java/com/example/xyz/XyzPlugin.java',
|
'android/src/main/java/com/example/xyz/XyzPlugin.java',
|
||||||
'example/android/app/src/main/java/com/example/xyz_example/MainActivity.java',
|
'example/android/app/src/main/java/com/example/xyz_example/MainActivity.java',
|
||||||
@ -529,7 +524,7 @@ void main() {
|
|||||||
testUsingContext('plugin project with invalid custom project name', () async {
|
testUsingContext('plugin project with invalid custom project name', () async {
|
||||||
expect(
|
expect(
|
||||||
() => _createProject(projectDir,
|
() => _createProject(projectDir,
|
||||||
<String>['--no-pub', '--template=plugin', '--project-name', 'xyz.xyz'],
|
<String>['--no-pub', '--template=plugin', '--project-name', 'xyz.xyz', '--platforms', 'android,ios',],
|
||||||
<String>[],
|
<String>[],
|
||||||
),
|
),
|
||||||
throwsToolExit(message: '"xyz.xyz" is not a valid Dart package name.'),
|
throwsToolExit(message: '"xyz.xyz" is not a valid Dart package name.'),
|
||||||
@ -642,7 +637,7 @@ void main() {
|
|||||||
final CreateCommand command = CreateCommand();
|
final CreateCommand command = CreateCommand();
|
||||||
final CommandRunner<void> runner = createTestCommandRunner(command);
|
final CommandRunner<void> runner = createTestCommandRunner(command);
|
||||||
|
|
||||||
await runner.run(<String>['create', '--no-pub', '--template=plugin', projectDir.path]);
|
await runner.run(<String>['create', '--no-pub', '--template=plugin', '--platforms', 'android', projectDir.path]);
|
||||||
|
|
||||||
void expectExists(String relPath) {
|
void expectExists(String relPath) {
|
||||||
expect(globals.fs.isFileSync('${projectDir.path}/$relPath'), true);
|
expect(globals.fs.isFileSync('${projectDir.path}/$relPath'), true);
|
||||||
@ -693,9 +688,14 @@ void main() {
|
|||||||
final CreateCommand command = CreateCommand();
|
final CreateCommand command = CreateCommand();
|
||||||
final CommandRunner<void> runner = createTestCommandRunner(command);
|
final CommandRunner<void> runner = createTestCommandRunner(command);
|
||||||
|
|
||||||
await runner.run(<String>['create', '--no-pub', '--template=plugin', projectDir.path]);
|
await runner.run(<String>['create', '--no-pub', '--template=plugin', '--platforms=linux', projectDir.path]);
|
||||||
|
|
||||||
expect(projectDir.childDirectory('linux').childFile('CMakeLists.txt').existsSync(), true);
|
expect(projectDir.childDirectory('linux').childFile('CMakeLists.txt').existsSync(), true);
|
||||||
|
expect(projectDir.childDirectory('example').childDirectory('linux').existsSync(), true);
|
||||||
|
validatePubspecForPlugin(projectDir: projectDir.absolute.path, expectedPlatforms: const <String>[
|
||||||
|
'linux',
|
||||||
|
], pluginClass: 'FlutterProjectPlugin',
|
||||||
|
unexpectedPlatforms: <String>['some_platform']);
|
||||||
}, overrides: <Type, Generator>{
|
}, overrides: <Type, Generator>{
|
||||||
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true),
|
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true),
|
||||||
});
|
});
|
||||||
@ -711,6 +711,7 @@ void main() {
|
|||||||
await runner.run(<String>['create', '--no-pub', '--template=plugin', projectDir.path]);
|
await runner.run(<String>['create', '--no-pub', '--template=plugin', projectDir.path]);
|
||||||
|
|
||||||
expect(projectDir.childDirectory('linux').childFile('CMakeLists.txt').existsSync(), false);
|
expect(projectDir.childDirectory('linux').childFile('CMakeLists.txt').existsSync(), false);
|
||||||
|
expect(projectDir.childDirectory('example').childDirectory('linux').existsSync(), false);
|
||||||
}, overrides: <Type, Generator>{
|
}, overrides: <Type, Generator>{
|
||||||
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: false),
|
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: false),
|
||||||
});
|
});
|
||||||
@ -738,9 +739,14 @@ void main() {
|
|||||||
final CreateCommand command = CreateCommand();
|
final CreateCommand command = CreateCommand();
|
||||||
final CommandRunner<void> runner = createTestCommandRunner(command);
|
final CommandRunner<void> runner = createTestCommandRunner(command);
|
||||||
|
|
||||||
await runner.run(<String>['create', '--no-pub', '--template=plugin', projectDir.path]);
|
await runner.run(<String>['create', '--no-pub', '--template=plugin', '--platforms=macos', projectDir.path]);
|
||||||
|
|
||||||
expect(projectDir.childDirectory('macos').childFile('flutter_project.podspec').existsSync(), true);
|
expect(projectDir.childDirectory('macos').childFile('flutter_project.podspec').existsSync(), true);
|
||||||
|
expect(projectDir.childDirectory('example').childDirectory('macos').existsSync(), true);
|
||||||
|
validatePubspecForPlugin(projectDir: projectDir.absolute.path, expectedPlatforms: const <String>[
|
||||||
|
'macos',
|
||||||
|
], pluginClass: 'FlutterProjectPlugin',
|
||||||
|
unexpectedPlatforms: <String>['some_platform']);
|
||||||
}, overrides: <Type, Generator>{
|
}, overrides: <Type, Generator>{
|
||||||
FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true),
|
FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true),
|
||||||
});
|
});
|
||||||
@ -756,6 +762,7 @@ void main() {
|
|||||||
await runner.run(<String>['create', '--no-pub', '--template=plugin', projectDir.path]);
|
await runner.run(<String>['create', '--no-pub', '--template=plugin', projectDir.path]);
|
||||||
|
|
||||||
expect(projectDir.childDirectory('macos').childFile('flutter_project.podspec').existsSync(), false);
|
expect(projectDir.childDirectory('macos').childFile('flutter_project.podspec').existsSync(), false);
|
||||||
|
expect(projectDir.childDirectory('example').childDirectory('macos').existsSync(), false);
|
||||||
}, overrides: <Type, Generator>{
|
}, overrides: <Type, Generator>{
|
||||||
FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: false),
|
FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: false),
|
||||||
});
|
});
|
||||||
@ -798,9 +805,14 @@ void main() {
|
|||||||
final CreateCommand command = CreateCommand();
|
final CreateCommand command = CreateCommand();
|
||||||
final CommandRunner<void> runner = createTestCommandRunner(command);
|
final CommandRunner<void> runner = createTestCommandRunner(command);
|
||||||
|
|
||||||
await runner.run(<String>['create', '--no-pub', '--template=plugin', projectDir.path]);
|
await runner.run(<String>['create', '--no-pub', '--template=plugin', '--platforms=windows', projectDir.path]);
|
||||||
|
|
||||||
expect(projectDir.childDirectory('windows').childFile('plugin.vcxproj').existsSync(), true);
|
expect(projectDir.childDirectory('windows').childFile('plugin.vcxproj').existsSync(), true);
|
||||||
|
expect(projectDir.childDirectory('example').childDirectory('windows').existsSync(), true);
|
||||||
|
validatePubspecForPlugin(projectDir: projectDir.absolute.path, expectedPlatforms: const <String>[
|
||||||
|
'windows'
|
||||||
|
], pluginClass: 'FlutterProjectPlugin',
|
||||||
|
unexpectedPlatforms: <String>['some_platform']);
|
||||||
}, overrides: <Type, Generator>{
|
}, overrides: <Type, Generator>{
|
||||||
FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true),
|
FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true),
|
||||||
});
|
});
|
||||||
@ -816,6 +828,7 @@ void main() {
|
|||||||
await runner.run(<String>['create', '--no-pub', '--template=plugin', projectDir.path]);
|
await runner.run(<String>['create', '--no-pub', '--template=plugin', projectDir.path]);
|
||||||
|
|
||||||
expect(projectDir.childDirectory('windows').childFile('plugin.vcxproj').existsSync(), false);
|
expect(projectDir.childDirectory('windows').childFile('plugin.vcxproj').existsSync(), false);
|
||||||
|
expect(projectDir.childDirectory('example').childDirectory('windows').existsSync(), false);
|
||||||
}, overrides: <Type, Generator>{
|
}, overrides: <Type, Generator>{
|
||||||
FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: false),
|
FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: false),
|
||||||
});
|
});
|
||||||
@ -1269,6 +1282,7 @@ void main() {
|
|||||||
'--org', 'com.bar.foo',
|
'--org', 'com.bar.foo',
|
||||||
'-i', 'objc',
|
'-i', 'objc',
|
||||||
'-a', 'java',
|
'-a', 'java',
|
||||||
|
'--platforms', 'ios,android'
|
||||||
],
|
],
|
||||||
<String>[],
|
<String>[],
|
||||||
);
|
);
|
||||||
@ -1276,7 +1290,7 @@ void main() {
|
|||||||
projectDir.childDirectory('ios').deleteSync(recursive: true);
|
projectDir.childDirectory('ios').deleteSync(recursive: true);
|
||||||
await _createProject(
|
await _createProject(
|
||||||
projectDir,
|
projectDir,
|
||||||
<String>['--no-pub', '--template=plugin', '-i', 'objc', '-a', 'java'],
|
<String>['--no-pub', '--template=plugin', '-i', 'objc', '-a', 'java', '--platforms', 'ios,android'],
|
||||||
<String>[
|
<String>[
|
||||||
'example/android/app/src/main/java/com/bar/foo/flutter_project_example/MainActivity.java',
|
'example/android/app/src/main/java/com/bar/foo/flutter_project_example/MainActivity.java',
|
||||||
'ios/Classes/FlutterProjectPlugin.h',
|
'ios/Classes/FlutterProjectPlugin.h',
|
||||||
@ -1506,6 +1520,306 @@ void main() {
|
|||||||
HttpClientFactory: () =>
|
HttpClientFactory: () =>
|
||||||
() => MockHttpClient(404, result: 'not found'),
|
() => MockHttpClient(404, result: 'not found'),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testUsingContext('plugin does not support any platform by default', () async {
|
||||||
|
Cache.flutterRoot = '../..';
|
||||||
|
when(mockFlutterVersion.frameworkRevision).thenReturn(frameworkRevision);
|
||||||
|
when(mockFlutterVersion.channel).thenReturn(frameworkChannel);
|
||||||
|
|
||||||
|
final CreateCommand command = CreateCommand();
|
||||||
|
final CommandRunner<void> runner = createTestCommandRunner(command);
|
||||||
|
|
||||||
|
await runner.run(<String>['create', '--no-pub', '--template=plugin', projectDir.path]);
|
||||||
|
|
||||||
|
// TODO(cyanglaz): no-op iOS folder should be removed after 1.20.0 release
|
||||||
|
// https://github.com/flutter/flutter/issues/59787
|
||||||
|
expect(projectDir.childDirectory('ios').existsSync(), true);
|
||||||
|
expect(projectDir.childDirectory('android').existsSync(), false);
|
||||||
|
expect(projectDir.childDirectory('web').existsSync(), false);
|
||||||
|
expect(projectDir.childDirectory('linux').existsSync(), false);
|
||||||
|
expect(projectDir.childDirectory('windows').existsSync(), false);
|
||||||
|
expect(projectDir.childDirectory('macos').existsSync(), false);
|
||||||
|
|
||||||
|
// TODO(cyanglaz): no-op iOS folder should be removed after 1.20.0 release
|
||||||
|
// https://github.com/flutter/flutter/issues/59787
|
||||||
|
expect(projectDir.childDirectory('example').childDirectory('ios').existsSync(), true);
|
||||||
|
expect(projectDir.childDirectory('example').childDirectory('android').existsSync(), false);
|
||||||
|
expect(projectDir.childDirectory('example').childDirectory('web').existsSync(), false);
|
||||||
|
expect(projectDir.childDirectory('example').childDirectory('linux').existsSync(), false);
|
||||||
|
expect(projectDir.childDirectory('example').childDirectory('windows').existsSync(), false);
|
||||||
|
expect(projectDir.childDirectory('example').childDirectory('macos').existsSync(), false);
|
||||||
|
validatePubspecForPlugin(projectDir: projectDir.absolute.path, expectedPlatforms: <String>[
|
||||||
|
'some_platform'
|
||||||
|
], pluginClass: 'somePluginClass',
|
||||||
|
unexpectedPlatforms: <String>[ 'ios', 'android', 'web', 'linux', 'windows', 'macos']);
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: false),
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// TODO(cyanglaz): no-op iOS folder should be removed after 1.20.0 release
|
||||||
|
// https://github.com/flutter/flutter/issues/59787
|
||||||
|
testUsingContext('create an empty plugin contains a no-op ios folder, but no pubspec entry.', () async {
|
||||||
|
Cache.flutterRoot = '../..';
|
||||||
|
when(mockFlutterVersion.frameworkRevision).thenReturn(frameworkRevision);
|
||||||
|
when(mockFlutterVersion.channel).thenReturn(frameworkChannel);
|
||||||
|
|
||||||
|
final CreateCommand command = CreateCommand();
|
||||||
|
final CommandRunner<void> runner = createTestCommandRunner(command);
|
||||||
|
await runner.run(<String>['create', '--no-pub', '--template=plugin', projectDir.path]);
|
||||||
|
|
||||||
|
expect(projectDir.childDirectory('ios').existsSync(), true);
|
||||||
|
expect(projectDir.childDirectory('example').childDirectory('ios').existsSync(), true);
|
||||||
|
validatePubspecForPlugin(projectDir: projectDir.absolute.path, expectedPlatforms: const <String>[
|
||||||
|
'some_platform'
|
||||||
|
], pluginClass: 'somePluginClass',
|
||||||
|
unexpectedPlatforms: <String>['ios']);
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('plugin supports ios if requested', () async {
|
||||||
|
Cache.flutterRoot = '../..';
|
||||||
|
when(mockFlutterVersion.frameworkRevision).thenReturn(frameworkRevision);
|
||||||
|
when(mockFlutterVersion.channel).thenReturn(frameworkChannel);
|
||||||
|
|
||||||
|
final CreateCommand command = CreateCommand();
|
||||||
|
final CommandRunner<void> runner = createTestCommandRunner(command);
|
||||||
|
|
||||||
|
await runner.run(<String>['create', '--no-pub', '--template=plugin', '--platforms=ios', projectDir.path]);
|
||||||
|
|
||||||
|
expect(projectDir.childDirectory('ios').existsSync(), true);
|
||||||
|
expect(projectDir.childDirectory('example').childDirectory('ios').existsSync(), true);
|
||||||
|
validatePubspecForPlugin(projectDir: projectDir.absolute.path, expectedPlatforms: <String>[
|
||||||
|
'ios',
|
||||||
|
], pluginClass: 'FlutterProjectPlugin',
|
||||||
|
unexpectedPlatforms: <String>['some_platform']);
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: false),
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('plugin supports android if requested', () async {
|
||||||
|
Cache.flutterRoot = '../..';
|
||||||
|
when(mockFlutterVersion.frameworkRevision).thenReturn(frameworkRevision);
|
||||||
|
when(mockFlutterVersion.channel).thenReturn(frameworkChannel);
|
||||||
|
|
||||||
|
final CreateCommand command = CreateCommand();
|
||||||
|
final CommandRunner<void> runner = createTestCommandRunner(command);
|
||||||
|
|
||||||
|
await runner.run(<String>['create', '--no-pub', '--template=plugin', '--platforms=android', projectDir.path]);
|
||||||
|
|
||||||
|
expect(projectDir.childDirectory('android').existsSync(), true);
|
||||||
|
expect(projectDir.childDirectory('example').childDirectory('android').existsSync(), true);
|
||||||
|
validatePubspecForPlugin(projectDir: projectDir.absolute.path, expectedPlatforms: const <String>[
|
||||||
|
'android'
|
||||||
|
], pluginClass: 'FlutterProjectPlugin',
|
||||||
|
unexpectedPlatforms: <String>['some_platform'],
|
||||||
|
androidIdentifier: 'com.example.flutter_project');
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: false),
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('plugin supports web if requested', () async {
|
||||||
|
Cache.flutterRoot = '../..';
|
||||||
|
when(mockFlutterVersion.frameworkRevision).thenReturn(frameworkRevision);
|
||||||
|
when(mockFlutterVersion.channel).thenReturn(frameworkChannel);
|
||||||
|
|
||||||
|
final CreateCommand command = CreateCommand();
|
||||||
|
final CommandRunner<void> runner = createTestCommandRunner(command);
|
||||||
|
|
||||||
|
await runner.run(<String>['create', '--no-pub', '--template=plugin', '--platforms=web', projectDir.path]);
|
||||||
|
expect(projectDir.childDirectory('lib').childFile('flutter_project_web.dart').existsSync(), true);
|
||||||
|
validatePubspecForPlugin(projectDir: projectDir.absolute.path, expectedPlatforms: const <String>[
|
||||||
|
'web'
|
||||||
|
], pluginClass: 'FlutterProjectWeb',
|
||||||
|
unexpectedPlatforms: <String>['some_platform'],
|
||||||
|
androidIdentifier: 'com.example.flutter_project',
|
||||||
|
webFileName: 'flutter_project_web.dart');
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
FeatureFlags: () => TestFeatureFlags(isWebEnabled: true),
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('plugin doe not support web if feature is not enabled', () async {
|
||||||
|
Cache.flutterRoot = '../..';
|
||||||
|
when(mockFlutterVersion.frameworkRevision).thenReturn(frameworkRevision);
|
||||||
|
when(mockFlutterVersion.channel).thenReturn(frameworkChannel);
|
||||||
|
|
||||||
|
final CreateCommand command = CreateCommand();
|
||||||
|
final CommandRunner<void> runner = createTestCommandRunner(command);
|
||||||
|
|
||||||
|
await runner.run(<String>['create', '--no-pub', '--template=plugin', '--platforms=web', projectDir.path]);
|
||||||
|
expect(projectDir.childDirectory('lib').childFile('flutter_project_web.dart').existsSync(), false);
|
||||||
|
validatePubspecForPlugin(projectDir: projectDir.absolute.path, expectedPlatforms: const <String>[
|
||||||
|
'some_platform'
|
||||||
|
], pluginClass: 'somePluginClass',
|
||||||
|
unexpectedPlatforms: <String>['web']);
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
FeatureFlags: () => TestFeatureFlags(isWebEnabled: false),
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('create an empty plugin, then add ios', () async {
|
||||||
|
Cache.flutterRoot = '../..';
|
||||||
|
when(mockFlutterVersion.frameworkRevision).thenReturn(frameworkRevision);
|
||||||
|
when(mockFlutterVersion.channel).thenReturn(frameworkChannel);
|
||||||
|
|
||||||
|
final CreateCommand command = CreateCommand();
|
||||||
|
final CommandRunner<void> runner = createTestCommandRunner(command);
|
||||||
|
await runner.run(<String>['create', '--no-pub', '--template=plugin', projectDir.path]);
|
||||||
|
await runner.run(<String>['create', '--no-pub', '--template=plugin', '--platforms=ios', projectDir.path]);
|
||||||
|
|
||||||
|
expect(projectDir.childDirectory('ios').existsSync(), true);
|
||||||
|
expect(projectDir.childDirectory('example').childDirectory('ios').existsSync(), true);
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: false),
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('create an empty plugin, then add android', () async {
|
||||||
|
Cache.flutterRoot = '../..';
|
||||||
|
when(mockFlutterVersion.frameworkRevision).thenReturn(frameworkRevision);
|
||||||
|
when(mockFlutterVersion.channel).thenReturn(frameworkChannel);
|
||||||
|
|
||||||
|
final CreateCommand command = CreateCommand();
|
||||||
|
final CommandRunner<void> runner = createTestCommandRunner(command);
|
||||||
|
await runner.run(<String>['create', '--no-pub', '--template=plugin', projectDir.path]);
|
||||||
|
await runner.run(<String>['create', '--no-pub', '--template=plugin', '--platforms=android', projectDir.path]);
|
||||||
|
|
||||||
|
expect(projectDir.childDirectory('android').existsSync(), true);
|
||||||
|
expect(projectDir.childDirectory('example').childDirectory('android').existsSync(), true);
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: false),
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('create an empty plugin, then add linux', () async {
|
||||||
|
Cache.flutterRoot = '../..';
|
||||||
|
when(mockFlutterVersion.frameworkRevision).thenReturn(frameworkRevision);
|
||||||
|
when(mockFlutterVersion.channel).thenReturn(frameworkChannel);
|
||||||
|
|
||||||
|
final CreateCommand command = CreateCommand();
|
||||||
|
final CommandRunner<void> runner = createTestCommandRunner(command);
|
||||||
|
await runner.run(<String>['create', '--no-pub', '--template=plugin', projectDir.path]);
|
||||||
|
await runner.run(<String>['create', '--no-pub', '--template=plugin', '--platforms=linux', projectDir.path]);
|
||||||
|
|
||||||
|
expect(projectDir.childDirectory('linux').existsSync(), true);
|
||||||
|
expect(projectDir.childDirectory('example').childDirectory('linux').existsSync(), true);
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true),
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('create an empty plugin, then add macos', () async {
|
||||||
|
Cache.flutterRoot = '../..';
|
||||||
|
when(mockFlutterVersion.frameworkRevision).thenReturn(frameworkRevision);
|
||||||
|
when(mockFlutterVersion.channel).thenReturn(frameworkChannel);
|
||||||
|
|
||||||
|
final CreateCommand command = CreateCommand();
|
||||||
|
final CommandRunner<void> runner = createTestCommandRunner(command);
|
||||||
|
await runner.run(<String>['create', '--no-pub', '--template=plugin', projectDir.path]);
|
||||||
|
await runner.run(<String>['create', '--no-pub', '--template=plugin', '--platforms=macos', projectDir.path]);
|
||||||
|
|
||||||
|
expect(projectDir.childDirectory('macos').existsSync(), true);
|
||||||
|
expect(projectDir.childDirectory('example').childDirectory('macos').existsSync(), true);
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true),
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('create an empty plugin, then add windows', () async {
|
||||||
|
Cache.flutterRoot = '../..';
|
||||||
|
when(mockFlutterVersion.frameworkRevision).thenReturn(frameworkRevision);
|
||||||
|
when(mockFlutterVersion.channel).thenReturn(frameworkChannel);
|
||||||
|
|
||||||
|
final CreateCommand command = CreateCommand();
|
||||||
|
final CommandRunner<void> runner = createTestCommandRunner(command);
|
||||||
|
await runner.run(<String>['create', '--no-pub', '--template=plugin', projectDir.path]);
|
||||||
|
await runner.run(<String>['create', '--no-pub', '--template=plugin', '--platforms=windows', projectDir.path]);
|
||||||
|
|
||||||
|
expect(projectDir.childDirectory('windows').existsSync(), true);
|
||||||
|
expect(projectDir.childDirectory('example').childDirectory('windows').existsSync(), true);
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true),
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('create an empty plugin, then add web', () async {
|
||||||
|
Cache.flutterRoot = '../..';
|
||||||
|
when(mockFlutterVersion.frameworkRevision).thenReturn(frameworkRevision);
|
||||||
|
when(mockFlutterVersion.channel).thenReturn(frameworkChannel);
|
||||||
|
|
||||||
|
final CreateCommand command = CreateCommand();
|
||||||
|
final CommandRunner<void> runner = createTestCommandRunner(command);
|
||||||
|
await runner.run(<String>['create', '--no-pub', '--template=plugin', projectDir.path]);
|
||||||
|
await runner.run(<String>['create', '--no-pub', '--template=plugin', '--platforms=web', projectDir.path]);
|
||||||
|
|
||||||
|
expect(projectDir.childDirectory('lib').childFile('flutter_project_web.dart').existsSync(), true);
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
FeatureFlags: () => TestFeatureFlags(isWebEnabled: true),
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('create a plugin with ios, then add macos', () async {
|
||||||
|
Cache.flutterRoot = '../..';
|
||||||
|
when(mockFlutterVersion.frameworkRevision).thenReturn(frameworkRevision);
|
||||||
|
when(mockFlutterVersion.channel).thenReturn(frameworkChannel);
|
||||||
|
|
||||||
|
final CreateCommand command = CreateCommand();
|
||||||
|
final CommandRunner<void> runner = createTestCommandRunner(command);
|
||||||
|
await runner.run(<String>['create', '--no-pub', '--template=plugin', '--platforms=ios', projectDir.path]);
|
||||||
|
expect(projectDir.childDirectory('ios').existsSync(), true);
|
||||||
|
expect(projectDir.childDirectory('example').childDirectory('ios').existsSync(), true);
|
||||||
|
validatePubspecForPlugin(projectDir: projectDir.absolute.path, expectedPlatforms: const <String>[
|
||||||
|
'ios',
|
||||||
|
], pluginClass: 'FlutterProjectPlugin',
|
||||||
|
unexpectedPlatforms: <String>['some_platform']);
|
||||||
|
|
||||||
|
await runner.run(<String>['create', '--no-pub', '--template=plugin', '--platforms=macos', projectDir.path]);
|
||||||
|
expect(projectDir.childDirectory('macos').existsSync(), true);
|
||||||
|
expect(projectDir.childDirectory('example').childDirectory('macos').existsSync(), true);
|
||||||
|
expect(projectDir.childDirectory('ios').existsSync(), true);
|
||||||
|
expect(projectDir.childDirectory('example').childDirectory('ios').existsSync(), true);
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true),
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('create a plugin with ios and android', () async {
|
||||||
|
Cache.flutterRoot = '../..';
|
||||||
|
when(mockFlutterVersion.frameworkRevision).thenReturn(frameworkRevision);
|
||||||
|
when(mockFlutterVersion.channel).thenReturn(frameworkChannel);
|
||||||
|
|
||||||
|
final CreateCommand command = CreateCommand();
|
||||||
|
final CommandRunner<void> runner = createTestCommandRunner(command);
|
||||||
|
await runner.run(<String>['create', '--no-pub', '--template=plugin', '--platforms=ios,android', projectDir.path]);
|
||||||
|
expect(projectDir.childDirectory('ios').existsSync(), true);
|
||||||
|
expect(projectDir.childDirectory('example').childDirectory('ios').existsSync(), true);
|
||||||
|
|
||||||
|
expect(projectDir.childDirectory('android').existsSync(), true);
|
||||||
|
expect(projectDir.childDirectory('example').childDirectory('android').existsSync(), true);
|
||||||
|
expect(projectDir.childDirectory('ios').existsSync(), true);
|
||||||
|
expect(projectDir.childDirectory('example').childDirectory('ios').existsSync(), true);
|
||||||
|
validatePubspecForPlugin(projectDir: projectDir.absolute.path, expectedPlatforms: const <String>[
|
||||||
|
'ios', 'android'
|
||||||
|
], pluginClass: 'FlutterProjectPlugin',
|
||||||
|
unexpectedPlatforms: <String>['some_platform'],
|
||||||
|
androidIdentifier: 'com.example.flutter_project');
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('create a module with --platforms throws error.', () async {
|
||||||
|
Cache.flutterRoot = '../..';
|
||||||
|
when(mockFlutterVersion.frameworkRevision).thenReturn(frameworkRevision);
|
||||||
|
when(mockFlutterVersion.channel).thenReturn(frameworkChannel);
|
||||||
|
|
||||||
|
final CreateCommand command = CreateCommand();
|
||||||
|
final CommandRunner<void> runner = createTestCommandRunner(command);
|
||||||
|
await expectLater(
|
||||||
|
runner.run(<String>['create', '--no-pub', '--template=module', '--platforms=ios', projectDir.path])
|
||||||
|
, throwsToolExit(message: 'The "--platforms" argument is not supported', exitCode:2));
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('create a package with --platforms throws error.', () async {
|
||||||
|
Cache.flutterRoot = '../..';
|
||||||
|
when(mockFlutterVersion.frameworkRevision).thenReturn(frameworkRevision);
|
||||||
|
when(mockFlutterVersion.channel).thenReturn(frameworkChannel);
|
||||||
|
|
||||||
|
final CreateCommand command = CreateCommand();
|
||||||
|
final CommandRunner<void> runner = createTestCommandRunner(command);
|
||||||
|
await expectLater(
|
||||||
|
runner.run(<String>['create', '--no-pub', '--template=package', '--platforms=ios', projectDir.path])
|
||||||
|
, throwsToolExit(message: 'The "--platforms" argument is not supported', exitCode: 2));
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _createProject(
|
Future<void> _createProject(
|
||||||
|
@ -375,7 +375,7 @@ void main() {
|
|||||||
testUsingContext('get fetches packages and injects plugin in plugin project', () async {
|
testUsingContext('get fetches packages and injects plugin in plugin project', () async {
|
||||||
final String projectPath = await createProject(
|
final String projectPath = await createProject(
|
||||||
tempDir,
|
tempDir,
|
||||||
arguments: <String>['--template=plugin', '--no-pub'],
|
arguments: <String>['--template=plugin', '--no-pub', '--platforms=ios,android'],
|
||||||
);
|
);
|
||||||
final String exampleProjectPath = globals.fs.path.join(projectPath, 'example');
|
final String exampleProjectPath = globals.fs.path.join(projectPath, 'example');
|
||||||
removeGeneratedFiles(projectPath);
|
removeGeneratedFiles(projectPath);
|
||||||
|
@ -900,6 +900,49 @@ flutter:
|
|||||||
|
|
||||||
expect(flutterManifest.isEmpty, false);
|
expect(flutterManifest.isEmpty, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWithoutContext('FlutterManifest getSupportedPlatforms return null if runs on legacy format', () {
|
||||||
|
const String manifest = '''
|
||||||
|
name: test
|
||||||
|
flutter:
|
||||||
|
plugin:
|
||||||
|
androidPackage: com.example
|
||||||
|
''';
|
||||||
|
final BufferLogger logger = BufferLogger.test();
|
||||||
|
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
|
||||||
|
manifest,
|
||||||
|
logger: logger,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(flutterManifest.isPlugin, true);
|
||||||
|
expect(flutterManifest.supportedPlatforms, null);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWithoutContext('FlutterManifest getSupportedPlatforms returns valid platforms.', () {
|
||||||
|
const String manifest = '''
|
||||||
|
name: test
|
||||||
|
flutter:
|
||||||
|
plugin:
|
||||||
|
platforms:
|
||||||
|
android:
|
||||||
|
package: com.example
|
||||||
|
pluginClass: SomeClass
|
||||||
|
ios:
|
||||||
|
pluginClass: SomeClass
|
||||||
|
''';
|
||||||
|
final BufferLogger logger = BufferLogger.test();
|
||||||
|
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
|
||||||
|
manifest,
|
||||||
|
logger: logger,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(flutterManifest.isPlugin, true);
|
||||||
|
expect(flutterManifest.supportedPlatforms['ios'],
|
||||||
|
<String, dynamic>{'pluginClass': 'SomeClass'});
|
||||||
|
expect(flutterManifest.supportedPlatforms['android'],
|
||||||
|
<String, dynamic>{'pluginClass': 'SomeClass',
|
||||||
|
'package': 'com.example'});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Matcher matchesManifest({
|
Matcher matchesManifest({
|
||||||
|
@ -10,15 +10,18 @@ import 'package:file_testing/file_testing.dart';
|
|||||||
import 'package:flutter_tools/src/base/time.dart';
|
import 'package:flutter_tools/src/base/time.dart';
|
||||||
import 'package:flutter_tools/src/dart/package_map.dart';
|
import 'package:flutter_tools/src/dart/package_map.dart';
|
||||||
import 'package:flutter_tools/src/features.dart';
|
import 'package:flutter_tools/src/features.dart';
|
||||||
|
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||||
import 'package:flutter_tools/src/ios/xcodeproj.dart';
|
import 'package:flutter_tools/src/ios/xcodeproj.dart';
|
||||||
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:flutter_tools/src/version.dart';
|
import 'package:flutter_tools/src/version.dart';
|
||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
import 'package:mockito/mockito.dart';
|
import 'package:mockito/mockito.dart';
|
||||||
|
import 'package:yaml/yaml.dart';
|
||||||
|
|
||||||
import '../src/common.dart';
|
import '../src/common.dart';
|
||||||
import '../src/context.dart';
|
import '../src/context.dart';
|
||||||
|
import '../src/pubspec_schema.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
group('plugins', () {
|
group('plugins', () {
|
||||||
@ -109,16 +112,14 @@ void main() {
|
|||||||
..writeAsStringSync('apackage:file://${dummyPackageDirectory.path}\n');
|
..writeAsStringSync('apackage:file://${dummyPackageDirectory.path}\n');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Makes the dummy package pointed to by packagesFile look like a plugin.
|
const String _pluginYaml = '''
|
||||||
void configureDummyPackageAsPlugin() {
|
|
||||||
dummyPackageDirectory.parent.childFile('pubspec.yaml')..createSync(recursive: true)..writeAsStringSync('''
|
|
||||||
flutter:
|
flutter:
|
||||||
plugin:
|
plugin:
|
||||||
platforms:
|
platforms:
|
||||||
ios:
|
ios:
|
||||||
pluginClass: FLESomePlugin
|
pluginClass: SomePlugin
|
||||||
macos:
|
macos:
|
||||||
pluginClass: FLESomePlugin
|
pluginClass: SomePlugin
|
||||||
windows:
|
windows:
|
||||||
pluginClass: SomePlugin
|
pluginClass: SomePlugin
|
||||||
linux:
|
linux:
|
||||||
@ -129,7 +130,10 @@ void main() {
|
|||||||
android:
|
android:
|
||||||
pluginClass: SomePlugin
|
pluginClass: SomePlugin
|
||||||
package: AndroidPackage
|
package: AndroidPackage
|
||||||
''');
|
''';
|
||||||
|
// Makes the dummy package pointed to by packagesFile look like a plugin.
|
||||||
|
void configureDummyPackageAsPlugin() {
|
||||||
|
dummyPackageDirectory.parent.childFile('pubspec.yaml')..createSync(recursive: true)..writeAsStringSync(_pluginYaml);
|
||||||
}
|
}
|
||||||
|
|
||||||
void createNewJavaPlugin1() {
|
void createNewJavaPlugin1() {
|
||||||
@ -1298,6 +1302,51 @@ flutter:
|
|||||||
FeatureFlags: () => featureFlags,
|
FeatureFlags: () => featureFlags,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
group('pubspec', () {
|
||||||
|
|
||||||
|
Directory projectDir;
|
||||||
|
Directory tempDir;
|
||||||
|
setUp(() {
|
||||||
|
tempDir = globals.fs.systemTempDirectory.createTempSync('plugin_test.');
|
||||||
|
projectDir = tempDir.childDirectory('flutter_project');
|
||||||
|
});
|
||||||
|
|
||||||
|
tearDown(() {
|
||||||
|
tryToDelete(tempDir);
|
||||||
|
});
|
||||||
|
|
||||||
|
void _createPubspecFile(String yamlString) {
|
||||||
|
projectDir.childFile('pubspec.yaml')..createSync(recursive: true)..writeAsStringSync(yamlString);
|
||||||
|
}
|
||||||
|
|
||||||
|
test('validatePubspecForPlugin works', () async {
|
||||||
|
_createPubspecFile(_pluginYaml);
|
||||||
|
validatePubspecForPlugin(projectDir: projectDir.absolute.path, pluginClass: 'SomePlugin', expectedPlatforms: <String>[
|
||||||
|
'ios', 'macos', 'windows', 'linux', 'android', 'web'
|
||||||
|
], androidIdentifier: 'AndroidPackage', webFileName: 'lib/SomeFile.dart');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('createPlatformsYamlMap should create the correct map', () async {
|
||||||
|
final YamlMap map = Plugin.createPlatformsYamlMap(<String>['ios', 'android', 'linux'], 'PluginClass', 'some.android.package');
|
||||||
|
expect(map['ios'], <String, String> {
|
||||||
|
'pluginClass' : 'PluginClass'
|
||||||
|
});
|
||||||
|
expect(map['android'], <String, String> {
|
||||||
|
'pluginClass' : 'PluginClass',
|
||||||
|
'package': 'some.android.package',
|
||||||
|
});
|
||||||
|
expect(map['linux'], <String, String> {
|
||||||
|
'pluginClass' : 'PluginClass'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('createPlatformsYamlMap should create empty map', () async {
|
||||||
|
final YamlMap map = Plugin.createPlatformsYamlMap(<String>[], null, null);
|
||||||
|
expect(map.isEmpty, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,10 @@
|
|||||||
import 'package:file/file.dart';
|
import 'package:file/file.dart';
|
||||||
import 'package:flutter_tools/src/base/file_system.dart';
|
import 'package:flutter_tools/src/base/file_system.dart';
|
||||||
import 'package:flutter_tools/src/flutter_manifest.dart';
|
import 'package:flutter_tools/src/flutter_manifest.dart';
|
||||||
|
import 'package:meta/meta.dart';
|
||||||
|
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||||
|
import 'package:yaml/yaml.dart';
|
||||||
|
import 'common.dart';
|
||||||
|
|
||||||
/// Writes a schemaData used for validating pubspec.yaml files when parsing
|
/// Writes a schemaData used for validating pubspec.yaml files when parsing
|
||||||
/// asset information.
|
/// asset information.
|
||||||
@ -22,3 +26,22 @@ void writeSchemaFile(FileSystem filesystem, String schemaData) {
|
|||||||
void writeEmptySchemaFile(FileSystem filesystem) {
|
void writeEmptySchemaFile(FileSystem filesystem) {
|
||||||
writeSchemaFile(filesystem, '{}');
|
writeSchemaFile(filesystem, '{}');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if the pubspec.yaml file under the `projectDir` is valid for a plugin project.
|
||||||
|
void validatePubspecForPlugin({@required String projectDir, @required String pluginClass, @required List<String> expectedPlatforms, List<String> unexpectedPlatforms = const <String>[], String androidIdentifier, String webFileName}) {
|
||||||
|
final FlutterManifest manifest = FlutterManifest.createFromPath(projectDir+'/pubspec.yaml', fileSystem: globals.fs, logger: globals.logger);
|
||||||
|
final YamlMap platformsMap = YamlMap.wrap(manifest.supportedPlatforms);
|
||||||
|
for (final String platform in expectedPlatforms) {
|
||||||
|
expect(platformsMap[platform], isNotNull);
|
||||||
|
expect(platformsMap[platform]['pluginClass'], pluginClass);
|
||||||
|
if (platform == 'android') {
|
||||||
|
expect(platformsMap[platform]['package'], androidIdentifier);
|
||||||
|
}
|
||||||
|
if (platform == 'web') {
|
||||||
|
expect(platformsMap[platform]['fileName'], webFileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (final String platform in unexpectedPlatforms) {
|
||||||
|
expect(platformsMap[platform], isNull);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user