Setting up your Flutter environment, the right way — Part 1

Setting up your Flutter environment, the right way — Part 1
TL;DR

This tutorial introduces Flutter Version Management (FVM), a tool that simplifies managing multiple Flutter SDK versions on your development machine. Unlike the official installation method, which only supports one version at a time, FVM allows you to install, switch between, and maintain different Flutter versions for various projects. This approach helps avoid compatibility issues when working with multiple projects or when testing against different Flutter releases.

After more than a decade of using macOS (and its predecessor, OS X), I admit I’ve been spoiled. As a full stack developer, I’ve gotten used to nice things — including Homebrew(opens in a new tab), which allows for both automated installation of many packages and version management.

So I was surprised when I started working more closely with Flutter and found out in its official documentation(opens in a new tab) that there’s lack of support for Homebrew. Actually, to be more precise, there’s Flutter in Homebrew formulas, but you can’t install any versions other than the latest one(opens in a new tab). However, it’s often necessary to keep older versions of Flutter for testing or for reproducing issues.

Difficulties

That said, downloading each version and remembering where I put it locally wasn’t necessarily easy for me. As a result, I ran into problems pretty quickly. To make things worse, Android Studio was installed on my computer via the JetBrains Toolbox app, which meant frequent updates took place in the background. So often, I had multiple versions of Android Studio, which suffice to say, I also needed for referencing Flutter’s local path.

I told myself there must be a better way. And then, I discovered Flutter Version Management(opens in a new tab) (FVM), which helped me get my Flutter affairs under control.

How it works

FVM is basically a native package manager, but for Flutter. Another similar tool you may recognize by using fvm is Ruby Version Manager(opens in a new tab) (RVM). In fact, if you’re familiar with RVM, you’ll probably recognize some of the FVM commands.

Installing FVM

The next section will outline how to install FVM.

macOS / Linux

Load the FVM repository into your Homebrew:

Terminal window
brew tap leoafarias/fvm

Install FVM:

Terminal window
brew install fvm

Windows

On Windows, run the following:

Terminal window
choco install fvm

There are other ways to install FVM locally, but what’s outlined above is good enough to start with.

Using FVM

Using FVM is almost as easy as installing it, but let’s first go over the Flutter lifecycle.

  1. Install Flutter (the latest one or a specific version):
Terminal window
#Usage:
fvm install - # Installs version found in the project configuration.
fvm install {version} - # Installs a specific version.
#Option:
# -h, --help Print this usage information.
# -s, --skip-setup Skips Flutter setup after install.

If you want to check the currently available versions, use the following command:

Terminal window
#Usage:
fvm releases

Some of the shortcut versions can be:

The above information is explained in detail here: Flutter build release channels(opens in a new tab).

  1. Switch to the active version (globally, or inside the local project directory):
Terminal window
#Usage:
fvm use {version}
#Or, if you need it globally:
fvm global {version}
#Option:
# -h, --help Print this usage information.
# -f, --force Skips Flutter project checks.
# -p, --pin Pins the latest release channel instead of the channel itself.
# --flavor Sets the version for a project flavor.
  1. List the installed Flutter versions (those currently present on your local machine):
Terminal window
#Usage:
fvm list
#Option:
# -h, --help Print this usage information.
  1. Remove or uninstall a specific Flutter version:
Terminal window
Usage:
fvm remove {version}
Option:
-h, --help Print this usage information.
--force Skips version global check.

The globally set Flutter version requires adding FVM’s bin folder path to .profile or .zshrc. FVM will offer you the exact path after executing fvm global {version}, but, for example, I have it set like this:

Terminal window
export PATH="$PATH:$HOME/fvm/default/bin"

Flutter flavors

Sometimes, your product or development process will require multiple environments and configurations, like staging, production, dev, and ci. Each of these usually requires a different configuration, different API endpoints, different authentication tokens, etc. So having them predefined and easily distinguishable from each other speeds up development and prevents potential mistakes.

We’ll cover the full process in detail in the second part of this series.

In the meantime, here’s an example of script commands you can use to address different environments:

Terminal window
# Flavor usage example
# Running flavors on DEBUG mode:
flutter run –flavor dev -t lib/main_dev.dart
flutter run –flavor prod -t lib/main_production.dart
# Running flavors on RELEASE mode:
flutter run –release –flavor dev -t lib/main_dev.dart
flutter run –release –flavor prod -t lib/main_production.dart

As an example, you’ll need to change the AppConfig class — with configuration sets for the development (dev) and production (prod) — separately:

import 'package:flutter/material.dart';
// 1
enum Environment { dev, prod }
// 2
class AppConfig extends InheritedWidget {
// 3
final Environment environment;
final String appTitle;
// 4
const AppConfig({
Key? key,
required Widget child,
required this.environment,
required this.appTitle,
}) : super(
key: key,
child: child,
);
// 5
static AppConfig of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<AppConfig>()!;
}
// 6
@override
bool updateShouldNotify(covariant InheritedWidget oldWidget) => false;
}

You can read more details in the documentation(opens in a new tab).

The example above isn’t a fully complete and working example, so you’ll need to complete a few more additional steps, which will be covered in part 2 of this series. In the meantime, please refer to the Flutter flavors documentation(opens in a new tab).

Android Studio challenges

Now, let’s return to my original difficulty with multiple Android Studio and JetBrains Toolbox installations on my computer.

After installing Flutter (in any of the ways, including downloading directly from the link), I had an issue after running the flutter doctor command. I’d get the same error every time:

Terminal window
*[!] Android Studio
    Unable to find bundled Java version.*

TL;DR

It turns out this error isn’t related to your Flutter installation, no matter how it was installed, but rather to the missing folder under the Android Studio installation folder.

Solution

In short, to fix this, you’ll need to add a symlink reference to a JDK folder path installed locally on your machine:

  1. Go to the Android Studio installation folder:
Terminal window
cd ~/Applications/Android\ Studio/
# Or, if it's installed via JetBrains Toolbox
cd ~/Library/Application\ Support/JetBrains/Toolbox/apps/AndroidStudio/{version}
# On my machine, the current version is `AndroidStudio/ch-1/213.7172.25.2211.8624637`.
  1. After finding a folder with a specific version, navigate to the Contents > jre folder:
Terminal window
cd Android\ Studio\ Preview.app/Contents/jre
  1. Symlink your current Java jdk folder to the jdk folder inside Android Studio/Contents/jre:
Terminal window
ln -s /Library/Java/JavaVirtualMachines/{jdk-version} jdk
# Example:
ln -s /Library/Java/JavaVirtualMachines/zulu-11.jdk jdk

You can check your Java_Home environment variable by using:

Terminal window
/usr/libexec/java_home

Conclusion

FVM can provide a really neat experience managing your Flutter versions without the need to remember the folder or path where you downloaded and installed things locally. Moreover, FVM tools can also be used in an automated CI pipeline and provide a more elegant way of handling downloading, installing, and upgrading Flutter versions.

I hope you’ll find it practical as well, and that your Flutter local version management headache will be a little bit more bearable.

See you soon in part 2, where I’ll explain the rest of the configuration related to Flutter flavors and different configuration environments.

Pedja Jevtic

Pedja Jevtic

Explore related topics

FREE TRIAL Ready to get started?