Skip to content

Commit 410af14

Browse files
authored
Select simulator runtime for tests based on Xcode's preferred runtime build (#139919)
When creating a simulator for a test, select the runtime based on the selected Xcode's preferred build. This is to prevent it from using a runtime greater than its greatest supported version. Fixes flutter/flutter#139917. Example test with both iOS 16 and 17 available: https://chromium-swarm.appspot.com/task?id=6672aca184395a10
1 parent da20262 commit 410af14

File tree

1 file changed

+42
-3
lines changed

1 file changed

+42
-3
lines changed

dev/devicelab/lib/framework/ios.dart

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,6 @@ Future<void> testWithNewIOSSimulator(
5656
SimulatorFunction testFunction, {
5757
String deviceTypeId = 'com.apple.CoreSimulator.SimDeviceType.iPhone-11',
5858
}) async {
59-
// Xcode 11.4 simctl create makes the runtime argument optional, and defaults to latest.
60-
// TODO(jmagman): Remove runtime parsing when devicelab upgrades to Xcode 11.4 https://github.com/flutter/flutter/issues/54889
6159
final String availableRuntimes = await eval(
6260
'xcrun',
6361
<String>[
@@ -68,11 +66,48 @@ Future<void> testWithNewIOSSimulator(
6866
workingDirectory: flutterDirectory.path,
6967
);
7068

69+
final String runtimesForSelectedXcode = await eval(
70+
'xcrun',
71+
<String>[
72+
'simctl',
73+
'runtime',
74+
'match',
75+
'list',
76+
'--json',
77+
],
78+
workingDirectory: flutterDirectory.path,
79+
);
80+
81+
// Get the preferred runtime build for the selected Xcode version. Preferred
82+
// means the runtime was either bundled with Xcode, exactly matched your SDK
83+
// version, or it's indicated a better match for your SDK.
84+
final Map<String, Object?> decodeResult = json.decode(runtimesForSelectedXcode) as Map<String, Object?>;
85+
final String? iosKey = decodeResult.keys
86+
.where((String key) => key.contains('iphoneos'))
87+
.firstOrNull;
88+
final Object? iosDetails = decodeResult[iosKey];
89+
String? runtimeBuildForSelectedXcode;
90+
if (iosDetails != null && iosDetails is Map<String, Object?>) {
91+
final Object? preferredBuild = iosDetails['preferredBuild'];
92+
if (preferredBuild is String) {
93+
runtimeBuildForSelectedXcode = preferredBuild;
94+
}
95+
}
96+
7197
String? iOSSimRuntime;
7298

7399
final RegExp iOSRuntimePattern = RegExp(r'iOS .*\) - (.*)');
74100

101+
// [availableRuntimes] may include runtime versions greater than the selected
102+
// Xcode's greatest supported version. Use [runtimeBuildForSelectedXcode] when
103+
// possible to pick which runtime to use.
104+
// For example, iOS 17 (released with Xcode 15) may be available even if the
105+
// selected Xcode version is 14.
75106
for (final String runtime in LineSplitter.split(availableRuntimes)) {
107+
if (runtimeBuildForSelectedXcode != null &&
108+
!runtime.contains(runtimeBuildForSelectedXcode)) {
109+
continue;
110+
}
76111
// These seem to be in order, so allow matching multiple lines so it grabs
77112
// the last (hopefully latest) one.
78113
final RegExpMatch? iOSRuntimeMatch = iOSRuntimePattern.firstMatch(runtime);
@@ -82,7 +117,11 @@ Future<void> testWithNewIOSSimulator(
82117
}
83118
}
84119
if (iOSSimRuntime == null) {
85-
throw 'No iOS simulator runtime found. Available runtimes:\n$availableRuntimes';
120+
if (runtimeBuildForSelectedXcode != null) {
121+
throw 'iOS simulator runtime $runtimeBuildForSelectedXcode not found. Available runtimes:\n$availableRuntimes';
122+
} else {
123+
throw 'No iOS simulator runtime found. Available runtimes:\n$availableRuntimes';
124+
}
86125
}
87126

88127
final String deviceId = await eval(

0 commit comments

Comments
 (0)