diff --git a/packages/flutter_tools/lib/src/ios/devices.dart b/packages/flutter_tools/lib/src/ios/devices.dart index 52f586390a..394f5a39a9 100644 --- a/packages/flutter_tools/lib/src/ios/devices.dart +++ b/packages/flutter_tools/lib/src/ios/devices.dart @@ -680,6 +680,14 @@ class IOSDevice extends Device { localUri = await Future.any( >[vmUrlFromMDns, vmUrlFromLogs] ); + + // If the first future to return is null, wait for the other to complete. + if (localUri == null) { + final List vmUrls = await Future.wait( + >[vmUrlFromMDns, vmUrlFromLogs] + ); + localUri = vmUrls.where((Uri? vmUrl) => vmUrl != null).firstOrNull; + } } else { localUri = await vmServiceDiscovery?.uri; // If the `ios-deploy` debugger loses connection before it finds the diff --git a/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart b/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart index 117888a844..0e03fb9329 100644 --- a/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart @@ -904,6 +904,68 @@ void main() { }, overrides: { MDnsVmServiceDiscovery: () => FakeMDnsVmServiceDiscovery(), }); + + group('IOSDevice.startApp attaches in debug mode via device logging', () { + late FakeMDnsVmServiceDiscovery mdnsDiscovery; + setUp(() { + mdnsDiscovery = FakeMDnsVmServiceDiscovery(returnsNull: true); + }); + + testUsingContext('when mDNS fails', () async { + final FileSystem fileSystem = MemoryFileSystem.test(); + final FakeProcessManager processManager = FakeProcessManager.empty(); + + final Directory temporaryXcodeProjectDirectory = fileSystem.systemTempDirectory.childDirectory('flutter_empty_xcode.rand0'); + final Directory bundleLocation = fileSystem.currentDirectory; + final IOSDevice device = setUpIOSDevice( + processManager: processManager, + fileSystem: fileSystem, + isCoreDevice: true, + coreDeviceControl: FakeIOSCoreDeviceControl(), + xcodeDebug: FakeXcodeDebug( + expectedProject: XcodeDebugProject( + scheme: 'Runner', + xcodeWorkspace: temporaryXcodeProjectDirectory.childDirectory('Runner.xcworkspace'), + xcodeProject: temporaryXcodeProjectDirectory.childDirectory('Runner.xcodeproj'), + hostAppProjectName: 'Runner', + ), + expectedDeviceId: '123', + expectedLaunchArguments: ['--enable-dart-profiling'], + expectedBundlePath: bundleLocation.path, + ) + ); + final IOSApp iosApp = PrebuiltIOSApp( + projectBundleId: 'app', + bundleName: 'Runner', + uncompressedBundle: bundleLocation, + applicationPackage: bundleLocation, + ); + final FakeDeviceLogReader deviceLogReader = FakeDeviceLogReader(); + + device.portForwarder = const NoOpDevicePortForwarder(); + device.setLogReader(iosApp, deviceLogReader); + + unawaited(mdnsDiscovery.completer.future.whenComplete(() { + // Start writing messages to the log reader. + Timer.run(() { + deviceLogReader.addLine('Foo'); + deviceLogReader.addLine('The Dart VM service is listening on http://127.0.0.1:456'); + }); + })); + + final LaunchResult launchResult = await device.startApp(iosApp, + prebuiltApplication: true, + debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug), + platformArgs: {}, + ); + + expect(launchResult.started, true); + expect(launchResult.hasVmService, true); + expect(await device.stopApp(iosApp), true); + }, overrides: { + MDnsVmServiceDiscovery: () => mdnsDiscovery, + }); + }); }); }); } @@ -974,6 +1036,10 @@ class FakeDevicePortForwarder extends Fake implements DevicePortForwarder { } class FakeMDnsVmServiceDiscovery extends Fake implements MDnsVmServiceDiscovery { + FakeMDnsVmServiceDiscovery({this.returnsNull = false}); + bool returnsNull; + + Completer completer = Completer(); @override Future getVMServiceUriForLaunch( String applicationId, @@ -984,6 +1050,11 @@ class FakeMDnsVmServiceDiscovery extends Fake implements MDnsVmServiceDiscovery bool useDeviceIPAsHost = false, Duration timeout = Duration.zero, }) async { + completer.complete(); + if (returnsNull) { + return null; + } + return Uri.tryParse('http://0.0.0.0:1234'); } }