mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Generate projects using the new Android embedding (#41666)
* Generate projects using the new Android embedding * Add comment about usesNewEmbedding:true * Feedback * Rework way to detect new embedding in new apps
This commit is contained in:
parent
890b939401
commit
5961bcc505
@ -940,7 +940,6 @@ Future<void> _buildGradleProjectV2(
|
||||
/// Returns [true] if the current app uses AndroidX.
|
||||
// TODO(egarciad): https://github.com/flutter/flutter/issues/40800
|
||||
// Remove `FlutterManifest.usesAndroidX` and provide a unified `AndroidProject.usesAndroidX`.
|
||||
@visibleForTesting
|
||||
bool isAppUsingAndroidX(Directory androidDirectory) {
|
||||
final File properties = androidDirectory.childFile('gradle.properties');
|
||||
if (!properties.existsSync()) {
|
||||
|
@ -623,6 +623,7 @@ To edit platform code in an IDE see https://flutter.dev/developing-packages/#edi
|
||||
'description': projectDescription,
|
||||
'dartSdk': '$flutterRoot/bin/cache/dart-sdk',
|
||||
'androidX': androidX,
|
||||
'useNewAndroidEmbedding': featureFlags.isNewAndroidEmbeddingEnabled,
|
||||
'androidMinApiLevel': android.minApiLevel,
|
||||
'androidSdkVersion': android_sdk.minimumAndroidSdkVersion,
|
||||
'androidFlutterJar': '$flutterRoot/bin/cache/artifacts/engine/android-arm/flutter.jar',
|
||||
|
@ -36,6 +36,9 @@ class FeatureFlags {
|
||||
/// Whether flutter desktop for Windows is enabled.
|
||||
bool get isWindowsEnabled => _isEnabled(flutterWindowsDesktopFeature);
|
||||
|
||||
/// Whether the new Android embedding is enabled.
|
||||
bool get isNewAndroidEmbeddingEnabled => _isEnabled(flutterNewAndroidEmbeddingFeature);
|
||||
|
||||
// Calculate whether a particular feature is enabled for the current channel.
|
||||
static bool _isEnabled(Feature feature) {
|
||||
final String currentChannel = FlutterVersion.instance.channel;
|
||||
@ -66,6 +69,7 @@ const List<Feature> allFeatures = <Feature>[
|
||||
flutterMacOSDesktopFeature,
|
||||
flutterWindowsDesktopFeature,
|
||||
flutterBuildPluginAsAarFeature,
|
||||
flutterNewAndroidEmbeddingFeature,
|
||||
];
|
||||
|
||||
/// The [Feature] for flutter web.
|
||||
@ -126,6 +130,16 @@ const Feature flutterBuildPluginAsAarFeature = Feature(
|
||||
),
|
||||
);
|
||||
|
||||
/// The [Feature] for generating projects using the new Android embedding.
|
||||
const Feature flutterNewAndroidEmbeddingFeature = Feature(
|
||||
name: 'flutter create generates projects using the new Android embedding',
|
||||
configSetting: 'enable-new-android-embedding',
|
||||
master: FeatureChannelSetting(
|
||||
available: true,
|
||||
enabledByDefault: false,
|
||||
),
|
||||
);
|
||||
|
||||
/// A [Feature] is a process for conditionally enabling tool features.
|
||||
///
|
||||
/// All settings are optional, and if not provided will generally default to
|
||||
|
@ -5,6 +5,10 @@
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:yaml/yaml.dart';
|
||||
|
||||
import 'base/common.dart';
|
||||
import 'base/file_system.dart';
|
||||
import 'features.dart';
|
||||
|
||||
/// Marker interface for all platform specific plugin config impls.
|
||||
abstract class PluginPlatform {
|
||||
const PluginPlatform();
|
||||
@ -17,18 +21,20 @@ abstract class PluginPlatform {
|
||||
/// 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 {
|
||||
const AndroidPlugin({
|
||||
AndroidPlugin({
|
||||
@required this.name,
|
||||
@required this.package,
|
||||
@required this.pluginClass,
|
||||
@required this.pluginPath,
|
||||
});
|
||||
|
||||
factory AndroidPlugin.fromYaml(String name, YamlMap yaml) {
|
||||
factory AndroidPlugin.fromYaml(String name, YamlMap yaml, String pluginPath) {
|
||||
assert(validate(yaml));
|
||||
return AndroidPlugin(
|
||||
name: name,
|
||||
package: yaml['package'],
|
||||
pluginClass: yaml['pluginClass'],
|
||||
pluginPath: pluginPath,
|
||||
);
|
||||
}
|
||||
|
||||
@ -41,18 +47,80 @@ class AndroidPlugin extends PluginPlatform {
|
||||
|
||||
static const String kConfigKey = 'android';
|
||||
|
||||
/// The plugin name defined in pubspec.yaml.
|
||||
final String name;
|
||||
|
||||
/// The plugin package name defined in pubspec.yaml.
|
||||
final String package;
|
||||
|
||||
/// The plugin main class defined in pubspec.yaml.
|
||||
final String pluginClass;
|
||||
|
||||
/// The absolute path to the plugin in the pub cache.
|
||||
final String pluginPath;
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toMap() {
|
||||
return <String, dynamic>{
|
||||
'name': name,
|
||||
'package': package,
|
||||
'class': pluginClass,
|
||||
'usesEmbedding2': _embeddingVersion == '2',
|
||||
};
|
||||
}
|
||||
|
||||
String _cachedEmbeddingVersion;
|
||||
|
||||
/// Returns the version of the Android embedding.
|
||||
String get _embeddingVersion => _cachedEmbeddingVersion ??= _getEmbeddingVersion();
|
||||
|
||||
String _getEmbeddingVersion() {
|
||||
if (!featureFlags.isNewAndroidEmbeddingEnabled) {
|
||||
return '1';
|
||||
}
|
||||
assert(pluginPath != null);
|
||||
final String baseMainPath = fs.path.join(
|
||||
pluginPath,
|
||||
'android',
|
||||
'src',
|
||||
'main',
|
||||
);
|
||||
File mainPluginClass = fs.file(
|
||||
fs.path.join(
|
||||
baseMainPath,
|
||||
'java',
|
||||
package.replaceAll('.', fs.path.separator),
|
||||
'$pluginClass.java',
|
||||
)
|
||||
);
|
||||
// Check if the plugin is implemented in Kotlin since the plugin's pubspec.yaml
|
||||
// doesn't include this information.
|
||||
if (!mainPluginClass.existsSync()) {
|
||||
mainPluginClass = fs.file(
|
||||
fs.path.join(
|
||||
baseMainPath,
|
||||
'kotlin',
|
||||
package.replaceAll('.', fs.path.separator),
|
||||
'$pluginClass.kt',
|
||||
)
|
||||
);
|
||||
}
|
||||
assert(mainPluginClass.existsSync());
|
||||
String mainClassContent;
|
||||
try {
|
||||
mainClassContent = mainPluginClass.readAsStringSync();
|
||||
} on FileSystemException {
|
||||
throwToolExit(
|
||||
'Couldn\'t read file $mainPluginClass even though it exists. '
|
||||
'Please verify that this file has read permission and try again.'
|
||||
);
|
||||
}
|
||||
if (mainClassContent
|
||||
.contains('io.flutter.embedding.engine.plugins.FlutterPlugin')) {
|
||||
return '2';
|
||||
}
|
||||
return '1';
|
||||
}
|
||||
}
|
||||
|
||||
/// Contains the parameters to template an iOS plugin.
|
||||
|
@ -5,8 +5,10 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:mustache/mustache.dart' as mustache;
|
||||
import 'package:xml/xml.dart' as xml;
|
||||
import 'package:yaml/yaml.dart';
|
||||
|
||||
import 'android/gradle.dart';
|
||||
import 'base/common.dart';
|
||||
import 'base/file_system.dart';
|
||||
import 'dart/package_map.dart';
|
||||
@ -63,9 +65,8 @@ class Plugin {
|
||||
}
|
||||
if (pluginYaml != null && pluginYaml['platforms'] != null) {
|
||||
return Plugin._fromMultiPlatformYaml(name, path, pluginYaml);
|
||||
} else {
|
||||
return Plugin._fromLegacyYaml(name, path, pluginYaml); // ignore: deprecated_member_use_from_same_package
|
||||
}
|
||||
return Plugin._fromLegacyYaml(name, path, pluginYaml); // ignore: deprecated_member_use_from_same_package
|
||||
}
|
||||
|
||||
factory Plugin._fromMultiPlatformYaml(String name, String path, dynamic pluginYaml) {
|
||||
@ -79,8 +80,11 @@ class Plugin {
|
||||
final Map<String, PluginPlatform> platforms = <String, PluginPlatform>{};
|
||||
|
||||
if (platformsYaml[AndroidPlugin.kConfigKey] != null) {
|
||||
platforms[AndroidPlugin.kConfigKey] =
|
||||
AndroidPlugin.fromYaml(name, platformsYaml[AndroidPlugin.kConfigKey]);
|
||||
platforms[AndroidPlugin.kConfigKey] = AndroidPlugin.fromYaml(
|
||||
name,
|
||||
platformsYaml[AndroidPlugin.kConfigKey],
|
||||
path,
|
||||
);
|
||||
}
|
||||
|
||||
if (platformsYaml[IOSPlugin.kConfigKey] != null) {
|
||||
@ -122,12 +126,12 @@ class Plugin {
|
||||
if (pluginYaml != null && pluginClass != null) {
|
||||
final String androidPackage = pluginYaml['androidPackage'];
|
||||
if (androidPackage != null) {
|
||||
platforms[AndroidPlugin.kConfigKey] =
|
||||
AndroidPlugin(
|
||||
name: name,
|
||||
package: pluginYaml['androidPackage'],
|
||||
pluginClass: pluginClass,
|
||||
);
|
||||
platforms[AndroidPlugin.kConfigKey] = AndroidPlugin(
|
||||
name: name,
|
||||
package: pluginYaml['androidPackage'],
|
||||
pluginClass: pluginClass,
|
||||
pluginPath: path,
|
||||
);
|
||||
}
|
||||
|
||||
final String iosPrefix = pluginYaml['iosPrefix'] ?? '';
|
||||
@ -221,14 +225,21 @@ Plugin _pluginFromPubspec(String name, Uri packageRoot) {
|
||||
}
|
||||
final String packageRootPath = fs.path.fromUri(packageRoot);
|
||||
printTrace('Found plugin $name at $packageRootPath');
|
||||
return Plugin.fromYaml(name, packageRootPath, flutterConfig['plugin']);
|
||||
return Plugin.fromYaml(
|
||||
name,
|
||||
packageRootPath,
|
||||
flutterConfig['plugin'],
|
||||
);
|
||||
}
|
||||
|
||||
List<Plugin> findPlugins(FlutterProject project) {
|
||||
final List<Plugin> plugins = <Plugin>[];
|
||||
Map<String, Uri> packages;
|
||||
try {
|
||||
final String packagesFile = fs.path.join(project.directory.path, PackageMap.globalPackagesPath);
|
||||
final String packagesFile = fs.path.join(
|
||||
project.directory.path,
|
||||
PackageMap.globalPackagesPath,
|
||||
);
|
||||
packages = PackageMap(packagesFile).map;
|
||||
} on FormatException catch (e) {
|
||||
printTrace('Invalid .packages file: $e');
|
||||
@ -269,7 +280,7 @@ String _readFlutterPluginsList(FlutterProject project) {
|
||||
: null;
|
||||
}
|
||||
|
||||
const String _androidPluginRegistryTemplate = '''package io.flutter.plugins;
|
||||
const String _androidPluginRegistryTemplateOldEmbedding = '''package io.flutter.plugins;
|
||||
|
||||
import io.flutter.plugin.common.PluginRegistry;
|
||||
{{#plugins}}
|
||||
@ -300,6 +311,41 @@ public final class GeneratedPluginRegistrant {
|
||||
}
|
||||
''';
|
||||
|
||||
const String _androidPluginRegistryTemplateNewEmbedding = '''package dev.flutter.plugins;
|
||||
|
||||
{{#androidX}}
|
||||
import androidx.annotation.NonNull;
|
||||
{{/androidX}}
|
||||
{{^androidX}}
|
||||
import android.support.annotation.NonNull;
|
||||
{{/androidX}}
|
||||
import io.flutter.embedding.engine.FlutterEngine;
|
||||
{{#needsShim}}
|
||||
import io.flutter.embedding.engine.plugins.shim.ShimPluginRegistry;
|
||||
{{/needsShim}}
|
||||
|
||||
/**
|
||||
* Generated file. Do not edit.
|
||||
* This file is generated by the Flutter tool based on the
|
||||
* plugins that support the Android platform.
|
||||
*/
|
||||
public final class GeneratedPluginRegistrant {
|
||||
public static void registerWith(@NonNull FlutterEngine flutterEngine) {
|
||||
{{#needsShim}}
|
||||
ShimPluginRegistry shimPluginRegistry = new ShimPluginRegistry(flutterEngine);
|
||||
{{/needsShim}}
|
||||
{{#plugins}}
|
||||
{{#usesEmbedding2}}
|
||||
flutterEngine.getPlugins().add(new {{package}}.{{class}}());
|
||||
{{/usesEmbedding2}}
|
||||
{{^usesEmbedding2}}
|
||||
{{package}}.{{class}}.registerWith(shimPluginRegistry.registrarFor("{{package}}.{{class}}"));
|
||||
{{/usesEmbedding2}}
|
||||
{{/plugins}}
|
||||
}
|
||||
}
|
||||
''';
|
||||
|
||||
List<Map<String, dynamic>> _extractPlatformMaps(List<Plugin> plugins, String type) {
|
||||
final List<Map<String, dynamic>> pluginConfigs = <Map<String, dynamic>>[];
|
||||
for (Plugin p in plugins) {
|
||||
@ -311,26 +357,92 @@ List<Map<String, dynamic>> _extractPlatformMaps(List<Plugin> plugins, String typ
|
||||
return pluginConfigs;
|
||||
}
|
||||
|
||||
Future<void> _writeAndroidPluginRegistrant(FlutterProject project, List<Plugin> plugins) async {
|
||||
final List<Map<String, dynamic>> androidPlugins = _extractPlatformMaps(plugins, AndroidPlugin.kConfigKey);
|
||||
final Map<String, dynamic> context = <String, dynamic>{
|
||||
'plugins': androidPlugins,
|
||||
};
|
||||
/// Returns the version of the Android embedding that the current
|
||||
/// [project] is using.
|
||||
String _getAndroidEmbeddingVersion(FlutterProject project) {
|
||||
if (!featureFlags.isNewAndroidEmbeddingEnabled) {
|
||||
return '1';
|
||||
}
|
||||
assert(project.android != null);
|
||||
final File androidManifest = project.android.appManifestFile;
|
||||
assert(androidManifest.existsSync());
|
||||
xml.XmlDocument document;
|
||||
try {
|
||||
document = xml.parse(androidManifest.readAsStringSync());
|
||||
} on xml.XmlParserException {
|
||||
throwToolExit('Error parsing ${project.android.appManifestFile} '
|
||||
'Please ensure that the android manifest is a valid XML document and try again.');
|
||||
} on FileSystemException {
|
||||
throwToolExit('Error reading ${project.android.appManifestFile} even though it exists. '
|
||||
'Please ensure that you have read permission to this file and try again.');
|
||||
}
|
||||
for (xml.XmlElement metaData in document.findAllElements('meta-data')) {
|
||||
final String name = metaData.getAttribute('android:name');
|
||||
if (name == 'flutterEmbedding') {
|
||||
return metaData.getAttribute('android:value');
|
||||
}
|
||||
}
|
||||
return '1';
|
||||
}
|
||||
|
||||
Future<void> _writeAndroidPluginRegistrant(FlutterProject project, List<Plugin> plugins) async {
|
||||
final List<Map<String, dynamic>> androidPlugins =
|
||||
_extractPlatformMaps(plugins, AndroidPlugin.kConfigKey);
|
||||
|
||||
final Map<String, dynamic> templateContext = <String, dynamic>{
|
||||
'plugins': androidPlugins,
|
||||
'androidX': isAppUsingAndroidX(project.android.hostAppGradleRoot),
|
||||
};
|
||||
final String javaSourcePath = fs.path.join(
|
||||
project.android.pluginRegistrantHost.path,
|
||||
'src',
|
||||
'main',
|
||||
'java',
|
||||
);
|
||||
final String registryPath = fs.path.join(
|
||||
javaSourcePath,
|
||||
'io',
|
||||
'flutter',
|
||||
'plugins',
|
||||
'GeneratedPluginRegistrant.java',
|
||||
|
||||
String registryPath;
|
||||
String templateContent;
|
||||
|
||||
final String appEmbeddingVersion = _getAndroidEmbeddingVersion(project);
|
||||
switch (appEmbeddingVersion) {
|
||||
case '2':
|
||||
templateContext['needsShim'] = false;
|
||||
// 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']) {
|
||||
templateContext['needsShim'] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
registryPath = fs.path.join(
|
||||
javaSourcePath,
|
||||
'dev',
|
||||
'flutter',
|
||||
'plugins',
|
||||
'GeneratedPluginRegistrant.java',
|
||||
);
|
||||
templateContent = _androidPluginRegistryTemplateNewEmbedding;
|
||||
break;
|
||||
case '1':
|
||||
registryPath = fs.path.join(
|
||||
javaSourcePath,
|
||||
'io',
|
||||
'flutter',
|
||||
'plugins',
|
||||
'GeneratedPluginRegistrant.java',
|
||||
);
|
||||
templateContent = _androidPluginRegistryTemplateOldEmbedding;
|
||||
break;
|
||||
default:
|
||||
throwToolExit('Unsupported Android embedding');
|
||||
}
|
||||
printTrace('Generating $registryPath');
|
||||
_renderTemplateToFile(
|
||||
templateContent,
|
||||
templateContext,
|
||||
registryPath,
|
||||
);
|
||||
_renderTemplateToFile(_androidPluginRegistryTemplate, context, registryPath);
|
||||
}
|
||||
|
||||
const String _objcPluginRegistryHeaderTemplate = '''//
|
||||
|
@ -608,7 +608,11 @@ class AndroidProject {
|
||||
|
||||
void _regenerateLibrary() {
|
||||
_deleteIfExistsSync(ephemeralDirectory);
|
||||
_overwriteFromTemplate(fs.path.join('module', 'android', 'library'), ephemeralDirectory);
|
||||
_overwriteFromTemplate(fs.path.join(
|
||||
'module',
|
||||
'android',
|
||||
featureFlags.isNewAndroidEmbeddingEnabled ? 'library_new_embedding' : 'library',
|
||||
), ephemeralDirectory);
|
||||
_overwriteFromTemplate(fs.path.join('module', 'android', 'gradle'), ephemeralDirectory);
|
||||
gradle.injectGradleWrapperIfNeeded(ephemeralDirectory);
|
||||
}
|
||||
@ -621,6 +625,7 @@ class AndroidProject {
|
||||
'projectName': parent.manifest.appName,
|
||||
'androidIdentifier': parent.manifest.androidPackage,
|
||||
'androidX': usesAndroidX,
|
||||
'useNewAndroidEmbedding': featureFlags.isNewAndroidEmbeddingEnabled,
|
||||
},
|
||||
printStatusWhenWriting: false,
|
||||
overwriteExisting: true,
|
||||
|
@ -1,5 +1,24 @@
|
||||
package {{androidIdentifier}};
|
||||
|
||||
{{#useNewAndroidEmbedding}}
|
||||
{{#androidX}}
|
||||
import androidx.annotation.NonNull;
|
||||
{{/androidX}}
|
||||
{{^androidX}}
|
||||
import android.support.annotation.NonNull;
|
||||
{{/androidX}}
|
||||
import dev.flutter.plugins.GeneratedPluginRegistrant;
|
||||
import io.flutter.embedding.android.FlutterActivity;
|
||||
import io.flutter.embedding.engine.FlutterEngine;
|
||||
|
||||
public class MainActivity extends FlutterActivity {
|
||||
@Override
|
||||
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
|
||||
GeneratedPluginRegistrant.registerWith(flutterEngine);
|
||||
}
|
||||
}
|
||||
{{/useNewAndroidEmbedding}}
|
||||
{{^useNewAndroidEmbedding}}
|
||||
import android.os.Bundle;
|
||||
import io.flutter.app.FlutterActivity;
|
||||
import io.flutter.plugins.GeneratedPluginRegistrant;
|
||||
@ -11,3 +30,4 @@ public class MainActivity extends FlutterActivity {
|
||||
GeneratedPluginRegistrant.registerWith(this);
|
||||
}
|
||||
}
|
||||
{{/useNewAndroidEmbedding}}
|
||||
|
@ -1,7 +1,24 @@
|
||||
package {{androidIdentifier}}
|
||||
|
||||
import android.os.Bundle
|
||||
{{#useNewAndroidEmbedding}}
|
||||
{{#androidX}}
|
||||
import androidx.annotation.NonNull;
|
||||
{{/androidX}}
|
||||
{{^androidX}}
|
||||
import android.support.annotation.NonNull;
|
||||
{{/androidX}}
|
||||
import dev.flutter.plugins.GeneratedPluginRegistrant
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
import io.flutter.embedding.engine.FlutterEngine
|
||||
|
||||
class MainActivity: FlutterActivity() {
|
||||
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
|
||||
GeneratedPluginRegistrant.registerWith(flutterEngine);
|
||||
}
|
||||
}
|
||||
{{/useNewAndroidEmbedding}}
|
||||
{{^useNewAndroidEmbedding}}
|
||||
import android.os.Bundle
|
||||
import io.flutter.app.FlutterActivity
|
||||
import io.flutter.plugins.GeneratedPluginRegistrant
|
||||
|
||||
@ -11,3 +28,4 @@ class MainActivity: FlutterActivity() {
|
||||
GeneratedPluginRegistrant.registerWith(this)
|
||||
}
|
||||
}
|
||||
{{/useNewAndroidEmbedding}}
|
||||
|
@ -1,6 +1,5 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="{{androidIdentifier}}">
|
||||
|
||||
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
|
||||
calls FlutterMain.startInitialization(this); in its onCreate method.
|
||||
In most cases you can leave this as-is, but you if you want to provide
|
||||
@ -29,5 +28,12 @@
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
{{#useNewAndroidEmbedding}}
|
||||
<!-- Don't delete the meta-data below.
|
||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2" />
|
||||
{{/useNewAndroidEmbedding}}
|
||||
</application>
|
||||
</manifest>
|
||||
|
@ -36,5 +36,12 @@
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
{{#useNewAndroidEmbedding}}
|
||||
<!-- Don't delete the meta-data below.
|
||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2" />
|
||||
{{/useNewAndroidEmbedding}}
|
||||
</application>
|
||||
</manifest>
|
||||
|
@ -1,6 +1,25 @@
|
||||
package {{androidIdentifier}}.host;
|
||||
|
||||
import android.os.Bundle;
|
||||
{{#useNewAndroidEmbedding}}
|
||||
{{#androidX}}
|
||||
import androidx.annotation.NonNull;
|
||||
{{/androidX}}
|
||||
{{^androidX}}
|
||||
import android.support.annotation.NonNull;
|
||||
{{/androidX}}
|
||||
import dev.flutter.plugins.GeneratedPluginRegistrant;
|
||||
import io.flutter.embedding.android.FlutterActivity;
|
||||
import io.flutter.embedding.engine.FlutterEngine;
|
||||
|
||||
public class MainActivity extends FlutterActivity {
|
||||
@Override
|
||||
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
|
||||
GeneratedPluginRegistrant.registerWith(flutterEngine);
|
||||
}
|
||||
}
|
||||
{{/useNewAndroidEmbedding}}
|
||||
{{^useNewAndroidEmbedding}}
|
||||
import io.flutter.app.FlutterActivity;
|
||||
import io.flutter.plugins.GeneratedPluginRegistrant;
|
||||
|
||||
@ -11,3 +30,4 @@ public class MainActivity extends FlutterActivity {
|
||||
GeneratedPluginRegistrant.registerWith(this);
|
||||
}
|
||||
}
|
||||
{{/useNewAndroidEmbedding}}
|
||||
|
@ -0,0 +1,55 @@
|
||||
// Generated file. Do not edit.
|
||||
|
||||
def localProperties = new Properties()
|
||||
def localPropertiesFile = new File(buildscript.sourceFile.parentFile.parentFile, 'local.properties')
|
||||
if (localPropertiesFile.exists()) {
|
||||
localPropertiesFile.withReader('UTF-8') { reader ->
|
||||
localProperties.load(reader)
|
||||
}
|
||||
}
|
||||
|
||||
def flutterRoot = localProperties.getProperty('flutter.sdk')
|
||||
if (flutterRoot == null) {
|
||||
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
|
||||
}
|
||||
|
||||
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
|
||||
if (flutterVersionCode == null) {
|
||||
flutterVersionCode = '1'
|
||||
}
|
||||
|
||||
def flutterVersionName = localProperties.getProperty('flutter.versionName')
|
||||
if (flutterVersionName == null) {
|
||||
flutterVersionName = '1.0'
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
||||
|
||||
group '{{androidIdentifier}}'
|
||||
version '1.0'
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 28
|
||||
versionCode flutterVersionCode.toInteger()
|
||||
versionName flutterVersionName
|
||||
{{#androidX}}
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
{{/androidX}}
|
||||
{{^androidX}}
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
{{/androidX}}
|
||||
}
|
||||
}
|
||||
|
||||
flutter {
|
||||
source '../..'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation 'junit:junit:4.12'
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module external.linked.project.id=":flutter" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/../../.." external.system.id="GRADLE" type="JAVA_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="android-gradle" name="Android-Gradle">
|
||||
<configuration>
|
||||
<option name="GRADLE_PROJECT_PATH" value=":flutter" />
|
||||
</configuration>
|
||||
</facet>
|
||||
<facet type="android" name="Android">
|
||||
<configuration>
|
||||
<option name="ALLOW_USER_CONFIGURATION" value="false" />
|
||||
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
|
||||
<output url="file://$MODULE_DIR$/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes" />
|
||||
<output-test url="file://$MODULE_DIR$/build/intermediates/javac/debugUnitTest/compileDebugUnitTestJavaWithJavac/classes" />
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Android API 28 Platform" jdkType="Android SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
@ -0,0 +1,16 @@
|
||||
<!-- Generated file. Do not edit. -->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="{{androidIdentifier}}"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<application tools:node="merge">
|
||||
<meta-data
|
||||
android:name="flutterProjectType"
|
||||
android:value="module" />
|
||||
<!-- Don't delete the meta-data below.
|
||||
It is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2" />
|
||||
</application>
|
||||
</manifest>
|
@ -0,0 +1,48 @@
|
||||
// Generated file. Do not edit.
|
||||
|
||||
def scriptFile = getClass().protectionDomain.codeSource.location.toURI()
|
||||
def flutterProjectRoot = new File(scriptFile).parentFile.parentFile
|
||||
|
||||
gradle.include ':flutter'
|
||||
gradle.project(':flutter').projectDir = new File(flutterProjectRoot, '.android/Flutter')
|
||||
|
||||
if (System.getProperty('build-plugins-as-aars') != 'true') {
|
||||
def plugins = new Properties()
|
||||
def pluginsFile = new File(flutterProjectRoot, '.flutter-plugins')
|
||||
if (pluginsFile.exists()) {
|
||||
pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
|
||||
}
|
||||
|
||||
plugins.each { name, path ->
|
||||
def pluginDirectory = flutterProjectRoot.toPath().resolve(path).resolve('android').toFile()
|
||||
gradle.include ":$name"
|
||||
gradle.project(":$name").projectDir = pluginDirectory
|
||||
}
|
||||
}
|
||||
gradle.getGradle().projectsLoaded { g ->
|
||||
g.rootProject.beforeEvaluate { p ->
|
||||
_mainModuleName = binding.variables['mainModuleName']
|
||||
if (_mainModuleName != null && !_mainModuleName.empty) {
|
||||
p.ext.mainModuleName = _mainModuleName
|
||||
}
|
||||
def subprojects = []
|
||||
def flutterProject
|
||||
p.subprojects { sp ->
|
||||
if (sp.name == 'flutter') {
|
||||
flutterProject = sp
|
||||
} else {
|
||||
subprojects.add(sp)
|
||||
}
|
||||
}
|
||||
assert flutterProject != null
|
||||
flutterProject.ext.hostProjects = subprojects
|
||||
flutterProject.ext.pluginBuildDir = new File(flutterProjectRoot, 'build/host')
|
||||
}
|
||||
g.rootProject.afterEvaluate { p ->
|
||||
p.subprojects { sp ->
|
||||
if (sp.name != 'flutter') {
|
||||
sp.evaluationDependsOn(':flutter')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
// Generated file. Do not edit.
|
||||
|
||||
rootProject.name = 'android_generated'
|
||||
setBinding(new Binding([gradle: this]))
|
||||
evaluate(new File(settingsDir, 'include_flutter.groovy'))
|
@ -1,5 +1,37 @@
|
||||
package {{androidIdentifier}};
|
||||
|
||||
{{#useNewAndroidEmbedding}}
|
||||
{{#androidX}}
|
||||
import androidx.annotation.NonNull;
|
||||
{{/androidX}}
|
||||
{{^androidX}}
|
||||
import android.support.annotation.NonNull;
|
||||
{{/androidX}}
|
||||
import io.flutter.embedding.engine.plugins.FlutterPlugin;
|
||||
import io.flutter.plugin.common.MethodCall;
|
||||
import io.flutter.plugin.common.MethodChannel;
|
||||
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
|
||||
import io.flutter.plugin.common.MethodChannel.Result;
|
||||
|
||||
/** {{pluginClass}} */
|
||||
public class {{pluginClass}} implements FlutterPlugin, MethodCallHandler {
|
||||
@Override
|
||||
public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
|
||||
final MethodChannel channel = new MethodChannel(flutterPluginBinding.getFlutterEngine().getDartExecutor(), "{{projectName}}");
|
||||
channel.setMethodCallHandler(new {{pluginClass}}());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
|
||||
if (call.method.equals("getPlatformVersion")) {
|
||||
result.success("Android " + android.os.Build.VERSION.RELEASE);
|
||||
} else {
|
||||
result.notImplemented();
|
||||
}
|
||||
}
|
||||
}
|
||||
{{/useNewAndroidEmbedding}}
|
||||
{{^useNewAndroidEmbedding}}
|
||||
import io.flutter.plugin.common.MethodCall;
|
||||
import io.flutter.plugin.common.MethodChannel;
|
||||
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
|
||||
@ -23,3 +55,4 @@ public class {{pluginClass}} implements MethodCallHandler {
|
||||
}
|
||||
}
|
||||
}
|
||||
{{/useNewAndroidEmbedding}}
|
||||
|
@ -1,5 +1,35 @@
|
||||
package {{androidIdentifier}}
|
||||
|
||||
{{#useNewAndroidEmbedding}}
|
||||
{{#androidX}}
|
||||
import androidx.annotation.NonNull;
|
||||
{{/androidX}}
|
||||
{{^androidX}}
|
||||
import android.support.annotation.NonNull;
|
||||
{{/androidX}}
|
||||
import io.flutter.embedding.engine.plugins.FlutterPlugin
|
||||
import io.flutter.plugin.common.MethodCall
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
|
||||
import io.flutter.plugin.common.MethodChannel.Result
|
||||
|
||||
/** {{pluginClass}} */
|
||||
public class {{pluginClass}}: FlutterPlugin, MethodCallHandler {
|
||||
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPluginBinding) {
|
||||
val channel = MethodChannel(flutterPluginBinding.getFlutterEngine().getDartExecutor(), "{{projectName}}")
|
||||
channel.setMethodCallHandler({{pluginClass}}());
|
||||
}
|
||||
|
||||
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
|
||||
if (call.method == "getPlatformVersion") {
|
||||
result.success("Android ${android.os.Build.VERSION.RELEASE}")
|
||||
} else {
|
||||
result.notImplemented()
|
||||
}
|
||||
}
|
||||
}
|
||||
{{/useNewAndroidEmbedding}}
|
||||
{{^useNewAndroidEmbedding}}
|
||||
import io.flutter.plugin.common.MethodCall
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
|
||||
@ -23,3 +53,4 @@ class {{pluginClass}}: MethodCallHandler {
|
||||
}
|
||||
}
|
||||
}
|
||||
{{/useNewAndroidEmbedding}}
|
||||
|
@ -5,22 +5,22 @@
|
||||
import 'package:file/file.dart';
|
||||
import 'package:file/memory.dart';
|
||||
import 'package:flutter_tools/src/dart/package_map.dart';
|
||||
import 'package:flutter_tools/src/features.dart';
|
||||
import 'package:flutter_tools/src/ios/xcodeproj.dart';
|
||||
import 'package:flutter_tools/src/plugins.dart';
|
||||
import 'package:flutter_tools/src/project.dart';
|
||||
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
||||
import '../src/common.dart';
|
||||
import '../src/context.dart';
|
||||
|
||||
class MockFlutterProject extends Mock implements FlutterProject {}
|
||||
class MockIosProject extends Mock implements IosProject {}
|
||||
class MockMacOSProject extends Mock implements MacOSProject {}
|
||||
|
||||
void main() {
|
||||
FileSystem fs;
|
||||
MockFlutterProject flutterProject;
|
||||
MockIosProject iosProject;
|
||||
MockMacOSProject macosProject;
|
||||
MockAndroidProject androidProject;
|
||||
File packagesFile;
|
||||
Directory dummyPackageDirectory;
|
||||
|
||||
@ -33,10 +33,17 @@ void main() {
|
||||
when(flutterProject.flutterPluginsFile).thenReturn(flutterProject.directory.childFile('.plugins'));
|
||||
iosProject = MockIosProject();
|
||||
when(flutterProject.ios).thenReturn(iosProject);
|
||||
when(iosProject.pluginRegistrantHost).thenReturn(flutterProject.directory.childDirectory('Runner'));
|
||||
when(iosProject.podfile).thenReturn(flutterProject.directory.childDirectory('ios').childFile('Podfile'));
|
||||
when(iosProject.podManifestLock).thenReturn(flutterProject.directory.childDirectory('ios').childFile('Podfile.lock'));
|
||||
macosProject = MockMacOSProject();
|
||||
when(flutterProject.macos).thenReturn(macosProject);
|
||||
when(macosProject.podfile).thenReturn(flutterProject.directory.childDirectory('macos').childFile('Podfile'));
|
||||
when(macosProject.podManifestLock).thenReturn(flutterProject.directory.childDirectory('macos').childFile('Podfile.lock'));
|
||||
androidProject = MockAndroidProject();
|
||||
when(flutterProject.android).thenReturn(androidProject);
|
||||
when(androidProject.pluginRegistrantHost).thenReturn(flutterProject.directory.childDirectory('android').childDirectory('app'));
|
||||
when(androidProject.hostAppGradleRoot).thenReturn(flutterProject.directory.childDirectory('android'));
|
||||
|
||||
// Set up a simple .packages file for all the tests to use, pointing to one package.
|
||||
dummyPackageDirectory = fs.directory('/pubcache/apackage/lib/');
|
||||
@ -103,4 +110,276 @@ flutter:
|
||||
FileSystem: () => fs,
|
||||
});
|
||||
});
|
||||
|
||||
group('injectPlugins', () {
|
||||
MockFeatureFlags featureFlags;
|
||||
MockXcodeProjectInterpreter xcodeProjectInterpreter;
|
||||
|
||||
const String kAndroidManifestUsingOldEmbedding = '''
|
||||
<manifest>
|
||||
<application>
|
||||
</application>
|
||||
</manifest>
|
||||
''';
|
||||
const String kAndroidManifestUsingNewEmbedding = '''
|
||||
<manifest>
|
||||
<application>
|
||||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2" />
|
||||
</application>
|
||||
</manifest>
|
||||
''';
|
||||
|
||||
setUp(() {
|
||||
featureFlags = MockFeatureFlags();
|
||||
when(featureFlags.isLinuxEnabled).thenReturn(false);
|
||||
when(featureFlags.isMacOSEnabled).thenReturn(false);
|
||||
when(featureFlags.isWindowsEnabled).thenReturn(false);
|
||||
when(featureFlags.isWebEnabled).thenReturn(false);
|
||||
|
||||
xcodeProjectInterpreter = MockXcodeProjectInterpreter();
|
||||
when(xcodeProjectInterpreter.isInstalled).thenReturn(false);
|
||||
});
|
||||
|
||||
testUsingContext('Registrant uses old embedding in app project', () async {
|
||||
when(flutterProject.isModule).thenReturn(false);
|
||||
when(featureFlags.isNewAndroidEmbeddingEnabled).thenReturn(false);
|
||||
|
||||
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,
|
||||
FeatureFlags: () => featureFlags,
|
||||
});
|
||||
|
||||
testUsingContext('Registrant uses new embedding if app uses new embedding', () async {
|
||||
when(flutterProject.isModule).thenReturn(false);
|
||||
when(featureFlags.isNewAndroidEmbeddingEnabled).thenReturn(true);
|
||||
|
||||
final File androidManifest = flutterProject.directory
|
||||
.childDirectory('android')
|
||||
.childFile('AndroidManifest.xml')
|
||||
..createSync(recursive: true)
|
||||
..writeAsStringSync(kAndroidManifestUsingNewEmbedding);
|
||||
when(androidProject.appManifestFile).thenReturn(androidManifest);
|
||||
|
||||
await injectPlugins(flutterProject);
|
||||
|
||||
final File registrant = flutterProject.directory
|
||||
.childDirectory(fs.path.join('android', 'app', 'src', 'main', 'java', 'dev', 'flutter', 'plugins'))
|
||||
.childFile('GeneratedPluginRegistrant.java');
|
||||
|
||||
expect(registrant.existsSync(), isTrue);
|
||||
expect(registrant.readAsStringSync(), contains('package dev.flutter.plugins'));
|
||||
expect(registrant.readAsStringSync(), contains('class GeneratedPluginRegistrant'));
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fs,
|
||||
FeatureFlags: () => featureFlags,
|
||||
});
|
||||
|
||||
testUsingContext('Registrant uses shim for plugins using old embedding if app uses new embedding', () async {
|
||||
when(flutterProject.isModule).thenReturn(false);
|
||||
when(featureFlags.isNewAndroidEmbeddingEnabled).thenReturn(true);
|
||||
|
||||
final File androidManifest = flutterProject.directory
|
||||
.childDirectory('android')
|
||||
.childFile('AndroidManifest.xml')
|
||||
..createSync(recursive: true)
|
||||
..writeAsStringSync(kAndroidManifestUsingNewEmbedding);
|
||||
when(androidProject.appManifestFile).thenReturn(androidManifest);
|
||||
|
||||
final Directory pluginUsingJavaAndNewEmbeddingDir =
|
||||
fs.systemTempDirectory.createTempSync('pluginUsingJavaAndNewEmbeddingDir.');
|
||||
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;');
|
||||
|
||||
final Directory pluginUsingKotlinAndNewEmbeddingDir =
|
||||
fs.systemTempDirectory.createTempSync('pluginUsingKotlinAndNewEmbeddingDir.');
|
||||
pluginUsingKotlinAndNewEmbeddingDir
|
||||
.childFile('pubspec.yaml')
|
||||
.writeAsStringSync('''
|
||||
flutter:
|
||||
plugin:
|
||||
androidPackage: plugin2
|
||||
pluginClass: UseNewEmbedding
|
||||
''');
|
||||
pluginUsingKotlinAndNewEmbeddingDir
|
||||
.childDirectory('android')
|
||||
.childDirectory('src')
|
||||
.childDirectory('main')
|
||||
.childDirectory('kotlin')
|
||||
.childDirectory('plugin2')
|
||||
.childFile('UseNewEmbedding.kt')
|
||||
..createSync(recursive: true)
|
||||
..writeAsStringSync('import io.flutter.embedding.engine.plugins.FlutterPlugin');
|
||||
|
||||
final Directory pluginUsingOldEmbeddingDir =
|
||||
fs.systemTempDirectory.createTempSync('pluginUsingOldEmbeddingDir.');
|
||||
pluginUsingOldEmbeddingDir
|
||||
.childFile('pubspec.yaml')
|
||||
.writeAsStringSync('''
|
||||
flutter:
|
||||
plugin:
|
||||
androidPackage: plugin3
|
||||
pluginClass: UseOldEmbedding
|
||||
''');
|
||||
pluginUsingOldEmbeddingDir
|
||||
.childDirectory('android')
|
||||
.childDirectory('src')
|
||||
.childDirectory('main')
|
||||
.childDirectory('java')
|
||||
.childDirectory('plugin3')
|
||||
.childFile('UseOldEmbedding.java')
|
||||
..createSync(recursive: true);
|
||||
|
||||
flutterProject.directory
|
||||
.childFile('.packages')
|
||||
.writeAsStringSync('''
|
||||
plugin1:${pluginUsingJavaAndNewEmbeddingDir.childDirectory('lib').uri.toString()}
|
||||
plugin2:${pluginUsingKotlinAndNewEmbeddingDir.childDirectory('lib').uri.toString()}
|
||||
plugin3:${pluginUsingOldEmbeddingDir.childDirectory('lib').uri.toString()}
|
||||
''');
|
||||
|
||||
await injectPlugins(flutterProject);
|
||||
|
||||
final File registrant = flutterProject.directory
|
||||
.childDirectory(fs.path.join('android', 'app', 'src', 'main', 'java', 'dev', 'flutter', 'plugins'))
|
||||
.childFile('GeneratedPluginRegistrant.java');
|
||||
|
||||
expect(registrant.readAsStringSync(),
|
||||
contains('flutterEngine.getPlugins().add(new plugin1.UseNewEmbedding());'));
|
||||
expect(registrant.readAsStringSync(),
|
||||
contains('flutterEngine.getPlugins().add(new plugin2.UseNewEmbedding());'));
|
||||
expect(registrant.readAsStringSync(),
|
||||
contains('plugin3.UseOldEmbedding.registerWith(shimPluginRegistry.registrarFor("plugin3.UseOldEmbedding"));'));
|
||||
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fs,
|
||||
FeatureFlags: () => featureFlags,
|
||||
XcodeProjectInterpreter: () => xcodeProjectInterpreter,
|
||||
});
|
||||
|
||||
testUsingContext('Registrant doesn\'t use new embedding if app doesn\'t use new embedding', () async {
|
||||
when(flutterProject.isModule).thenReturn(false);
|
||||
when(featureFlags.isNewAndroidEmbeddingEnabled).thenReturn(true);
|
||||
|
||||
final File androidManifest = flutterProject.directory
|
||||
.childDirectory('android')
|
||||
.childFile('AndroidManifest.xml')
|
||||
..createSync(recursive: true)
|
||||
..writeAsStringSync(kAndroidManifestUsingOldEmbedding);
|
||||
when(androidProject.appManifestFile).thenReturn(androidManifest);
|
||||
|
||||
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,
|
||||
FeatureFlags: () => featureFlags,
|
||||
});
|
||||
|
||||
testUsingContext('Registrant uses old embedding in module project', () async {
|
||||
when(flutterProject.isModule).thenReturn(true);
|
||||
when(featureFlags.isNewAndroidEmbeddingEnabled).thenReturn(false);
|
||||
|
||||
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,
|
||||
FeatureFlags: () => featureFlags,
|
||||
});
|
||||
|
||||
testUsingContext('Registrant uses new embedding if module uses new embedding', () async {
|
||||
when(flutterProject.isModule).thenReturn(true);
|
||||
when(featureFlags.isNewAndroidEmbeddingEnabled).thenReturn(true);
|
||||
|
||||
final File androidManifest = flutterProject.directory
|
||||
.childDirectory('android')
|
||||
.childFile('AndroidManifest.xml')
|
||||
..createSync(recursive: true)
|
||||
..writeAsStringSync(kAndroidManifestUsingNewEmbedding);
|
||||
when(androidProject.appManifestFile).thenReturn(androidManifest);
|
||||
|
||||
await injectPlugins(flutterProject);
|
||||
|
||||
final File registrant = flutterProject.directory
|
||||
.childDirectory(fs.path.join('android', 'app', 'src', 'main', 'java', 'dev', 'flutter', 'plugins'))
|
||||
.childFile('GeneratedPluginRegistrant.java');
|
||||
|
||||
expect(registrant.existsSync(), isTrue);
|
||||
expect(registrant.readAsStringSync(), contains('package dev.flutter.plugins'));
|
||||
expect(registrant.readAsStringSync(), contains('class GeneratedPluginRegistrant'));
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fs,
|
||||
FeatureFlags: () => featureFlags,
|
||||
});
|
||||
|
||||
testUsingContext('Registrant doesn\'t use new embedding if module doesn\'t use new embedding', () async {
|
||||
when(flutterProject.isModule).thenReturn(true);
|
||||
when(featureFlags.isNewAndroidEmbeddingEnabled).thenReturn(true);
|
||||
|
||||
final File androidManifest = flutterProject.directory
|
||||
.childDirectory('android')
|
||||
.childFile('AndroidManifest.xml')
|
||||
..createSync(recursive: true)
|
||||
..writeAsStringSync(kAndroidManifestUsingOldEmbedding);
|
||||
when(androidProject.appManifestFile).thenReturn(androidManifest);
|
||||
|
||||
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,
|
||||
FeatureFlags: () => featureFlags,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
class MockAndroidProject extends Mock implements AndroidProject {}
|
||||
class MockFeatureFlags extends Mock implements FeatureFlags {}
|
||||
class MockFlutterProject extends Mock implements FlutterProject {}
|
||||
class MockIosProject extends Mock implements IosProject {}
|
||||
class MockMacOSProject extends Mock implements MacOSProject {}
|
||||
class MockXcodeProjectInterpreter extends Mock implements XcodeProjectInterpreter {}
|
||||
|
@ -689,6 +689,7 @@ class TestFeatureFlags implements FeatureFlags {
|
||||
this.isMacOSEnabled = false,
|
||||
this.isWebEnabled = false,
|
||||
this.isWindowsEnabled = false,
|
||||
this.isNewAndroidEmbeddingEnabled = false,
|
||||
});
|
||||
|
||||
@override
|
||||
@ -702,4 +703,7 @@ class TestFeatureFlags implements FeatureFlags {
|
||||
|
||||
@override
|
||||
final bool isWindowsEnabled;
|
||||
|
||||
@override
|
||||
final bool isNewAndroidEmbeddingEnabled;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user