flutter/packages/flutter_tools/test/general.shard/ios
Loïc Sharma ea208f824b
Fix flutter run on Mac x64 hosts if Swift Package Manager is enabled (#154645)
### Problem

Enabling the Swift Package Manager feature caused post-submit tests to fail on Mac x64 hosts:

<details>
<summary>Example error...</summary>

https://ci.chromium.org/ui/p/flutter/builders/prod/Mac_ios%20rrect_blur_perf_ios__timeline_summary/575/overview

```
♦ ... flutter --verbose assemble ... -dIosArchs=x86_64 ... profile_unpack_ios

Target profile_unpack_ios failed:
Exception: Binary ... build/ios/Profile-iphoneos/Flutter.framework/Flutter does not contain x86_64.

Running lipo -info:
Non-fat file: ... build/ios/Profile-iphoneos/Flutter.framework/Flutter is architecture: arm64

#0      UnpackIOS._thinFramework (package:flutter_tools/src/build_system/targets/ios.dart:351:7)
<asynchronous suspension>
#1      UnpackIOS.build (package:flutter_tools/src/build_system/targets/ios.dart:298:5)
<asynchronous suspension>
...
```

</details>

### Reproduction

On a mac x64 host:

1. Switch to the latest master channel: `flutter channel master ; flutter upgrade`
1. Disable the Swift Package Manager feature: `flutter config --no-enable-swift-package-manager`
2. Create a Flutter project
2. [Edit the Xcode project manually to add the prepare pre-action](https://docs.flutter.dev/packages-and-plugins/swift-package-manager/for-app-developers#step-2-add-run-prepare-flutter-framework-script-pre-action)
3. Run `flutter run` (`flutter build ios` does not reproduce this issue).

### Background

Previously, the Flutter framework was unpacked in the Xcode target's build. Unfortunately, this happens after Swift packages are built; this prevented Swift packages from using the Flutter framework.

To fix this, we added an Xcode pre-action that unpacks the Flutter framework _before_ Swift Package Manager builds packages. The Xcode target still runs the Flutter framework unpack step, but this step no-ops if the unpack step has the exact same inputs. 

```mermaid
flowchart LR
  A[flutter run -d iphone] --> B(Build Xcode project)
  B --> C(Xcode 'prepare framework' pre-action)
  B --> G[Build Swift packages]
  B --> D(Build 'Runner' target)
  C --> E[Unpack Flutter framework #1]
  D --> F["
  Unpack Flutter framework #2
  (No-ops if inputs are same as #1)
  "]
```

https://github.com/flutter/flutter/pull/150052 added an optimization that made it more likely the second unpack step no-ops by fixing a case where the target architecture input could be different:

> When using SwiftPM, we use `flutter assemble` in an Xcode Pre-action to run the `debug_unpack_macos` (or profile/release) target. This target is also later used in a Run Script build phase. Depending on `ARCHS` build setting, the Flutter/FlutterMacOS binary is thinned. In the Run Script build phase, `ARCHS` is filtered to the active arch. However, in the Pre-action it doesn't always filter to the active arch. As a workaround, assume arm64 if the [`NATIVE_ARCH`](https://developer.apple.com/documentation/xcode/build-settings-reference/#NATIVEARCH) is arm, otherwise assume x86_64.

This optimization is only applied if [`ONLY_ACTIVE_ARCH`](https://developer.apple.com/library/archive/documentation/DeveloperTools/Reference/XcodeBuildSettingRef/1-Build_Setting_Reference/build_setting_ref.html#//apple_ref/doc/uid/TP40003931-CH3-SW157) is `YES`.

> [!IMPORTANT]
> [`ONLY_ACTIVE_ARCH`](https://developer.apple.com/library/archive/documentation/DeveloperTools/Reference/XcodeBuildSettingRef/1-Build_Setting_Reference/build_setting_ref.html#//apple_ref/doc/uid/TP40003931-CH3-SW157)'s name is misleading. It specifies whether the product includes only object code for the native architecture.
>
> A value of `YES` means the product includes only code for the native architecture ([NATIVE_ARCH](https://developer.apple.com/library/archive/documentation/DeveloperTools/Reference/XcodeBuildSettingRef/1-Build_Setting_Reference/build_setting_ref.html#//apple_ref/doc/uid/TP40003931-CH3-SW59)).
>
> A value of `NO` means the product includes code for the architectures specified in [ARCHS (Architectures)](https://developer.apple.com/library/archive/documentation/DeveloperTools/Reference/XcodeBuildSettingRef/1-Build_Setting_Reference/build_setting_ref.html#//apple_ref/doc/uid/TP40003931-CH3-SW62).

### Problem

`buildXcodeProject` incorrectly always sets `ONLY_ACTIVE_ARCH` to `YES` if the Xcode built is for a single architecture:

6abef22251/packages/flutter_tools/lib/src/ios/mac.dart (L353-L361)

This is incorrect! If the host architecture is `x64` but the target architecture is `arm64`, [`ONLY_ACTIVE_ARCH`](https://developer.apple.com/library/archive/documentation/DeveloperTools/Reference/XcodeBuildSettingRef/1-Build_Setting_Reference/build_setting_ref.html#//apple_ref/doc/uid/TP40003931-CH3-SW157) should be `NO`.

This caused the prepare pre-action to incorrectly use x64 as the target architecture for arm64 devices on an x64 host, which in turn caused builds to fail if Swift Package Manager was enabled.

### Solution

This change updates `buildXcodeProject` to set `ONLY_ACTIVE_ARCH` correctly.

This change also updates the prepare pre-action's to be more conservative in applying the optimization that filters the target architecture. This ensures that the build still works (but without the optimization) if `ONLY_ACTIVE_ARCH` is incorrectly set.

Follow-up PR: https://github.com/flutter/flutter/pull/154649

This unblocks: https://github.com/flutter/flutter/issues/151567

### DeviceLab test

This problem reproduces if you `flutter run` to an iPhone Arm64 device from an x64 mac host with the Swift Package Manager feature enabled.

I ran an affected DeviceLab test to verify the fix works as expected:

Description | CI test | Result
-- | -- | --
SwiftPM enabled without this fix: https://github.com/flutter/flutter/pull/154750 | [Link](https://ci.chromium.org/ui/p/flutter/builders/try.shadow/Mac_ios%20rrect_blur_perf_ios__timeline_summary/7/overview) | ❌ 
SwiftPM enabled with this fix: https://github.com/flutter/flutter/pull/154749 | [Link](https://ci.chromium.org/ui/p/flutter/builders/try.shadow/Mac_ios%20rrect_blur_perf_ios__timeline_summary/8/overview) | âœ
2024-09-11 20:03:22 +00:00
..
code_signing_test.dart [tool] when writing to openssl as a part of macOS/iOS code-signing, flush the stdin stream before closing it (#150120) 2024-06-28 22:01:04 +00:00
core_devices_test.dart [flutter_tools] add debugging to ios/core_devices.dart (#142187) 2024-01-31 15:36:15 -08:00
devices_test.dart Fixed race condition in PollingDeviceDiscovery. (#145506) 2024-03-21 22:37:08 +00:00
ios_deploy_test.dart Make ios_deploy_test.dart more robust (#153147) 2024-08-09 12:53:15 +02:00
ios_device_install_test.dart Print warning and exit when iOS device is unpaired (#144551) 2024-03-04 23:01:11 +00:00
ios_device_logger_test.dart [flutter_tools] catch SocketException writing to ios-deploy stdin (#139784) 2023-12-12 00:32:18 +00:00
ios_device_port_forwarder_test.dart [tool] Consistent FakeProcessManager.run/runSync (#103947) 2022-05-17 11:15:54 -07:00
ios_device_project_test.dart Print warning and exit when iOS device is unpaired (#144551) 2024-03-04 23:01:11 +00:00
ios_device_start_nonprebuilt_test.dart Fix flutter run on Mac x64 hosts if Swift Package Manager is enabled (#154645) 2024-09-11 20:03:22 +00:00
ios_device_start_prebuilt_test.dart Print warning and exit when iOS device is unpaired (#144551) 2024-03-04 23:01:11 +00:00
ios_project_migration_test.dart [tool] Remove some usages of deprecated usage package (#151359) 2024-07-09 18:17:21 +00:00
ios_workflow_test.dart Only show iOS simulators, reduce output spew in verbose (#108345) 2022-07-26 19:08:06 +00:00
mac_test.dart Reland "Load parent package config" (#153754) 2024-08-20 15:30:46 +02:00
simulators_test.dart Reland "Launch DDS from Dart SDK and prepare to serve DevTools from DDS (#146593)" (#152386) 2024-07-26 20:51:19 +00:00
xcode_debug_test.dart chore: fix some comments (#145397) 2024-03-19 17:00:24 +00:00
xcodeproj_test.dart Remove -sdk for watchOS simulator in tool (#152992) 2024-08-08 19:34:20 +00:00
xcresult_test_data.dart Reland "Print pretty error when xcodebuild fails due to missing simulator #130286" (#130506) 2023-07-13 19:36:10 +00:00
xcresult_test.dart Add xcresulttool --legacy flag for deprecated usage (#152988) 2024-08-07 19:59:11 +00:00