Windows 11で始めるFlutter開発環境 の次に、案件ごとの差分をどう吸収するかをそろえておくと、後続の記事や実務作業へ入りやすくなります。この記事では FVM を導入し、Flutter SDK をプロジェクト単位で固定して、fvm flutter run でアプリを起動するところまでをまとめます。iOS、CI、monorepo は扱いません。
1. ゴールと非対象
対象読者
- Windows 11 で Flutter の環境構築までは終わっている人
- 複数案件や複数サンプルで Flutter SDK の版ずれを避けたい人
- まずは VS Code + Android Emulator で FVM の最小運用を固めたい人
この記事で到達する状態
- Windows で FVM を導入できる
- プロジェクトごとに Flutter SDK のバージョンを固定できる
.fvmrcと VS Code 連携の役割を説明できるfvm flutter runで固定した SDK からアプリを起動できる
非対象
- Riverpod や REST API などのアプリ実装テーマ
- CI での FVM キャッシュ最適化
- Flutter fork や commit hash 指定の高度な運用
- Android Studio の詳細設定
グローバル Flutter を消して FVM だけに寄せる話ではありません。最初の導入は Windows 11で始めるFlutter開発環境 で済みます。案件ごとの差分だけを FVM に持たせる構成です。
2. 先に FVM が必要な理由を掴む
グローバル Flutter だけで運用すると、どのプロジェクトも同じ SDK を見に行きます。1 本のサンプルだけなら困りませんが、案件 A は古めの stable、案件 B は新しい stable といった状態になると、どこかで版ずれが出ます。
flowchart LR
G[グローバル Flutter] --> A[project-a]
G --> B[project-b]
A --> X[同じ SDK を参照]
B --> X
subgraph FVM運用
A2[project-a + .fvmrc] --> A3[project-a 用 SDK]
B2[project-b + .fvmrc] --> B3[project-b 用 SDK]
end
FVM を入れる目的は、Flutter SDK をもう 1 回インストールし直すことではありません。プロジェクトごとに「このフォルダはこの Flutter を使う」という設定を持たせることにあります。
- グローバル Flutter:
flutter createや最初の導入確認に使う土台 - FVM: プロジェクトごとの Flutter SDK を固定する仕組み
.fvmrc: どのバージョンを使うかを残す設定ファイル
ここを分けておくと、後続の Flutterで最初に詰まりやすいDartの書き方 や API 通信の記事を試すときも、「どの SDK で動かしているか」が曖昧になりません。
3. FVM を入れ、プロジェクトとエミュレーターを用意する
3-1. 前提の環境構築がまだなら先に済ませる
環境構築がまだの場合は Windows 11で始めるFlutter開発環境 を先に参照してください。
この記事は、すでに次の状態になっている前提で進めます。
flutter --versionが通るflutter doctorで Android 向けの最低限がそろっている- Android Emulator を起動できる
3-2. Windows で FVM を導入する
Flutter が入っていれば dart コマンドも使えるはずなので、PowerShell で次を実行します。
dart pub global activate fvm
続けて fvm コマンドが見えるか確認します。
fvm --version
fvm が見つからない場合は、PowerShell を閉じて開き直してから再実行してください。それでも通らない場合は、%LOCALAPPDATA%\Pub\Cache\bin が User PATH に入っているか確認します。
次のコマンドで LOCALAPPDATA の実際の値を確認します。
$env:LOCALAPPDATA
出力例:
C:\Users\<ユーザー名>\AppData\Local
この出力に \Pub\Cache\bin を足したパスが User PATH に含まれている必要があります。
C:\Users\<ユーザー名>\AppData\Local\Pub\Cache\bin
3-3. Flutter プロジェクトを作成する
FVM を導入したあと、サンプル用のプロジェクトを作成します。
flutter create my_fvm_app
cd my_fvm_app
ここではいったんグローバル Flutter でプロジェクトを作ります。固定対象はこの次の手順で設定します。
3-4. エミュレーターを起動する
利用可能なエミュレーターを確認します。
flutter emulators
表示された ID を指定して起動します。
flutter emulators --launch <emulator_id>
この時点ではまだ FVM 固定前です。先にエミュレーターだけ立ち上げておくと、後で fvm flutter run の確認がスムーズです。
4. プロジェクトごとの Flutter バージョンを固定する
4-1. stable の最新を固定する
プロジェクト直下で次を実行します。
fvm use stable --pin
このコマンドで行われることは 3 つです。
- 指定した Flutter SDK をキャッシュへ取得する
- プロジェクト直下に
.fvmrcを作る .fvmディレクトリと VS Code 向け設定を更新する
参考(今は実行不要): チームで使う版がすでに決まっている場合は、
stable --pinの代わりに具体版を指定できます。初めて試すときは上のstable --pinで進めてください。fvm use 3.29.2
stable --pin は「いまの stable を 1 回固定する」コマンドです。毎回最新へ自動追従するわけではないため、あとで更新したいときは改めて fvm use stable --pin を実行します。
4-2. 何が作られたか確認する
固定後の見え方は次のようになります。
my_fvm_app/
├─ .fvm/
├─ .fvmrc
├─ .vscode/
├─ lib/
└─ pubspec.yaml
ここで最低限押さえたいのは次の 2 点です。
.fvmrcは「このプロジェクトが使う Flutter の版」を表す- VS Code では
.vscode/settings.jsonが更新され、プロジェクトごとの Flutter SDK を参照しやすくなる
VS Code の統合ターミナルでは、FVM が設定した SDK を Dart Code 拡張が拾うため、flutter コマンドがプロジェクトの SDK を向くことがあります。最初は混乱しやすいので、この記事では明示的に fvm flutter ... を使います。
必要に応じて診断コマンドでも確認できます。
fvm doctor
fvm flutter --version
fvm doctor の VSCode 欄に No .vscode directory found と表示される場合は、VS Code でプロジェクトを一度開くと .vscode/settings.json が生成されます。
5. lib/main.dart を書き換えて fvm flutter run で確認する
5-1. lib/main.dart を次の内容に書き換える
lib/main.dart は次の内容で書き換えます。
このファイルは、FVM で固定した SDK を前提にアプリが起動する状態を確認するための最小画面です。.fvmrc、VS Code 連携、fvm flutter run という3つの確認点が UI 上にも見えるようにしています。
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'FVM Version Pinning Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.teal),
),
home: const FvmPinnedHomePage(),
);
}
}
class FvmPinnedHomePage extends StatelessWidget {
const FvmPinnedHomePage({super.key});
@override
Widget build(BuildContext context) {
final ColorScheme colorScheme = Theme.of(context).colorScheme;
return Scaffold(
appBar: AppBar(
title: const Text('Flutter + FVM'),
),
body: ListView(
padding: const EdgeInsets.all(16),
children: <Widget>[
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const <Widget>[
Text(
'このプロジェクトは FVM で SDK を固定しています。',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
SizedBox(height: 8),
Text('グローバル Flutter ではなく、プロジェクトの設定を優先して実行する想定です。'),
],
),
),
),
const SizedBox(height: 16),
Text(
'確認ポイント',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: colorScheme.primary,
),
),
const SizedBox(height: 8),
const ChecklistTile(
title: '`.fvmrc` がプロジェクト直下にある',
description: 'どの Flutter 版を使うかを共有する設定です。',
),
const ChecklistTile(
title: '`fvm flutter run` でアプリが起動する',
description: 'どの SDK を使っているかをコマンドで明示できます。',
),
const ChecklistTile(
title: 'VS Code で Flutter SDK の切り替えが追従する',
description: '`.vscode/settings.json` の更新対象です。',
),
const SizedBox(height: 16),
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: colorScheme.surfaceContainerHighest,
borderRadius: BorderRadius.circular(16),
),
child: const Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'次に覚えるコマンド',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
SizedBox(height: 8),
Text('fvm flutter doctor'),
Text('fvm flutter run'),
Text('fvm use stable --pin'),
],
),
),
],
),
);
}
}
class ChecklistTile extends StatelessWidget {
const ChecklistTile({
super.key,
required this.title,
required this.description,
});
final String title;
final String description;
@override
Widget build(BuildContext context) {
return Card(
child: ListTile(
leading: const Icon(Icons.check_circle_outline),
title: Text(title),
subtitle: Text(description),
),
);
}
}
コードのポイント
① アプリの入り口で FVM 前提の確認画面へ集約している
return MaterialApp(
title: 'FVM Version Pinning Demo',
home: const FvmPinnedHomePage(),
);
home を専用の FvmPinnedHomePage に寄せることで、このサンプルが何を確認する画面かを明確にしています。SDK の切り替え確認が目的の記事なので、カウンターアプリを残すより、確認項目がそのまま見える画面にしたほうが意図が伝わります。
② .fvmrc と fvm flutter run を画面上のチェック項目にしている
const ChecklistTile(
title: '`.fvmrc` がプロジェクト直下にある',
description: 'どの Flutter 版を使うかを共有する設定です。',
),
const ChecklistTile(
title: '`fvm flutter run` でアプリが起動する',
description: 'どの SDK を使っているかをコマンドで明示できます。',
),
確認ポイントを本文だけでなく UI にも置いているため、起動後に「何が確認できれば成功か」を見失いにくくなります。.fvmrc と実行コマンドの両方を並べることで、設定ファイルと実行経路の役割差も読み取りやすくしています。
③ 補助 Widget に分けて同じ見た目を繰り返している
class ChecklistTile extends StatelessWidget {
const ChecklistTile({
super.key,
required this.title,
required this.description,
});
同じカードを3回並べる箇所を ChecklistTile へ切り出すと、本文で説明したい論点が UI の構造に埋もれません。小さな部品に分けておくことで、あとから確認項目を増やす場合も本文との差分を最小限に保てます。
5-2. 固定した SDK で起動する
次のコマンドを実行します。
fvm flutter run
複数デバイスが見えている場合は、fvm flutter devices で ID を確認してから -d を付けて起動します。
fvm flutter devices
fvm flutter run -d <device_id>
確認したいのはアプリの見た目より、次の 3 点です。
fvm flutter runでビルドが最後まで通ること- エミュレーターにアプリが表示されること
- 今後のコマンド実行も
fvm flutter ...でそろえられること
6. チームで共有するときの最小ルール
FVM を入れる目的は、ほかの開発者も同じ SDK で再現できる状態を共有することです。
- 最低限共有するのは
.fvmrc - ローカルの SDK 実体そのものを配布する必要はない
- 版上げするときは
fvm use stable --pinかfvm use <version>をもう一度実行する
FVM は .gitignore の更新も補助できますが、共有するのは SDK 本体ではなく、どの SDK を使うかという設定ファイルです。
Android Studio を使う場合は、Flutter SDK の参照先をプロジェクト内の .fvm/flutter_sdk へ向け直す必要があります。VS Code より一段手数が増えるため、最初の 1 本としては VS Code のほうが進めやすいです。
7. まとめ
Flutter の最初の環境構築はグローバル Flutter で十分です。そのあとで案件ごとの差分を吸収したくなったら、FVM を足して .fvmrc でプロジェクト単位の版を固定します。この二層構成にしておくと、新しい記事を試すときも、チームで同じサンプルを動かすときも、参照中の SDK が曖昧なまま進まなくて済みます。
次は Flutterで画像・SVG・アイコンを管理する(flutter_gen最小構成) に進むと、FVM でそろえた環境の上でアセット参照の置き場所まで先に整えられます。そのあとで Dart の読み書きを整理したい場合は Flutterで最初に詰まりやすいDartの書き方 へ進むと流れがつながります。