diff --git a/packages/flutter_tools/lib/src/ios/xcodeproj.dart b/packages/flutter_tools/lib/src/ios/xcodeproj.dart index 9625f32ef0d7..7980039e2c1d 100644 --- a/packages/flutter_tools/lib/src/ios/xcodeproj.dart +++ b/packages/flutter_tools/lib/src/ios/xcodeproj.dart @@ -47,6 +47,7 @@ class XcodeProjectInterpreter { required FileSystem fileSystem, required Usage usage, Version? version, + String? build, }) : _platform = platform, _fileSystem = fileSystem, _logger = logger, @@ -58,6 +59,7 @@ class XcodeProjectInterpreter { processManager: processManager, ), _version = version, + _build = build, _versionText = version?.toString(), _usage = usage; @@ -70,6 +72,7 @@ class XcodeProjectInterpreter { factory XcodeProjectInterpreter.test({ required ProcessManager processManager, Version? version = const Version.withText(1000, 0, 0, '1000.0.0'), + String? build = '13C100', }) { final Platform platform = FakePlatform( operatingSystem: 'macos', @@ -82,6 +85,7 @@ class XcodeProjectInterpreter { usage: TestUsage(), logger: BufferLogger.test(), version: version, + build: build, ); } @@ -91,8 +95,7 @@ class XcodeProjectInterpreter { final OperatingSystemUtils _operatingSystemUtils; final Logger _logger; final Usage _usage; - - static final RegExp _versionRegex = RegExp(r'Xcode ([0-9.]+)'); + static final RegExp _versionRegex = RegExp(r'Xcode ([0-9.]+).*Build version (\w+)'); void _updateVersion() { if (!_platform.isMacOS || !_fileSystem.file('/usr/bin/xcodebuild').existsSync()) { @@ -118,6 +121,7 @@ class XcodeProjectInterpreter { final int minorVersion = components.length < 2 ? 0 : int.parse(components[1]); final int patchVersion = components.length < 3 ? 0 : int.parse(components[2]); _version = Version(majorVersion, minorVersion, patchVersion); + _build = match.group(2); } on ProcessException { // Ignored, leave values null. } @@ -134,6 +138,7 @@ class XcodeProjectInterpreter { } Version? _version; + String? _build; Version? get version { if (_version == null) { _updateVersion(); @@ -141,6 +146,13 @@ class XcodeProjectInterpreter { return _version; } + String? get build { + if (_build == null) { + _updateVersion(); + } + return _build; + } + /// The `xcrun` Xcode command to run or locate development /// tools and properties. /// diff --git a/packages/flutter_tools/lib/src/macos/xcode.dart b/packages/flutter_tools/lib/src/macos/xcode.dart index 1096e0eb9e61..d92fd26e135f 100644 --- a/packages/flutter_tools/lib/src/macos/xcode.dart +++ b/packages/flutter_tools/lib/src/macos/xcode.dart @@ -101,6 +101,8 @@ class Xcode { Version? get currentVersion => _xcodeProjectInterpreter.version; + String? get buildVersion => _xcodeProjectInterpreter.build; + String? get versionText => _xcodeProjectInterpreter.versionText; bool? _eulaSigned; diff --git a/packages/flutter_tools/lib/src/macos/xcode_validator.dart b/packages/flutter_tools/lib/src/macos/xcode_validator.dart index 31030410c964..b3e1dbd2e46d 100644 --- a/packages/flutter_tools/lib/src/macos/xcode_validator.dart +++ b/packages/flutter_tools/lib/src/macos/xcode_validator.dart @@ -37,6 +37,9 @@ class XcodeValidator extends DoctorValidator { 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()))); diff --git a/packages/flutter_tools/test/general.shard/ios/xcodeproj_test.dart b/packages/flutter_tools/test/general.shard/ios/xcodeproj_test.dart index 52046d48d879..9b2a0d23f7bc 100644 --- a/packages/flutter_tools/test/general.shard/ios/xcodeproj_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/xcodeproj_test.dart @@ -146,6 +146,7 @@ void main() { ]); expect(xcodeProjectInterpreter.version, Version(11, 4, 1)); + expect(xcodeProjectInterpreter.build, '11N111s'); expect(fakeProcessManager, hasNoRemainingExpectations); }); @@ -173,6 +174,7 @@ void main() { ), ]); expect(xcodeProjectInterpreter.version, isNull); + expect(xcodeProjectInterpreter.build, isNull); expect(fakeProcessManager, hasNoRemainingExpectations); }); diff --git a/packages/flutter_tools/test/general.shard/macos/xcode_validator_test.dart b/packages/flutter_tools/test/general.shard/macos/xcode_validator_test.dart index 26f422314148..9ddd7e76e193 100644 --- a/packages/flutter_tools/test/general.shard/macos/xcode_validator_test.dart +++ b/packages/flutter_tools/test/general.shard/macos/xcode_validator_test.dart @@ -183,11 +183,12 @@ void main() { final XcodeValidator validator = XcodeValidator(xcode: xcode, userMessages: UserMessages()); final ValidationResult result = await validator.validate(); expect(result.type, ValidationType.installed); - expect(result.messages.length, 1); + expect(result.messages.length, 2); final ValidationMessage firstMessage = result.messages.first; expect(firstMessage.type, ValidationMessageType.information); expect(firstMessage.message, 'Xcode at /Library/Developer/CommandLineTools'); expect(result.statusInfo, '1000.0.0'); + expect(result.messages[1].message, 'Build 13C100'); }); }); } diff --git a/packages/flutter_tools/test/src/context.dart b/packages/flutter_tools/test/src/context.dart index 0cf2b5754143..9f6f61e54110 100644 --- a/packages/flutter_tools/test/src/context.dart +++ b/packages/flutter_tools/test/src/context.dart @@ -296,6 +296,9 @@ class FakeXcodeProjectInterpreter implements XcodeProjectInterpreter { @override Version get version => Version(13, null, null); + @override + String get build => '13C100'; + @override Future> getBuildSettings( String projectPath, {