blob: 1604876fb9c0c9362c38ecf7e7c655109b709235 [file] [log] [blame]
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import '../base/user_messages.dart';
import '../base/version.dart';
import '../build_info.dart';
import '../doctor_validator.dart';
import '../ios/simulators.dart';
import 'xcode.dart';
String _iOSSimulatorMissing(String version) => '''
iOS $version Simulator not installed; this may be necessary for iOS and macOS development.
To download and install the platform, open Xcode, select Xcode > Settings > Platforms,
and click the GET button for the required platform.
For more information, please visit:
https://developer.apple.com/documentation/xcode/installing-additional-simulator-runtimes''';
class XcodeValidator extends DoctorValidator {
XcodeValidator({
required Xcode xcode,
required IOSSimulatorUtils iosSimulatorUtils,
required UserMessages userMessages,
}) : _xcode = xcode,
_iosSimulatorUtils = iosSimulatorUtils,
_userMessages = userMessages,
super('Xcode - develop for iOS and macOS');
final Xcode _xcode;
final IOSSimulatorUtils _iosSimulatorUtils;
final UserMessages _userMessages;
@override
Future<ValidationResult> validate() async {
final List<ValidationMessage> messages = <ValidationMessage>[];
ValidationType xcodeStatus = ValidationType.missing;
String? xcodeVersionInfo;
final String? xcodeSelectPath = _xcode.xcodeSelectPath;
if (_xcode.isInstalled) {
xcodeStatus = ValidationType.success;
if (xcodeSelectPath != null) {
messages.add(ValidationMessage(_userMessages.xcodeLocation(xcodeSelectPath)));
}
final String? versionText = _xcode.versionText;
if (versionText != null) {
xcodeVersionInfo = versionText;
if (xcodeVersionInfo.contains(',')) {
xcodeVersionInfo = xcodeVersionInfo.substring(0, xcodeVersionInfo.indexOf(','));
}
}
if (_xcode.buildVersion != null) {
messages.add(ValidationMessage('Build ${_xcode.buildVersion}'));
}
if (!_xcode.isInstalledAndMeetsVersionCheck) {
xcodeStatus = ValidationType.partial;
messages.add(ValidationMessage.error(_userMessages.xcodeOutdated(xcodeRequiredVersion.toString())));
} else if (!_xcode.isRecommendedVersionSatisfactory) {
xcodeStatus = ValidationType.partial;
messages.add(ValidationMessage.hint(_userMessages.xcodeRecommended(xcodeRecommendedVersion.toString())));
}
if (!_xcode.eulaSigned) {
xcodeStatus = ValidationType.partial;
messages.add(ValidationMessage.error(_userMessages.xcodeEula));
}
if (!_xcode.isSimctlInstalled) {
xcodeStatus = ValidationType.partial;
messages.add(ValidationMessage.error(_userMessages.xcodeMissingSimct));
}
final ValidationMessage? missingSimulatorMessage = await _validateSimulatorRuntimeInstalled();
if (missingSimulatorMessage != null) {
xcodeStatus = ValidationType.partial;
messages.add(missingSimulatorMessage);
}
} else {
xcodeStatus = ValidationType.missing;
if (xcodeSelectPath == null || xcodeSelectPath.isEmpty) {
messages.add(ValidationMessage.error(_userMessages.xcodeMissing));
} else {
messages.add(ValidationMessage.error(_userMessages.xcodeIncomplete));
}
}
return ValidationResult(xcodeStatus, messages, statusInfo: xcodeVersionInfo);
}
/// Validate the Xcode-installed iOS simulator SDK has a corresponding iOS
/// simulator runtime installed.
///
/// Starting with Xcode 15, the iOS simulator runtime is no longer downloaded
/// with Xcode and must be downloaded and installed separately.
/// iOS applications cannot be run without it.
Future<ValidationMessage?> _validateSimulatorRuntimeInstalled() async {
// Skip this validation if Xcode is not installed, Xcode is a version less
// than 15, simctl is not installed, or if the EULA is not signed.
if (!_xcode.isInstalled ||
_xcode.currentVersion == null ||
_xcode.currentVersion!.major < 15 ||
!_xcode.isSimctlInstalled ||
!_xcode.eulaSigned) {
return null;
}
final Version? platformSDKVersion = await _xcode.sdkPlatformVersion(EnvironmentType.simulator);
if (platformSDKVersion == null) {
return const ValidationMessage.error('Unable to find the iPhone Simulator SDK.');
}
final List<IOSSimulatorRuntime> runtimes = await _iosSimulatorUtils.getAvailableIOSRuntimes();
if (runtimes.isEmpty) {
return const ValidationMessage.error('Unable to get list of installed Simulator runtimes.');
}
// Verify there is a simulator runtime installed matching the
// iphonesimulator SDK major version.
try {
runtimes.firstWhere(
(IOSSimulatorRuntime runtime) =>
runtime.version?.major == platformSDKVersion.major,
);
} on StateError {
return ValidationMessage.hint(_iOSSimulatorMissing(platformSDKVersion.toString()));
}
return null;
}
}