Skip to content

[tool][iOS] Slow Apple Watch companion detection: scans every SwiftPM scheme #186004

Closed

Description

@lukemmtt

Summary

When an iOS app has a watchOS companion target and uses Swift Package Manager, Flutter's watch-companion detection probes every SwiftPM package scheme with xcodebuild -showBuildSettings -destination generic/platform=watchOS before finding the real watch scheme. In my project this added 161.5 seconds (60 scheme probes, ~2.7s each) before Running Xcode build....

A literal WKCompanionAppBundleIdentifier in the watch target's Info.plist is an effective workaround, but the underlying fallback scan is still over-broad.

Steps to reproduce

Project shape:

  • iOS app target + watchOS companion target.
  • SwiftPM enabled for iOS dependencies.
  • Runner.xcodeproj/project.pbxproj sets INFOPLIST_KEY_WKCompanionAppBundleIdentifier = com.example.App.
  • The watch target's Info.plist does not contain a literal WKCompanionAppBundleIdentifier key (it's only in build settings).

Run:

flutter build ios --debug --simulator --no-pub -v

IosProject.containsWatchCompanion() falls through the cheap Info.plist check into the build-settings fallback, which iterates projectInfo.schemes. With SwiftPM, that list contains every package/plugin scheme.

Expected

Flutter detects the watch companion without probing unrelated SwiftPM package schemes. The fallback should only consider schemes that can plausibly be host/watch app schemes.

Actual

Flutter runs xcodebuild -showBuildSettings ... -destination generic/platform=watchOS for each SwiftPM package scheme before reaching the real watch scheme. Examples from -v output:

xcodebuild -project Runner.xcodeproj -scheme advertising-id      -destination generic/platform=watchOS -showBuildSettings ...
xcodebuild -project Runner.xcodeproj -scheme amplitude-flutter   -destination generic/platform=watchOS -showBuildSettings ...
xcodebuild -project Runner.xcodeproj -scheme Amplitude-Swift     -destination generic/platform=watchOS -showBuildSettings ...
xcodebuild -project Runner.xcodeproj -scheme app-links           -destination generic/platform=watchOS -showBuildSettings ...
xcodebuild -project Runner.xcodeproj -scheme cloud-firestore     -destination generic/platform=watchOS -showBuildSettings ...
xcodebuild -project Runner.xcodeproj -scheme device-calendar     -destination generic/platform=watchOS -showBuildSettings ...

The build appears stalled (nothing else prints) until the scan finishes.

Workaround (user side)

containsWatchCompanion() first does a cheap check for a literal WKCompanionAppBundleIdentifier key in the watch target's Info.plist. If that key is present, the expensive fallback never runs.

Adding the key explicitly to the watch target's Info.plist (e.g. ios/<WatchTarget>/Info.plist) short-circuits detection:

<key>WKCompanionAppBundleIdentifier</key>
<string>com.example.App</string>

This is effective but it's a workaround, not a fix. Projects that rely on INFOPLIST_KEY_WKCompanionAppBundleIdentifier in project.pbxproj (the modern Xcode-generated form) still hit the slow path until they manually duplicate the value into the plist. Worth documenting either way.

Suggested fix direction (Flutter side)

The fallback loop lives in packages/flutter_tools/lib/src/xcode_project.dart. Restrict it to schemes that actually have an .xcscheme file in the host Xcode project, so SwiftPM package schemes are skipped before any xcodebuild -showBuildSettings call:

final Directory hostSchemesDir = xcodeProject
    .childDirectory('xcshareddata')
    .childDirectory('xcschemes');

for (final String scheme in projectInfo.schemes) {
  // Flutter assumes single build target per scheme, so skip default scheme.
  if (scheme == defaultScheme) {
    continue;
  }
  // SwiftPM package schemes can't be a watch companion. Only consider
  // schemes declared in the host .xcodeproj.
  if (!hostSchemesDir.childFile('$scheme.xcscheme').existsSync()) {
    continue;
  }

  final Map<String, String>? allBuildSettings = await buildSettingsForBuildInfo(
    buildInfo,
    scheme: scheme,
    isWatch: true,
  );
  // ...unchanged...
}

I ran a prototype of this filter against the same project and measured it (table below).

Measurements

All runs on Flutter 3.41.6.

Variant Outcome Time to detection
Baseline (no plist key, unpatched Flutter) 60 watchOS scheme probes; fallback scan completes; finds WatchApp 161.5s (avg 2.69s, median 2.66s, slowest 3.88s per probe)
Local flutter_tools patch implementing the filter below (no plist key) No package-scheme probes; fallback reaches WatchApp directly 22.0s
Workaround (plist key added, unpatched Flutter) Cheap path hits; Watch companion app found. printed 11.3s

Related

Environment

Flutter 3.41.6
Xcode 26.4.1 (Build version 17E202)
macOS 26.4.1

Activity

  1. changed the title [-]iOS watch companion detection scans SwiftPM package schemes and can stall before build[/-] [+]iOS watch companion detection stalls during build while scanning SPM package schemes[/+] on May 4, 2026
  2. changed the title [-]iOS watch companion detection stalls during build while scanning SPM package schemes[/-] [+][iOS, Apple Watch] Watch companion detection stalls during build due to scanning of SPM package schemes[/+] on May 4, 2026
  3. changed the title [-][iOS, Apple Watch] Watch companion detection stalls during build due to scanning of SPM package schemes[/-] [+][tool][iOS] Slow Apple Watch companion detection: scans every SwiftPM scheme[/+] on May 4, 2026
  4. added
    platform-iosiOS applications specifically
    platform-macosBuilding on or for macOS specifically
    team-iosOwned by iOS platform team
    toolAffects the "flutter" command-line tool. See also t: labels.
    c: performanceRelates to speed or footprint issues (see "perf:" labels)
    on May 5, 2026
  5. mbcorona commented on May 5, 2026

    @mbcorona
    Member

    Hi @lukemmtt, thanks for the analysis, the performance breakdown, and for already opening a PR with the fix.
    Routed to team-ios for review.

  6. added
    P1High-priority issues at the top of the work list
    on May 7, 2026
  7. added a commit that references this issue on May 22, 2026
    cc7a86d
  8. added a commit that references this issue on Jun 26, 2026
    e877b34
  9. github-actions commented on Jul 14, 2026

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  10. locked as resolved and limited conversation to collaborators on Jul 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High-priority issues at the top of the work listc: performanceRelates to speed or footprint issues (see "perf:" labels)platform-iosiOS applications specificallyplatform-macosBuilding on or for macOS specificallyteam-iosOwned by iOS platform teamtoolAffects the "flutter" command-line tool. See also t: labels.triaged-iosTriaged by iOS platform team

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions