Show warning when attempting to flutter run on an ios device with developer mode turned off (#125710)
This PR adds a warning when a user attempt to `flutter run -d <device id>` on a device without developer mode enabled. <img width="738" alt="Screenshot 2023-05-09 at 3 53 18 AM" src="https://github.com/flutter/flutter/assets/36148254/6f473a6a-5a0d-438b-9e6f-06d09eb1f3a9"> Also handles multiple partial matches. <img width="788" alt="Screenshot 2023-05-09 at 3 52 24 AM" src="https://github.com/flutter/flutter/assets/36148254/60c82b3c-d501-4a01-95ad-d6309fe39576"> Fixes https://github.com/flutter/flutter/issues/111988
This commit is contained in:
parent
487ed57388
commit
e345a830ba
@ -261,6 +261,7 @@ class IOSDevice extends Device {
|
|||||||
required this.cpuArchitecture,
|
required this.cpuArchitecture,
|
||||||
required this.connectionInterface,
|
required this.connectionInterface,
|
||||||
required this.isConnected,
|
required this.isConnected,
|
||||||
|
required this.devModeEnabled,
|
||||||
String? sdkVersion,
|
String? sdkVersion,
|
||||||
required Platform platform,
|
required Platform platform,
|
||||||
required IOSDeploy iosDeploy,
|
required IOSDeploy iosDeploy,
|
||||||
@ -323,6 +324,8 @@ class IOSDevice extends Device {
|
|||||||
|
|
||||||
DevicePortForwarder? _portForwarder;
|
DevicePortForwarder? _portForwarder;
|
||||||
|
|
||||||
|
bool devModeEnabled = false;
|
||||||
|
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
IOSDeployDebugger? iosDeployDebugger;
|
IOSDeployDebugger? iosDeployDebugger;
|
||||||
|
|
||||||
|
@ -505,7 +505,7 @@ class XCDevice {
|
|||||||
if (identifier == null || name == null) {
|
if (identifier == null || name == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
bool devModeEnabled = true;
|
||||||
bool isConnected = true;
|
bool isConnected = true;
|
||||||
final Map<String, Object?>? errorProperties = _errorProperties(device);
|
final Map<String, Object?>? errorProperties = _errorProperties(device);
|
||||||
if (errorProperties != null) {
|
if (errorProperties != null) {
|
||||||
@ -525,6 +525,10 @@ class XCDevice {
|
|||||||
if (code != -10) {
|
if (code != -10) {
|
||||||
isConnected = false;
|
isConnected = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (code == 6) {
|
||||||
|
devModeEnabled = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String? sdkVersion = _sdkVersion(device);
|
String? sdkVersion = _sdkVersion(device);
|
||||||
@ -549,6 +553,7 @@ class XCDevice {
|
|||||||
iosDeploy: _iosDeploy,
|
iosDeploy: _iosDeploy,
|
||||||
iMobileDevice: _iMobileDevice,
|
iMobileDevice: _iMobileDevice,
|
||||||
platform: globals.platform,
|
platform: globals.platform,
|
||||||
|
devModeEnabled: devModeEnabled
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,8 @@ String _foundSpecifiedDevicesMessage(int count, String deviceId) =>
|
|||||||
'Found $count devices with name or id matching $deviceId:';
|
'Found $count devices with name or id matching $deviceId:';
|
||||||
String _noMatchingDeviceMessage(String deviceId) => 'No supported devices found with name or id '
|
String _noMatchingDeviceMessage(String deviceId) => 'No supported devices found with name or id '
|
||||||
"matching '$deviceId'.";
|
"matching '$deviceId'.";
|
||||||
|
String flutterSpecifiedDeviceDevModeDisabled(String deviceName) => 'To use '
|
||||||
|
"'$deviceName' for development, enable Developer Mode in Settings → Privacy & Security.";
|
||||||
|
|
||||||
/// This class handles functionality of finding and selecting target devices.
|
/// This class handles functionality of finding and selecting target devices.
|
||||||
///
|
///
|
||||||
@ -486,18 +488,39 @@ class TargetDevicesWithExtendedWirelessDeviceDiscovery extends TargetDevices {
|
|||||||
// If there are multiple matches, continue on to wait for all attached
|
// If there are multiple matches, continue on to wait for all attached
|
||||||
// and wireless devices to load so the user can select between all
|
// and wireless devices to load so the user can select between all
|
||||||
// connected matches.
|
// connected matches.
|
||||||
final List<Device> devices = await _getDeviceById(
|
final List<Device> specifiedDevices = await _getDeviceById(
|
||||||
includeDevicesUnsupportedByProject: includeDevicesUnsupportedByProject,
|
includeDevicesUnsupportedByProject: includeDevicesUnsupportedByProject,
|
||||||
includeDisconnected: true,
|
includeDisconnected: true,
|
||||||
);
|
);
|
||||||
if (devices.length == 1) {
|
|
||||||
Device? matchedDevice = devices.first;
|
if (specifiedDevices.length == 1) {
|
||||||
|
Device? matchedDevice = specifiedDevices.first;
|
||||||
|
// If the only matching device does not have Developer Mode enabled,
|
||||||
|
// print a warning
|
||||||
|
if (matchedDevice is IOSDevice && !matchedDevice.devModeEnabled) {
|
||||||
|
_logger.printStatus(
|
||||||
|
flutterSpecifiedDeviceDevModeDisabled(matchedDevice.name)
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (!matchedDevice.isConnected && matchedDevice is IOSDevice) {
|
if (!matchedDevice.isConnected && matchedDevice is IOSDevice) {
|
||||||
matchedDevice = await _waitForIOSDeviceToConnect(matchedDevice);
|
matchedDevice = await _waitForIOSDeviceToConnect(matchedDevice);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matchedDevice != null && matchedDevice.isConnected) {
|
if (matchedDevice != null && matchedDevice.isConnected) {
|
||||||
return <Device>[matchedDevice];
|
return <Device>[matchedDevice];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
for (final Device device in specifiedDevices) {
|
||||||
|
// Print warning for every matching device that does not have Developer Mode enabled.
|
||||||
|
if (device is IOSDevice && !device.devModeEnabled) {
|
||||||
|
_logger.printStatus(
|
||||||
|
flutterSpecifiedDeviceDevModeDisabled(device.name)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,6 +76,7 @@ void main() {
|
|||||||
cpuArchitecture: DarwinArch.arm64,
|
cpuArchitecture: DarwinArch.arm64,
|
||||||
connectionInterface: DeviceConnectionInterface.attached,
|
connectionInterface: DeviceConnectionInterface.attached,
|
||||||
isConnected: true,
|
isConnected: true,
|
||||||
|
devModeEnabled: true,
|
||||||
);
|
);
|
||||||
expect(device.isSupported(), isTrue);
|
expect(device.isSupported(), isTrue);
|
||||||
});
|
});
|
||||||
@ -93,6 +94,7 @@ void main() {
|
|||||||
cpuArchitecture: DarwinArch.armv7,
|
cpuArchitecture: DarwinArch.armv7,
|
||||||
connectionInterface: DeviceConnectionInterface.attached,
|
connectionInterface: DeviceConnectionInterface.attached,
|
||||||
isConnected: true,
|
isConnected: true,
|
||||||
|
devModeEnabled: true,
|
||||||
);
|
);
|
||||||
expect(device.isSupported(), isFalse);
|
expect(device.isSupported(), isFalse);
|
||||||
});
|
});
|
||||||
@ -111,6 +113,7 @@ void main() {
|
|||||||
sdkVersion: '1.0.0',
|
sdkVersion: '1.0.0',
|
||||||
connectionInterface: DeviceConnectionInterface.attached,
|
connectionInterface: DeviceConnectionInterface.attached,
|
||||||
isConnected: true,
|
isConnected: true,
|
||||||
|
devModeEnabled: true,
|
||||||
).majorSdkVersion, 1);
|
).majorSdkVersion, 1);
|
||||||
expect(IOSDevice(
|
expect(IOSDevice(
|
||||||
'device-123',
|
'device-123',
|
||||||
@ -125,6 +128,7 @@ void main() {
|
|||||||
sdkVersion: '13.1.1',
|
sdkVersion: '13.1.1',
|
||||||
connectionInterface: DeviceConnectionInterface.attached,
|
connectionInterface: DeviceConnectionInterface.attached,
|
||||||
isConnected: true,
|
isConnected: true,
|
||||||
|
devModeEnabled: true,
|
||||||
).majorSdkVersion, 13);
|
).majorSdkVersion, 13);
|
||||||
expect(IOSDevice(
|
expect(IOSDevice(
|
||||||
'device-123',
|
'device-123',
|
||||||
@ -139,6 +143,7 @@ void main() {
|
|||||||
sdkVersion: '10',
|
sdkVersion: '10',
|
||||||
connectionInterface: DeviceConnectionInterface.attached,
|
connectionInterface: DeviceConnectionInterface.attached,
|
||||||
isConnected: true,
|
isConnected: true,
|
||||||
|
devModeEnabled: true,
|
||||||
).majorSdkVersion, 10);
|
).majorSdkVersion, 10);
|
||||||
expect(IOSDevice(
|
expect(IOSDevice(
|
||||||
'device-123',
|
'device-123',
|
||||||
@ -153,6 +158,7 @@ void main() {
|
|||||||
sdkVersion: '0',
|
sdkVersion: '0',
|
||||||
connectionInterface: DeviceConnectionInterface.attached,
|
connectionInterface: DeviceConnectionInterface.attached,
|
||||||
isConnected: true,
|
isConnected: true,
|
||||||
|
devModeEnabled: true,
|
||||||
).majorSdkVersion, 0);
|
).majorSdkVersion, 0);
|
||||||
expect(IOSDevice(
|
expect(IOSDevice(
|
||||||
'device-123',
|
'device-123',
|
||||||
@ -167,6 +173,7 @@ void main() {
|
|||||||
sdkVersion: 'bogus',
|
sdkVersion: 'bogus',
|
||||||
connectionInterface: DeviceConnectionInterface.attached,
|
connectionInterface: DeviceConnectionInterface.attached,
|
||||||
isConnected: true,
|
isConnected: true,
|
||||||
|
devModeEnabled: true,
|
||||||
).majorSdkVersion, 0);
|
).majorSdkVersion, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -184,6 +191,7 @@ void main() {
|
|||||||
cpuArchitecture: DarwinArch.arm64,
|
cpuArchitecture: DarwinArch.arm64,
|
||||||
connectionInterface: DeviceConnectionInterface.attached,
|
connectionInterface: DeviceConnectionInterface.attached,
|
||||||
isConnected: true,
|
isConnected: true,
|
||||||
|
devModeEnabled: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(await device.sdkNameAndVersion,'iOS 13.3 17C54');
|
expect(await device.sdkNameAndVersion,'iOS 13.3 17C54');
|
||||||
@ -203,6 +211,7 @@ void main() {
|
|||||||
cpuArchitecture: DarwinArch.arm64,
|
cpuArchitecture: DarwinArch.arm64,
|
||||||
connectionInterface: DeviceConnectionInterface.attached,
|
connectionInterface: DeviceConnectionInterface.attached,
|
||||||
isConnected: true,
|
isConnected: true,
|
||||||
|
devModeEnabled: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(device.supportsRuntimeMode(BuildMode.debug), true);
|
expect(device.supportsRuntimeMode(BuildMode.debug), true);
|
||||||
@ -228,6 +237,7 @@ void main() {
|
|||||||
cpuArchitecture: DarwinArch.arm64,
|
cpuArchitecture: DarwinArch.arm64,
|
||||||
connectionInterface: DeviceConnectionInterface.attached,
|
connectionInterface: DeviceConnectionInterface.attached,
|
||||||
isConnected: true,
|
isConnected: true,
|
||||||
|
devModeEnabled: true,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
throwsAssertionError,
|
throwsAssertionError,
|
||||||
@ -319,6 +329,7 @@ void main() {
|
|||||||
cpuArchitecture: DarwinArch.arm64,
|
cpuArchitecture: DarwinArch.arm64,
|
||||||
connectionInterface: DeviceConnectionInterface.attached,
|
connectionInterface: DeviceConnectionInterface.attached,
|
||||||
isConnected: true,
|
isConnected: true,
|
||||||
|
devModeEnabled: true,
|
||||||
);
|
);
|
||||||
logReader1 = createLogReader(device, appPackage1, process1);
|
logReader1 = createLogReader(device, appPackage1, process1);
|
||||||
logReader2 = createLogReader(device, appPackage2, process2);
|
logReader2 = createLogReader(device, appPackage2, process2);
|
||||||
@ -381,6 +392,7 @@ void main() {
|
|||||||
fileSystem: MemoryFileSystem.test(),
|
fileSystem: MemoryFileSystem.test(),
|
||||||
connectionInterface: DeviceConnectionInterface.attached,
|
connectionInterface: DeviceConnectionInterface.attached,
|
||||||
isConnected: true,
|
isConnected: true,
|
||||||
|
devModeEnabled: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
device2 = IOSDevice(
|
device2 = IOSDevice(
|
||||||
@ -396,6 +408,7 @@ void main() {
|
|||||||
fileSystem: MemoryFileSystem.test(),
|
fileSystem: MemoryFileSystem.test(),
|
||||||
connectionInterface: DeviceConnectionInterface.attached,
|
connectionInterface: DeviceConnectionInterface.attached,
|
||||||
isConnected: true,
|
isConnected: true,
|
||||||
|
devModeEnabled: true,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -687,6 +700,7 @@ void main() {
|
|||||||
fileSystem: MemoryFileSystem.test(),
|
fileSystem: MemoryFileSystem.test(),
|
||||||
connectionInterface: DeviceConnectionInterface.attached,
|
connectionInterface: DeviceConnectionInterface.attached,
|
||||||
isConnected: false,
|
isConnected: false,
|
||||||
|
devModeEnabled: true,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -360,5 +360,6 @@ IOSDevice setUpIOSDevice({
|
|||||||
iProxy: IProxy.test(logger: logger, processManager: processManager),
|
iProxy: IProxy.test(logger: logger, processManager: processManager),
|
||||||
connectionInterface: interfaceType ?? DeviceConnectionInterface.attached,
|
connectionInterface: interfaceType ?? DeviceConnectionInterface.attached,
|
||||||
isConnected: true,
|
isConnected: true,
|
||||||
|
devModeEnabled: true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -101,5 +101,6 @@ IOSDevice setUpIOSDevice(FileSystem fileSystem) {
|
|||||||
iProxy: IProxy.test(logger: logger, processManager: processManager),
|
iProxy: IProxy.test(logger: logger, processManager: processManager),
|
||||||
connectionInterface: DeviceConnectionInterface.attached,
|
connectionInterface: DeviceConnectionInterface.attached,
|
||||||
isConnected: true,
|
isConnected: true,
|
||||||
|
devModeEnabled: true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -339,6 +339,7 @@ IOSDevice setUpIOSDevice({
|
|||||||
cpuArchitecture: DarwinArch.arm64,
|
cpuArchitecture: DarwinArch.arm64,
|
||||||
connectionInterface: DeviceConnectionInterface.attached,
|
connectionInterface: DeviceConnectionInterface.attached,
|
||||||
isConnected: true,
|
isConnected: true,
|
||||||
|
devModeEnabled: true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -649,6 +649,7 @@ IOSDevice setUpIOSDevice({
|
|||||||
cpuArchitecture: DarwinArch.arm64,
|
cpuArchitecture: DarwinArch.arm64,
|
||||||
connectionInterface: interfaceType,
|
connectionInterface: interfaceType,
|
||||||
isConnected: true,
|
isConnected: true,
|
||||||
|
devModeEnabled: true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1262,6 +1262,45 @@ target-device (mobile) • xxx • ios • iOS 16 (unsupported)
|
|||||||
expect(deviceManager.iosDiscoverer.xcdevice.waitedForDeviceToConnect, isFalse);
|
expect(deviceManager.iosDiscoverer.xcdevice.waitedForDeviceToConnect, isFalse);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testUsingContext('when only matching device is dev mode disabled', () async {
|
||||||
|
deviceManager.iosDiscoverer.deviceList = <Device>[FakeIOSDevice(deviceName: 'target-device', devModeEnabled: false)];
|
||||||
|
|
||||||
|
final List<Device>? devices = await targetDevices.findAllTargetDevices();
|
||||||
|
|
||||||
|
expect(logger.statusText, equals('''
|
||||||
|
To use 'target-device' for development, enable Developer Mode in Settings → Privacy & Security.
|
||||||
|
'''));
|
||||||
|
expect(devices, isNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
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)];
|
||||||
|
|
||||||
|
final List<Device>? devices = await targetDevices.findAllTargetDevices();
|
||||||
|
expect(logger.statusText, equals('''
|
||||||
|
To use 'target-device-1' for development, enable Developer Mode in Settings → Privacy & Security.
|
||||||
|
Checking for wireless devices...
|
||||||
|
'''));
|
||||||
|
expect(devices, isNotNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('when all matching devices are dev mode disabled', () async {
|
||||||
|
deviceManager.iosDiscoverer.deviceList = <Device>[FakeIOSDevice(deviceName: 'target-device-1', devModeEnabled: false, isConnected: false),
|
||||||
|
FakeIOSDevice(deviceName: 'target-device-2', devModeEnabled: false, isConnected: false)];
|
||||||
|
|
||||||
|
final List<Device>? devices = await targetDevices.findAllTargetDevices();
|
||||||
|
|
||||||
|
expect(logger.statusText, equals('''
|
||||||
|
To use 'target-device-1' for development, enable Developer Mode in Settings → Privacy & Security.
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
|
||||||
group('when deviceConnectionInterface does not match', () {
|
group('when deviceConnectionInterface does not match', () {
|
||||||
testUsingContext('filter of wireless', () async {
|
testUsingContext('filter of wireless', () async {
|
||||||
final FakeIOSDevice device1 = FakeIOSDevice.notConnectedWireless(deviceName: 'not-a-match');
|
final FakeIOSDevice device1 = FakeIOSDevice.notConnectedWireless(deviceName: 'not-a-match');
|
||||||
@ -2691,6 +2730,7 @@ class FakeIOSDevice extends Fake implements IOSDevice {
|
|||||||
FakeIOSDevice({
|
FakeIOSDevice({
|
||||||
String? deviceId,
|
String? deviceId,
|
||||||
String? deviceName,
|
String? deviceName,
|
||||||
|
bool? devModeEnabled,
|
||||||
bool deviceSupported = true,
|
bool deviceSupported = true,
|
||||||
bool deviceSupportForProject = true,
|
bool deviceSupportForProject = true,
|
||||||
this.ephemeral = true,
|
this.ephemeral = true,
|
||||||
@ -2699,6 +2739,7 @@ class FakeIOSDevice extends Fake implements IOSDevice {
|
|||||||
this.connectionInterface = DeviceConnectionInterface.attached,
|
this.connectionInterface = DeviceConnectionInterface.attached,
|
||||||
}) : id = deviceId ?? 'xxx',
|
}) : id = deviceId ?? 'xxx',
|
||||||
name = deviceName ?? 'test',
|
name = deviceName ?? 'test',
|
||||||
|
devModeEnabled = devModeEnabled ?? true,
|
||||||
_isSupported = deviceSupported,
|
_isSupported = deviceSupported,
|
||||||
_isSupportedForProject = deviceSupportForProject;
|
_isSupportedForProject = deviceSupportForProject;
|
||||||
|
|
||||||
@ -2710,6 +2751,7 @@ class FakeIOSDevice extends Fake implements IOSDevice {
|
|||||||
this.ephemeral = true,
|
this.ephemeral = true,
|
||||||
this.isConnected = false,
|
this.isConnected = false,
|
||||||
this.platformType = PlatformType.ios,
|
this.platformType = PlatformType.ios,
|
||||||
|
this.devModeEnabled = true,
|
||||||
this.connectionInterface = DeviceConnectionInterface.wireless,
|
this.connectionInterface = DeviceConnectionInterface.wireless,
|
||||||
}) : id = deviceId ?? 'xxx',
|
}) : id = deviceId ?? 'xxx',
|
||||||
name = deviceName ?? 'test',
|
name = deviceName ?? 'test',
|
||||||
@ -2723,6 +2765,7 @@ class FakeIOSDevice extends Fake implements IOSDevice {
|
|||||||
bool deviceSupportForProject = true,
|
bool deviceSupportForProject = true,
|
||||||
this.ephemeral = true,
|
this.ephemeral = true,
|
||||||
this.isConnected = true,
|
this.isConnected = true,
|
||||||
|
this.devModeEnabled = true,
|
||||||
this.platformType = PlatformType.ios,
|
this.platformType = PlatformType.ios,
|
||||||
this.connectionInterface = DeviceConnectionInterface.wireless,
|
this.connectionInterface = DeviceConnectionInterface.wireless,
|
||||||
}) : id = deviceId ?? 'xxx',
|
}) : id = deviceId ?? 'xxx',
|
||||||
@ -2739,6 +2782,9 @@ class FakeIOSDevice extends Fake implements IOSDevice {
|
|||||||
@override
|
@override
|
||||||
final bool ephemeral;
|
final bool ephemeral;
|
||||||
|
|
||||||
|
@override
|
||||||
|
final bool devModeEnabled;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String id;
|
String id;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user