Skip to content

Filter out SwiftPM schemes when fetching schemes#186006

Merged
auto-submit[bot] merged 11 commits into
flutter:masterfrom
lukemmtt:fix-watch-companion-swiftpm-scheme-scan
May 22, 2026
Merged

Filter out SwiftPM schemes when fetching schemes#186006
auto-submit[bot] merged 11 commits into
flutter:masterfrom
lukemmtt:fix-watch-companion-swiftpm-scheme-scan

Conversation

@lukemmtt
Copy link
Copy Markdown
Contributor

@lukemmtt lukemmtt commented May 4, 2026

Summary

In iOS projects with a watchOS companion target and Swift Package Manager enabled, IosProject.containsWatchCompanion() has a fallback path for modern Xcode projects where the companion relationship is declared through INFOPLIST_KEY_WKCompanionAppBundleIdentifier in project.pbxproj, rather than as a literal WKCompanionAppBundleIdentifier key in the watch target Info.plist.

That fallback iterates projectInfo.schemes and runs:

xcodebuild -showBuildSettings -destination generic/platform=watchOS

for each non-default scheme until it finds the watch companion scheme.

With SwiftPM enabled, xcodebuild -list can include schemes for direct Flutter plugin packages and transitive Swift packages, such as advertising-id, amplitude-flutter, Amplitude-Swift, RevenueCatUI, and SuperwallKit. Those schemes cannot be the host project's watch companion, but each failed watchOS build-settings probe can take multiple seconds.

This PR filters those non-host schemes earlier, in XcodeProjectInterpreter.getInfo(), before they become part of XcodeProjectInfo.schemes.

The current filter excludes:

  • FlutterGeneratedPluginSwiftPackage
  • FlutterFramework
  • plugin names from xcodeProject.getPlugins()
  • dashed and capitalized plugin-name variants, e.g. cloud_firestore, cloud-firestore, Cloud-firestore
  • transitive SwiftPM package schemes found under build/ios/SourcePackages/checkouts/*/.swiftpm/xcode/xcshareddata/xcschemes/*.xcscheme

I also removed the earlier shared-scheme-location filter from containsWatchCompanion(). That earlier approach was present in 0cfdd3a67c2, but it could skip valid non-shared host schemes. The current approach keeps the fallback behavior scheme-based while removing known SwiftPM package schemes from the candidate list.

Fixes #186004.

Measurements

Test project: TimeFinder app.

Command:

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

Benchmark condition for fallback rows: the literal WKCompanionAppBundleIdentifier key was removed from the watch target Info.plist, while the modern INFOPLIST_KEY_WKCompanionAppBundleIdentifier entries remained in project.pbxproj.

Scenario Unique watchOS probes before detection Time to detection, 3 trials Median Fallback scan only, 3 trials Median
Literal plist key present, no fallback 0 92.8s, 70.0s, 70.9s 70.9s n/a n/a
Unpatched baseline, no plist key 60 244.2s, 235.4s, 238.9s 238.9s 174.1s, 170.8s, 165.6s 170.8s
Earlier shared-scheme approach, no plist key 5 90.2s, 89.8s, 87.7s 89.8s 16.9s, 21.0s, 17.6s 17.6s
Current PR, no plist key 3 85.3s, 80.7s, 83.3s 83.3s 12.5s, 11.5s, 11.8s 11.8s

In this project, Xcode listed 67 schemes. The current filter reduced that to 6 retained schemes, and the fallback reached TimeFinderWatchApp after probing only:

  • LiveActivityWidgetExtension
  • ScheduleWidgetExtension
  • TimeFinderWatchApp

It did not probe direct plugin schemes or transitive SwiftPM package schemes, including Patrol, Amplitude-Swift, RevenueCatUI, RevenueCatUITests, or SuperwallKit.

Worth noting: TimeFinder is a worst-case-ish benchmark project for this issue: it has many SwiftPM package schemes, and xcodebuild -list returns schemes alphabetically here, so TimeFinderWatchApp is near the end of the candidate sequence. A project with a watch scheme that sorts early, such as AAAWatchApp, would see far less baseline overhead and therefore less benefit from this PR.

Test Plan

  • flutter test test/general.shard/ios/xcodeproj_test.dart
  • flutter test test/general.shard/project_test.dart --plain-name 'watch companion'
  • flutter analyze in packages/flutter_tools
  • git diff --check

@lukemmtt lukemmtt requested review from a team as code owners May 4, 2026 19:01
@github-actions github-actions Bot added tool Affects the "flutter" command-line tool. See also t: labels. team-ios Owned by iOS platform team team-macos Owned by the macOS platform team labels May 4, 2026
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements a filtering mechanism for Xcode schemes to skip Swift Package Manager schemes, reducing the time spent probing for watchOS companion targets. It verifies the existence of an .xcscheme file in the host project's shared schemes directory. Tests were updated to reflect this requirement and a new test case was added. Feedback indicates that the current implementation may skip valid schemes in workspaces or those not marked as shared.

Comment thread packages/flutter_tools/lib/src/xcode_project.dart Outdated
@lukemmtt lukemmtt changed the title Skip non-host schemes in watch companion fallback to avoid SwiftPM scan Skip schemes outside Runner.xcodeproj when detecting watch companion May 4, 2026
@LouiseHsu LouiseHsu added the CICD Run CI/CD label May 5, 2026
@vashworth vashworth self-requested a review May 5, 2026 17:36
Comment thread packages/flutter_tools/lib/src/xcode_project.dart Outdated
@vashworth vashworth added the waiting for response The Flutter team cannot make further progress on this issue until the original reporter responds label May 12, 2026
@vashworth
Copy link
Copy Markdown
Contributor

@lukemmtt Do you think this is something you have bandwidth for sometime this week or next? If not, I'll have my team take over so we can get this fixed ASAP. Let me know :)

@lukemmtt
Copy link
Copy Markdown
Contributor Author

Thanks for the note! Yes, I'll take a stab at it today and let you know :)

@github-actions github-actions Bot removed the waiting for response The Flutter team cannot make further progress on this issue until the original reporter responds label May 13, 2026
@okorohelijah okorohelijah self-requested a review May 13, 2026 20:52
lukemmtt added 3 commits May 13, 2026 16:54
In iOS projects with a watchOS companion target and Swift Package Manager enabled, IosProject.containsWatchCompanion()'s fallback path iterates every entry in projectInfo.schemes and runs xcodebuild -showBuildSettings -destination generic/platform=watchOS for each one. With SwiftPM, that list contains a scheme per resolved package and plugin, none of which can be a watch companion. Each probe takes ~2-3 seconds, so on a real project this added ~160s (60 probes) before the actual build started.

This change restricts the fallback to schemes that have an .xcscheme file under the host Xcode project's xcshareddata/xcschemes/ directory, so SwiftPM package schemes are skipped without an xcodebuild call.

Fixes flutter#186004
Addresses review feedback: the previous filter only checked
Runner.xcodeproj/xcshareddata/xcschemes, which would falsely skip
projects whose watch scheme is shared at the workspace level
(Runner.xcworkspace/xcshareddata/xcschemes) instead.

The host-shared check now passes when an .xcscheme file exists in
either the project's or the workspace's xcshareddata/xcschemes
directory. SwiftPM package schemes still appear in neither, so they
continue to be skipped.

Adds a test that places the scheme only at the workspace level and
asserts that containsWatchCompanion finds it.
Moves SwiftPM scheme filtering into XcodeProjectInterpreter.getInfo so callers receive an XcodeProjectInfo that excludes Flutter-generated Swift package schemes, direct plugin scheme names, plugin dash variants, and transitive Swift package schemes discovered under SourcePackages checkouts.

This keeps watch companion detection from probing SwiftPM package schemes while avoiding a host .xcscheme file requirement for valid non-shared project schemes.

Adds getInfo coverage for direct plugin schemes and transitive .swiftpm schemes, and restores watch companion tests to exercise generic non-default scheme probing.
@lukemmtt lukemmtt force-pushed the fix-watch-companion-swiftpm-scheme-scan branch from 28d6b49 to f9975fc Compare May 13, 2026 20:54
@github-actions github-actions Bot added platform-ios iOS applications specifically and removed CICD Run CI/CD labels May 13, 2026
@lukemmtt
Copy link
Copy Markdown
Contributor Author

Thanks again for the heads-up about #186378 landing; I’ve now rebased onto the latest main, force-pushed, and revisited this approach as follows:

The filtering logic has been moved earlier, into XcodeProjectInterpreter.getInfo(). It now excludes:

  • Default Flutter schemes (FlutterGeneratedPluginSwiftPackage, FlutterFramework)
  • Plugin schemes from xcodeProject.getPlugins() (as well as dashed and capitalized variants)
  • Transitive SwiftPM package schemes under SourcePackages/checkouts/*/.swiftpm/*

I’ve also removed the earlier shared-scheme filter from containsWatchCompanion(), so valid non-shared host schemes won’t be accidentally skipped.

Local testing against my TimeFinder app showed the scheme count reduced significantly as expected (67 → 6), and correctly detecting the watch companion (TimeFinderWatchApp) without probing unrelated plugin schemes (Patrol, Amplitude-Swift, etc).

Happy to address any needed revisions as quickly as I can. Thanks for the attention to this Victoria!

@lukemmtt lukemmtt changed the title Skip schemes outside Runner.xcodeproj when detecting watch companion Filter SwiftPM schemes when detecting watch companion May 14, 2026
Copy link
Copy Markdown
Contributor

@vashworth vashworth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks really great! Thanks for working on it! I think it just needs some doc comments and then should be good to go

Comment thread packages/flutter_tools/lib/src/ios/xcodeproj.dart
Comment thread packages/flutter_tools/lib/src/ios/xcodeproj.dart Outdated
Comment thread packages/flutter_tools/lib/src/ios/xcodeproj.dart Outdated
Comment thread packages/flutter_tools/lib/src/ios/xcodeproj.dart
@vashworth vashworth added the CICD Run CI/CD label May 15, 2026
lukemmtt added 3 commits May 18, 2026 16:32
Compare schemes parsed from `xcodebuild -list` against ignored scheme candidates case-insensitively instead of generating sentence-cased plugin variants. The ignored set still enumerates known plugin spellings (`snake_case` and dashed), while casing is handled at lookup time.

Add comments explaining why the watch companion fallback excludes generated Flutter SwiftPM package schemes, plugin scheme-name candidates, and schemes contributed by transitive SwiftPM checkouts. Addresses review feedback on flutter#186006.
@github-actions github-actions Bot removed the CICD Run CI/CD label May 18, 2026
@lukemmtt
Copy link
Copy Markdown
Contributor Author

Thanks for the thoughtful review @vashworth; I believe I've addressed all the comments. Let me know if you have any other suggestions. Thank you!

@lukemmtt
Copy link
Copy Markdown
Contributor Author

@okorohelijah Resolved 👍🏻

hellohuanlin
hellohuanlin previously approved these changes May 20, 2026
return ignoredSchemes;
}

/// Returns scheme names contributed by resolved Swift package checkouts.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are "transitive SwiftPM dependencies" covered by this helper? Maybe point it out in the comment?

@hellohuanlin hellohuanlin added the CICD Run CI/CD label May 20, 2026
Spell out that checkout-scheme filtering covers both direct and transitive Swift package checkouts. This addresses review feedback asking whether transitive SwiftPM dependencies are covered by the helper.
@vashworth
Copy link
Copy Markdown
Contributor

@lukemmtt Sorry looks like there are merge conflicts again, can you resolve?

@lukemmtt
Copy link
Copy Markdown
Contributor Author

For sure, doing it now, thanks!

…on-swiftpm-scheme-scan

# Conflicts:
#	packages/flutter_tools/lib/src/ios/xcodeproj.dart
#	packages/flutter_tools/test/general.shard/ios/xcodeproj_test.dart
@lukemmtt
Copy link
Copy Markdown
Contributor Author

Resolved 👍🏻

@vashworth vashworth added the CICD Run CI/CD label May 21, 2026
@vashworth vashworth added the autosubmit Merge PR when tree becomes green via auto submit App label May 21, 2026
@auto-submit auto-submit Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label May 21, 2026
@auto-submit
Copy link
Copy Markdown
Contributor

auto-submit Bot commented May 21, 2026

autosubmit label was removed for flutter/flutter/186006, because This PR has not met approval requirements for merging. The PR author is not a member of flutter-hackers and needs 1 more review(s) in order to merge this PR.

  • Merge guidelines: A PR needs at least one approved review if the author is already part of flutter-hackers or two member reviews if the author is not a member of flutter-hackers before re-applying the autosubmit label. Reviewers: If you left a comment approving, please use the "approve" review action instead.

@hellohuanlin hellohuanlin added the autosubmit Merge PR when tree becomes green via auto submit App label May 21, 2026
@github-actions github-actions Bot removed the CICD Run CI/CD label May 22, 2026
@okorohelijah okorohelijah added CICD Run CI/CD autosubmit Merge PR when tree becomes green via auto submit App and removed autosubmit Merge PR when tree becomes green via auto submit App labels May 22, 2026
@auto-submit auto-submit Bot added this pull request to the merge queue May 22, 2026
Merged via the queue into flutter:master with commit cc7a86d May 22, 2026
167 checks passed
@flutter-dashboard flutter-dashboard Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label May 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CICD Run CI/CD platform-ios iOS applications specifically team-ios Owned by iOS platform team team-macos Owned by the macOS platform team tool Affects the "flutter" command-line tool. See also t: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

6 participants