@@ -9,6 +9,7 @@ import 'package:process/process.dart';
99import 'package:vm_service/vm_service.dart' as vm_service;
1010
1111import '../application_package.dart' ;
12+ import '../base/common.dart' ;
1213import '../base/file_system.dart' ;
1314import '../base/io.dart' ;
1415import '../base/logger.dart' ;
@@ -21,6 +22,7 @@ import '../device.dart';
2122import '../device_port_forwarder.dart' ;
2223import '../globals.dart' as globals;
2324import '../macos/xcdevice.dart' ;
25+ import '../mdns_discovery.dart' ;
2426import '../project.dart' ;
2527import '../protocol_discovery.dart' ;
2628import '../vmservice.dart' ;
@@ -189,15 +191,6 @@ class IOSDevice extends Device {
189191 return majorVersionString != null ? int .tryParse (majorVersionString) ?? 0 : 0 ;
190192 }
191193
192- @override
193- bool get supportsHotReload => interfaceType == IOSDeviceConnectionInterface .usb;
194-
195- @override
196- bool get supportsHotRestart => interfaceType == IOSDeviceConnectionInterface .usb;
197-
198- @override
199- bool get supportsFlutterExit => interfaceType == IOSDeviceConnectionInterface .usb;
200-
201194 @override
202195 final String name;
203196
@@ -318,7 +311,11 @@ class IOSDevice extends Device {
318311 @visibleForTesting Duration ? discoveryTimeout,
319312 }) async {
320313 String ? packageId;
321-
314+ if (interfaceType == IOSDeviceConnectionInterface .network &&
315+ debuggingOptions.debuggingEnabled &&
316+ debuggingOptions.disablePortPublication) {
317+ throwToolExit ('Cannot start app on wirelessly tethered iOS device. Try running again with the --publish-port flag' );
318+ }
322319 if (! prebuiltApplication) {
323320 _logger.printTrace ('Building ${package .name } for $id ' );
324321
@@ -353,8 +350,10 @@ class IOSDevice extends Device {
353350 EnvironmentType .physical,
354351 route,
355352 platformArgs,
353+ ipv6: ipv6,
354+ interfaceType: interfaceType,
356355 );
357- final Status installStatus = _logger.startProgress (
356+ Status startAppStatus = _logger.startProgress (
358357 'Installing and launching...' ,
359358 );
360359 try {
@@ -379,9 +378,10 @@ class IOSDevice extends Device {
379378 deviceLogReader.debuggerStream = iosDeployDebugger;
380379 }
381380 }
381+ // Don't port foward if debugging with a network device.
382382 observatoryDiscovery = ProtocolDiscovery .observatory (
383383 deviceLogReader,
384- portForwarder: portForwarder,
384+ portForwarder: interfaceType == IOSDeviceConnectionInterface .network ? null : portForwarder,
385385 hostPort: debuggingOptions.hostVmServicePort,
386386 devicePort: debuggingOptions.deviceVmServicePort,
387387 ipv6: ipv6,
@@ -412,12 +412,59 @@ class IOSDevice extends Device {
412412 return LaunchResult .succeeded ();
413413 }
414414
415- _logger.printTrace ('Application launched on the device. Waiting for observatory url.' );
416- final Timer timer = Timer (discoveryTimeout ?? const Duration (seconds: 30 ), () {
417- _logger.printError ('iOS Observatory not discovered after 30 seconds. This is taking much longer than expected...' );
418- iosDeployDebugger? .pauseDumpBacktraceResume ();
415+ _logger.printTrace ('Application launched on the device. Waiting for Dart VM Service url.' );
416+
417+ final int defaultTimeout = interfaceType == IOSDeviceConnectionInterface .network ? 45 : 30 ;
418+ final Timer timer = Timer (discoveryTimeout ?? Duration (seconds: defaultTimeout), () {
419+ _logger.printError ('The Dart VM Service was not discovered after $defaultTimeout seconds. This is taking much longer than expected...' );
420+
421+ // If debugging with a wireless device and the timeout is reached, remind the
422+ // user to allow local network permissions.
423+ if (interfaceType == IOSDeviceConnectionInterface .network) {
424+ _logger.printError (
425+ '\n Click "Allow" to the prompt asking if you would like to find and connect devices on your local network. '
426+ 'This is required for wireless debugging. If you selected "Don\' t Allow", '
427+ 'you can turn it on in Settings > Your App Name > Local Network. '
428+ "If you don't see your app in the Settings, uninstall the app and rerun to see the prompt again."
429+ );
430+ } else {
431+ iosDeployDebugger? .pauseDumpBacktraceResume ();
432+ }
419433 });
420- final Uri ? localUri = await observatoryDiscovery? .uri;
434+
435+ Uri ? localUri;
436+ if (interfaceType == IOSDeviceConnectionInterface .network) {
437+ // Wait for Dart VM Service to start up.
438+ final Uri ? serviceURL = await observatoryDiscovery? .uri;
439+ if (serviceURL == null ) {
440+ await iosDeployDebugger? .stopAndDumpBacktrace ();
441+ return LaunchResult .failed ();
442+ }
443+
444+ // If Dart VM Service URL with the device IP is not found within 5 seconds,
445+ // change the status message to prompt users to click Allow. Wait 5 seconds because it
446+ // should only show this message if they have not already approved the permissions.
447+ // MDnsVmServiceDiscovery usually takes less than 5 seconds to find it.
448+ final Timer mDNSLookupTimer = Timer (const Duration (seconds: 5 ), () {
449+ startAppStatus.stop ();
450+ startAppStatus = _logger.startProgress (
451+ 'Waiting for approval of local network permissions...' ,
452+ );
453+ });
454+
455+ // Get Dart VM Service URL with the device IP as the host.
456+ localUri = await MDnsVmServiceDiscovery .instance! .getVMServiceUriForLaunch (
457+ packageId,
458+ this ,
459+ usesIpv6: ipv6,
460+ deviceVmservicePort: serviceURL.port,
461+ isNetworkDevice: true ,
462+ );
463+
464+ mDNSLookupTimer.cancel ();
465+ } else {
466+ localUri = await observatoryDiscovery? .uri;
467+ }
421468 timer.cancel ();
422469 if (localUri == null ) {
423470 await iosDeployDebugger? .stopAndDumpBacktrace ();
@@ -429,7 +476,7 @@ class IOSDevice extends Device {
429476 _logger.printError (e.message);
430477 return LaunchResult .failed ();
431478 } finally {
432- installStatus .stop ();
479+ startAppStatus .stop ();
433480 }
434481 }
435482
@@ -569,7 +616,6 @@ String decodeSyslog(String line) {
569616 }
570617}
571618
572- @visibleForTesting
573619class IOSDeviceLogReader extends DeviceLogReader {
574620 IOSDeviceLogReader ._(
575621 this ._iMobileDevice,
0 commit comments