Skip to content

Commit 674fbd2

Browse files
[flutter_tools] Ensure flutter daemon clients can detect preview device (#140112)
Part of flutter/flutter#130277
1 parent 90badf7 commit 674fbd2

File tree

6 files changed

+360
-82
lines changed

6 files changed

+360
-82
lines changed

packages/flutter_tools/doc/daemon.md

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,22 @@ The `shutdown()` command will terminate the flutter daemon. It is not necessary
6262

6363
#### daemon.getSupportedPlatforms
6464

65-
The `getSupportedPlatforms()` command will enumerate all platforms supported by the project located at the provided `projectRoot`. It returns a Map with the key 'platforms' containing a List of strings which describe the set of all possibly supported platforms. Possible values include:
66-
- android
67-
- ios
68-
- linux #experimental
69-
- macos #experimental
70-
- windows #experimental
71-
- fuchsia #experimental
72-
- web #experimental
65+
The `getSupportedPlatforms()` command will enumerate all platforms supported
66+
by the project located at the provided `projectRoot`. It returns a Map with
67+
the key 'platformTypes' containing a Map of platform types to a Map with the
68+
following entries:
69+
70+
- isSupported (bool) - whether or not the platform type is supported
71+
- reasons (List<Map<String, Object>>, only included if isSupported == false) - a list of reasons why the platform is not supported
72+
73+
The schema for each element in `reasons` is:
74+
75+
- reasonText (String) - a description of why the platform is not supported
76+
- fixText (String) - human readable instructions of how to fix this reason
77+
- fixCode (String) - stringified version of the `_ReasonCode` enum. To be used
78+
by daemon clients who intend to auto-fix.
79+
80+
The possible platform types are the `PlatformType` enumeration in the lib/src/device.dart library.
7381

7482
#### Events
7583

packages/flutter_tools/lib/src/commands/daemon.dart

Lines changed: 170 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -416,36 +416,167 @@ class DaemonDomain extends Domain {
416416
/// is correct.
417417
Future<Map<String, Object>> getSupportedPlatforms(Map<String, Object?> args) async {
418418
final String? projectRoot = _getStringArg(args, 'projectRoot', required: true);
419-
final List<String> result = <String>[];
419+
final List<String> platformTypes = <String>[];
420+
final Map<String, Object> platformTypesMap = <String, Object>{};
420421
try {
421422
final FlutterProject flutterProject = FlutterProject.fromDirectory(globals.fs.directory(projectRoot));
422423
final Set<SupportedPlatform> supportedPlatforms = flutterProject.getSupportedPlatforms().toSet();
423-
if (featureFlags.isLinuxEnabled && supportedPlatforms.contains(SupportedPlatform.linux)) {
424-
result.add('linux');
425-
}
426-
if (featureFlags.isMacOSEnabled && supportedPlatforms.contains(SupportedPlatform.macos)) {
427-
result.add('macos');
428-
}
429-
if (featureFlags.isWindowsEnabled && supportedPlatforms.contains(SupportedPlatform.windows)) {
430-
result.add('windows');
431-
}
432-
if (featureFlags.isIOSEnabled && supportedPlatforms.contains(SupportedPlatform.ios)) {
433-
result.add('ios');
434-
}
435-
if (featureFlags.isAndroidEnabled && supportedPlatforms.contains(SupportedPlatform.android)) {
436-
result.add('android');
437-
}
438-
if (featureFlags.isWebEnabled && supportedPlatforms.contains(SupportedPlatform.web)) {
439-
result.add('web');
440-
}
441-
if (featureFlags.isFuchsiaEnabled && supportedPlatforms.contains(SupportedPlatform.fuchsia)) {
442-
result.add('fuchsia');
443-
}
444-
if (featureFlags.areCustomDevicesEnabled) {
445-
result.add('custom');
424+
425+
void handlePlatformType(
426+
PlatformType platform,
427+
) {
428+
final List<Map<String, Object>> reasons = <Map<String, Object>>[];
429+
switch (platform) {
430+
case PlatformType.linux:
431+
if (!featureFlags.isLinuxEnabled) {
432+
reasons.add(<String, Object>{
433+
'reasonText': 'the Linux feature is not enabled',
434+
'fixText': 'Run "flutter config --enable-linux-desktop"',
435+
'fixCode': _ReasonCode.config.name,
436+
});
437+
}
438+
if (!supportedPlatforms.contains(SupportedPlatform.linux)) {
439+
reasons.add(<String, Object>{
440+
'reasonText': 'the Linux platform is not enabled for this project',
441+
'fixText': 'Run "flutter create --platforms=linux ." in your application directory',
442+
'fixCode': _ReasonCode.create.name,
443+
});
444+
}
445+
case PlatformType.macos:
446+
if (!featureFlags.isMacOSEnabled) {
447+
reasons.add(<String, Object>{
448+
'reasonText': 'the macOS feature is not enabled',
449+
'fixText': 'Run "flutter config --enable-macos-desktop"',
450+
'fixCode': _ReasonCode.config.name,
451+
});
452+
}
453+
if (!supportedPlatforms.contains(SupportedPlatform.macos)) {
454+
reasons.add(<String, Object>{
455+
'reasonText': 'the macOS platform is not enabled for this project',
456+
'fixText': 'Run "flutter create --platforms=macos ." in your application directory',
457+
'fixCode': _ReasonCode.create.name,
458+
});
459+
}
460+
case PlatformType.windows:
461+
if (!featureFlags.isWindowsEnabled) {
462+
reasons.add(<String, Object>{
463+
'reasonText': 'the Windows feature is not enabled',
464+
'fixText': 'Run "flutter config --enable-windows-desktop"',
465+
'fixCode': _ReasonCode.config.name,
466+
});
467+
}
468+
if (!supportedPlatforms.contains(SupportedPlatform.windows)) {
469+
reasons.add(<String, Object>{
470+
'reasonText': 'the Windows platform is not enabled for this project',
471+
'fixText': 'Run "flutter create --platforms=windows ." in your application directory',
472+
'fixCode': _ReasonCode.create.name,
473+
});
474+
}
475+
case PlatformType.ios:
476+
if (!featureFlags.isIOSEnabled) {
477+
reasons.add(<String, Object>{
478+
'reasonText': 'the iOS feature is not enabled',
479+
'fixText': 'Run "flutter config --enable-ios"',
480+
'fixCode': _ReasonCode.config.name,
481+
});
482+
}
483+
if (!supportedPlatforms.contains(SupportedPlatform.ios)) {
484+
reasons.add(<String, Object>{
485+
'reasonText': 'the iOS platform is not enabled for this project',
486+
'fixText': 'Run "flutter create --platforms=ios ." in your application directory',
487+
'fixCode': _ReasonCode.create.name,
488+
});
489+
}
490+
case PlatformType.android:
491+
if (!featureFlags.isAndroidEnabled) {
492+
reasons.add(<String, Object>{
493+
'reasonText': 'the Android feature is not enabled',
494+
'fixText': 'Run "flutter config --enable-android"',
495+
'fixCode': _ReasonCode.config.name,
496+
});
497+
}
498+
if (!supportedPlatforms.contains(SupportedPlatform.android)) {
499+
reasons.add(<String, Object>{
500+
'reasonText': 'the Android platform is not enabled for this project',
501+
'fixText': 'Run "flutter create --platforms=android ." in your application directory',
502+
'fixCode': _ReasonCode.create.name,
503+
});
504+
}
505+
case PlatformType.web:
506+
if (!featureFlags.isWebEnabled) {
507+
reasons.add(<String, Object>{
508+
'reasonText': 'the Web feature is not enabled',
509+
'fixText': 'Run "flutter config --enable-web"',
510+
'fixCode': _ReasonCode.config.name,
511+
});
512+
}
513+
if (!supportedPlatforms.contains(SupportedPlatform.web)) {
514+
reasons.add(<String, Object>{
515+
'reasonText': 'the Web platform is not enabled for this project',
516+
'fixText': 'Run "flutter create --platforms=web ." in your application directory',
517+
'fixCode': _ReasonCode.create.name,
518+
});
519+
}
520+
case PlatformType.fuchsia:
521+
if (!featureFlags.isFuchsiaEnabled) {
522+
reasons.add(<String, Object>{
523+
'reasonText': 'the Fuchsia feature is not enabled',
524+
'fixText': 'Run "flutter config --enable-fuchsia"',
525+
'fixCode': _ReasonCode.config.name,
526+
});
527+
}
528+
if (!supportedPlatforms.contains(SupportedPlatform.fuchsia)) {
529+
reasons.add(<String, Object>{
530+
'reasonText': 'the Fuchsia platform is not enabled for this project',
531+
'fixText': 'Run "flutter create --platforms=fuchsia ." in your application directory',
532+
'fixCode': _ReasonCode.create.name,
533+
});
534+
}
535+
case PlatformType.custom:
536+
if (!featureFlags.areCustomDevicesEnabled) {
537+
reasons.add(<String, Object>{
538+
'reasonText': 'the custom devices feature is not enabled',
539+
'fixText': 'Run "flutter config --enable-custom-devices"',
540+
'fixCode': _ReasonCode.config.name,
541+
});
542+
}
543+
case PlatformType.windowsPreview:
544+
// TODO(fujino): detect if there any plugins with native code
545+
if (!featureFlags.isPreviewDeviceEnabled) {
546+
reasons.add(<String, Object>{
547+
'reasonText': 'the Preview Device feature is not enabled',
548+
'fixText': 'Run "flutter config --enable-flutter-preview',
549+
'fixCode': _ReasonCode.config.name,
550+
});
551+
}
552+
if (!supportedPlatforms.contains(SupportedPlatform.windows)) {
553+
reasons.add(<String, Object>{
554+
'reasonText': 'the Windows platform is not enabled for this project',
555+
'fixText': 'Run "flutter create --platforms=windows ." in your application directory',
556+
'fixCode': _ReasonCode.create.name,
557+
});
558+
}
559+
}
560+
561+
if (reasons.isEmpty) {
562+
platformTypes.add(platform.name);
563+
platformTypesMap[platform.name] = const <String, Object>{
564+
'isSupported': true,
565+
};
566+
} else {
567+
platformTypesMap[platform.name] = <String, Object>{
568+
'isSupported': false,
569+
'reasons': reasons,
570+
};
571+
}
446572
}
573+
574+
PlatformType.values.forEach(handlePlatformType);
575+
447576
return <String, Object>{
448-
'platforms': result,
577+
// TODO(fujino): delete this key https://github.com/flutter/flutter/issues/140473
578+
'platforms': platformTypes,
579+
'platformTypes': platformTypesMap,
449580
};
450581
} on Exception catch (err, stackTrace) {
451582
sendEvent('log', <String, Object?>{
@@ -454,12 +585,16 @@ class DaemonDomain extends Domain {
454585
'error': true,
455586
});
456587
// On any sort of failure, fall back to Android and iOS for backwards
457-
// comparability.
458-
return <String, Object>{
588+
// compatibility.
589+
return const <String, Object>{
459590
'platforms': <String>[
460591
'android',
461592
'ios',
462593
],
594+
'platformTypes': <String, Object>{
595+
'android': <String, Object>{'isSupported': true},
596+
'ios': <String, Object>{'isSupported': true},
597+
},
463598
};
464599
}
465600
}
@@ -470,6 +605,14 @@ class DaemonDomain extends Domain {
470605
}
471606
}
472607

608+
/// The reason a [PlatformType] is not currently supported.
609+
///
610+
/// The [name] of this value will be sent as a response to daemon client.
611+
enum _ReasonCode {
612+
create,
613+
config,
614+
}
615+
473616
typedef RunOrAttach = Future<void> Function({
474617
Completer<DebugConnectionInfo>? connectionInfoCompleter,
475618
Completer<void>? appStartedCompleter,

packages/flutter_tools/lib/src/device.dart

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -45,34 +45,20 @@ enum Category {
4545

4646
/// The platform sub-folder that a device type supports.
4747
enum PlatformType {
48-
web._('web'),
49-
android._('android'),
50-
ios._('ios'),
51-
linux._('linux'),
52-
macos._('macos'),
53-
windows._('windows'),
54-
fuchsia._('fuchsia'),
55-
custom._('custom');
56-
57-
const PlatformType._(this.value);
58-
59-
final String value;
48+
web,
49+
android,
50+
ios,
51+
linux,
52+
macos,
53+
windows,
54+
fuchsia,
55+
custom,
56+
windowsPreview;
6057

6158
@override
62-
String toString() => value;
59+
String toString() => name;
6360

64-
static PlatformType? fromString(String platformType) {
65-
return const <String, PlatformType>{
66-
'web': web,
67-
'android': android,
68-
'ios': ios,
69-
'linux': linux,
70-
'macos': macos,
71-
'windows': windows,
72-
'fuchsia': fuchsia,
73-
'custom': custom,
74-
}[platformType];
75-
}
61+
static PlatformType? fromString(String platformType) => values.asNameMap()[platformType];
7662
}
7763

7864
/// A discovery mechanism for flutter-supported development devices.

packages/flutter_tools/lib/src/preview_device.dart

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ BundleBuilder _defaultBundleBuilder() {
2929
return BundleBuilder();
3030
}
3131

32-
class PreviewDeviceDiscovery extends DeviceDiscovery {
32+
class PreviewDeviceDiscovery extends PollingDeviceDiscovery {
3333
PreviewDeviceDiscovery({
3434
required Platform platform,
3535
required Artifacts artifacts,
@@ -42,7 +42,8 @@ class PreviewDeviceDiscovery extends DeviceDiscovery {
4242
_processManager = processManager,
4343
_fileSystem = fileSystem,
4444
_platform = platform,
45-
_features = featureFlags;
45+
_features = featureFlags,
46+
super('Flutter preview device');
4647

4748
final Platform _platform;
4849
final Artifacts _artifacts;
@@ -61,9 +62,8 @@ class PreviewDeviceDiscovery extends DeviceDiscovery {
6162
List<String> get wellKnownIds => <String>['preview'];
6263

6364
@override
64-
Future<List<Device>> devices({
65+
Future<List<Device>> pollingGetDevices({
6566
Duration? timeout,
66-
DeviceDiscoveryFilter? filter,
6767
}) async {
6868
final File previewBinary = _fileSystem.file(_artifacts.getArtifactPath(Artifact.flutterPreviewDevice));
6969
if (!previewBinary.existsSync()) {
@@ -76,16 +76,8 @@ class PreviewDeviceDiscovery extends DeviceDiscovery {
7676
processManager: _processManager,
7777
previewBinary: previewBinary,
7878
);
79-
final bool matchesRequirements;
80-
if (!_features.isPreviewDeviceEnabled) {
81-
matchesRequirements = false;
82-
} else if (filter == null) {
83-
matchesRequirements = true;
84-
} else {
85-
matchesRequirements = await filter.matchesRequirements(device);
86-
}
8779
return <Device>[
88-
if (matchesRequirements)
80+
if (_features.isPreviewDeviceEnabled)
8981
device,
9082
];
9183
}
@@ -114,7 +106,7 @@ class PreviewDevice extends Device {
114106
_fileSystem = fileSystem,
115107
_bundleBuilderFactory = builderFactory,
116108
_artifacts = artifacts,
117-
super('preview', ephemeral: false, category: Category.desktop, platformType: PlatformType.custom);
109+
super('preview', ephemeral: false, category: Category.desktop, platformType: PlatformType.windowsPreview);
118110

119111
final ProcessManager _processManager;
120112
final Logger _logger;
@@ -161,7 +153,7 @@ class PreviewDevice extends Device {
161153
bool isSupportedForProject(FlutterProject flutterProject) => true;
162154

163155
@override
164-
String get name => 'preview';
156+
String get name => 'Preview';
165157

166158
@override
167159
DevicePortForwarder get portForwarder => const NoOpDevicePortForwarder();

0 commit comments

Comments
 (0)