mirror of
https://github.com/flutter/flutter
synced 2024-08-25 11:07:06 +00:00
Print warning and exit when iOS device is unpaired (#144551)
Explicitly handle the case where the iOS device is not paired. On `flutter run` show an error and bail instead of trying and failing to launch on the device. On this PR: ``` $ flutter run -d 00008110-0009588C2651401E 'iPhone' is not paired. Open Xcode and trust this computer when prompted. $ ``` Fixes https://github.com/flutter/flutter/issues/144447 Closes https://github.com/flutter/flutter/pull/144095
This commit is contained in:
parent
d9eea7963d
commit
9b442b2749
|
@ -267,6 +267,7 @@ class IOSDevice extends Device {
|
|||
required this.cpuArchitecture,
|
||||
required this.connectionInterface,
|
||||
required this.isConnected,
|
||||
required this.isPaired,
|
||||
required this.devModeEnabled,
|
||||
required this.isCoreDevice,
|
||||
String? sdkVersion,
|
||||
|
@ -336,6 +337,11 @@ class IOSDevice extends Device {
|
|||
@override
|
||||
bool isConnected;
|
||||
|
||||
bool devModeEnabled = false;
|
||||
|
||||
/// Device has trusted this computer and paired.
|
||||
bool isPaired = false;
|
||||
|
||||
/// CoreDevice is a device connectivity stack introduced in Xcode 15. Devices
|
||||
/// with iOS 17 or greater are CoreDevices.
|
||||
final bool isCoreDevice;
|
||||
|
@ -344,8 +350,6 @@ class IOSDevice extends Device {
|
|||
|
||||
DevicePortForwarder? _portForwarder;
|
||||
|
||||
bool devModeEnabled = false;
|
||||
|
||||
@visibleForTesting
|
||||
IOSDeployDebugger? iosDeployDebugger;
|
||||
|
||||
|
|
|
@ -544,6 +544,7 @@ class XCDevice {
|
|||
}
|
||||
bool devModeEnabled = true;
|
||||
bool isConnected = true;
|
||||
bool isPaired = true;
|
||||
final Map<String, Object?>? errorProperties = _errorProperties(device);
|
||||
if (errorProperties != null) {
|
||||
final String? errorMessage = _parseErrorMessage(errorProperties);
|
||||
|
@ -564,6 +565,10 @@ class XCDevice {
|
|||
if (code != -10) {
|
||||
isConnected = false;
|
||||
}
|
||||
// Error: iPhone is not paired with your computer. To use iPhone with Xcode, unlock it and choose to trust this computer when prompted. (code -9)
|
||||
if (code == -9) {
|
||||
isPaired = false;
|
||||
}
|
||||
|
||||
if (code == 6) {
|
||||
devModeEnabled = false;
|
||||
|
@ -635,6 +640,7 @@ class XCDevice {
|
|||
xcodeDebug: _xcodeDebug,
|
||||
platform: globals.platform,
|
||||
devModeEnabled: devModeEnabled,
|
||||
isPaired: isPaired,
|
||||
isCoreDevice: coreDevice != null,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -30,6 +30,8 @@ String _noMatchingDeviceMessage(String deviceId) => 'No supported devices found
|
|||
"matching '$deviceId'.";
|
||||
String flutterSpecifiedDeviceDevModeDisabled(String deviceName) => 'To use '
|
||||
"'$deviceName' for development, enable Developer Mode in Settings → Privacy & Security.";
|
||||
String flutterSpecifiedDeviceUnpaired(String deviceName) => "'$deviceName' is not paired. "
|
||||
'Open Xcode and trust this computer when prompted.';
|
||||
|
||||
/// This class handles functionality of finding and selecting target devices.
|
||||
///
|
||||
|
@ -494,27 +496,39 @@ class TargetDevicesWithExtendedWirelessDeviceDiscovery extends TargetDevices {
|
|||
|
||||
if (specifiedDevices.length == 1) {
|
||||
Device? matchedDevice = specifiedDevices.first;
|
||||
if (matchedDevice is IOSDevice) {
|
||||
// If the only matching device is not paired, print a warning
|
||||
if (!matchedDevice.isPaired) {
|
||||
_logger.printStatus(flutterSpecifiedDeviceUnpaired(matchedDevice.name));
|
||||
return null;
|
||||
}
|
||||
// If the only matching device does not have Developer Mode enabled,
|
||||
// print a warning
|
||||
if (matchedDevice is IOSDevice && !matchedDevice.devModeEnabled) {
|
||||
if (!matchedDevice.devModeEnabled) {
|
||||
_logger.printStatus(
|
||||
flutterSpecifiedDeviceDevModeDisabled(matchedDevice.name)
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!matchedDevice.isConnected && matchedDevice is IOSDevice) {
|
||||
if (!matchedDevice.isConnected) {
|
||||
matchedDevice = await _waitForIOSDeviceToConnect(matchedDevice);
|
||||
}
|
||||
}
|
||||
|
||||
if (matchedDevice != null && matchedDevice.isConnected) {
|
||||
return <Device>[matchedDevice];
|
||||
}
|
||||
|
||||
} else {
|
||||
for (final Device device in specifiedDevices) {
|
||||
for (final IOSDevice device in specifiedDevices.whereType<IOSDevice>()) {
|
||||
// Print warning for every matching unpaired device.
|
||||
if (!device.isPaired) {
|
||||
_logger.printStatus(flutterSpecifiedDeviceUnpaired(device.name));
|
||||
}
|
||||
|
||||
// Print warning for every matching device that does not have Developer Mode enabled.
|
||||
if (device is IOSDevice && !device.devModeEnabled) {
|
||||
if (!device.devModeEnabled) {
|
||||
_logger.printStatus(
|
||||
flutterSpecifiedDeviceDevModeDisabled(device.name)
|
||||
);
|
||||
|
|
|
@ -85,6 +85,7 @@ void main() {
|
|||
cpuArchitecture: DarwinArch.arm64,
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
isConnected: true,
|
||||
isPaired: true,
|
||||
devModeEnabled: true,
|
||||
isCoreDevice: false,
|
||||
);
|
||||
|
@ -106,6 +107,7 @@ void main() {
|
|||
cpuArchitecture: DarwinArch.armv7,
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
isConnected: true,
|
||||
isPaired: true,
|
||||
devModeEnabled: true,
|
||||
isCoreDevice: false,
|
||||
);
|
||||
|
@ -128,6 +130,7 @@ void main() {
|
|||
sdkVersion: '1.0.0',
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
isConnected: true,
|
||||
isPaired: true,
|
||||
devModeEnabled: true,
|
||||
isCoreDevice: false,
|
||||
).majorSdkVersion, 1);
|
||||
|
@ -146,6 +149,7 @@ void main() {
|
|||
sdkVersion: '13.1.1',
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
isConnected: true,
|
||||
isPaired: true,
|
||||
devModeEnabled: true,
|
||||
isCoreDevice: false,
|
||||
).majorSdkVersion, 13);
|
||||
|
@ -164,6 +168,7 @@ void main() {
|
|||
sdkVersion: '10',
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
isConnected: true,
|
||||
isPaired: true,
|
||||
devModeEnabled: true,
|
||||
isCoreDevice: false,
|
||||
).majorSdkVersion, 10);
|
||||
|
@ -182,6 +187,7 @@ void main() {
|
|||
sdkVersion: '0',
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
isConnected: true,
|
||||
isPaired: true,
|
||||
devModeEnabled: true,
|
||||
isCoreDevice: false,
|
||||
).majorSdkVersion, 0);
|
||||
|
@ -200,6 +206,7 @@ void main() {
|
|||
sdkVersion: 'bogus',
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
isConnected: true,
|
||||
isPaired: true,
|
||||
devModeEnabled: true,
|
||||
isCoreDevice: false,
|
||||
).majorSdkVersion, 0);
|
||||
|
@ -221,6 +228,7 @@ void main() {
|
|||
sdkVersion: '13.3.1',
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
isConnected: true,
|
||||
isPaired: true,
|
||||
devModeEnabled: true,
|
||||
isCoreDevice: false,
|
||||
).sdkVersion;
|
||||
|
@ -244,6 +252,7 @@ void main() {
|
|||
sdkVersion: '13.3.1 (20ADBC)',
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
isConnected: true,
|
||||
isPaired: true,
|
||||
devModeEnabled: true,
|
||||
isCoreDevice: false,
|
||||
).sdkVersion;
|
||||
|
@ -267,6 +276,7 @@ void main() {
|
|||
sdkVersion: '16.4.1(a) (20ADBC)',
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
isConnected: true,
|
||||
isPaired: true,
|
||||
devModeEnabled: true,
|
||||
isCoreDevice: false,
|
||||
).sdkVersion;
|
||||
|
@ -290,6 +300,7 @@ void main() {
|
|||
sdkVersion: '0',
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
isConnected: true,
|
||||
isPaired: true,
|
||||
devModeEnabled: true,
|
||||
isCoreDevice: false,
|
||||
).sdkVersion;
|
||||
|
@ -312,6 +323,7 @@ void main() {
|
|||
cpuArchitecture: DarwinArch.arm64,
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
isConnected: true,
|
||||
isPaired: true,
|
||||
devModeEnabled: true,
|
||||
isCoreDevice: false,
|
||||
).sdkVersion;
|
||||
|
@ -332,6 +344,7 @@ void main() {
|
|||
sdkVersion: 'bogus',
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
isConnected: true,
|
||||
isPaired: true,
|
||||
devModeEnabled: true,
|
||||
isCoreDevice: false,
|
||||
).sdkVersion;
|
||||
|
@ -354,6 +367,7 @@ void main() {
|
|||
cpuArchitecture: DarwinArch.arm64,
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
isConnected: true,
|
||||
isPaired: true,
|
||||
devModeEnabled: true,
|
||||
isCoreDevice: false,
|
||||
);
|
||||
|
@ -377,6 +391,7 @@ void main() {
|
|||
cpuArchitecture: DarwinArch.arm64,
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
isConnected: true,
|
||||
isPaired: true,
|
||||
devModeEnabled: true,
|
||||
isCoreDevice: false,
|
||||
);
|
||||
|
@ -406,6 +421,7 @@ void main() {
|
|||
cpuArchitecture: DarwinArch.arm64,
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
isConnected: true,
|
||||
isPaired: true,
|
||||
devModeEnabled: true,
|
||||
isCoreDevice: false,
|
||||
);
|
||||
|
@ -501,6 +517,7 @@ void main() {
|
|||
cpuArchitecture: DarwinArch.arm64,
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
isConnected: true,
|
||||
isPaired: true,
|
||||
devModeEnabled: true,
|
||||
isCoreDevice: false,
|
||||
);
|
||||
|
@ -571,6 +588,7 @@ void main() {
|
|||
fileSystem: MemoryFileSystem.test(),
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
isConnected: true,
|
||||
isPaired: true,
|
||||
devModeEnabled: true,
|
||||
isCoreDevice: false,
|
||||
);
|
||||
|
@ -590,6 +608,7 @@ void main() {
|
|||
fileSystem: MemoryFileSystem.test(),
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
isConnected: true,
|
||||
isPaired: true,
|
||||
devModeEnabled: true,
|
||||
isCoreDevice: false,
|
||||
);
|
||||
|
@ -889,6 +908,7 @@ void main() {
|
|||
fileSystem: MemoryFileSystem.test(),
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
isConnected: false,
|
||||
isPaired: true,
|
||||
devModeEnabled: true,
|
||||
isCoreDevice: false,
|
||||
);
|
||||
|
|
|
@ -434,6 +434,7 @@ IOSDevice setUpIOSDevice({
|
|||
iProxy: IProxy.test(logger: logger, processManager: processManager),
|
||||
connectionInterface: interfaceType ?? DeviceConnectionInterface.attached,
|
||||
isConnected: true,
|
||||
isPaired: true,
|
||||
devModeEnabled: true,
|
||||
isCoreDevice: isCoreDevice,
|
||||
);
|
||||
|
|
|
@ -106,6 +106,7 @@ IOSDevice setUpIOSDevice(FileSystem fileSystem) {
|
|||
iProxy: IProxy.test(logger: logger, processManager: processManager),
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
isConnected: true,
|
||||
isPaired: true,
|
||||
devModeEnabled: true,
|
||||
isCoreDevice: false,
|
||||
);
|
||||
|
|
|
@ -869,6 +869,7 @@ IOSDevice setUpIOSDevice({
|
|||
cpuArchitecture: DarwinArch.arm64,
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
isConnected: true,
|
||||
isPaired: true,
|
||||
devModeEnabled: true,
|
||||
isCoreDevice: isCoreDevice,
|
||||
);
|
||||
|
|
|
@ -1094,6 +1094,7 @@ IOSDevice setUpIOSDevice({
|
|||
cpuArchitecture: DarwinArch.arm64,
|
||||
connectionInterface: interfaceType,
|
||||
isConnected: true,
|
||||
isPaired: true,
|
||||
devModeEnabled: true,
|
||||
isCoreDevice: isCoreDevice,
|
||||
);
|
||||
|
|
|
@ -1275,7 +1275,7 @@ To use 'target-device' for development, enable Developer Mode in Settings → Pr
|
|||
|
||||
testUsingContext('when one of the matching devices has dev mode disabled', () async {
|
||||
deviceManager.iosDiscoverer.deviceList = <Device>[FakeIOSDevice(deviceName: 'target-device-1', devModeEnabled: false, isConnected: false),
|
||||
FakeIOSDevice(deviceName: 'target-device-2', devModeEnabled: true)];
|
||||
FakeIOSDevice(deviceName: 'target-device-2')];
|
||||
|
||||
final List<Device>? devices = await targetDevices.findAllTargetDevices();
|
||||
expect(logger.statusText, equals('''
|
||||
|
@ -1296,6 +1296,45 @@ To use 'target-device-1' for development, enable Developer Mode in Settings →
|
|||
To use 'target-device-2' for development, enable Developer Mode in Settings → Privacy & Security.
|
||||
No devices found yet. Checking for wireless devices...
|
||||
|
||||
No supported devices found with name or id matching 'target-device'.
|
||||
'''));
|
||||
expect(devices, isNull);
|
||||
});
|
||||
|
||||
testUsingContext('when only matching device is unpaired', () async {
|
||||
deviceManager.iosDiscoverer.deviceList = <Device>[FakeIOSDevice(deviceName: 'target-device', isPaired: false)];
|
||||
|
||||
final List<Device>? devices = await targetDevices.findAllTargetDevices();
|
||||
|
||||
expect(logger.statusText, equals('''
|
||||
'target-device' is not paired. Open Xcode and trust this computer when prompted.
|
||||
'''));
|
||||
expect(devices, isNull);
|
||||
});
|
||||
|
||||
testUsingContext('when one of the matching devices is unpaired', () async {
|
||||
deviceManager.iosDiscoverer.deviceList = <Device>[FakeIOSDevice(deviceName: 'target-device-1', isPaired: false, isConnected: false),
|
||||
FakeIOSDevice(deviceName: 'target-device-2')];
|
||||
|
||||
final List<Device>? devices = await targetDevices.findAllTargetDevices();
|
||||
expect(logger.statusText, contains('''
|
||||
'target-device-1' is not paired. Open Xcode and trust this computer when prompted.
|
||||
Checking for wireless devices...
|
||||
'''));
|
||||
expect(devices, isNotNull);
|
||||
});
|
||||
|
||||
testUsingContext('when all matching devices are unpaired', () async {
|
||||
deviceManager.iosDiscoverer.deviceList = <Device>[FakeIOSDevice(deviceName: 'target-device-1', isPaired: false, isConnected: false),
|
||||
FakeIOSDevice(deviceName: 'target-device-2', isPaired: false, isConnected: false)];
|
||||
|
||||
final List<Device>? devices = await targetDevices.findAllTargetDevices();
|
||||
|
||||
expect(logger.statusText, contains('''
|
||||
'target-device-1' is not paired. Open Xcode and trust this computer when prompted.
|
||||
'target-device-2' is not paired. Open Xcode and trust this computer when prompted.
|
||||
No devices found yet. Checking for wireless devices...
|
||||
|
||||
No supported devices found with name or id matching 'target-device'.
|
||||
'''));
|
||||
expect(devices, isNull);
|
||||
|
@ -2777,16 +2816,16 @@ class FakeIOSDevice extends Fake implements IOSDevice {
|
|||
FakeIOSDevice({
|
||||
String? deviceId,
|
||||
String? deviceName,
|
||||
bool? devModeEnabled,
|
||||
bool deviceSupported = true,
|
||||
bool deviceSupportForProject = true,
|
||||
this.ephemeral = true,
|
||||
this.isConnected = true,
|
||||
this.devModeEnabled = true,
|
||||
this.isPaired = true,
|
||||
this.platformType = PlatformType.ios,
|
||||
this.connectionInterface = DeviceConnectionInterface.attached,
|
||||
}) : id = deviceId ?? 'xxx',
|
||||
name = deviceName ?? 'test',
|
||||
devModeEnabled = devModeEnabled ?? true,
|
||||
_isSupported = deviceSupported,
|
||||
_isSupportedForProject = deviceSupportForProject;
|
||||
|
||||
|
@ -2799,6 +2838,7 @@ class FakeIOSDevice extends Fake implements IOSDevice {
|
|||
this.isConnected = false,
|
||||
this.platformType = PlatformType.ios,
|
||||
this.devModeEnabled = true,
|
||||
this.isPaired = true,
|
||||
this.connectionInterface = DeviceConnectionInterface.wireless,
|
||||
}) : id = deviceId ?? 'xxx',
|
||||
name = deviceName ?? 'test',
|
||||
|
@ -2813,6 +2853,7 @@ class FakeIOSDevice extends Fake implements IOSDevice {
|
|||
this.ephemeral = true,
|
||||
this.isConnected = true,
|
||||
this.devModeEnabled = true,
|
||||
this.isPaired = true,
|
||||
this.platformType = PlatformType.ios,
|
||||
this.connectionInterface = DeviceConnectionInterface.wireless,
|
||||
}) : id = deviceId ?? 'xxx',
|
||||
|
@ -2832,6 +2873,9 @@ class FakeIOSDevice extends Fake implements IOSDevice {
|
|||
@override
|
||||
final bool devModeEnabled;
|
||||
|
||||
@override
|
||||
final bool isPaired;
|
||||
|
||||
@override
|
||||
String id;
|
||||
|
||||
|
|
Loading…
Reference in a new issue