Releasing for iOS
This page takes a Flutter app from Xcode signing setup to a build on the App
Store that can receive Shorebird patches. Steps 1 and 2 are the same one-time
setup any Flutter app needs. Step 3 builds the archive and IPA with
shorebird release ios on a Mac, and step 4 uploads that build to App Store
Connect.
Step 1: Configure bundle identifier and signing in Xcode
Section titled “Step 1: Configure bundle identifier and signing in Xcode”Open the ios directory in Xcode:
- Select the
Runnerproject in the sidebar. - Under the Signing & Capabilities tab, select your Team registered with the Apple Developer Program.
- Set a unique Bundle Identifier (e.g.,
com.example.myapp). - Choose Automatically manage signing (recommended for standard release flows) or configure custom provisioning profiles.
shorebird release ios signs the IPA with these settings. If it stops with a
signing or provisioning profile error, see
Signing issues.
Step 2: Privacy manifests and permission descriptions
Section titled “Step 2: Privacy manifests and permission descriptions”Apple requires explicit usage descriptions in ios/Runner/Info.plist for any
hardware or sensitive APIs accessed by your app or third-party packages (see
Apple Info.plist Keys):
App Store Connect also requires a
privacy manifest
(PrivacyInfo.xcprivacy) for apps that use required reason APIs, declaring why
the app or its dependencies call them. Apple enforces this for every app
submitted since May 1, 2024, whatever iOS version the app targets.
Step 3: Create a Shorebird release
Section titled “Step 3: Create a Shorebird release”On a Mac with Xcode, build the release with Shorebird’s Flutter. This archives your app, exports a signed IPA, and uploads the compiled Dart code to Shorebird as the base that later patches apply to:
It writes the archive to build/ios/archive/ and the IPA to build/ios/ipa/,
and prints the ways to upload them when it finishes.
shorebird release takes the common flutter build options, such as
--flavor, --target, --build-name, --build-number and --dart-define,
and passes any other flutter build argument you put after a -- separator. To
sign with a specific certificate and provisioning profile, pass an
--export-options-plist. See Create a Release for those,
and run shorebird release --help for every option.
To obfuscate your Dart code, pass --obfuscate, and --split-debug-info with a
directory to keep the symbol files in:
Obfuscation on iOS needs a release built with Flutter 3.41.2 or later. Patches to an obfuscated release are obfuscated the same way automatically. See Code obfuscation and debug symbols.
If you sign the app in a later step, pass --no-codesign. Shorebird then builds
only the .xcarchive in build/ios/archive/. Sign and upload that archive,
without rebuilding it, by hand in Xcode (the Xcode tab below) or in CI with
xcodebuild -exportArchive or fastlane. Whatever signs and uploads it must keep
the build number; see the caution in step 4.
Step 4: Upload to App Store Connect
Section titled “Step 4: Upload to App Store Connect”Upload the build from step 3 using one of these methods:
- Download the Transporter app from the Mac App Store.
- Drag and drop the
.ipafile frombuild/ios/ipa/into Transporter. - Click Deliver to upload.
Upload with Apple’s altool, authenticating with an App Store Connect API key
(see man altool):
-
Open the archive Shorebird built, which adds it to Xcode’s Organizer:
-
Select it, click Distribute App, and choose Custom, then App Store Connect and Upload, so the dialog shows its distribution options.
-
Uncheck Manage Version and Build Number (see the caution below), then follow the prompts to upload.
Step 5: TestFlight and store submission
Section titled “Step 5: TestFlight and store submission”- TestFlight Internal Testing: Available immediately after processing for members of your App Store Connect team.
- TestFlight External Testing: Distribute builds to up to 10,000 external testers using TestFlight (requires a brief initial Beta App Review from Apple).
- App Store submission: Fill out App Store listing metadata, screenshots, age ratings, and privacy nutrition labels, then submit for App Review. Apple offers Phased Release for Automatic Updates (rolling out over 7 days).
The build you test in TestFlight is the same build you submit, so it receives the same patches. To try a patch on TestFlight devices before everyone gets it, see Testing patches.
Step 6: Ship fixes as patches
Section titled “Step 6: Ship fixes as patches”When you change Dart code in this version later, ship the change as a patch instead of a new store build:
A change to native code, a plugin with native code, assets such as images and
fonts, or the Flutter version needs a new store release: bump the version in
pubspec.yaml, then repeat steps 3 and 4. iOS patches only install on physical
devices, not the Simulator. See Create a Patch.
Building without Shorebird
Section titled “Building without Shorebird”For background: a Flutter app that doesn’t use Shorebird builds its store
release with flutter build ipa (which writes the same build/ios/archive/ and
build/ios/ipa/ outputs) or by archiving in Xcode. A build made with the
standard Flutter has no Shorebird updater, so it can never receive a patch. Once
your app uses Shorebird, use shorebird release ios for every build you upload
to App Store Connect.