fix(flet build ipa): validate the provisioning profile up front and report the real artifact - #6796
Open
ndonkoHenri wants to merge 10 commits into
Open
fix(flet build ipa): validate the provisioning profile up front and report the real artifact#6796ndonkoHenri wants to merge 10 commits into
flet build ipa): validate the provisioning profile up front and report the real artifact#6796ndonkoHenri wants to merge 10 commits into
Conversation
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.
Contributor
There was a problem hiding this comment.
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 ipato distinguish unsigned.xcarchivebuilds from signed.ipabuilds 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, | ||
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
flet build ipahands 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: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:
Error building Flet app - see the log of failed command aboveWhat it checks
New
flet_cli/utils/ios_sign.pyreads the installed profiles (both~/Library/MobileDevice/Provisioning Profilesand the~/Library/Developer/Xcode/UserData/Provisioning Profileslocation Xcode 16 introduced), andpreflight_ios_signing()resolves the configured specifier the way Xcode does — by name or UUID — then checks:team_idA build with no profile configured is left alone: that's the supported unsigned
.xcarchivepath.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:And detecting a failed export was broken:
flutter build ipaexits 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-vstreams it instead. Verbose builds therefore reported export failures as successes. It now checks for the.ipaitself when signing was configured, keeping the string check for the non-verbose path.Docs
.ipais exported only for a signed app; an unsigned build stops at the.xcarchive.p12secret (cross-referencing the macOS walkthrough), the profile downloaded per run viaapple-actions/download-provisioning-profilesso no stale copy lives in a secret, and thealtoolupload.ipa":::warning Titleinstead of:::warning[Title]and didn't render (Android + storage paths guides)Testing
test_build_ios.py: 12 tests inTestBuildOutputandTestProvisioningPreflight— every rejection path, both specifier forms, wildcard coverage, whitespace tolerance, and the unsigned-build skip. Suite: 170 passing..ipaunchanged; an unsigned build reports.xcarchivewith the explanation.Summary by Sourcery
Make
flet build ipavalidate signing configuration early and accurately report the artifact produced.Bug Fixes:
.xcarchiveoutput from signed.ipaoutput and detecting failed exports even when verbose output is streamed.Enhancements:
Documentation:
Tests: