diff --git a/dev/benchmarks/complex_layout/android/app/src/main/AndroidManifest.xml b/dev/benchmarks/complex_layout/android/app/src/main/AndroidManifest.xml
index 8200a24452..f550d95c2a 100644
--- a/dev/benchmarks/complex_layout/android/app/src/main/AndroidManifest.xml
+++ b/dev/benchmarks/complex_layout/android/app/src/main/AndroidManifest.xml
@@ -7,8 +7,8 @@ found in the LICENSE file. -->
-
-
+
+
diff --git a/dev/benchmarks/macrobenchmarks/android/app/src/main/AndroidManifest.xml b/dev/benchmarks/macrobenchmarks/android/app/src/main/AndroidManifest.xml
index 643354e964..1f764191b6 100644
--- a/dev/benchmarks/macrobenchmarks/android/app/src/main/AndroidManifest.xml
+++ b/dev/benchmarks/macrobenchmarks/android/app/src/main/AndroidManifest.xml
@@ -17,7 +17,7 @@ found in the LICENSE file. -->
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
-
-
+
-
+
-
+
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
-
+
+
+
diff --git a/dev/integration_tests/android_semantics_testing/android/app/src/main/java/com/yourcompany/platforminteraction/MainActivity.java b/dev/integration_tests/android_semantics_testing/android/app/src/main/java/com/yourcompany/platforminteraction/MainActivity.java
index 325569c98e..e753f4eda6 100644
--- a/dev/integration_tests/android_semantics_testing/android/app/src/main/java/com/yourcompany/platforminteraction/MainActivity.java
+++ b/dev/integration_tests/android_semantics_testing/android/app/src/main/java/com/yourcompany/platforminteraction/MainActivity.java
@@ -16,13 +16,16 @@ import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.WindowManager;
import android.content.Context;
+import androidx.annotation.NonNull;
-import io.flutter.app.FlutterActivity;
+import io.flutter.embedding.android.FlutterActivity;
+import io.flutter.embedding.engine.FlutterEngine;
+import io.flutter.embedding.android.FlutterActivity;
+import io.flutter.embedding.android.FlutterView;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugins.GeneratedPluginRegistrant;
-import io.flutter.view.FlutterView;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeProvider;
@@ -30,10 +33,10 @@ import android.view.accessibility.AccessibilityNodeInfo;
public class MainActivity extends FlutterActivity {
@Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- GeneratedPluginRegistrant.registerWith(this);
- new MethodChannel(getFlutterView(), "semantics").setMethodCallHandler(new SemanticsTesterMethodHandler());
+ public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
+ GeneratedPluginRegistrant.registerWith(flutterEngine);
+ new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), "semantics")
+ .setMethodCallHandler(new SemanticsTesterMethodHandler());
}
class SemanticsTesterMethodHandler implements MethodCallHandler {
@@ -41,7 +44,7 @@ public class MainActivity extends FlutterActivity {
@Override
public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
- FlutterView flutterView = getFlutterView();
+ FlutterView flutterView = findViewById(FLUTTER_VIEW_ID);
AccessibilityNodeProvider provider = flutterView.getAccessibilityNodeProvider();
DisplayMetrics displayMetrics = new DisplayMetrics();
WindowManager wm = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
diff --git a/dev/integration_tests/android_views/android/app/src/main/AndroidManifest.xml b/dev/integration_tests/android_views/android/app/src/main/AndroidManifest.xml
index 8387ccf580..b3427f9afe 100644
--- a/dev/integration_tests/android_views/android/app/src/main/AndroidManifest.xml
+++ b/dev/integration_tests/android_views/android/app/src/main/AndroidManifest.xml
@@ -9,7 +9,7 @@ found in the LICENSE file. -->
In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
-
+
+
+
diff --git a/dev/integration_tests/flavors/android/app/src/main/AndroidManifest.xml b/dev/integration_tests/flavors/android/app/src/main/AndroidManifest.xml
index e1a37c0da7..664706aee1 100644
--- a/dev/integration_tests/flavors/android/app/src/main/AndroidManifest.xml
+++ b/dev/integration_tests/flavors/android/app/src/main/AndroidManifest.xml
@@ -8,7 +8,7 @@ found in the LICENSE file. -->
+
+
diff --git a/dev/integration_tests/flavors/android/app/src/main/java/com/yourcompany/flavors/MainActivity.java b/dev/integration_tests/flavors/android/app/src/main/java/com/yourcompany/flavors/MainActivity.java
index 7e6d4fe711..1bdb38564a 100644
--- a/dev/integration_tests/flavors/android/app/src/main/java/com/yourcompany/flavors/MainActivity.java
+++ b/dev/integration_tests/flavors/android/app/src/main/java/com/yourcompany/flavors/MainActivity.java
@@ -6,21 +6,19 @@ package com.yourcompany.flavors;
import android.os.Bundle;
-import io.flutter.app.FlutterActivity;
+import io.flutter.embedding.android.FlutterActivity;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
-import io.flutter.plugins.GeneratedPluginRegistrant;
public class MainActivity extends FlutterActivity {
@Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- GeneratedPluginRegistrant.registerWith(this);
- new MethodChannel(getFlutterView(), "flavor").setMethodCallHandler(new MethodChannel.MethodCallHandler() {
- @Override
- public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
- result.success(BuildConfig.FLAVOR);
- }
- });
+ public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
+ GeneratedPluginRegistrant.registerWith(flutterEngine);
+ new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), "flavor")
+ .setMethodCallHandler(
+ (call, result) -> {
+ result.success(BuildConfig.FLAVOR);
+ }
+ );
}
}
diff --git a/dev/integration_tests/gradle_deprecated_settings/android/app/src/main/AndroidManifest.xml b/dev/integration_tests/gradle_deprecated_settings/android/app/src/main/AndroidManifest.xml
index e1a37c0da7..664706aee1 100644
--- a/dev/integration_tests/gradle_deprecated_settings/android/app/src/main/AndroidManifest.xml
+++ b/dev/integration_tests/gradle_deprecated_settings/android/app/src/main/AndroidManifest.xml
@@ -8,7 +8,7 @@ found in the LICENSE file. -->
+
+
diff --git a/dev/integration_tests/gradle_deprecated_settings/android/app/src/main/java/com/yourcompany/flavors/MainActivity.java b/dev/integration_tests/gradle_deprecated_settings/android/app/src/main/java/com/yourcompany/flavors/MainActivity.java
index 24f93ca13d..488c7fb7e6 100644
--- a/dev/integration_tests/gradle_deprecated_settings/android/app/src/main/java/com/yourcompany/flavors/MainActivity.java
+++ b/dev/integration_tests/gradle_deprecated_settings/android/app/src/main/java/com/yourcompany/flavors/MainActivity.java
@@ -4,15 +4,6 @@
package com.yourcompany.flavors;
-import android.os.Bundle;
+import io.flutter.embedding.android.FlutterActivity;
-import io.flutter.app.FlutterActivity;
-import io.flutter.plugins.GeneratedPluginRegistrant;
-
-public class MainActivity extends FlutterActivity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- GeneratedPluginRegistrant.registerWith(this);
- }
-}
+public class MainActivity extends FlutterActivity {}
diff --git a/dev/integration_tests/hybrid_android_views/android/app/src/main/AndroidManifest.xml b/dev/integration_tests/hybrid_android_views/android/app/src/main/AndroidManifest.xml
index afc37761cd..0e3e9627e4 100644
--- a/dev/integration_tests/hybrid_android_views/android/app/src/main/AndroidManifest.xml
+++ b/dev/integration_tests/hybrid_android_views/android/app/src/main/AndroidManifest.xml
@@ -9,7 +9,7 @@ found in the LICENSE file. -->
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
-
+
+
+
diff --git a/dev/integration_tests/platform_interaction/android/app/src/main/java/com/yourcompany/platforminteraction/MainActivity.java b/dev/integration_tests/platform_interaction/android/app/src/main/java/com/yourcompany/platforminteraction/MainActivity.java
index c8bc0f9f87..d4ec979a53 100644
--- a/dev/integration_tests/platform_interaction/android/app/src/main/java/com/yourcompany/platforminteraction/MainActivity.java
+++ b/dev/integration_tests/platform_interaction/android/app/src/main/java/com/yourcompany/platforminteraction/MainActivity.java
@@ -6,16 +6,10 @@ package com.yourcompany.platforminteraction;
import android.os.Bundle;
-import io.flutter.app.FlutterActivity;
+import io.flutter.embedding.android.FlutterActivity;
import io.flutter.plugin.common.*;
-import io.flutter.plugins.GeneratedPluginRegistrant;
public class MainActivity extends FlutterActivity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- GeneratedPluginRegistrant.registerWith(this);
- }
public void finish() {
BasicMessageChannel channel =
new BasicMessageChannel<>(getFlutterView(), "navigation-test", StringCodec.INSTANCE);
diff --git a/dev/integration_tests/release_smoke_test/android/app/src/main/AndroidManifest.xml b/dev/integration_tests/release_smoke_test/android/app/src/main/AndroidManifest.xml
index f93ecc4b9e..988e75c010 100644
--- a/dev/integration_tests/release_smoke_test/android/app/src/main/AndroidManifest.xml
+++ b/dev/integration_tests/release_smoke_test/android/app/src/main/AndroidManifest.xml
@@ -11,7 +11,7 @@ found in the LICENSE file. -->
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
-
+
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
boolArg('ignore-deprecation') ? DeprecationBehavior.ignore : DeprecationBehavior.exit;
+
@override
Future> get requiredArtifacts async => {
DevelopmentArtifact.androidGenSnapshot,
diff --git a/packages/flutter_tools/lib/src/commands/build_appbundle.dart b/packages/flutter_tools/lib/src/commands/build_appbundle.dart
index 0cd619c7bf..40611f2a7b 100644
--- a/packages/flutter_tools/lib/src/commands/build_appbundle.dart
+++ b/packages/flutter_tools/lib/src/commands/build_appbundle.dart
@@ -42,6 +42,7 @@ class BuildAppBundleCommand extends BuildSubCommand {
usesAnalyzeSizeFlag();
addAndroidSpecificBuildOptions(hide: !verboseHelp);
addMultidexOption();
+ addIgnoreDeprecationOption();
argParser.addMultiOption('target-platform',
splitCommas: true,
defaultsTo: ['android-arm', 'android-arm64', 'android-x64'],
@@ -72,6 +73,9 @@ class BuildAppBundleCommand extends BuildSubCommand {
@override
final String name = 'appbundle';
+ @override
+ DeprecationBehavior get deprecationBehavior => boolArg('ignore-deprecation') ? DeprecationBehavior.ignore : DeprecationBehavior.exit;
+
@override
Future> get requiredArtifacts async => {
DevelopmentArtifact.androidGenSnapshot,
diff --git a/packages/flutter_tools/lib/src/commands/run.dart b/packages/flutter_tools/lib/src/commands/run.dart
index 695541256a..01d34cea6a 100644
--- a/packages/flutter_tools/lib/src/commands/run.dart
+++ b/packages/flutter_tools/lib/src/commands/run.dart
@@ -251,6 +251,7 @@ class RunCommand extends RunCommandBase {
// without needing to know the port.
addPublishPort(verboseHelp: verboseHelp);
addMultidexOption();
+ addIgnoreDeprecationOption();
argParser
..addFlag('enable-software-rendering',
negatable: false,
@@ -342,6 +343,10 @@ class RunCommand extends RunCommandBase {
@override
final String name = 'run';
+ @override
+ DeprecationBehavior get deprecationBehavior => boolArg('ignore-deprecation') ? DeprecationBehavior.ignore : _deviceDeprecationBehavior;
+ DeprecationBehavior _deviceDeprecationBehavior = DeprecationBehavior.none;
+
@override
final String description = 'Run your Flutter app on an attached device.';
@@ -475,6 +480,10 @@ class RunCommand extends RunCommandBase {
'--${FlutterOptions.kDeviceUser} is only supported for Android. At least one Android device is required.'
);
}
+
+ if (devices.any((Device device) => device is AndroidDevice)) {
+ _deviceDeprecationBehavior = DeprecationBehavior.exit;
+ }
// Only support "web mode" with a single web device due to resident runner
// refactoring required otherwise.
webMode = featureFlags.isWebEnabled &&
diff --git a/packages/flutter_tools/lib/src/project.dart b/packages/flutter_tools/lib/src/project.dart
index d13a9a698f..59ec19b3c5 100644
--- a/packages/flutter_tools/lib/src/project.dart
+++ b/packages/flutter_tools/lib/src/project.dart
@@ -20,6 +20,7 @@ import 'flutter_manifest.dart';
import 'flutter_plugins.dart';
import 'globals.dart' as globals;
import 'platform_plugins.dart';
+import 'reporting/reporting.dart';
import 'template.dart';
import 'xcode_project.dart';
@@ -282,7 +283,7 @@ class FlutterProject {
/// registrants for app and module projects only.
///
/// Will not create project platform directories if they do not already exist.
- Future regeneratePlatformSpecificTooling() async {
+ Future regeneratePlatformSpecificTooling({DeprecationBehavior deprecationBehavior = DeprecationBehavior.none}) async {
return ensureReadyForPlatformSpecificTooling(
androidPlatform: android.existsSync(),
iosPlatform: ios.existsSync(),
@@ -293,6 +294,7 @@ class FlutterProject {
windowsPlatform: featureFlags.isWindowsEnabled && windows.existsSync(),
webPlatform: featureFlags.isWebEnabled && web.existsSync(),
winUwpPlatform: featureFlags.isWindowsUwpEnabled && windowsUwp.existsSync(),
+ deprecationBehavior: deprecationBehavior,
);
}
@@ -306,13 +308,14 @@ class FlutterProject {
bool windowsPlatform = false,
bool webPlatform = false,
bool winUwpPlatform = false,
+ DeprecationBehavior deprecationBehavior = DeprecationBehavior.none,
}) async {
if (!directory.existsSync() || hasExampleApp || isPlugin) {
return;
}
await refreshPluginsList(this, iosPlatform: iosPlatform, macOSPlatform: macOSPlatform);
if (androidPlatform) {
- await android.ensureReadyForPlatformSpecificTooling();
+ await android.ensureReadyForPlatformSpecificTooling(deprecationBehavior: deprecationBehavior);
}
if (iosPlatform) {
await ios.ensureReadyForPlatformSpecificTooling();
@@ -344,6 +347,12 @@ class FlutterProject {
);
}
+ void checkForDeprecation({DeprecationBehavior deprecationBehavior = DeprecationBehavior.none}) {
+ if (android.existsSync()) {
+ android.checkForDeprecation(deprecationBehavior: deprecationBehavior);
+ }
+ }
+
/// Returns a json encoded string containing the [appName], [version], and [buildNumber] that is used to generate version.json
String getVersionInfo() {
final String? buildName = manifest.buildName;
@@ -478,7 +487,7 @@ class AndroidProject extends FlutterProjectPlatform {
return parent.directory.childDirectory('build');
}
- Future ensureReadyForPlatformSpecificTooling() async {
+ Future ensureReadyForPlatformSpecificTooling({DeprecationBehavior deprecationBehavior = DeprecationBehavior.none}) async {
if (isModule && _shouldRegenerateFromTemplate()) {
await _regenerateLibrary();
// Add ephemeral host app, if an editable host app does not already exist.
@@ -536,6 +545,41 @@ class AndroidProject extends FlutterProjectPlatform {
);
}
+ void checkForDeprecation({DeprecationBehavior deprecationBehavior = DeprecationBehavior.none}) {
+ if (getEmbeddingVersion() == AndroidEmbeddingVersion.v1) {
+ globals.printStatus(
+'''
+━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+Warning
+──────────────────────────────────────────────────────────────────────────────
+Your Flutter application is created using an older version of the Android
+embedding. It is being deprecated in favor of Android embedding v2. Follow the
+steps at
+
+https://flutter.dev/go/android-project-migration
+
+to migrate your project. You may also pass the --ignore-deprecation flag to
+ignore this check and continue with the deprecated v1 embedding. However,
+the v1 Android embedding will be removed in future versions of Flutter.
+━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+'''
+ );
+ switch (deprecationBehavior) {
+ case DeprecationBehavior.none:
+ break;
+ case DeprecationBehavior.ignore:
+ BuildEvent('deprecated-v1-android-embedding-ignored', type: 'gradle', flutterUsage: globals.flutterUsage).send();
+ break;
+ case DeprecationBehavior.exit:
+ BuildEvent('deprecated-v1-android-embedding-failed', type: 'gradle', flutterUsage: globals.flutterUsage).send();
+ throwToolExit(
+ 'Build failed due to use of deprecated Android v1 embedding.',
+ exitCode: 1,
+ );
+ }
+ }
+ }
+
AndroidEmbeddingVersion getEmbeddingVersion() {
if (isModule) {
// A module type's Android project is used in add-to-app scenarios and
@@ -555,6 +599,12 @@ class AndroidProject extends FlutterProjectPlatform {
throwToolExit('Error reading $appManifestFile even though it exists. '
'Please ensure that you have read permission to this file and try again.');
}
+ for (final XmlElement application in document.findAllElements('application')) {
+ final String? applicationName = application.getAttribute('android:name');
+ if (applicationName == 'io.flutter.app.FlutterApplication') {
+ return AndroidEmbeddingVersion.v1;
+ }
+ }
for (final XmlElement metaData in document.findAllElements('meta-data')) {
final String? name = metaData.getAttribute('android:name');
if (name == 'flutterEmbedding') {
@@ -579,6 +629,16 @@ enum AndroidEmbeddingVersion {
v2,
}
+// What the tool should do when encountering deprecated API in applications.
+enum DeprecationBehavior {
+ // The command being run does not care about deprecation status.
+ none,
+ // The command should continue and ignore the deprecation warning.
+ ignore,
+ // The command should exit the tool.
+ exit,
+}
+
/// Represents the web sub-project of a Flutter project.
class WebProject extends FlutterProjectPlatform {
WebProject._(this.parent);
diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart
index 3ea9aaa019..bd526eeb64 100644
--- a/packages/flutter_tools/lib/src/runner/flutter_command.dart
+++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart
@@ -181,6 +181,8 @@ abstract class FlutterCommand extends Command {
bool _usesFatalWarnings = false;
+ DeprecationBehavior get deprecationBehavior => DeprecationBehavior.none;
+
bool get shouldRunPub => _usesPubOption && boolArg('pub');
bool get shouldUpdateCache => true;
@@ -834,6 +836,15 @@ abstract class FlutterCommand extends Command {
);
}
+ void addIgnoreDeprecationOption({ bool hide = false }) {
+ argParser.addFlag('ignore-deprecation',
+ negatable: false,
+ help: 'Indicates that the app should ignore deprecation warnings and continue to build '
+ 'using deprecated APIs. Use of this flag may cause your app to fail to build when '
+ 'deprecated APIs are removed.',
+ );
+ }
+
/// Adds build options common to all of the desktop build commands.
void addCommonDesktopBuildOptions({ required bool verboseHelp }) {
addBuildModeFlags(verboseHelp: verboseHelp);
@@ -1263,8 +1274,10 @@ abstract class FlutterCommand extends Command {
await validateCommand();
+ final FlutterProject project = FlutterProject.current();
+ project.checkForDeprecation(deprecationBehavior: deprecationBehavior);
+
if (shouldRunPub) {
- final FlutterProject project = FlutterProject.current();
final Environment environment = Environment(
artifacts: globals.artifacts!,
logger: globals.logger,
diff --git a/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart
index 6ca5fc6acc..0c0791a7f4 100644
--- a/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart
+++ b/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart
@@ -14,12 +14,15 @@ import 'dart:async';
import 'package:file/file.dart';
import 'package:file/memory.dart';
+import 'package:flutter_tools/src/android/android_device.dart';
+import 'package:flutter_tools/src/android/android_sdk.dart';
import 'package:flutter_tools/src/application_package.dart';
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/logger.dart';
+import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/user_messages.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/cache.dart';
@@ -217,6 +220,88 @@ void main() {
Cache: () => Cache.test(processManager: FakeProcessManager.any()),
});
+ testUsingContext('fails when v1 FlutterApplication is detected', () async {
+ fs.file('pubspec.yaml').createSync();
+ fs.file('android/AndroidManifest.xml')
+ ..createSync(recursive: true)
+ ..writeAsStringSync('''
+
+
+
+
+ ''', flush: true);
+ fs.file('.packages').writeAsStringSync('\n');
+ fs.file('lib/main.dart').createSync(recursive: true);
+ final AndroidDevice device = AndroidDevice('1234',
+ modelID: 'TestModel',
+ logger: testLogger,
+ platform: FakePlatform(),
+ androidSdk: FakeAndroidSdk(),
+ fileSystem: fs,
+ processManager: FakeProcessManager.any(),
+ );
+
+ mockDeviceManager
+ ..devices = [device]
+ ..targetDevices = [device];
+
+ final RunCommand command = RunCommand();
+ await expectLater(createTestCommandRunner(command).run([
+ 'run',
+ '--pub',
+ ]), throwsToolExit(message: 'Build failed due to use of deprecated Android v1 embedding.'));
+ }, overrides: {
+ FileSystem: () => fs,
+ ProcessManager: () => FakeProcessManager.any(),
+ DeviceManager: () => mockDeviceManager,
+ Stdio: () => FakeStdio(),
+ Cache: () => Cache.test(processManager: FakeProcessManager.any()),
+ });
+
+ testUsingContext('fails when v1 metadata is detected', () async {
+ fs.file('pubspec.yaml').createSync();
+ fs.file('android/AndroidManifest.xml')
+ ..createSync(recursive: true)
+ ..writeAsStringSync('''
+
+
+
+
+
+ ''', flush: true);
+ fs.file('.packages').writeAsStringSync('\n');
+ fs.file('lib/main.dart').createSync(recursive: true);
+ final AndroidDevice device = AndroidDevice('1234',
+ modelID: 'TestModel',
+ logger: testLogger,
+ platform: FakePlatform(),
+ androidSdk: FakeAndroidSdk(),
+ fileSystem: fs,
+ processManager: FakeProcessManager.any(),
+ );
+
+ mockDeviceManager
+ ..devices = [device]
+ ..targetDevices = [device];
+
+ final RunCommand command = RunCommand();
+ await expectLater(createTestCommandRunner(command).run([
+ 'run',
+ '--pub',
+ ]), throwsToolExit(message: 'Build failed due to use of deprecated Android v1 embedding.'));
+ }, overrides: {
+ FileSystem: () => fs,
+ ProcessManager: () => FakeProcessManager.any(),
+ DeviceManager: () => mockDeviceManager,
+ Stdio: () => FakeStdio(),
+ Cache: () => Cache.test(processManager: FakeProcessManager.any()),
+ });
+
testUsingContext('shows unsupported devices when no supported devices are found', () async {
final RunCommand command = RunCommand();
final FakeDevice mockDevice = FakeDevice(targetPlatform: TargetPlatform.android_arm, isLocalEmulator: true, sdkNameAndVersion: 'api-14');
@@ -535,6 +620,10 @@ class FakeDeviceManager extends Fake implements DeviceManager {
}
}
+class FakeAndroidSdk extends Fake implements AndroidSdk {
+ @override
+ String get adbPath => 'adb';
+}
class TestRunCommand extends RunCommand {
@override
diff --git a/packages/flutter_tools/test/general.shard/project_test.dart b/packages/flutter_tools/test/general.shard/project_test.dart
index 3915d7d4cb..76a9c8b11a 100644
--- a/packages/flutter_tools/test/general.shard/project_test.dart
+++ b/packages/flutter_tools/test/general.shard/project_test.dart
@@ -182,8 +182,29 @@ void main() {
// v1 embedding, as opposed to having .
- await project.regeneratePlatformSpecificTooling();
- expect(testLogger.warningText, contains('https://github.com/flutter/flutter/wiki/Upgrading-pre-1.12-Android-projects'));
+ project.checkForDeprecation(deprecationBehavior: DeprecationBehavior.none);
+ expect(testLogger.statusText, contains('https://flutter.dev/go/android-project-migration'));
+ });
+ _testInMemory('Android project not on v2 embedding exits', () async {
+ final FlutterProject project = await someProject();
+ // The default someProject with an empty already indicates
+ // v1 embedding, as opposed to having .
+
+ await expectToolExitLater(
+ Future.sync(() => project.checkForDeprecation(deprecationBehavior: DeprecationBehavior.exit)),
+ contains('Build failed due to use of deprecated Android v1 embedding.')
+ );
+ expect(testLogger.statusText, contains('https://flutter.dev/go/android-project-migration'));
+ });
+ _testInMemory('Android project not on v2 embedding ignore continues', () async {
+ final FlutterProject project = await someProject();
+ // The default someProject with an empty already indicates
+ // v1 embedding, as opposed to having .
+
+ project.checkForDeprecation(deprecationBehavior: DeprecationBehavior.ignore);
+ expect(testLogger.statusText, contains('https://flutter.dev/go/android-project-migration'));
});
_testInMemory('Android plugin without example app does not show a warning', () async {
final FlutterProject project = await aPluginProject();
diff --git a/packages/integration_test/example/android/app/src/main/AndroidManifest.xml b/packages/integration_test/example/android/app/src/main/AndroidManifest.xml
index 32833b71c9..9e0765f4e9 100644
--- a/packages/integration_test/example/android/app/src/main/AndroidManifest.xml
+++ b/packages/integration_test/example/android/app/src/main/AndroidManifest.xml
@@ -11,7 +11,7 @@ found in the LICENSE file. -->
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->