Unverified Commit 5961bcc5 authored by Emmanuel Garcia's avatar Emmanuel Garcia Committed by GitHub

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
parent 890b9394
......@@ -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,11 +126,11 @@ class Plugin {
if (pluginYaml != null && pluginClass != null) {
final String androidPackage = pluginYaml['androidPackage'];
if (androidPackage != null) {
platforms[AndroidPlugin.kConfigKey] =
AndroidPlugin(
platforms[AndroidPlugin.kConfigKey] = AndroidPlugin(
name: name,
package: pluginYaml['androidPackage'],
pluginClass: pluginClass,
pluginPath: path,
);
}
......@@ -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;
}
/// 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> context = <String, dynamic>{
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(
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',
);
_renderTemplateToFile(_androidPluginRegistryTemplate, context, registryPath);
templateContent = _androidPluginRegistryTemplateOldEmbedding;
break;
default:
throwToolExit('Unsupported Android embedding');
}
printTrace('Generating $registryPath');
_renderTemplateToFile(
templateContent,
templateContext,
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,
......
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}}
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}}
<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>
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}}
// 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'
}
<?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>
\ No newline at end of file
<!-- 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>
// 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')
}
}
}
}
// Generated file. Do not edit.
rootProject.name = 'android_generated'
setBinding(new Binding([gradle: this]))
evaluate(new File(settingsDir, 'include_flutter.groovy'))
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}}
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}}
......@@ -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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment