Separate hot reload and hot restart capabilities. (#24122)
diff --git a/packages/flutter_tools/lib/src/android/android_device.dart b/packages/flutter_tools/lib/src/android/android_device.dart
index 94b165e..601b04a 100644
--- a/packages/flutter_tools/lib/src/android/android_device.dart
+++ b/packages/flutter_tools/lib/src/android/android_device.dart
@@ -469,7 +469,10 @@
}
@override
- bool get supportsHotMode => true;
+ bool get supportsHotReload => true;
+
+ @override
+ bool get supportsHotRestart => true;
@override
Future<bool> stopApp(ApplicationPackage app) {
diff --git a/packages/flutter_tools/lib/src/commands/attach.dart b/packages/flutter_tools/lib/src/commands/attach.dart
index b2282c1..a4d9d6c 100644
--- a/packages/flutter_tools/lib/src/commands/attach.dart
+++ b/packages/flutter_tools/lib/src/commands/attach.dart
@@ -209,7 +209,9 @@
}
} finally {
final List<ForwardedPort> ports = device.portForwarder.forwardedPorts.toList();
- ports.forEach(device.portForwarder.unforward);
+ for (ForwardedPort port in ports) {
+ await device.portForwarder.unforward(port);
+ }
}
return null;
}
diff --git a/packages/flutter_tools/lib/src/commands/daemon.dart b/packages/flutter_tools/lib/src/commands/daemon.dart
index f8799ae..5bf05f4 100644
--- a/packages/flutter_tools/lib/src/commands/daemon.dart
+++ b/packages/flutter_tools/lib/src/commands/daemon.dart
@@ -458,7 +458,7 @@
}
bool isRestartSupported(bool enableHotReload, Device device) =>
- enableHotReload && device.supportsHotMode;
+ enableHotReload && device.supportsHotRestart;
Future<OperationResult> _inProgressHotReload;
diff --git a/packages/flutter_tools/lib/src/commands/run.dart b/packages/flutter_tools/lib/src/commands/run.dart
index 461c4fc..cb0e66e 100644
--- a/packages/flutter_tools/lib/src/commands/run.dart
+++ b/packages/flutter_tools/lib/src/commands/run.dart
@@ -336,8 +336,8 @@
if (hotMode) {
for (Device device in devices) {
- if (!device.supportsHotMode)
- throwToolExit('Hot mode is not supported by ${device.name}. Run with --no-hot.');
+ if (!device.supportsHotReload)
+ throwToolExit('Hot reload is not supported by ${device.name}. Run with --no-hot.');
}
}
diff --git a/packages/flutter_tools/lib/src/device.dart b/packages/flutter_tools/lib/src/device.dart
index 8225f4f..3c6d378 100644
--- a/packages/flutter_tools/lib/src/device.dart
+++ b/packages/flutter_tools/lib/src/device.dart
@@ -270,8 +270,11 @@
bool ipv6 = false,
});
- /// Does this device implement support for hot reloading / restarting?
- bool get supportsHotMode => true;
+ /// Whether this device implements support for hot reload.
+ bool get supportsHotReload => true;
+
+ /// Whether this device implements support for hot restart.
+ bool get supportsHotRestart => true;
/// Stop an app package on the current device.
Future<bool> stopApp(ApplicationPackage app);
diff --git a/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart b/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart
index 42ea084..dba2a3a 100644
--- a/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart
+++ b/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart
@@ -97,7 +97,10 @@
FuchsiaDevice(String id, { this.name }) : super(id);
@override
- bool get supportsHotMode => true;
+ bool get supportsHotReload => true;
+
+ @override
+ bool get supportsHotRestart => false;
@override
final String name;
diff --git a/packages/flutter_tools/lib/src/ios/devices.dart b/packages/flutter_tools/lib/src/ios/devices.dart
index d65689f..c55cb85 100644
--- a/packages/flutter_tools/lib/src/ios/devices.dart
+++ b/packages/flutter_tools/lib/src/ios/devices.dart
@@ -124,7 +124,10 @@
final String _sdkVersion;
@override
- bool get supportsHotMode => true;
+ bool get supportsHotReload => true;
+
+ @override
+ bool get supportsHotRestart => true;
@override
final String name;
diff --git a/packages/flutter_tools/lib/src/ios/simulators.dart b/packages/flutter_tools/lib/src/ios/simulators.dart
index 14b8dcb..69c8a1c 100644
--- a/packages/flutter_tools/lib/src/ios/simulators.dart
+++ b/packages/flutter_tools/lib/src/ios/simulators.dart
@@ -223,7 +223,10 @@
Future<bool> get isLocalEmulator async => true;
@override
- bool get supportsHotMode => true;
+ bool get supportsHotReload => true;
+
+ @override
+ bool get supportsHotRestart => true;
Map<ApplicationPackage, _IOSSimulatorLogReader> _logReaders;
_IOSSimulatorDevicePortForwarder _portForwarder;
diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart
index 05c9562..5be4191 100644
--- a/packages/flutter_tools/lib/src/resident_runner.dart
+++ b/packages/flutter_tools/lib/src/resident_runner.dart
@@ -460,6 +460,17 @@
bool get isRunningRelease => debuggingOptions.buildInfo.isRelease;
bool get supportsServiceProtocol => isRunningDebug || isRunningProfile;
+ /// Whether this runner can hot restart.
+ ///
+ /// To prevent scenarios where only a subset of devices are hot restarted,
+ /// the runner requires that all attached devices can support hot restart
+ /// before enabling it.
+ bool get canHotRestart {
+ return flutterDevices.every((FlutterDevice device) {
+ return device.device.supportsHotRestart;
+ });
+ }
+
/// Start the app and keep the process running during its lifetime.
Future<int> run({
Completer<DebugConnectionInfo> connectionInfoCompleter,
diff --git a/packages/flutter_tools/lib/src/run_hot.dart b/packages/flutter_tools/lib/src/run_hot.dart
index b0de03a..ded7a25 100644
--- a/packages/flutter_tools/lib/src/run_hot.dart
+++ b/packages/flutter_tools/lib/src/run_hot.dart
@@ -289,7 +289,16 @@
Future<void> handleTerminalCommand(String code) async {
final String lower = code.toLowerCase();
if (lower == 'r') {
- final OperationResult result = await restart(fullRestart: code == 'R');
+ OperationResult result;
+ if (code == 'R') {
+ // If hot restart is not supported for all devices, ignore the command.
+ if (!canHotRestart) {
+ return;
+ }
+ result = await restart(fullRestart: true);
+ } else {
+ result = await restart(fullRestart: false);
+ }
if (!result.isOk) {
// TODO(johnmccutchan): Attempt to determine the number of errors that
// occurred and tighten this message.
@@ -541,6 +550,9 @@
Future<OperationResult> restart({ bool fullRestart = false, bool pauseAfterRestart = false, String reason }) async {
final Stopwatch timer = Stopwatch()..start();
if (fullRestart) {
+ if (!canHotRestart) {
+ return OperationResult(1, 'hotRestart not supported');
+ }
final Status status = logger.startProgress(
'Performing hot restart...',
progressId: 'hot.restart',
@@ -780,9 +792,12 @@
@override
void printHelp({ @required bool details }) {
const String fire = '🔥';
+ String rawMessage = ' To hot reload changes while running, press "r". ';
+ if (canHotRestart) {
+ rawMessage += 'To hot restart (and rebuild state), press "R".';
+ }
final String message = terminal.color(
- fire + terminal.bolden(' To hot reload changes while running, press "r". '
- 'To hot restart (and rebuild state), press "R".'),
+ fire + terminal.bolden(rawMessage),
TerminalColor.red,
);
printStatus(message);