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

This commit is contained in:
Gary Qian 2021-11-11 14:49:35 -08:00 committed by GitHub
parent 9659db7be8
commit eabb7cbc34
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 278 additions and 64 deletions

View File

@ -7,8 +7,8 @@ found in the LICENSE file. -->
<uses-permission android:name="android.permission.INTERNET"/> <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" <activity android:name="io.flutter.embedding.android.FlutterActivity"
android:exported="true" android:exported="true"
android:launchMode="singleTop" android:launchMode="singleTop"
android:theme="@android:style/Theme.Black.NoTitleBar" android:theme="@android:style/Theme.Black.NoTitleBar"
@ -20,5 +20,8 @@ found in the LICENSE file. -->
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter> </intent-filter>
</activity> </activity>
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application> </application>
</manifest> </manifest>

View File

@ -17,7 +17,7 @@ found in the LICENSE file. -->
additional functionality it is fine to subclass or reimplement additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. --> FlutterApplication and put your custom class here. -->
<application <application
android:name="io.flutter.app.FlutterApplication" android:name="${applicationName}"
android:label="macrobenchmarks" android:label="macrobenchmarks"
android:icon="@mipmap/ic_launcher"> android:icon="@mipmap/ic_launcher">
<activity <activity

View File

@ -7,8 +7,8 @@ found in the LICENSE file. -->
<uses-permission android:name="android.permission.INTERNET"/> <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" <activity android:name="io.flutter.embedding.android.FlutterActivity"
android:launchMode="singleTop" android:launchMode="singleTop"
android:theme="@android:style/Theme.Black.NoTitleBar" android:theme="@android:style/Theme.Black.NoTitleBar"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"

View File

@ -7,7 +7,7 @@ found in the LICENSE file. -->
<uses-permission android:name="android.permission.INTERNET"/> <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" <activity android:name=".DummyPlatformViewActivity"
android:launchMode="singleTop" android:launchMode="singleTop"
android:theme="@android:style/Theme.Black.NoTitleBar" android:theme="@android:style/Theme.Black.NoTitleBar"

View File

@ -7,7 +7,7 @@ found in the LICENSE file. -->
<uses-permission android:name="android.permission.INTERNET"/> <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" <activity android:name=".DummyPlatformViewActivity"
android:launchMode="singleTop" android:launchMode="singleTop"
android:theme="@android:style/Theme.Black.NoTitleBar" android:theme="@android:style/Theme.Black.NoTitleBar"

View File

@ -12,7 +12,7 @@ found in the LICENSE file. -->
additional functionality it is fine to subclass or reimplement additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. --> FlutterApplication and put your custom class here. -->
<application <application
android:name="io.flutter.app.FlutterApplication" android:name="${applicationName}"
android:label="abstract_method_smoke_test"> android:label="abstract_method_smoke_test">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"

View File

@ -10,7 +10,7 @@ found in the LICENSE file. -->
additional functionality it is fine to subclass or reimplement additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. --> FlutterApplication and put your custom class here. -->
<application <application
android:name="io.flutter.app.FlutterApplication" android:name="${applicationName}"
android:label="android_embedding_v2_smoke_test"> android:label="android_embedding_v2_smoke_test">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"

View File

@ -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 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 additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. --> 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" <activity android:name="com.yourcompany.platforminteraction.MainActivity"
android:launchMode="singleTop" android:launchMode="singleTop"
android:theme="@android:style/Theme.Black.NoTitleBar" android:theme="@android:style/Theme.Black.NoTitleBar"
@ -28,5 +28,10 @@ found in the LICENSE file. -->
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter> </intent-filter>
</activity> </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> </application>
</manifest> </manifest>

View File

@ -16,13 +16,16 @@ import android.os.Bundle;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.view.WindowManager; import android.view.WindowManager;
import android.content.Context; 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.MethodCall;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler; import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugins.GeneratedPluginRegistrant; import io.flutter.plugins.GeneratedPluginRegistrant;
import io.flutter.view.FlutterView;
import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeProvider; import android.view.accessibility.AccessibilityNodeProvider;
@ -30,10 +33,10 @@ import android.view.accessibility.AccessibilityNodeInfo;
public class MainActivity extends FlutterActivity { public class MainActivity extends FlutterActivity {
@Override @Override
protected void onCreate(Bundle savedInstanceState) { public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
super.onCreate(savedInstanceState); GeneratedPluginRegistrant.registerWith(flutterEngine);
GeneratedPluginRegistrant.registerWith(this); new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), "semantics")
new MethodChannel(getFlutterView(), "semantics").setMethodCallHandler(new SemanticsTesterMethodHandler()); .setMethodCallHandler(new SemanticsTesterMethodHandler());
} }
class SemanticsTesterMethodHandler implements MethodCallHandler { class SemanticsTesterMethodHandler implements MethodCallHandler {
@ -41,7 +44,7 @@ public class MainActivity extends FlutterActivity {
@Override @Override
public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) { public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
FlutterView flutterView = getFlutterView(); FlutterView flutterView = findViewById(FLUTTER_VIEW_ID);
AccessibilityNodeProvider provider = flutterView.getAccessibilityNodeProvider(); AccessibilityNodeProvider provider = flutterView.getAccessibilityNodeProvider();
DisplayMetrics displayMetrics = new DisplayMetrics(); DisplayMetrics displayMetrics = new DisplayMetrics();
WindowManager wm = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE); WindowManager wm = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);

View File

@ -9,7 +9,7 @@ found in the LICENSE file. -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application <application
android:name="io.flutter.app.FlutterApplication" android:name="${applicationName}"
android:label="platform_views"> android:label="platform_views">
<activity <activity
android:exported="true" android:exported="true"

View File

@ -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 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 additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. --> 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" <activity android:name=".MainActivity"
android:launchMode="singleTop" android:launchMode="singleTop"
android:theme="@android:style/Theme.Black.NoTitleBar" android:theme="@android:style/Theme.Black.NoTitleBar"

View File

@ -8,7 +8,7 @@ found in the LICENSE file. -->
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<application <application
android:name="io.flutter.app.FlutterApplication" android:name="${applicationName}"
android:label="external_ui"> android:label="external_ui">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
@ -21,5 +21,10 @@ found in the LICENSE file. -->
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter> </intent-filter>
</activity> </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> </application>
</manifest> </manifest>

View File

@ -8,7 +8,7 @@ found in the LICENSE file. -->
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<application <application
android:name="io.flutter.app.FlutterApplication" android:name="${applicationName}"
android:label="flavors"> android:label="flavors">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
@ -21,5 +21,10 @@ found in the LICENSE file. -->
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter> </intent-filter>
</activity> </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> </application>
</manifest> </manifest>

View File

@ -6,21 +6,19 @@ package com.yourcompany.flavors;
import android.os.Bundle; 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.MethodCall;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugins.GeneratedPluginRegistrant;
public class MainActivity extends FlutterActivity { public class MainActivity extends FlutterActivity {
@Override @Override
protected void onCreate(Bundle savedInstanceState) { public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
super.onCreate(savedInstanceState); GeneratedPluginRegistrant.registerWith(flutterEngine);
GeneratedPluginRegistrant.registerWith(this); new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), "flavor")
new MethodChannel(getFlutterView(), "flavor").setMethodCallHandler(new MethodChannel.MethodCallHandler() { .setMethodCallHandler(
@Override (call, result) -> {
public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
result.success(BuildConfig.FLAVOR); result.success(BuildConfig.FLAVOR);
} }
}); );
} }
} }

View File

@ -8,7 +8,7 @@ found in the LICENSE file. -->
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<application <application
android:name="io.flutter.app.FlutterApplication" android:name="${applicationName}"
android:label="flavors"> android:label="flavors">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
@ -21,5 +21,10 @@ found in the LICENSE file. -->
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter> </intent-filter>
</activity> </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> </application>
</manifest> </manifest>

View File

@ -4,15 +4,6 @@
package com.yourcompany.flavors; package com.yourcompany.flavors;
import android.os.Bundle; import io.flutter.embedding.android.FlutterActivity;
import io.flutter.app.FlutterActivity; public class MainActivity extends FlutterActivity {}
import io.flutter.plugins.GeneratedPluginRegistrant;
public class MainActivity extends FlutterActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
}
}

View File

@ -9,7 +9,7 @@ found in the LICENSE file. -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application <application
android:name="io.flutter.app.FlutterApplication" android:name="${applicationName}"
android:label="platform_views"> android:label="platform_views">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"

View File

@ -10,7 +10,7 @@ found in the LICENSE file. -->
additional functionality it is fine to subclass or reimplement additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. --> FlutterApplication and put your custom class here. -->
<application <application
android:name="io.flutter.app.FlutterApplication" android:name="${applicationName}"
android:label="non_nullable" android:label="non_nullable"
android:icon="@mipmap/ic_launcher"> android:icon="@mipmap/ic_launcher">
<activity <activity

View File

@ -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 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 additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. --> 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" <activity android:name="com.yourcompany.platforminteraction.MainActivity"
android:launchMode="singleTop" android:launchMode="singleTop"
android:theme="@android:style/Theme.Black.NoTitleBar" android:theme="@android:style/Theme.Black.NoTitleBar"
@ -28,5 +28,10 @@ found in the LICENSE file. -->
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter> </intent-filter>
</activity> </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> </application>
</manifest> </manifest>

View File

@ -6,16 +6,10 @@ package com.yourcompany.platforminteraction;
import android.os.Bundle; import android.os.Bundle;
import io.flutter.app.FlutterActivity; import io.flutter.embedding.android.FlutterActivity;
import io.flutter.plugin.common.*; import io.flutter.plugin.common.*;
import io.flutter.plugins.GeneratedPluginRegistrant;
public class MainActivity extends FlutterActivity { public class MainActivity extends FlutterActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
}
public void finish() { public void finish() {
BasicMessageChannel channel = BasicMessageChannel channel =
new BasicMessageChannel<>(getFlutterView(), "navigation-test", StringCodec.INSTANCE); new BasicMessageChannel<>(getFlutterView(), "navigation-test", StringCodec.INSTANCE);

View File

@ -11,7 +11,7 @@ found in the LICENSE file. -->
additional functionality it is fine to subclass or reimplement additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. --> FlutterApplication and put your custom class here. -->
<application <application
android:name="io.flutter.app.FlutterApplication" android:name="${applicationName}"
android:label="release_smoke_test" android:label="release_smoke_test"
android:icon="@mipmap/ic_launcher"> android:icon="@mipmap/ic_launcher">
<activity <activity

View File

@ -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 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 additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. --> 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" <activity android:name=".MainActivity"
android:launchMode="singleTop" android:launchMode="singleTop"
android:theme="@android:style/Theme.Black.NoTitleBar" android:theme="@android:style/Theme.Black.NoTitleBar"

View File

@ -10,7 +10,7 @@ found in the LICENSE file. -->
additional functionality it is fine to subclass or reimplement additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. --> FlutterApplication and put your custom class here. -->
<application <application
android:name="io.flutter.app.FlutterApplication" android:name="${applicationName}"
android:label="manual_tests" android:label="manual_tests"
android:icon="@mipmap/ic_launcher"> android:icon="@mipmap/ic_launcher">
<activity <activity

View File

@ -36,6 +36,7 @@ class BuildApkCommand extends BuildSubCommand {
usesAnalyzeSizeFlag(); usesAnalyzeSizeFlag();
addAndroidSpecificBuildOptions(hide: !verboseHelp); addAndroidSpecificBuildOptions(hide: !verboseHelp);
addMultidexOption(); addMultidexOption();
addIgnoreDeprecationOption();
argParser argParser
..addFlag('split-per-abi', ..addFlag('split-per-abi',
negatable: false, negatable: false,
@ -54,6 +55,9 @@ class BuildApkCommand extends BuildSubCommand {
@override @override
final String name = 'apk'; final String name = 'apk';
@override
DeprecationBehavior get deprecationBehavior => boolArg('ignore-deprecation') ? DeprecationBehavior.ignore : DeprecationBehavior.exit;
@override @override
Future<Set<DevelopmentArtifact>> get requiredArtifacts async => <DevelopmentArtifact>{ Future<Set<DevelopmentArtifact>> get requiredArtifacts async => <DevelopmentArtifact>{
DevelopmentArtifact.androidGenSnapshot, DevelopmentArtifact.androidGenSnapshot,

View File

@ -42,6 +42,7 @@ class BuildAppBundleCommand extends BuildSubCommand {
usesAnalyzeSizeFlag(); usesAnalyzeSizeFlag();
addAndroidSpecificBuildOptions(hide: !verboseHelp); addAndroidSpecificBuildOptions(hide: !verboseHelp);
addMultidexOption(); addMultidexOption();
addIgnoreDeprecationOption();
argParser.addMultiOption('target-platform', argParser.addMultiOption('target-platform',
splitCommas: true, splitCommas: true,
defaultsTo: <String>['android-arm', 'android-arm64', 'android-x64'], defaultsTo: <String>['android-arm', 'android-arm64', 'android-x64'],
@ -72,6 +73,9 @@ class BuildAppBundleCommand extends BuildSubCommand {
@override @override
final String name = 'appbundle'; final String name = 'appbundle';
@override
DeprecationBehavior get deprecationBehavior => boolArg('ignore-deprecation') ? DeprecationBehavior.ignore : DeprecationBehavior.exit;
@override @override
Future<Set<DevelopmentArtifact>> get requiredArtifacts async => <DevelopmentArtifact>{ Future<Set<DevelopmentArtifact>> get requiredArtifacts async => <DevelopmentArtifact>{
DevelopmentArtifact.androidGenSnapshot, DevelopmentArtifact.androidGenSnapshot,

View File

@ -251,6 +251,7 @@ class RunCommand extends RunCommandBase {
// without needing to know the port. // without needing to know the port.
addPublishPort(verboseHelp: verboseHelp); addPublishPort(verboseHelp: verboseHelp);
addMultidexOption(); addMultidexOption();
addIgnoreDeprecationOption();
argParser argParser
..addFlag('enable-software-rendering', ..addFlag('enable-software-rendering',
negatable: false, negatable: false,
@ -342,6 +343,10 @@ class RunCommand extends RunCommandBase {
@override @override
final String name = 'run'; final String name = 'run';
@override
DeprecationBehavior get deprecationBehavior => boolArg('ignore-deprecation') ? DeprecationBehavior.ignore : _deviceDeprecationBehavior;
DeprecationBehavior _deviceDeprecationBehavior = DeprecationBehavior.none;
@override @override
final String description = 'Run your Flutter app on an attached device.'; 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.' '--${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 // Only support "web mode" with a single web device due to resident runner
// refactoring required otherwise. // refactoring required otherwise.
webMode = featureFlags.isWebEnabled && webMode = featureFlags.isWebEnabled &&

View File

@ -20,6 +20,7 @@ import 'flutter_manifest.dart';
import 'flutter_plugins.dart'; import 'flutter_plugins.dart';
import 'globals.dart' as globals; import 'globals.dart' as globals;
import 'platform_plugins.dart'; import 'platform_plugins.dart';
import 'reporting/reporting.dart';
import 'template.dart'; import 'template.dart';
import 'xcode_project.dart'; import 'xcode_project.dart';
@ -282,7 +283,7 @@ class FlutterProject {
/// registrants for app and module projects only. /// registrants for app and module projects only.
/// ///
/// Will not create project platform directories if they do not already exist. /// 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( return ensureReadyForPlatformSpecificTooling(
androidPlatform: android.existsSync(), androidPlatform: android.existsSync(),
iosPlatform: ios.existsSync(), iosPlatform: ios.existsSync(),
@ -293,6 +294,7 @@ class FlutterProject {
windowsPlatform: featureFlags.isWindowsEnabled && windows.existsSync(), windowsPlatform: featureFlags.isWindowsEnabled && windows.existsSync(),
webPlatform: featureFlags.isWebEnabled && web.existsSync(), webPlatform: featureFlags.isWebEnabled && web.existsSync(),
winUwpPlatform: featureFlags.isWindowsUwpEnabled && windowsUwp.existsSync(), winUwpPlatform: featureFlags.isWindowsUwpEnabled && windowsUwp.existsSync(),
deprecationBehavior: deprecationBehavior,
); );
} }
@ -306,13 +308,14 @@ class FlutterProject {
bool windowsPlatform = false, bool windowsPlatform = false,
bool webPlatform = false, bool webPlatform = false,
bool winUwpPlatform = false, bool winUwpPlatform = false,
DeprecationBehavior deprecationBehavior = DeprecationBehavior.none,
}) async { }) async {
if (!directory.existsSync() || hasExampleApp || isPlugin) { if (!directory.existsSync() || hasExampleApp || isPlugin) {
return; return;
} }
await refreshPluginsList(this, iosPlatform: iosPlatform, macOSPlatform: macOSPlatform); await refreshPluginsList(this, iosPlatform: iosPlatform, macOSPlatform: macOSPlatform);
if (androidPlatform) { if (androidPlatform) {
await android.ensureReadyForPlatformSpecificTooling(); await android.ensureReadyForPlatformSpecificTooling(deprecationBehavior: deprecationBehavior);
} }
if (iosPlatform) { if (iosPlatform) {
await ios.ensureReadyForPlatformSpecificTooling(); 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 /// Returns a json encoded string containing the [appName], [version], and [buildNumber] that is used to generate version.json
String getVersionInfo() { String getVersionInfo() {
final String? buildName = manifest.buildName; final String? buildName = manifest.buildName;
@ -478,7 +487,7 @@ class AndroidProject extends FlutterProjectPlatform {
return parent.directory.childDirectory('build'); return parent.directory.childDirectory('build');
} }
Future<void> ensureReadyForPlatformSpecificTooling() async { Future<void> ensureReadyForPlatformSpecificTooling({DeprecationBehavior deprecationBehavior = DeprecationBehavior.none}) async {
if (isModule && _shouldRegenerateFromTemplate()) { if (isModule && _shouldRegenerateFromTemplate()) {
await _regenerateLibrary(); await _regenerateLibrary();
// Add ephemeral host app, if an editable host app does not already exist. // 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() { AndroidEmbeddingVersion getEmbeddingVersion() {
if (isModule) { if (isModule) {
// A module type's Android project is used in add-to-app scenarios and // 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. ' throwToolExit('Error reading $appManifestFile even though it exists. '
'Please ensure that you have read permission to this file and try again.'); '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')) { for (final XmlElement metaData in document.findAllElements('meta-data')) {
final String? name = metaData.getAttribute('android:name'); final String? name = metaData.getAttribute('android:name');
if (name == 'flutterEmbedding') { if (name == 'flutterEmbedding') {
@ -579,6 +629,16 @@ enum AndroidEmbeddingVersion {
v2, 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. /// Represents the web sub-project of a Flutter project.
class WebProject extends FlutterProjectPlatform { class WebProject extends FlutterProjectPlatform {
WebProject._(this.parent); WebProject._(this.parent);

View File

@ -181,6 +181,8 @@ abstract class FlutterCommand extends Command<void> {
bool _usesFatalWarnings = false; bool _usesFatalWarnings = false;
DeprecationBehavior get deprecationBehavior => DeprecationBehavior.none;
bool get shouldRunPub => _usesPubOption && boolArg('pub'); bool get shouldRunPub => _usesPubOption && boolArg('pub');
bool get shouldUpdateCache => true; bool get shouldUpdateCache => true;
@ -834,6 +836,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. /// Adds build options common to all of the desktop build commands.
void addCommonDesktopBuildOptions({ required bool verboseHelp }) { void addCommonDesktopBuildOptions({ required bool verboseHelp }) {
addBuildModeFlags(verboseHelp: verboseHelp); addBuildModeFlags(verboseHelp: verboseHelp);
@ -1263,8 +1274,10 @@ abstract class FlutterCommand extends Command<void> {
await validateCommand(); await validateCommand();
if (shouldRunPub) {
final FlutterProject project = FlutterProject.current(); final FlutterProject project = FlutterProject.current();
project.checkForDeprecation(deprecationBehavior: deprecationBehavior);
if (shouldRunPub) {
final Environment environment = Environment( final Environment environment = Environment(
artifacts: globals.artifacts!, artifacts: globals.artifacts!,
logger: globals.logger, logger: globals.logger,

View File

@ -14,12 +14,15 @@ import 'dart:async';
import 'package:file/file.dart'; import 'package:file/file.dart';
import 'package:file/memory.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/application_package.dart';
import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/logger.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/base/user_messages.dart';
import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/cache.dart';
@ -217,6 +220,88 @@ void main() {
Cache: () => Cache.test(processManager: FakeProcessManager.any()), 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 { testUsingContext('shows unsupported devices when no supported devices are found', () async {
final RunCommand command = RunCommand(); final RunCommand command = RunCommand();
final FakeDevice mockDevice = FakeDevice(targetPlatform: TargetPlatform.android_arm, isLocalEmulator: true, sdkNameAndVersion: 'api-14'); 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 { class TestRunCommand extends RunCommand {
@override @override

View File

@ -182,8 +182,29 @@ void main() {
// v1 embedding, as opposed to having <meta-data // v1 embedding, as opposed to having <meta-data
// android:name="flutterEmbedding" android:value="2" />. // android:name="flutterEmbedding" android:value="2" />.
await project.regeneratePlatformSpecificTooling(); project.checkForDeprecation(deprecationBehavior: DeprecationBehavior.none);
expect(testLogger.warningText, contains('https://github.com/flutter/flutter/wiki/Upgrading-pre-1.12-Android-projects')); 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 { _testInMemory('Android plugin without example app does not show a warning', () async {
final FlutterProject project = await aPluginProject(); final FlutterProject project = await aPluginProject();

View File

@ -11,7 +11,7 @@ found in the LICENSE file. -->
additional functionality it is fine to subclass or reimplement additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. --> FlutterApplication and put your custom class here. -->
<application <application
android:name="io.flutter.app.FlutterApplication" android:name="${applicationName}"
android:label="integration_test_example" android:label="integration_test_example"
android:icon="@mipmap/ic_launcher"> android:icon="@mipmap/ic_launcher">
<activity <activity