Skip to content

fix(flet build ipa): validate the provisioning profile up front and report the real artifact - #6796

Open
ndonkoHenri wants to merge 10 commits into
mainfrom
fix/ios-provisioning-preflight
Open

fix(flet build ipa): validate the provisioning profile up front and report the real artifact#6796
ndonkoHenri wants to merge 10 commits into
mainfrom
fix/ios-provisioning-preflight

Conversation

@ndonkoHenri

@ndonkoHenri ndonkoHenri commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

flet build ipa hands the configured provisioning profile to Xcode and lets Xcode resolve it — which happens only at the archive step, minutes into the build. When nothing matches, Xcode reports:

Error (Xcode): No profile for team 'V34TLMVP4R' matching 'release-testing it.edblcc.symplebeam' found:
Xcode couldn't find any provisioning profiles matching ...

It cannot say what is installed, so the ordinary causes — a name that differs from the portal's, a profile downloaded but never installed, a team mismatch — are indistinguishable. The user is then pointed at Xcode's Signing & Capabilities tab, which a Flet project doesn't have.

Closes #5100

Before / after

Configuring a profile name that matches nothing installed:

before after
time to failure 87s (hello-world, warm caches) 9s, before any build work
what you see Xcode's error at line 80 of a 123-line log, then Error building Flet app - see the log of failed command above the message below
Provisioning profile 'this profile does not exist' is not installed — Xcode
would fail once the build reaches signing. Configure the profile's name or
UUID exactly as the portal shows it.
Installed profiles:
  - 'ITMS91065 Repro' (team VF87YBANRR, UUID 49ac84cf-7660-47de-b6e2-4330ef35562b)
  - 'itms91065-repro2' (team VF87YBANRR, UUID 69b3237d-11ef-4367-be53-b542661ee20b)
  - 'iOS Team Provisioning Profile: *' (team GXTRQJK434, UUID 5065afb4-…)

What it checks

New flet_cli/utils/ios_sign.py reads the installed profiles (both ~/Library/MobileDevice/Provisioning Profiles and the ~/Library/Developer/Xcode/UserData/Provisioning Profiles location Xcode 16 introduced), and preflight_ios_signing() resolves the configured specifier the way Xcode does — by name or UUID — then checks:

  • the profile is installed
  • it hasn't expired
  • its team matches the configured team_id
  • its App ID covers the app's bundle id (wildcard-aware)

A build with no profile configured is left alone: that's the supported unsigned .xcarchive path.

Also fixed: the build lied about what it produced

An unsigned build yields only an .xcarchive, yet the command announced "Successfully built your .ipa bundle" and pointed at a directory containing no .ipa — the second half of #5100's report, and independently reported elsewhere. It now names the artifact that exists, in both the step log and the final message:

Successfully built your .xcarchive (Xcode archive) for iOS! 🥳 Find it in build/ipa directory. 📁
No .ipa was produced: Xcode exports one only for a signed app. Configure a
provisioning profile and a signing certificate to get an uploadable bundle:
https://flet.dev/docs/publish/ios

And detecting a failed export was broken: flutter build ipa exits 0 when Xcode's export step fails, and the string check that compensated ("Encountered error while creating the IPA" in stderr) reads captured output — which is empty whenever -v streams it instead. Verbose builds therefore reported export failures as successes. It now checks for the .ipa itself when signing was configured, keeping the string check for the non-verbose path.

Docs

  • .ipa is exported only for a signed app; an unsigned build stops at the .xcarchive
  • the profile may be given by name or UUID — previously undocumented, though Xcode has always accepted both
  • the second profile directory used by Xcode 16 and later
  • a new Building and signing in CI section: certificate as a base64 .p12 secret (cross-referencing the macOS walkthrough), the profile downloaded per run via apple-actions/download-provisioning-profiles so no stale copy lives in a secret, and the altool upload
  • two troubleshooting rows: unresolvable profile, and "succeeded but there's no .ipa"
  • unrelated drive-by: two admonition titles were written as :::warning Title instead of :::warning[Title] and didn't render (Android + storage paths guides)

Testing

  • test_build_ios.py: 12 tests in TestBuildOutput and TestProvisioningPreflight — every rejection path, both specifier forms, wildcard coverage, whitespace tolerance, and the unsigned-build skip. Suite: 170 passing.
  • Verified on real device builds (Xcode 26.3, Apple Distribution cert, App Store profile), in both directions for each change: a bad profile name fails in 9s with the listing; a correct one builds a signed .ipa unchanged; an unsigned build reports .xcarchive with the explanation.

Summary by Sourcery

Make flet build ipa validate signing configuration early and accurately report the artifact produced.

Bug Fixes:

  • Validate configured iOS provisioning profiles before builds and provide actionable diagnostics for missing, expired, mismatched, or incompatible profiles.
  • Report the actual iOS build artifact, distinguishing unsigned .xcarchive output from signed .ipa output and detecting failed exports even when verbose output is streamed.

Enhancements:

  • Support provisioning profile resolution by name or UUID across both profile directories used by Xcode.
  • Document iOS signing behavior, CI setup, profile installation, artifact expectations, and related troubleshooting guidance.

Documentation:

  • Add iOS CI signing and App Store Connect upload instructions, clarify provisioning profile and unsigned-build behavior, and correct malformed admonition headings in the documentation.

Tests:

  • Add coverage for iOS artifact reporting and provisioning preflight validation, including profile resolution, expiry, team and bundle-ID checks, wildcard coverage, whitespace handling, and unsigned builds.

flet passes the configured profile to Xcode as
PROVISIONING_PROFILE_SPECIFIER and lets Xcode resolve it — which happens
only at the archive step, minutes into the build. When nothing matches,
Xcode reports "No profile for team 'X' matching 'Y' found" without
naming the profiles it did find, so the usual causes (a name that
differs from the portal's, a profile downloaded but never installed, a
team mismatch) are indistinguishable. Users are then pointed at Xcode's
Signing & Capabilities tab, which a flet project does not have.

Resolve the same specifier up front, the same way Xcode does — by name
or UUID, across both the classic ~/Library/MobileDevice and the Xcode 16
~/Library/Developer/Xcode/UserData profile directories — and also check
expiry, team match, and bundle-id coverage (wildcard-aware). A miss now
fails in seconds and lists the installed profiles with their teams and
UUIDs, making a typo self-evident.

No profile configured stays a supported unsigned .xcarchive build and
skips the check entirely.

Measured on a hello-world with a name matching nothing: 87s -> 9s, with
the actionable listing replacing Xcode's error buried at line 80 of a
123-line log. Verified in both directions on real hardware — a correct
profile name still builds a signed .ipa unchanged.

Closes #5100
An unsigned ipa build produces only an .xcarchive — Xcode exports an
.ipa for signed apps only — but the command announced "Successfully
built your .ipa bundle" and sent users to a directory with no .ipa in
it. Name the artifact that exists instead, in both the step log and the
final message, and say what to configure to get an uploadable bundle.

Detecting a failed export was also broken: `flutter build ipa` exits 0
when Xcode's export step fails, and the string check that compensated
reads captured output, which is empty whenever -v streams it instead.
Verbose builds therefore reported export failures as successes. Check
for the .ipa itself when signing was configured; keep the string check
for the non-verbose path.

Verified on device builds both ways: unsigned now reports .xcarchive
with the explanation, signed still reports .ipa unchanged.
- state that an .ipa is exported only for a signed app, so an unsigned
  build stops at the .xcarchive
- document that the provisioning profile may be given by name or UUID,
  and that it is validated (installed, unexpired, right team, covers the
  bundle id) before the build starts
- note the second profile directory Xcode 16 introduced
- troubleshooting rows for an unresolvable profile and for a build that
  produced no .ipa
Rename test_build_ios_output.py to test_build_ios.py and put the
existing cases in a TestBuildOutput class, matching the grouping style
used by test_project_dependencies.py. The file now covers iOS builds
generally, so later cases get a class of their own instead of a new
file, with make_command shared between them.
One file per platform command, with a class per concern: TestBuildOutput
and TestProvisioningPreflight now share make_command, which builds a
Command whose cleanup raises instead of exiting, plus the profile
fixture and the installed-profiles stub.
A runner has neither certificate nor profile, and installing the profile
is the step that usually goes wrong. Document both: the certificate as a
base64 .p12 secret (cross-referencing the macOS export walkthrough
rather than repeating it), and the profile downloaded per run from the
portal with the App Store Connect API key, so no stale copy lives in a
secret. Ends with the altool upload, which needs the same key.
Docusaurus takes an admonition title as `:::type[Title]`; without the
brackets the text is not a title. Two were written bare — the R8 keep
rules warning in the Android guide and a note in the storage paths
guide — and rendered wrong.

@sourcery-ai sourcery-ai Bot left a comment

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.

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 28, 2026

Copy link
Copy Markdown

Deploying flet-website-v2 with  Cloudflare Pages  Cloudflare Pages

Latest commit: 0b4ed4c
Status:🚫  Build failed.

View logs

Copilot AI left a comment

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.

Pull request overview

This PR improves the flet build ipa experience by failing fast on invalid iOS provisioning profile configuration (with actionable diagnostics) and by reporting the actual artifact produced (.ipa vs .xcarchive), including correctly detecting export failures in verbose builds.

Changes:

  • Add iOS provisioning profile discovery + resolution (by name or UUID) and a preflight_ios_signing() validation step before starting the build.
  • Fix output reporting for flet build ipa to distinguish unsigned .xcarchive builds from signed .ipa builds and to detect “export failed but exit code 0” cases.
  • Update docs and changelog; add unit tests covering preflight validation and output reporting.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
sdk/python/packages/flet-cli/src/flet_cli/utils/ios_sign.py New utilities to scan installed provisioning profiles and resolve a specifier by name/UUID.
sdk/python/packages/flet-cli/src/flet_cli/commands/build.py Runs iOS signing preflight and improves success messaging to reflect actual artifacts produced.
sdk/python/packages/flet-cli/src/flet_cli/commands/build_base.py Detects flutter build ipa export failures by checking for a produced .ipa, even when verbose output is streamed.
sdk/python/packages/flet-cli/tests/test_build_ios.py Adds tests for .ipa/.xcarchive reporting and all provisioning preflight rejection paths.
website/docs/publish/ios.md Clarifies signing behavior, profile resolution by name/UUID, Xcode profile directories, and CI signing guidance.
website/docs/publish/android.md Fixes malformed admonition syntax so it renders correctly.
website/docs/services/storagepaths.md Fixes malformed admonition syntax so it renders correctly.
CHANGELOG.md Documents the early provisioning validation and accurate artifact reporting changes.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +324 to +329
hint = (
"No unexpired profiles are installed. Download the "
"profile from the Apple Developer portal and double-click "
"it, or copy it into "
"~/Library/MobileDevice/Provisioning Profiles."
)
Comment on lines +77 to +81
result = subprocess.run(
["security", "cms", "-D", "-i", str(path)],
capture_output=True,
text=True,
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

flet build ipa - iOS provisioning profile fails

2 participants