Unverified Commit 6153bbef authored by Gary Qian's avatar Gary Qian Committed by GitHub

Exit on deprecated v1 embedding when trying to run or build (#92901)

parent 5842c33c
......@@ -7,7 +7,7 @@ found in the LICENSE file. -->
<uses-permission android:name="android.permission.INTERNET"/>
<application android:name="io.flutter.app.FlutterApplication" android:label="complex_layout" android:icon="@mipmap/ic_launcher">
<application android:name="${applicationName}" android:label="complex_layout" android:icon="@mipmap/ic_launcher">
<activity android:name="io.flutter.app.FlutterActivity"
android:exported="true"
android:launchMode="singleTop"
......@@ -20,5 +20,8 @@ found in the LICENSE file. -->
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
</manifest>
......@@ -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. -->
<application
android:name="io.flutter.app.FlutterApplication"
android:name="${applicationName}"
android:label="macrobenchmarks"
android:icon="@mipmap/ic_launcher">
<activity
......
......@@ -7,7 +7,7 @@ found in the LICENSE file. -->
<uses-permission android:name="android.permission.INTERNET"/>
<application android:name="io.flutter.app.FlutterApplication" android:label="microbenchmarks" android:icon="@mipmap/ic_launcher">
<application android:name="${applicationName}" android:label="microbenchmarks" android:icon="@mipmap/ic_launcher">
<activity android:name="io.flutter.app.FlutterActivity"
android:launchMode="singleTop"
android:theme="@android:style/Theme.Black.NoTitleBar"
......
......@@ -7,7 +7,7 @@ found in the LICENSE file. -->
<uses-permission android:name="android.permission.INTERNET"/>
<application android:name="io.flutter.app.FlutterApplication" android:label="platform_view_layout">
<application android:name="${applicationName}" android:label="platform_view_layout">
<activity android:name=".DummyPlatformViewActivity"
android:launchMode="singleTop"
android:theme="@android:style/Theme.Black.NoTitleBar"
......
......@@ -7,7 +7,7 @@ found in the LICENSE file. -->
<uses-permission android:name="android.permission.INTERNET"/>
<application android:name="io.flutter.app.FlutterApplication" android:label="platform_view_layout">
<application android:name="${applicationName}" android:label="platform_view_layout">
<activity android:name=".DummyPlatformViewActivity"
android:launchMode="singleTop"
android:theme="@android:style/Theme.Black.NoTitleBar"
......
......@@ -12,7 +12,7 @@ found in the LICENSE file. -->
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<application
android:name="io.flutter.app.FlutterApplication"
android:name="${applicationName}"
android:label="abstract_method_smoke_test">
<activity
android:name=".MainActivity"
......
......@@ -10,7 +10,7 @@ found in the LICENSE file. -->
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<application
android:name="io.flutter.app.FlutterApplication"
android:name="${applicationName}"
android:label="android_embedding_v2_smoke_test">
<activity
android:name=".MainActivity"
......
......@@ -16,7 +16,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. -->
<application android:name="io.flutter.app.FlutterApplication" android:label="Platform Interaction" android:icon="@mipmap/ic_launcher">
<application android:name="${applicationName}" android:label="Platform Interaction" android:icon="@mipmap/ic_launcher">
<activity android:name="com.yourcompany.platforminteraction.MainActivity"
android:launchMode="singleTop"
android:theme="@android:style/Theme.Black.NoTitleBar"
......@@ -28,5 +28,10 @@ found in the LICENSE file. -->
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- 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" />
</application>
</manifest>
......@@ -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);
......
......@@ -9,7 +9,7 @@ found in the LICENSE file. -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:name="io.flutter.app.FlutterApplication"
android:name="${applicationName}"
android:label="platform_views">
<activity
android:exported="true"
......
......@@ -16,7 +16,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. -->
<application android:name="io.flutter.app.FlutterApplication" android:label="channels" android:icon="@mipmap/ic_launcher">
<application android:name="${applicationName}" android:label="channels" android:icon="@mipmap/ic_launcher">
<activity android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="@android:style/Theme.Black.NoTitleBar"
......
......@@ -8,7 +8,7 @@ found in the LICENSE file. -->
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:name="io.flutter.app.FlutterApplication"
android:name="${applicationName}"
android:label="external_ui">
<activity
android:name=".MainActivity"
......@@ -21,5 +21,10 @@ found in the LICENSE file. -->
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- 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" />
</application>
</manifest>
......@@ -8,7 +8,7 @@ found in the LICENSE file. -->
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:name="io.flutter.app.FlutterApplication"
android:name="${applicationName}"
android:label="flavors">
<activity
android:name=".MainActivity"
......@@ -21,5 +21,10 @@ found in the LICENSE file. -->
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- 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" />
</application>
</manifest>
......@@ -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);
}
);
}
}
......@@ -8,7 +8,7 @@ found in the LICENSE file. -->
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:name="io.flutter.app.FlutterApplication"
android:name="${applicationName}"
android:label="flavors">
<activity
android:name=".MainActivity"
......@@ -21,5 +21,10 @@ found in the LICENSE file. -->
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- 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" />
</application>
</manifest>
......@@ -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 {}
......@@ -9,7 +9,7 @@ found in the LICENSE file. -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:name="io.flutter.app.FlutterApplication"
android:name="${applicationName}"
android:label="platform_views">
<activity
android:name=".MainActivity"
......
......@@ -10,7 +10,7 @@ found in the LICENSE file. -->
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<application
android:name="io.flutter.app.FlutterApplication"
android:name="${applicationName}"
android:label="non_nullable"
android:icon="@mipmap/ic_launcher">
<activity
......
......@@ -16,7 +16,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. -->
<application android:name="io.flutter.app.FlutterApplication" android:label="Platform Interaction" android:icon="@mipmap/ic_launcher">
<application android:name="${applicationName}" android:label="Platform Interaction" android:icon="@mipmap/ic_launcher">
<activity android:name="com.yourcompany.platforminteraction.MainActivity"
android:launchMode="singleTop"
android:theme="@android:style/Theme.Black.NoTitleBar"
......@@ -28,5 +28,10 @@ found in the LICENSE file. -->
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- 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" />
</application>
</manifest>
......@@ -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);
......
......@@ -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. -->
<application
android:name="io.flutter.app.FlutterApplication"
android:name="${applicationName}"
android:label="release_smoke_test"
android:icon="@mipmap/ic_launcher">
<activity
......
......@@ -16,7 +16,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. -->
<application android:name="io.flutter.app.FlutterApplication" android:label="IntegrationUI">
<application android:name="${applicationName}" android:label="IntegrationUI">
<activity android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="@android:style/Theme.Black.NoTitleBar"
......
......@@ -10,7 +10,7 @@ found in the LICENSE file. -->
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<application
android:name="io.flutter.app.FlutterApplication"
android:name="${applicationName}"
android:label="manual_tests"
android:icon="@mipmap/ic_launcher">
<activity
......
......@@ -36,6 +36,7 @@ class BuildApkCommand extends BuildSubCommand {
usesAnalyzeSizeFlag();
addAndroidSpecificBuildOptions(hide: !verboseHelp);
addMultidexOption();
addIgnoreDeprecationOption();
argParser
..addFlag('split-per-abi',
negatable: false,
......@@ -54,6 +55,9 @@ class BuildApkCommand extends BuildSubCommand {
@override
final String name = 'apk';
@override
DeprecationBehavior get deprecationBehavior => boolArg('ignore-deprecation') ? DeprecationBehavior.ignore : DeprecationBehavior.exit;
@override
Future<Set<DevelopmentArtifact>> get requiredArtifacts async => <DevelopmentArtifact>{
DevelopmentArtifact.androidGenSnapshot,
......
......@@ -40,6 +40,7 @@ class BuildAppBundleCommand extends BuildSubCommand {
usesAnalyzeSizeFlag();
addAndroidSpecificBuildOptions(hide: !verboseHelp);
addMultidexOption();
addIgnoreDeprecationOption();
argParser.addMultiOption('target-platform',
splitCommas: true,
defaultsTo: <String>['android-arm', 'android-arm64', 'android-x64'],
......@@ -70,6 +71,9 @@ class BuildAppBundleCommand extends BuildSubCommand {
@override
final String name = 'appbundle';
@override
DeprecationBehavior get deprecationBehavior => boolArg('ignore-deprecation') ? DeprecationBehavior.ignore : DeprecationBehavior.exit;
@override
Future<Set<DevelopmentArtifact>> get requiredArtifacts async => <DevelopmentArtifact>{
DevelopmentArtifact.androidGenSnapshot,
......
......@@ -250,6 +250,7 @@ class RunCommand extends RunCommandBase {
// without needing to know the port.
addPublishPort(verboseHelp: verboseHelp);
addMultidexOption();
addIgnoreDeprecationOption();
argParser
..addFlag('enable-software-rendering',
negatable: false,
......@@ -341,6 +342,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.';
......@@ -474,6 +479,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 &&
......
......@@ -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<void> regeneratePlatformSpecificTooling() async {
Future<void> 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,24 +487,7 @@ class AndroidProject extends FlutterProjectPlatform {
return parent.directory.childDirectory('build');
}
Future<void> ensureReadyForPlatformSpecificTooling() async {
if (getEmbeddingVersion() == AndroidEmbeddingVersion.v1) {
globals.printStatus(
"""
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Warning
──────────────────────────────────────────────────────────────────────────────
Your Flutter application is created using an older version of the Android
embedding. It's being deprecated in favor of Android embedding v2. Follow the
steps at
https://flutter.dev/go/android-project-migration
to migrate your project.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
"""
);
}
Future<void> ensureReadyForPlatformSpecificTooling({DeprecationBehavior deprecationBehavior = DeprecationBehavior.none}) async {
if (isModule && _shouldRegenerateFromTemplate()) {
await _regenerateLibrary();
// Add ephemeral host app, if an editable host app does not already exist.
......@@ -553,6 +545,41 @@ to migrate your project.
);
}
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
......@@ -572,6 +599,12 @@ to migrate your project.
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') {
......@@ -596,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);
......
......@@ -178,6 +178,8 @@ abstract class FlutterCommand extends Command<void> {
bool _usesIpv6Flag = false;
DeprecationBehavior get deprecationBehavior => DeprecationBehavior.none;
bool get shouldRunPub => _usesPubOption && boolArg('pub');
bool get shouldUpdateCache => true;
......@@ -822,6 +824,15 @@ abstract class FlutterCommand extends Command<void> {
);
}
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);
......@@ -1246,8 +1257,10 @@ abstract class FlutterCommand extends Command<void> {
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,
......
......@@ -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('''
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.v1">
<application
android:name="io.flutter.app.FlutterApplication">
</application>
</manifest>
''', 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>[device]
..targetDevices = <Device>[device];
final RunCommand command = RunCommand();
await expectLater(createTestCommandRunner(command).run(<String>[
'run',
'--pub',
]), throwsToolExit(message: 'Build failed due to use of deprecated Android v1 embedding.'));
}, overrides: <Type, Generator>{
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('''
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.v1">
<application >
<meta-data
android:name="flutterEmbedding"
android:value="1" />
</application>
</manifest>
''', 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>[device]
..targetDevices = <Device>[device];
final RunCommand command = RunCommand();
await expectLater(createTestCommandRunner(command).run(<String>[
'run',
'--pub',
]), throwsToolExit(message: 'Build failed due to use of deprecated Android v1 embedding.'));
}, overrides: <Type, Generator>{
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');
......@@ -466,6 +551,10 @@ class FakeDeviceManager extends Fake implements DeviceManager {
}
}
class FakeAndroidSdk extends Fake implements AndroidSdk {
@override
String get adbPath => 'adb';
}
class TestRunCommand extends RunCommand {
@override
......
......@@ -182,7 +182,28 @@ void main() {
// v1 embedding, as opposed to having <meta-data
// android:name="flutterEmbedding" android:value="2" />.
await project.regeneratePlatformSpecificTooling();
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 <manifest> already indicates
// v1 embedding, as opposed to having <meta-data
// android:name="flutterEmbedding" android:value="2" />.
await expectToolExitLater(
Future<dynamic>.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 <manifest> already indicates
// v1 embedding, as opposed to having <meta-data
// android:name="flutterEmbedding" android:value="2" />.
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 {
......
......@@ -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. -->
<application
android:name="io.flutter.app.FlutterApplication"
android:name="${applicationName}"
android:label="integration_test_example"
android:icon="@mipmap/ic_launcher">
<activity
......
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