diff --git a/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart b/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart index a0de64f755a..54307a49dbb 100644 --- a/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart +++ b/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart @@ -130,6 +130,9 @@ class ResidentWebRunner extends ResidentRunner { FlutterDevice? get device => flutterDevices.first; final FlutterProject flutterProject; + // Mapping from service name to service method. + final Map _registeredMethodsForService = {}; + // Used with the new compiler to generate a bootstrap file containing plugins // and platform initialization. Directory? _generatedEntrypointDirectory; @@ -156,6 +159,7 @@ class ResidentWebRunner extends ResidentRunner { ConnectionResult? _connectionResult; StreamSubscription? _stdOutSub; StreamSubscription? _stdErrSub; + StreamSubscription? _serviceSub; StreamSubscription? _extensionEventSub; bool _exited = false; WipConnection? _wipConnection; @@ -190,8 +194,10 @@ class ResidentWebRunner extends ResidentRunner { await residentDevtoolsHandler!.shutdown(); await _stdOutSub?.cancel(); await _stdErrSub?.cancel(); + await _serviceSub?.cancel(); await _extensionEventSub?.cancel(); await device!.device!.stopApp(null); + _registeredMethodsForService.clear(); try { _generatedEntrypointDirectory?.deleteSync(recursive: true); } on FileSystemException { @@ -444,7 +450,11 @@ Please provide a valid TCP port (an integer between 0 and 65535, inclusive). if (!deviceIsDebuggable) { _logger.printStatus('Recompile complete. Page requires refresh.'); } else if (isRunningDebug) { - await _vmService.service.callMethod('hotRestart'); + // If the hot-restart service extension method is registered, then use + // it. Otherwise, default to calling "hotRestart" without a namespace. + final String hotRestartMethod = + _registeredMethodsForService['hotRestart'] ?? 'hotRestart'; + await _vmService.service.callMethod(hotRestartMethod); } else { // On non-debug builds, a hard refresh is required to ensure the // up to date sources are loaded. @@ -615,17 +625,24 @@ Please provide a valid TCP port (an integer between 0 and 65535, inclusive). _stdOutSub = _vmService.service.onStdoutEvent.listen(onLogEvent); _stdErrSub = _vmService.service.onStderrEvent.listen(onLogEvent); + _serviceSub = _vmService.service.onServiceEvent.listen(_onServiceEvent); try { await _vmService.service.streamListen(vmservice.EventStreams.kStdout); } on vmservice.RPCError { // It is safe to ignore this error because we expect an error to be - // thrown if we're not already subscribed. + // thrown if we're already subscribed. } try { await _vmService.service.streamListen(vmservice.EventStreams.kStderr); } on vmservice.RPCError { // It is safe to ignore this error because we expect an error to be - // thrown if we're not already subscribed. + // thrown if we're already subscribed. + } + try { + await _vmService.service.streamListen(vmservice.EventStreams.kService); + } on vmservice.RPCError { + // It is safe to ignore this error because we expect an error to be + // thrown if we're already subscribed. } try { await _vmService.service.streamListen(vmservice.EventStreams.kIsolate); @@ -703,6 +720,18 @@ Please provide a valid TCP port (an integer between 0 and 65535, inclusive). await device!.exitApps(); appFinished(); } + + void _onServiceEvent(vmservice.Event e) { + if (e.kind == vmservice.EventKind.kServiceRegistered) { + final String serviceName = e.service!; + _registeredMethodsForService[serviceName] = e.method!; + } + + if (e.kind == vmservice.EventKind.kServiceUnregistered) { + final String serviceName = e.service!; + _registeredMethodsForService.remove(serviceName); + } + } } Uri _httpUriFromWebsocketUri(Uri websocketUri) { diff --git a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart index 761c4168c4e..775e926a1e2 100644 --- a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart @@ -62,6 +62,9 @@ const List kAttachLogExpectations = const List kAttachIsolateExpectations = [ + FakeVmServiceRequest(method: 'streamListen', args: { + 'streamId': 'Service', + }), FakeVmServiceRequest(method: 'streamListen', args: { 'streamId': 'Isolate', }),