| [ Web Proxy ] |
| Viewing: https://docs.flutter.dev/deployment/cd#xcode-cloud | [Back] [Original] |
How to automate continuous building and releasing of your Flutter app.
Follow continuous delivery best practices with Flutter to make sure your application is delivered to your beta testers and validated on a frequent basis without resorting to manual workflows.
There are a number of continuous integration (CI) and continuous delivery (CD) options available to help automate the delivery of your application.
You can use fastlane with the following tooling:
This guide shows how to set up fastlane and then integrate it with your existing testing and continuous integration (CI) workflows. For more information, see "Integrating fastlane with existing workflow".
fastlane is an open-source tool suite to automate releases and deployments for your app.
It's recommended that you test the build and deployment process locally before migrating to a cloud-based system. You could also choose to perform continuous delivery from a local machine.
gem install fastlane or brew install fastlane.
Visit the fastlane docs for more info.
FLUTTER_ROOT,
and set it to the root directory of your Flutter SDK.
(This is required for the scripts that deploy for iOS.)
Appfiles to ensure they have adequate metadata for your app.
[Android] Check that package_name in
[project]/android/fastlane/Appfile matches your package name in AndroidManifest.xml.
[iOS] Check that app_identifier in
[project]/ios/fastlane/Appfile also matches Info.plist's bundle identifier. Fill in
apple_id, itc_team_id, team_id with your respective account info.
[Android] Follow the Supply setup steps
and ensure that fastlane supply init successfully syncs data from your
Play Store console. Treat the .json file like your password and do not check
it into any public source control repositories.
[iOS] Your iTunes Connect username is already
in your Appfile's apple_id field. Set the FASTLANE_PASSWORD
shell
environment variable with your iTunes Connect password. Otherwise, you'll be
prompted when uploading to iTunes/TestFlight.
[Android] Follow the Android app signing steps.
[iOS] On iOS, create and sign using a
distribution certificate instead of a development certificate when you're
ready to test and deploy using TestFlight or App Store.open [project]/ios/Runner.xcworkspace/ and select the distribution
certificate in your target's settings pane.Fastfile script for each platform.
[Android] On Android, follow the
fastlane Android beta deployment guide.
Your edit could be as simple as adding a lane that calls
upload_to_play_store.
Set the aab argument to ../build/app/outputs/bundle/release/app-release.aab
to use the app bundle flutter build already built.
[iOS] On iOS, follow the
fastlane iOS beta deployment guide.
You can specify the archive path to avoid rebuilding the project. For example:
build_app(
skip_build_archive: true,
archive_path: "../build/ios/archive/Runner.xcarchive",
)
upload_to_testflight
You're now ready to perform deployments locally or migrate the deployment process to a continuous integration (CI) system.
First, follow the local setup section described in 'Local setup' to make sure the process works before migrating onto a cloud system like Travis.
The main thing to consider is that since cloud instances are ephemeral and untrusted, you won't be leaving your credentials like your Play Store service account JSON or your iTunes distribution certificate on the server.
Continuous Integration (CI) systems generally support encrypted environment
variables to store private data. You can pass these environment variables
using --dart-define MY_VAR=MY_VALUE while building the app.
Take precaution not to re-echo those variable values back onto the console in your test scripts. Those variables are also not available in pull requests until they're merged to ensure that malicious actors cannot create a pull request that prints these secrets out. Be careful with interactions with these secrets in pull requests that you accept and merge.
Make login credentials ephemeral.
[Android] On Android:json_key_file field from Appfile and store the string
content of the JSON in your CI system's encrypted variable.
Read the environment variable directly in your Fastfile.upload_to_play_store(
...
json_key_data: ENV['<variable name>']
)
echo "$PLAY_STORE_UPLOAD_KEY" | base64 --decode > [path to your upload keystore]
[iOS] On iOS:FASTLANE_PASSWORD to use
encrypted environment variables on the CI system.It's recommended to use a Gemfile instead of using an indeterministic
gem install fastlane on the CI system each time to ensure the fastlane
dependencies are stable and reproducible between local and cloud machines.
However, this step is optional.
[project]/android and [project]/ios folders, create a
Gemfile containing the following content:source "https://rubygems.org"
gem "fastlane"
bundle update and check both Gemfile and
Gemfile.lock into source control.bundle exec fastlane instead of fastlane.Create the CI test script such as .travis.yml or .cirrus.yml in your
repository root.
gem install bundler.bundle install in [project]/android or [project]/ios.PATH.ANDROID_SDK_ROOT
path is set.osx_image: xcode9.2).flutter build appbundle or
flutter build ios --release --no-codesign --config-only,
depending on the platform.cd android or cd iosbundle exec fastlane [name of the lane]Xcode Cloud is a continuous integration and delivery service for building, testing, and distributing apps and frameworks for Apple platforms.
Xcode Cloud recognizes custom build scripts
that can be
used to perform additional tasks at a designated time. It also includes a set
of predefined environment variables, such as
$CI_WORKSPACE, which is the
location of your cloned repository.
The temporary build environment that Xcode Cloud uses includes tools that are part of macOS and Xcodefor example, Pythonand additionally Homebrew to support installing third-party dependencies and tools.
Leverage the post-clone custom build script that runs after Xcode Cloud clones your Git repository using the following instructions:
Create a file at ios/ci_scripts/ci_post_clone.sh and add the content below.
#!/bin/sh
# Fail this script if any subcommand fails.
set -e
# The default execution directory of this script is the ci_scripts directory.
cd $CI_PRIMARY_REPOSITORY_PATH # change working directory to the root of your cloned repo.
# Install Flutter using git.
git clone https://github.com/flutter/flutter.git --depth 1 -b stable $HOME/flutter
export PATH="$PATH:$HOME/flutter/bin"
# Install Flutter artifacts for iOS (--ios), or macOS (--macos) platforms.
flutter precache --ios
# Install Flutter dependencies.
flutter pub get
# Install CocoaPods using Homebrew.
HOMEBREW_NO_AUTO_UPDATE=1 # disable homebrew's automatic updates.
brew install cocoapods
# Install CocoaPods dependencies.
cd ios && pod install # run `pod install` in the `ios` directory.
exit 0
This file should be added to your git repository and marked as executable.
git add --chmod=+x ios/ci_scripts/ci_post_clone.sh
An Xcode Cloud workflow defines the steps performed in the CI/CD process when your workflow is triggered.
This requires that your project is already initialized with Git and linked to a remote repository.
To create a new workflow in Xcode, use the following instructions:
Choose Product > Xcode Cloud > Create Workflow to open the Create Workflow sheet.
Select the product (app) that the workflow should be attached to, then click the Next button.
The next sheet displays an overview of the default workflow provided by Xcode, and can be customized by clicking the Edit Workflow button.
By default Xcode suggests the Branch Changes condition that starts a new build for every change to your Git repository's default branch.
For your app's iOS variant, it's reasonable that you would want Xcode Cloud to
trigger your workflow after you've made changes to your flutter packages, or
modified either the Dart or iOS source files within the lib\ and ios\
directories.
This can be achieved by using the following Files and Folders conditions:
[Xcode Workflow Branch Changes]
Xcode Cloud defaults the build number for new workflows to 1 and increments
it per successful build. If you're using an existing app with a higher build
number, you'll need to configure Xcode Cloud to use the correct build number
for its builds by simply specifying the Next Build Number in your iteration.
Check out Setting the next build number for Xcode Cloud builds for more information.
Unless stated otherwise, the documentation on this site reflects Flutter 3.47. Page last updated on 2026-07-31. View source or report an issue.
| Web Proxy Viewer | New URL | Original Page |