Workaround for New Flutter Version on MacOS Catalina
Tags: flutter, macos, ios
Published: 2023-01-09 18:44:28

The Flutter SDK is a development framework that allows developers to write code once and run on multiple platforms such as mobile, web, and desktop.

In order to do iOS development, Flutter must be run on MacOS with an XCode installation. Since Flutter 3.0, XCode 13 is required. XCode 13 is not supported on MacOS Catalina (12.4 is the last XCode supported on MacOS Catalina). This means you can no longer do Flutter 3.0 development on MacOS Catalina.

Not everyone can afford to upgrade to Apple's pricy hardware. (Although the newly released M2 Mac mini makes it the cheapest Apple hardware to date, there are still a lot of folks in other parts of the world where household income is not high) For the developers with an old (and unsupported) Mac, this is frustrating.

Host Mac Version | Highest XCode | Target MacOS Version | Target iOS Version | Flutter Version | Dart SDK Version
---   | ---    | ---          | ---  | ---  | ---
10.15 | 12.4   | 11.1 | 14.4 | 2.10 | 2.16
11    | 13.2.1 | 12.1 | 15.2 | 3.0  | 2.17

I discovered a workaround that allows Flutter 3 to continue building on MacOS Catalina, but keep in mind this is not supported by the Flutter team and may cause unexpected issues.

The XCode version check is done in `packages/flutter_tools/lib/src/macos/xcode.dart` inside the Flutter SDK root folder. To reverse the check, we need to do something opposite of what https://github.com/flutter/flutter/pull/97746 did.

For Flutter 3.0.5: 

```diff
--- a/packages/flutter_tools/lib/src/macos/xcode.dart
+++ b/packages/flutter_tools/lib/src/macos/xcode.dart
@@ -18,11 +18,11 @@ import '../base/version.dart';
 import '../build_info.dart';
 import '../ios/xcodeproj.dart';

-Version get xcodeRequiredVersion => Version(13, null, null);
+Version get xcodeRequiredVersion => Version(12, 3, null, text: '12.3');

 /// Diverging this number from the minimum required version will provide a doctor
 /// warning, not error, that users should upgrade Xcode.
-Version get xcodeRecommendedVersion => xcodeRequiredVersion;
+Version get xcodeRecommendedVersion => Version(13, null, null, text: '13');

 /// SDK name passed to `xcrun --sdk`. Corresponds to undocumented Xcode
 /// SUPPORTED_PLATFORMS values.
```

For Flutter 3.3.10 / 3.7.9 / 3.10.6

```diff
--- a/packages/flutter_tools/lib/src/macos/xcode.dart
+++ b/packages/flutter_tools/lib/src/macos/xcode.dart
@@ -18,7 +18,7 @@ import '../base/version.dart';
 import '../build_info.dart';
 import '../ios/xcodeproj.dart';

-Version get xcodeRequiredVersion => Version(13, null, null);
+Version get xcodeRequiredVersion => Version(12, 3, null, text: '12.3');

 /// Diverging this number from the minimum required version will provide a doctor
 /// warning, not error, that users should upgrade Xcode.
```

For Flutter 3.13.0

```diff
--- a/packages/flutter_tools/lib/src/macos/xcode.dart
+++ b/packages/flutter_tools/lib/src/macos/xcode.dart
@@ -20,7 +20,7 @@ import '../base/version.dart';
 import '../build_info.dart';
 import '../ios/xcodeproj.dart';

-Version get xcodeRequiredVersion => Version(14, null, null);
+Version get xcodeRequiredVersion => Version(12, 3, null, text: '12.3');

 /// Diverging this number from the minimum required version will provide a doctor
 /// warning, not error, that users should upgrade Xcode.
```

Dart compiles the source on the fly when required, but if cache is available, it will use the compiled cache which will not contain our version check hack. You will need to delete the following file after making the above change:

```shell
rm bin/cache/flutter_tools.snapshot
```

After that, you can run your flutter normally. The first run will re-compile the flutter tools package with our version check hack.

This workaround merely disables the version check. As I can confirm with my experience with Flutter 3.0.5, 3.3.10, and 3.7.9, this change does not cause any major issue with building Flutter Apps for iOS for both the iOS emulator and for a real device. However, do note that if features relying on the newer XCode version are added, your build will break. 

I would only recommend using this workaround for development. If you need to produce production builds, I strongly recommend using a virtual machine with the latest MacOS version (which is painful to setup and use, but will nonetheless be able to run the latest XCode and Flutter "natively").

For now though, you can use continue to use your outdated Mac for a little longer for development and testing purposes.

PS: Yet another workaround is to upgrade your unsupported Mac to Big Sur/Monterey using OCLP. But at least for my iMac with an NVidia GPU, that configuration requires a little extra effort to inject the NVidia drivers and is less stable. So a few line changes in the SDK is a bit simpler for me.