Continuous delivery with Flutter
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.
CI/CD Options
There are a number of continuous integration (CI) and continuous delivery (CD) options available to help automate the delivery of your application.
All-in-one options with built-in Flutter functionality
Integrating fastlane with existing workflows
You can use fastlane with the following tooling:
-
GitHub Actions
- Example: Flutter Gallery’s Github Actions workflows
- Example: Github Action in Flutter Project
- Cirrus
- Travis
- GitLab
- CircleCI * Building and deploying Flutter apps with Fastlane
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
fastlane is an open-source tool suite to automate releases and deployments for your app.
Local setup
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.
- Install fastlane
gem install fastlane
orbrew install fastlane
. Visit the fastlane docs for more info. - Create an environment variable named
FLUTTER_ROOT
, and set it to the root directory of your Flutter SDK. (This is required for the scripts that deploy for iOS.) - Create your Flutter project, and when ready, make sure that your project builds via
-
flutter build appbundle
; and -
flutter build ios --release --no-codesign
.
-
- Initialize the fastlane projects for each platform.
-
In your
[project]/android
directory, runfastlane init
. -
In your
[project]/ios
directory, runfastlane init
.
-
In your
- Edit the
Appfile
s to ensure they have adequate metadata for your app.-
Check that
package_name
in[project]/android/fastlane/Appfile
matches your package name in AndroidManifest.xml. -
Check that
app_identifier
in[project]/ios/fastlane/Appfile
also matches Info.plist’s bundle identifier. Fill inapple_id
,itc_team_id
,team_id
with your respective account info.
-
Check that
- Set up your local login credentials for the stores.
-
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. -
Your iTunes Connect username is already
in your
Appfile
’sapple_id
field. Set theFASTLANE_PASSWORD
shell environment variable with your iTunes Connect password. Otherwise, you’ll be prompted when uploading to iTunes/TestFlight.
-
Follow the Supply setup steps
and ensure that
- Set up code signing.
- Follow the Android app signing steps.
-
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.
- Create and download a distribution certificate in your Apple Developer Account console.
-
open [project]/ios/Runner.xcworkspace/
and select the distribution certificate in your target’s settings pane.
- Create a
Fastfile
script for each platform.-
On Android, follow the
fastlane Android beta deployment guide.
Your edit could be as simple as adding a
lane
that callsupload_to_play_store
. Set theaab
argument to../build/app/outputs/bundle/release/app-release.aab
to use the app bundleflutter build
already built. -
On iOS, follow the
fastlane iOS beta deployment guide.
Your edit could be as simple as adding a
lane
that callsbuild_ios_app
withexport_method: 'app-store'
andupload_to_testflight
. On iOS an extra build is required sinceflutter build
builds an .app rather than archiving .ipas for release.
-
On Android, follow the
fastlane Android beta deployment guide.
Your edit could be as simple as adding a
You’re now ready to perform deployments locally or migrate the deployment process to a continuous integration (CI) system.
Running deployment locally
- Build the release mode app.
-
flutter build appbundle
. -
flutter build ios --release --no-codesign
. No need to sign now since fastlane will sign when archiving.
-
- Run the Fastfile script on each platform.
-
cd android
thenfastlane [name of the lane you created]
. -
cd ios
thenfastlane [name of the lane you created]
.
-
Cloud build and deploy setup
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.
-
On Android:
- Remove the
json_key_file
field fromAppfile
and store the string content of the JSON in your CI system’s encrypted variable. Read the environment variable directly in yourFastfile
.upload_to_play_store( ... json_key_data: ENV['<variable name>'] )
- Serialize your upload key (for example, using base64) and save it as
an encrypted environment variable. You can deserialize it on your CI
system during the install phase with
echo "$PLAY_STORE_UPLOAD_KEY" | base64 --decode > [path to your upload keystore]
- Remove the
-
On iOS:
- Move the local environment variable
FASTLANE_PASSWORD
to use encrypted environment variables on the CI system. - The CI system needs access to your distribution certificate. fastlane’s Match system is recommended to synchronize your certificates across machines.
- Move the local environment variable
-
On Android:
- 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.- In both your
[project]/android
and[project]/ios
folders, create aGemfile
containing the following content:source "https://rubygems.org" gem "fastlane"
- In both directories, run
bundle update
and check bothGemfile
andGemfile.lock
into source control. - When running locally, use
bundle exec fastlane
instead offastlane
.
- In both your
- Create the CI test script such as
.travis.yml
or.cirrus.yml
in your repository root.- See fastlane CI documentation for CI specific setup.
- Shard your script to run on both Linux and macOS platforms.
- During the setup phase of the CI task, do the following:
- Ensure Bundler is available using
gem install bundler
. - Run
bundle install
in[project]/android
or[project]/ios
. - Make sure the Flutter SDK is available and set in
PATH
. - For Android, ensure the Android SDK is available and the
ANDROID_SDK_ROOT
path is set. - For iOS, you may have to specify a dependency on Xcode (for example
osx_image: xcode9.2
).
- Ensure Bundler is available using
- In the script phase of the CI task:
- Run
flutter build appbundle
orflutter build ios --release --no-codesign
, depending on the platform. -
cd android
orcd ios
bundle exec fastlane [name of the lane]
- Run