Skip to content

Conversation

@MohammedTarigg
Copy link
Contributor

flutter_tools: Auto-generate ExportOptions.plist for manual iOS code signing

Summary

Enhance flutter build ipa to automatically generate a complete ExportOptions.plist for manual code signing configurations, eliminating the need for users to create and maintain one manually.

Fixes: #177853

Problem

When using manual code signing (CODE_SIGN_STYLE=Manual) with flutter build ipa for Release/Profile builds, the archive succeeds but the export step fails with:

error: exportArchive: "Runner.app" requires a provisioning profile with the Push Notifications and Sign in with Apple features.

Root cause: Flutter generated an incomplete ExportOptions.plist that only included method and uploadBitcode. When using manual signing, xcodebuild -exportArchive requires:

  • teamID (from project's DEVELOPMENT_TEAM)
  • signingStyle=manual
  • provisioningProfiles (mapping bundle ID to provisioning profile UUID)

Without these, Xcode cannot resolve the provisioning profile for export, even if the profile is correctly configured and contains the required entitlements.

Solution

Enhanced _createExportPlist() in BuildIOSArchiveCommand to automatically generate a complete ExportOptions.plist when:

  1. CODE_SIGN_STYLE=Manual is detected for the main app target
  2. Build mode is Release or Profile (production builds only)
  3. A valid provisioning profile can be located and parsed

The generated plist includes:

  • method (app-store, ad-hoc, enterprise, etc. - respects user's --export-method flag)
  • teamID (from DEVELOPMENT_TEAM build setting)
  • signingStyle=manual
  • provisioningProfiles mapping main app bundle ID to provisioning profile UUID

Fallback behavior:

  • If profile lookup fails: silently fall back to simple plist (no regression)
  • For Automatic signing: unchanged behavior
  • For Debug builds: unchanged behavior (not App Store export)
  • For multi-target apps (extensions): falls back to simple plist today (see TODO below)

Changes

Core Implementation

  • Added ProfileData class to encapsulate provisioning profile info (UUID and name)
  • Refactored profile handling into reusable static methods for testability
  • Enhanced _createExportPlist() with manual signing detection and profile lookup
  • Added _findProvisioningProfileUuid() to locate provisioning profiles by specifier
  • Added _parseProvisioningProfileInfo() to decode provisioning profile data once
  • Added comprehensive trace logging for debugging

Testing

  • Created build_ipa_export_plist_test.dart with 7 unit tests covering:
    • Manual signing with profile found → enhanced plist generated ✓
    • Automatic signing → simple plist (unchanged behavior) ✓
    • Debug builds → simple plist (unchanged behavior) ✓
    • Different export methods → respected in generated plist ✓
    • Profile lookup failures → fallback to simple plist ✓
    • Null codeSignStyle → handled gracefully ✓
  • All existing flutter_tools tests continue to pass

Documentation

Added extensive inline comments explaining:

  • Enhancement conditions and fallback behavior
  • Provisioning profile search strategy and error handling
  • Performance and security considerations
  • Future enhancements (multi-target support)

Safety & Scope

What This Fixes

  • ✅ Manual signing export failures for apps with Push Notifications / Sign in with Apple
  • ✅ Auto-generates correct plist for any entitlements covered by provisioning profile
  • ✅ Unblocks users from manual --export-options-plist workaround
  • ✅ Improves iOS build UX for enterprise teams doing manual signing

What This Does NOT Change

  • ✅ Automatic signing behavior (unchanged)
  • ✅ Debug builds (unchanged)
  • ✅ CLI interface (no new flags)
  • ✅ Ad-hoc / enterprise distributions (unchanged if not using manual signing)

Known Limitations (Future Enhancements)

  • Currently only supports single-target apps (main app bundle ID only)
  • TODO: Multi-target apps with extensions (notification service, widgets, watch, etc.) - each extension target bundle ID may need separate entry in provisioningProfiles dict
  • TODO: Support for multiple provisioning profiles if app uses multiple signing identities

Pre-merge Checklist

Safety Notes

  • This code only runs for manual code signing in flutter build ipa for Release/Profile builds
  • Debug builds and automatic signing behavior are completely unchanged
  • If no provisioning profile UUID is found, we silently fall back to the old exportOptions.plist logic instead of failing
  • Added trace-level logging explaining success/fallback scenarios for debugging
  • No breaking changes - existing workarounds continue to work
  • Minimal blast radius - only affects manual signing export path

Verification

Users can verify the fix by:

  1. Creating an iOS app with CODE_SIGN_STYLE=Manual, DEVELOPMENT_TEAM set, and Push Notifications entitlements
  2. Running flutter build ipa --release --verbose
  3. Confirming the trace log shows "Generated ExportOptions.plist with teamID, signingStyle=manual, and provisioningProfiles"
  4. Verifying the IPA is successfully created without needing --export-options-plist

Related Issues

@MohammedTarigg MohammedTarigg requested a review from a team as a code owner November 1, 2025 20:40
@github-actions github-actions bot added tool Affects the "flutter" command-line tool. See also t: labels. team-ios Owned by iOS platform team labels Nov 1, 2025
Copy link
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 enhances flutter build ipa to automatically generate a complete ExportOptions.plist for manual code signing configurations. This is a significant improvement for developers using manual signing, especially for apps with entitlements like Push Notifications. The changes include adding logic to detect manual signing, find the correct provisioning profile, and generate an enhanced plist with the necessary signing information. The implementation includes robust fallback mechanisms and extensive logging. New unit tests have been added to cover the new logic, and existing tests are updated. The code is well-documented and follows good practices for testability and maintainability. I have a couple of minor suggestions for improving code style and readability.

MohammedTarigg added a commit to MohammedTarigg/flutter that referenced this pull request Nov 1, 2025
…est practices

- Simplify FakeXcodeProjectInterpreter.getBuildSettings by defining defaults
  first, then spreading overrides (eliminates redundant ?? operators)
- Replace listSync() with await for (using list()) in _findProvisioningProfileUuid
  for better asynchronous code style and non-blocking file system operations

Addresses code review feedback from PR flutter#177888
MohammedTarigg added a commit to MohammedTarigg/flutter that referenced this pull request Nov 1, 2025
…iene

Add comments directly above skip parameters explaining why integration
tests are skipped. This satisfies Flutter's tree hygiene requirement
that all skipped tests must have justification comments.

Fixes CI failure in PR flutter#177888
MohammedTarigg added a commit to MohammedTarigg/flutter that referenced this pull request Nov 2, 2025
…est practices

- Simplify FakeXcodeProjectInterpreter.getBuildSettings by defining defaults
  first, then spreading overrides (eliminates redundant ?? operators)
- Replace listSync() with await for (using list()) in _findProvisioningProfileUuid
  for better asynchronous code style and non-blocking file system operations

Addresses code review feedback from PR flutter#177888
MohammedTarigg added a commit to MohammedTarigg/flutter that referenced this pull request Nov 2, 2025
…iene

Add comments directly above skip parameters explaining why integration
tests are skipped. This satisfies Flutter's tree hygiene requirement
that all skipped tests must have justification comments.

Fixes CI failure in PR flutter#177888
@MohammedTarigg MohammedTarigg force-pushed the improve-ios-export-options-manual-signing branch from 8d1771c to 959303b Compare November 2, 2025 10:26
MohammedTarigg added a commit to MohammedTarigg/flutter that referenced this pull request Nov 2, 2025
…est practices

- Simplify FakeXcodeProjectInterpreter.getBuildSettings by defining defaults
  first, then spreading overrides (eliminates redundant ?? operators)
- Replace listSync() with await for (using list()) in _findProvisioningProfileUuid
  for better asynchronous code style and non-blocking file system operations

Addresses code review feedback from PR flutter#177888
MohammedTarigg added a commit to MohammedTarigg/flutter that referenced this pull request Nov 2, 2025
…iene

Add comments directly above skip parameters explaining why integration
tests are skipped. This satisfies Flutter's tree hygiene requirement
that all skipped tests must have justification comments.

Fixes CI failure in PR flutter#177888
@MohammedTarigg MohammedTarigg force-pushed the improve-ios-export-options-manual-signing branch from cfd6ca6 to 0ac20f1 Compare November 2, 2025 15:52
MohammedTarigg added a commit to MohammedTarigg/flutter that referenced this pull request Nov 3, 2025
…est practices

- Simplify FakeXcodeProjectInterpreter.getBuildSettings by defining defaults
  first, then spreading overrides (eliminates redundant ?? operators)
- Replace listSync() with await for (using list()) in _findProvisioningProfileUuid
  for better asynchronous code style and non-blocking file system operations

Addresses code review feedback from PR flutter#177888
MohammedTarigg added a commit to MohammedTarigg/flutter that referenced this pull request Nov 3, 2025
…iene

Add comments directly above skip parameters explaining why integration
tests are skipped. This satisfies Flutter's tree hygiene requirement
that all skipped tests must have justification comments.

Fixes CI failure in PR flutter#177888
@MohammedTarigg MohammedTarigg force-pushed the improve-ios-export-options-manual-signing branch from f9b8aa3 to a10a5f0 Compare November 3, 2025 06:27
@MohammedTarigg MohammedTarigg force-pushed the improve-ios-export-options-manual-signing branch from 028bcb9 to b3a900b Compare November 8, 2025 10:18
MohammedTarigg added a commit to MohammedTarigg/flutter that referenced this pull request Nov 8, 2025
…est practices

- Simplify FakeXcodeProjectInterpreter.getBuildSettings by defining defaults
  first, then spreading overrides (eliminates redundant ?? operators)
- Replace listSync() with await for (using list()) in _findProvisioningProfileUuid
  for better asynchronous code style and non-blocking file system operations

Addresses code review feedback from PR flutter#177888
@MohammedTarigg MohammedTarigg force-pushed the improve-ios-export-options-manual-signing branch from b3a900b to 7c71a1f Compare November 8, 2025 10:23
MohammedTarigg added a commit to MohammedTarigg/flutter that referenced this pull request Nov 8, 2025
…iene

Add comments directly above skip parameters explaining why integration
tests are skipped. This satisfies Flutter's tree hygiene requirement
that all skipped tests must have justification comments.

Fixes CI failure in PR flutter#177888
Copy link
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.

Thanks for the contribution! Overall the concept sounds good to me. I left some comments on tweaking the implementation to make it more testable.

@MohammedTarigg MohammedTarigg force-pushed the improve-ios-export-options-manual-signing branch from a9e070d to 7c71a1f Compare November 14, 2025 10:31
@fluttergithubbot
Copy link
Contributor

An existing Git SHA, 7c71a1f7e35b45bfb7f476276f41ae920b91b09e, was detected, and no actions were taken.

To re-trigger presubmits after closing or re-opeing a PR, or pushing a HEAD commit (i.e. with --force) that already was pushed before, push a blank commit (git commit --allow-empty -m "Trigger Build") or rebase to continue.

MohammedTarigg added a commit to MohammedTarigg/flutter that referenced this pull request Nov 14, 2025
- Remove design decision comment from BuildIOSArchiveCommand class doc
- Remove empty integration test placeholders (move rationale to PR description)
- Remove redundant buildInfo declaration (line 575)
- Make createExportPlist public with buildSettings parameter
- Fetch buildSettings at call site and pass to public method
- Remove test-only createExportPlistForTesting method
- Remove unnecessary private wrapper methods
- Update tests to use public createExportPlist method via command instance
- Update all tests to pass buildSettings instead of individual parameters

Follows Flutter's style guide: test APIs belong in test frameworks, not in the codebase.
MohammedTarigg added a commit to MohammedTarigg/flutter that referenced this pull request Nov 14, 2025
- Remove design decision comment from BuildIOSArchiveCommand class doc
- Remove empty integration test placeholders (move rationale to PR description)
- Remove redundant buildInfo declaration (line 575)
- Make createExportPlist public with buildSettings parameter
- Fetch buildSettings at call site and pass to public method
- Remove test-only createExportPlistForTesting method
- Remove unnecessary private wrapper methods
- Update tests to use public createExportPlist method via command instance
- Update all tests to pass buildSettings instead of individual parameters

Follows Flutter's style guide: test APIs belong in test frameworks, not in the codebase.
@MohammedTarigg MohammedTarigg force-pushed the improve-ios-export-options-manual-signing branch from 4070b45 to afa4f9a Compare November 14, 2025 10:36
MohammedTarigg added a commit to MohammedTarigg/flutter that referenced this pull request Nov 14, 2025
- Remove design decision comment from BuildIOSArchiveCommand class doc
- Remove empty integration test placeholders (move rationale to PR description)
- Remove redundant buildInfo declaration (line 575)
- Make createExportPlist public with buildSettings parameter
- Fetch buildSettings at call site and pass to public method
- Remove test-only createExportPlistForTesting method
- Remove unnecessary private wrapper methods
- Update tests to use public createExportPlist method via command instance
- Update all tests to pass buildSettings instead of individual parameters

Follows Flutter's style guide: test APIs belong in test frameworks, not in the codebase.
@auto-submit
Copy link
Contributor

auto-submit bot commented Jan 7, 2026

autosubmit label was removed for flutter/flutter/177888, because The base commit of the PR is older than 7 days and can not be merged. Please merge the latest changes from the main into this branch and resubmit the PR.

@okorohelijah okorohelijah added the autosubmit Merge PR when tree becomes green via auto submit App label Jan 8, 2026
@auto-submit auto-submit bot added this pull request to the merge queue Jan 8, 2026
Merged via the queue into flutter:master with commit 93cba59 Jan 8, 2026
141 checks passed
@flutter-dashboard flutter-dashboard bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Jan 8, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jan 8, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jan 8, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jan 8, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jan 8, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jan 9, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jan 9, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jan 9, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jan 9, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jan 10, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jan 10, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jan 10, 2026
auto-submit bot pushed a commit to flutter/packages that referenced this pull request Jan 10, 2026
Roll Flutter from 01d37bc to 73769a2 (65 revisions)

flutter/flutter@01d37bc...73769a2

2026-01-10 engine-flutter-autoroll@skia.org Roll Dart SDK from 5e855c2bb3ef to 87fbfd5381b6 (1 revision) (flutter/flutter#180800)
2026-01-10 engine-flutter-autoroll@skia.org Roll Skia from b2b109f0e980 to f39cc645b1dd (2 revisions) (flutter/flutter#180796)
2026-01-10 engine-flutter-autoroll@skia.org Roll Dart SDK from b7963905e6a2 to 5e855c2bb3ef (2 revisions) (flutter/flutter#180794)
2026-01-10 ahmedsameha1@gmail.com Make sure that a CupertinoTabScaffold doesn't crash in 0x0 environment (flutter/flutter#179824)
2026-01-10 engine-flutter-autoroll@skia.org Roll Dart SDK from d25ad331b7ea to b7963905e6a2 (2 revisions) (flutter/flutter#180783)
2026-01-10 ahmedsameha1@gmail.com Make sure that a Container doesn't crash in 0x0 environment (flutter/flutter#180350)
2026-01-10 ahmedsameha1@gmail.com Make sure that an Expansible doesn't crash in 0x0 environment (flutter/flutter#180478)
2026-01-10 98614782+auto-submit[bot]@users.noreply.github.com Reverts "Enabled some disabled impeller fragment shader dart tests (#180759)" (flutter/flutter#180785)
2026-01-09 dkwingsmt@users.noreply.github.com Merge `widget_tester_leaks_free_test.dart` into `widget_tester_test.dart` (flutter/flutter#180600)
2026-01-09 codefu@google.com fix: there are no riscv fuchsia artifacts (flutter/flutter#180779)
2026-01-09 engine-flutter-autoroll@skia.org Roll Skia from 7386219151e6 to b2b109f0e980 (1 revision) (flutter/flutter#180771)
2026-01-09 chinmaygarde@google.com Re-prioritize pipeline compile jobs and perform them eagerly instead of waiting. (flutter/flutter#180022)
2026-01-09 30870216+gaaclarke@users.noreply.github.com Enabled some disabled impeller fragment shader dart tests (flutter/flutter#180759)
2026-01-09 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from rxeg-6UB678HKJ4UQ... to 83Favz_zzMzdVuOHg... (flutter/flutter#180765)
2026-01-09 jhy03261997@gmail.com [A11y ] Add `clearSemantics`in table (flutter/flutter#180665)
2026-01-09 chinmaygarde@google.com Update CODEOWNERS to remove chinmaygarde. (flutter/flutter#180703)
2026-01-09 vhaudiquet343@hotmail.fr [ Tool ] Add support for linux riscv64 architecture (flutter/flutter#178711)
2026-01-09 engine-flutter-autoroll@skia.org Roll Skia from e9b3264ade0c to 7386219151e6 (12 revisions) (flutter/flutter#180754)
2026-01-09 engine-flutter-autoroll@skia.org Roll Dart SDK from fe2ba2c5dd50 to d25ad331b7ea (10 revisions) (flutter/flutter#180741)
2026-01-09 98614782+auto-submit[bot]@users.noreply.github.com Reverts "Unpin google_mobile_ads (#180573)" (flutter/flutter#180761)
2026-01-09 koichi20021217@gmail.com Fix typo in dropdown_menu.dart (flutter/flutter#180172)
2026-01-09 engine-flutter-autoroll@skia.org Roll Packages from 039a026 to 51fe1d9 (1 revision) (flutter/flutter#180742)
2026-01-09 goderbauer@google.com Unpin google_mobile_ads (flutter/flutter#180573)
2026-01-09 evanwall@buffalo.edu Update flutter changelog for 3.38.6 (flutter/flutter#180708)
2026-01-08 98614782+auto-submit[bot]@users.noreply.github.com Reverts "Fix iOS xattr removal to clear all extended attributes (#180355)" (flutter/flutter#180709)
2026-01-08 ahmedsameha1@gmail.com Make sure that an EditableText doesn't crash in 0x0 environment (flutter/flutter#180457)
2026-01-08 matt.kosarek@canonical.com Implementation of tooltip windows for win32 (flutter/flutter#179147)
2026-01-08 mdebbar@google.com [web] Don't serve files outside of project (flutter/flutter#180699)
2026-01-08 engine-flutter-autoroll@skia.org Roll Skia from 837be28dd218 to e9b3264ade0c (1 revision) (flutter/flutter#180702)
2026-01-08 sokolovskyi.konstantin@gmail.com Add new motion accessibility features to iOS. (flutter/flutter#178102)
2026-01-08 104009581+Saqib198@users.noreply.github.com Fix iOS xattr removal to clear all extended attributes (flutter/flutter#180355)
2026-01-08 bkonyi@google.com [ Widget Preview ] Move widget_preview_scaffold tests to `dev/integration_tests/widget_preview_scaffold` (flutter/flutter#180658)
2026-01-08 30870216+gaaclarke@users.noreply.github.com De-interleaves engine dart test output (flutter/flutter#180651)
2026-01-08 zhongliu88889@gmail.com [web] Fix SemanticsService.announce not working inside dialogs (flutter/flutter#179958)
2026-01-08 engine-flutter-autoroll@skia.org Roll Skia from 42233226ac56 to 837be28dd218 (2 revisions) (flutter/flutter#180693)
2026-01-08 iinozemtsev@google.com Roll Dart SDK to 3.11.0-296.2.beta (flutter/flutter#180685)
2026-01-08 116356835+AbdeMohlbi@users.noreply.github.com Improve code quality in `AndroidTouchProcessorTest.java` (flutter/flutter#180583)
2026-01-08 1961493+harryterkelsen@users.noreply.github.com Revert "Reverts "[reland] Unify canvas creation and Surface code in S…kwasm and CanvasKit (#179473)" (#180152)" (flutter/flutter#180610)
2026-01-08 engine-flutter-autoroll@skia.org Roll Skia from a0c407bce408 to 42233226ac56 (4 revisions) (flutter/flutter#180688)
2026-01-08 bkonyi@google.com [ Tool ] Fix flake in overall_experience_test.dart (flutter/flutter#180655)
2026-01-08 engine-flutter-autoroll@skia.org Roll Packages from 9705815 to 039a026 (6 revisions) (flutter/flutter#180684)
2026-01-08 104147021+MohammedTarigg@users.noreply.github.com flutter_tools: Auto-generate ExportOptions.plist for manual iOS code signing (flutter/flutter#177888)
2026-01-08 engine-flutter-autoroll@skia.org Roll Skia from 58837e160874 to a0c407bce408 (2 revisions) (flutter/flutter#180679)
2026-01-08 engine-flutter-autoroll@skia.org Roll Skia from 1e3266fdba86 to 58837e160874 (1 revision) (flutter/flutter#180677)
2026-01-08 engine-flutter-autoroll@skia.org Roll Skia from 3c47ea10638f to 1e3266fdba86 (4 revisions) (flutter/flutter#180675)
2026-01-08 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from dTvN_JVSCfGFRasvH... to rxeg-6UB678HKJ4UQ... (flutter/flutter#180673)
...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

platform-ios iOS applications specifically team-ios Owned by iOS 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.

5 participants