website/docs/publish/ios.md
import TabItem from '@theme/TabItem'; import Tabs from '@theme/Tabs';
Instructions for packaging a Flet app into an Xcode archive and, when signing is configured, an IPA for distribution.
:::tip[Info] This guide provides detailed on iOS-specific information. Complementary and more general information is available here. :::
Some Flutter tooling and dependencies still ship as Intel binaries. Install Rosetta 2 on Apple Silicon if Flutter or CocoaPods prompts for it:
sudo softwareupdate --install-rosetta --agree-to-license
Xcode 15 or later to compile native Swift or Objective-C code. Open Xcode once after installation to accept the license and install additional components.
CocoaPods 1.16 or later to compile and enable Flutter plugins.
Binary Python packages (vs "pure" Python packages written in Python only)
are packages that are partially written in C, Rust, or other languages producing native code.
Example packages are numpy, cryptography, or pydantic-core.
Make sure all non-pure (binary) packages used in your Flet app have pre-built wheels for iOS.
flet build ipa:::caution[Supported host platforms] This command can be run on macOS only. :::
Builds an iOS app archive (.xcarchive) and, when signing is configured,
exports an .ipa for testing or distribution.
To generate an .ipa for testing on your device or uploading to App Store Connect
for distribution, you will need the following:
flet build ios-simulator:::caution[Supported host platforms] This command can be run on macOS only. :::
Builds an (unsigned) iOS Simulator .app bundle, intended for testing on iOS Simulator
and does not require a signing certificate, provisioning profile, or Apple Developer Program setup.
A unique string that identifies your app within the Apple ecosystem. It is required to sign and distribute an iOS app and is used for various services like Push Notifications, App Groups, iCloud, and In-App Purchases.
It consists of two parts:
com.example.myapp).graph TD
A[App ID: ABCDEFE234.com.example.myapp] --> B[Team ID: ABCDEFE234]
A --> C[Bundle ID: com.example.myapp]
The Bundle ID in your Flet configuration must match the Bundle ID registered in the App ID.
com.example.myapp) – Recommended for most apps.com.example.*) – Allows multiple apps to use the same identifier (rarely used).Now you have Bundle ID and Team ID that will be used to identify your app.
The developer team ID to include in export options.
Its value is determined in the following order of precedence:
--ios-team-id[tool.flet.ios].team_id[tool.flet.ios.export_methods."EXPORT_METHOD"].team_idThe certificate name, SHA-1 hash, or automatic selector to use for signing the iOS app bundle. Automatic selectors allow Xcode to pick the newest installed certificate of a particular type.
The available automatic selectors are:
"Apple Development""Apple Distribution""Developer ID Application""iOS Developer""iOS Distribution""Mac App Distribution""Mac Developer"Before creating a development or distribution certificate, you need a CSR (Certificate Signing Request).
.certSigningRequest file, and click Save..cer file..cer file to install it in Keychain Access.Its value is determined in the following order of precedence:
--ios-signing-certificate[tool.flet.ios].signing_certificate[tool.flet.ios.export_methods."EXPORT_METHOD"].signing_certificateA Provisioning Profile is a file that allows an iOS app to run on physical devices and be distributed through the App Store or internally. It links your App ID, Developer/Distribution Certificate, and Registered Devices.
There are different types of provisioning profiles:
Follow these steps to create a provisioning profile via the Apple Developer Portal:
MyApp Development Profile);.mobileprovision file.Provisioning profiles are stored in ~/Library/MobileDevice/Provisioning Profiles directory.
To install a downloaded provisioning profile, copy it to ~/Library/MobileDevice/Provisioning\ Profiles
directory with a new {UUID}.mobileprovision name.
Run the following command to get profile UUID:
profile_uuid=$(security cms -D -i ~/Downloads/{profile-name}.mobileprovision | xmllint --xpath "string(//key[.='UUID']/following-sibling::string[1])" -)
echo $profile_uuid
Run this command to copy profile to ~/Library/MobileDevice/Provisioning Profiles with a new name {UUID}.mobileprovision:
cp ~/Downloads/{profile-name}.mobileprovision ~/Library/MobileDevice/Provisioning\ Profiles/${profile_uuid}.mobileprovision
:::note[Note]
If the copied profile disappears from the ~/Library/MobileDevice/Provisioning Profiles directory,
ensure that the Xcode process is not running in the background.
:::
Finally, you can use the command below to list all installed provisioning profiles, with their names and UUIDs:
for profile in ~/Library/MobileDevice/Provisioning\ Profiles/*.mobileprovision; do security cms -D -i "$profile" | grep -E -A1 '<key>(Name|UUID)</key>' | sed -n 's/.*<string>\(.*\)<\/string>/\1/p' | paste -d ' | ' - -; done
Its value is determined in the following order of precedence:
--ios-provisioning-profile[tool.flet.ios].provisioning_profile[tool.flet.ios.export_methods."EXPORT_METHOD"].provisioning_profileThe profile must match your Bundle ID.
Additional keys to include in the generated exportOptions.plist
of the build template.
For a complete list of supported keys and values, run the following command:
xcodebuild -help
and find the section titled "Available keys for -exportOptionsPlist".
Its value is determined in the following order of precedence:
[tool.flet.ios].export_options (if set, per-method export options are ignored)[tool.flet.ios.export_methods."EXPORT_METHOD"].export_options (see export methods){} (no extra keys)Numbers are not yet supported. </TabItem> </Tabs>
[tool.flet.ios.export_options.manifest] appURL = "https://example.com/app.ipa" displayImageURL = "https://example.com/icon57.png" fullSizeImageURL = "https://example.com/icon512.png"
</TabItem>
</Tabs>
<details>
<summary>Template translation</summary>
In the [`ios/exportOptions.plist`](index.md#build-template),
the example above will be translated accordingly into this:
```xml
<key>uploadSymbols</key>
<false/>
<key>compileBitcode</key>
<false/>
<key>thinning</key>
<string><none></string>
<key>manifest</key>
<dict>
<key>appURL</key>
<string>https://example.com/app.ipa</string>
<key>displayImageURL</key>
<string>https://example.com/icon57.png</string>
<key>fullSizeImageURL</key>
<string>https://example.com/icon512.png</string>
</dict>
Defines how the app should be packaged when exporting the .ipa file.
Can be one of the following:
debugging (or deprecated development): used for debugging and testing on development devices.release-testing (or deprecated ad-hoc): used for distributing the app outside the App Store to specific registered devices.app-store-connect (or deprecated app-store): used for submitting the app to the App Store.enterprise: used for internal distribution within an organization (requires an enterprise account).To configure individual settings for one or more export methods, see export methods.
Its value is determined in the following order of precedence:
--ios-export-method[tool.flet.ios].export_method"debugging"Signing settings can be configured individually per export method.
Per-method values are used only when the corresponding top-level
[tool.flet.ios] setting is not set. The method key must match the export_method value exactly.
Supported keys (same as the top-level settings):
[tool.flet.ios.export_methods."release-testing"] provisioning_profile = "release-testing com.mycompany.example-app" team_id = "ABCDEFE234" signing_certificate = "Apple Distribution" export_options = { uploadSymbols = false }
[tool.flet.ios.export_methods."app-store-connect"] provisioning_profile = "app-store-connect com.mycompany.example-app" team_id = "ABCDEFE234" signing_certificate = "Apple Distribution" export_options = { uploadSymbols = true }
</TabItem>
</Tabs>
### Permissions
iOS permissions are declared through [`Info.plist`](#infoplist) privacy usage strings.
You can also use the [cross-platform permission bundles](index.md#predefined-cross-platform-permission-bundles)
to inject common entries, then override or extend them with platform-specific values.
#### Info.plist
Add or override `Info.plist` entries for iOS builds.
These values are written to `ios/Runner/Info.plist` of the [build project](index.md#build-template).
##### Resolution order
Its value is determined in the following order of precedence:
1. [`--info-plist`](../cli/flet-build.md#--info-plist)
2. `[tool.flet.ios.info]`
3. Values injected by [cross-platform permission bundles](index.md#permissions), if any.
#### Supported value forms
<Tabs groupId="flet-build--pyproject-toml">
<TabItem value="flet-build" label="flet build">
Accepts repeated `<key>=<value>` entries.
The `<value>` can be in one of the following forms:
- `true` or `false` (case-insensitive) for boolean values
- integer and real number literals, for example `32` or `0.5`
- TOML array literals, for example `["myapp", "myapp-beta"]`
- TOML inline tables, for example `{ NSAllowsArbitraryLoads = false }`
- any other value is treated as a string
</TabItem>
<TabItem value="pyproject-toml" label="pyproject.toml">
Both simple and complex structures are supported:
- string
- boolean
- integer
- real
- dictionary (nested key-value object)
- array of strings
- array of booleans
- array of integers
- array of reals
- array of dictionaries (including dictionaries that contain arrays)
</TabItem>
</Tabs>
##### Example
<Tabs groupId="flet-build--pyproject-toml">
<TabItem value="flet-build" label="flet build">
```bash
flet build ipa \
--info-plist NSCameraUsageDescription="This app needs camera access." \
--info-plist UIFileSharingEnabled=true \
--info-plist ExampleInteger=32 \
--info-plist ExampleReal=0.5 \
--info-plist 'LSApplicationQueriesSchemes=["myapp", "myapp-beta"]' \
--info-plist 'FeatureFlags=[true, false]' \
--info-plist 'RetryDelays=[1, 2, 3]' \
--info-plist 'OpacitySteps=[0.25, 0.5, 0.75]' \
--info-plist 'NSAppTransportSecurity={ NSAllowsArbitraryLoads = false }' \
--info-plist 'CFBundleURLTypes=[{ CFBundleTypeRole = "Editor", CFBundleURLName = "example.com", CFBundleURLSchemes = ["myapp"] }, { CFBundleTypeRole = "Viewer", CFBundleURLName = "example.org", CFBundleURLSchemes = ["myapp-beta"] }]'
In the ios/Runner/Info.plist, the
example above will be translated accordingly into this:
<plist version="1.0">
<dict>
<key>NSCameraUsageDescription</key>
<string>This app needs camera access.</string>
<key>UIFileSharingEnabled</key>
<true/>
<key>ExampleInteger</key>
<integer>32</integer>
<key>ExampleReal</key>
<real>0.5</real>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>myapp</string>
<string>myapp-beta</string>
</array>
<key>FeatureFlags</key>
<array>
<true/>
<false/>
</array>
<key>RetryDelays</key>
<array>
<integer>1</integer>
<integer>2</integer>
<integer>3</integer>
</array>
<key>OpacitySteps</key>
<array>
<real>0.25</real>
<real>0.5</real>
<real>0.75</real>
</array>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<false/>
</dict>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>example.com</string>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
</array>
</dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>CFBundleURLName</key>
<string>example.org</string>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp-beta</string>
</array>
</dict>
</array>
</dict>
</plist>
You can deploy .ipa files directly to an iPhone or iPad on macOS—ideal for
internal testing without publishing to the App Store.
Follow these steps:
.ipa File.ipa file onto the connected device in Apple Configurator;.ipa file from your Mac.If your app is signed with an Ad Hoc or Enterprise provisioning profile, you'll need to manually trust the developer:
.ipa File.ipa file using the app-store-connect export method.
(release-testing is for Ad Hoc device distribution, not App Store Connect.).ipa File in Transporter.ipa file directly into the Transporter window, or click "Add App" and select your .ipa file from your Mac..ipa file to App Store Connect.