Blog Post

Setting Up Your Flutter Environment, the Right Way — Part 1

Illustration: Setting Up Your Flutter Environment, the Right Way — Part 1

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, 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 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. 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 (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 (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:

brew tap leoafarias/fvm

Install FVM:

brew install fvm

Windows

On Windows, run the following:

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):

#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:

#Usage:

fvm releases

Some of the shortcut versions can be:

The above information is explained in detail here: Flutter build release channels.

  1. Switch to the active version (globally, or inside the local project directory):

#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):

#Usage:
    fvm list

#Option:
#    -h, --help     Print this usage information.
  1. Remove or uninstall a specific Flutter version:

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:

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:

# 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.

ℹ️ Note: 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.

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:

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

TLDR

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:

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:

cd Android\ Studio\ Preview.app/Contents/jre
  1. Symlink your current Java jdk folder to the jdk folder inside Android Studio/Contents/jre:

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:

/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.

Explore related topics

Share post
Free trial Ready to get started?
Free trial