Skip to content

Commit

Permalink
Exit tool if a plugin supports the embedding v2 but the app doesn't (f…
Browse files Browse the repository at this point in the history
  • Loading branch information
Emmanuel Garcia authored and jonahwilliams committed Nov 4, 2019
1 parent 97cf355 commit b94c1a4
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 12 deletions.
21 changes: 15 additions & 6 deletions packages/flutter_tools/lib/src/platform_plugins.dart
Original file line number Diff line number Diff line change
Expand Up @@ -64,17 +64,20 @@ class AndroidPlugin extends PluginPlatform {
'name': name,
'package': package,
'class': pluginClass,
'usesEmbedding2': _embeddingVersion == '2',
// Mustache doesn't support complex types.
'supportsEmbeddingV1': _supportedEmbedings.contains('1'),
'supportsEmbeddingV2': _supportedEmbedings.contains('2'),
};
}

String _cachedEmbeddingVersion;
Set<String> _cachedEmbeddingVersion;

/// Returns the version of the Android embedding.
String get _embeddingVersion => _cachedEmbeddingVersion ??= _getEmbeddingVersion();
Set<String> get _supportedEmbedings => _cachedEmbeddingVersion ??= _getSupportedEmbeddings();

String _getEmbeddingVersion() {
Set<String> _getSupportedEmbeddings() {
assert(pluginPath != null);
final Set<String> supportedEmbeddings = <String>{};
final String baseMainPath = fs.path.join(
pluginPath,
'android',
Expand Down Expand Up @@ -113,9 +116,15 @@ class AndroidPlugin extends PluginPlatform {
}
if (mainClassContent
.contains('io.flutter.embedding.engine.plugins.FlutterPlugin')) {
return '2';
supportedEmbeddings.add('2');
} else {
supportedEmbeddings.add('1');
}
return '1';
if (mainClassContent.contains('registerWith(Registrar registrar)') ||
mainClassContent.contains('registerWith(registrar: Registrar)')) {
supportedEmbeddings.add('1');
}
return supportedEmbeddings;
}
}

Expand Down
23 changes: 17 additions & 6 deletions packages/flutter_tools/lib/src/plugins.dart
Original file line number Diff line number Diff line change
Expand Up @@ -338,12 +338,14 @@ public final class GeneratedPluginRegistrant {
ShimPluginRegistry shimPluginRegistry = new ShimPluginRegistry(flutterEngine);
{{/needsShim}}
{{#plugins}}
{{#usesEmbedding2}}
{{#supportsEmbeddingV2}}
flutterEngine.getPlugins().add(new {{package}}.{{class}}());
{{/usesEmbedding2}}
{{^usesEmbedding2}}
{{package}}.{{class}}.registerWith(shimPluginRegistry.registrarFor("{{package}}.{{class}}"));
{{/usesEmbedding2}}
{{/supportsEmbeddingV2}}
{{^supportsEmbeddingV2}}
{{#supportsEmbeddingV1}}
{{package}}.{{class}}.registerWith(shimPluginRegistry.registrarFor("{{package}}.{{class}}"));
{{/supportsEmbeddingV1}}
{{/supportsEmbeddingV2}}
{{/plugins}}
}
}
Expand Down Expand Up @@ -417,14 +419,23 @@ Future<void> _writeAndroidPluginRegistrant(FlutterProject project, List<Plugin>
// If a plugin is using an embedding version older than 2.0 and the app is using 2.0,
// then add shim for the old plugins.
for (Map<String, dynamic> plugin in androidPlugins) {
if (!plugin['usesEmbedding2']) {
if (plugin['supportsEmbeddingV1'] && !plugin['supportsEmbeddingV2']) {
templateContext['needsShim'] = true;
break;
}
}
templateContent = _androidPluginRegistryTemplateNewEmbedding;
break;
case '1':
for (Map<String, dynamic> plugin in androidPlugins) {
if (!plugin['supportsEmbeddingV1'] && plugin['supportsEmbeddingV2']) {
throwToolExit(
'The plugin `${plugin['name']}` requires your app to be migrated to '
'the Android embedding v2. Follow the steps on https://flutter.dev/go/android-project-migration '
'and re-run this command.'
);
}
}
templateContent = _androidPluginRegistryTemplateOldEmbedding;
break;
default:
Expand Down
105 changes: 105 additions & 0 deletions packages/flutter_tools/test/general.shard/plugins_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,111 @@ plugin3:${pluginUsingOldEmbeddingDir.childDirectory('lib').uri.toString()}
XcodeProjectInterpreter: () => xcodeProjectInterpreter,
});

testUsingContext('exits the tool if an app uses the v1 embedding and a plugin only supports the v2 embedding', () async {
when(flutterProject.isModule).thenReturn(false);

final File androidManifest = flutterProject.directory
.childDirectory('android')
.childFile('AndroidManifest.xml')
..createSync(recursive: true)
..writeAsStringSync(kAndroidManifestUsingOldEmbedding);
when(androidProject.appManifestFile).thenReturn(androidManifest);

final Directory pluginUsingJavaAndNewEmbeddingDir =
fs.systemTempDirectory.createTempSync('flutter_plugin_using_java_and_new_embedding_dir.');
pluginUsingJavaAndNewEmbeddingDir
.childFile('pubspec.yaml')
.writeAsStringSync('''
flutter:
plugin:
androidPackage: plugin1
pluginClass: UseNewEmbedding
''');
pluginUsingJavaAndNewEmbeddingDir
.childDirectory('android')
.childDirectory('src')
.childDirectory('main')
.childDirectory('java')
.childDirectory('plugin1')
.childFile('UseNewEmbedding.java')
..createSync(recursive: true)
..writeAsStringSync('import io.flutter.embedding.engine.plugins.FlutterPlugin;');

flutterProject.directory
.childFile('.packages')
.writeAsStringSync('''
plugin1:${pluginUsingJavaAndNewEmbeddingDir.childDirectory('lib').uri.toString()}
''');
await expectLater(
() async {
await injectPlugins(flutterProject);
},
throwsToolExit(
message: 'The plugin `plugin1` requires your app to be migrated to the Android embedding v2. '
'Follow the steps on https://flutter.dev/go/android-project-migration and re-run this command.'
),
);
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(),
FeatureFlags: () => featureFlags,
XcodeProjectInterpreter: () => xcodeProjectInterpreter,
});

testUsingContext('allows app use a plugin that supports v1 and v2 embedding', () async {
when(flutterProject.isModule).thenReturn(false);

final File androidManifest = flutterProject.directory
.childDirectory('android')
.childFile('AndroidManifest.xml')
..createSync(recursive: true)
..writeAsStringSync(kAndroidManifestUsingOldEmbedding);
when(androidProject.appManifestFile).thenReturn(androidManifest);

final Directory pluginUsingJavaAndNewEmbeddingDir =
fs.systemTempDirectory.createTempSync('flutter_plugin_using_java_and_new_embedding_dir.');
pluginUsingJavaAndNewEmbeddingDir
.childFile('pubspec.yaml')
.writeAsStringSync('''
flutter:
plugin:
androidPackage: plugin1
pluginClass: UseNewEmbedding
''');
pluginUsingJavaAndNewEmbeddingDir
.childDirectory('android')
.childDirectory('src')
.childDirectory('main')
.childDirectory('java')
.childDirectory('plugin1')
.childFile('UseNewEmbedding.java')
..createSync(recursive: true)
..writeAsStringSync(
'import io.flutter.embedding.engine.plugins.FlutterPlugin;'
'registerWith(Registrar registrar)'
);

flutterProject.directory
.childFile('.packages')
.writeAsStringSync('''
plugin1:${pluginUsingJavaAndNewEmbeddingDir.childDirectory('lib').uri.toString()}
''');
await injectPlugins(flutterProject);

final File registrant = flutterProject.directory
.childDirectory(fs.path.join('android', 'app', 'src', 'main', 'java', 'io', 'flutter', 'plugins'))
.childFile('GeneratedPluginRegistrant.java');

expect(registrant.existsSync(), isTrue);
expect(registrant.readAsStringSync(), contains('package io.flutter.plugins'));
expect(registrant.readAsStringSync(), contains('class GeneratedPluginRegistrant'));
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(),
FeatureFlags: () => featureFlags,
XcodeProjectInterpreter: () => xcodeProjectInterpreter,
});

testUsingContext('Registrant doesn\'t use new embedding if app doesn\'t use new embedding', () async {
when(flutterProject.isModule).thenReturn(false);

Expand Down

0 comments on commit b94c1a4

Please sign in to comment.