Vendoring Flutter into your app repo

Published on May 01, 2019

In this post, I’ll describe how to vendor Flutter into your app’s repo using Git Submodules, so that you can easily change Flutter versions in your app between stable, beta, or even the code merged into master right this minute!

Why though?

The biggest reason is, we want our app’s dependencies to be self-contained and not rely on the external environment. Just like we use pubspec.lock to pin library versions so that all the developers on the team are getting the same libraries, we want the same thing for Flutter itself.

Vendoring Flutter makes changing the version of Flutter as easy as changing the version of one of your libraries, so that everyone on your team is on the same page. Another benefit is that setting up Flutter in CI is a bit easier, since you don’t have to find a temp directory to extract it to, download and verify zips, etc etc, as well as being able to use the newest Flutter features without waiting for stable.

Setting it up

First, run this command in the root of your Git repo to set up Flutter in a vendor folder in your repo:

git submodule add https://github.com/flutter/flutter

cd ./vendor/flutter
git checkout v1.2.1
cd ../../

git add .gitmodules ./vendor
git commit -m "Set Flutter to v1.2.1"

Now, we’ll add a script to make it a bit easier to use. Similar to gradlew which wraps Gradle to make sure you get the version you want, we’re going to make a new script. Add these two files to the root of your repo:

For macOS / Linux: ./flutterw

#!/bin/bash
set -euo pipefail

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
export PATH="$DIR/vendor/flutter/bin:$PATH"

exec flutter $@

(Make sure to chmod +x this script after you add it!)

For Windows: ./flutterw.cmd

%~dp0vendor\flutter\bin\flutter.bat" %*

Now, we can run all of the commands we’re used to, only with flutterw instead of flutter:

./flutterw doctor

Setting up VS Code

In order to get VS Code to understand our new vendored Flutter, we need to add one more file. In your .vscode/settings.json, merge in the following settings (if you don’t have this file, create it):

{
  "dart.flutterSdkPath": "vendor/flutter",
  "dart.analysisExcludedFolders": [
    "vendor"
  ],
  "dart.doNotFormat": [
    "vendor/**/*.dart"
  ],
}

This tells VS Code that when you start the debugger where to find Flutter, and it also tells VS Code not to try to treat all of Flutter as your app’s code (without this, the Dart Analyzer will throw lots and lots of unrelated errors).

Configuring CI

The good news is, this step is actually a lot easier now. Your entire build script for Android is now as simple as:

git submodule update --init --recursive
./flutterw test
./flutterw build apk

If you’re using Azure Pipelines (try it! it’s very good!), it’s usually better to split out setting up Flutter into its own step so that you can measure test and build time independently:

steps:
  - script: git submodule update --init --recursive && ./flutterw doctor
    displayName: 'Update submodules and set up Flutter'
  - script: ./flutterw test
    displayName: 'Flutter Test'
  - script: ./flutterw build apk
    displayName: 'Release build'

Switching Flutter Versions

When you want to switch versions of Flutter, you change the pinned submodule. Here’s an example of how to change to the latest tag (as of this writing):

cd ./vendor/flutter
git fetch --tags
git checkout v1.5.8

cd ../..
git add -u ./vendor
git commit -m "Bump Flutter to v1.5.8"

## This last part will update the Dart SDK and related tools
./flutterw doctor

And that’s it! Let me know on Twitter if this helped you out or if you’re stuck.


Anaïs Betts

Written by Anaïs [a.na'is] Betts, who lives in San Francisco.

Twitter LogoCopyright 2018 Anaïs BettsGitHub Logo