お久しぶりの投稿です。
今回はMacでのFlutterの環境構築手順についてまとめたいと思います。今後Flutter開発していくエディタはVSCodeを想定しています。
(最近Macbookを新調し、改めてFlutterの環境構築を調べていましたが、記事の内容が古く、これまでの方法と異なっているものが多々あり、自分でも備忘録としてまとめようと思ったのがきっかけになります。)
Flutterとは
2018年にアプリ開発用のフレームワークとしてGoogleがリリースしたものが「Flutter」です。Flutterは「Dart」と呼ばれる、こちらもGoogleが2011年にリリースしたプログラミング言語のフレームワークになります。
環境構築手順
1. Flutterのインストール
1-1. Flutter SDKのインストール
こちらのリンクからFlutterの公式ドキュメントにアクセスし、自身のMacに合ったFlutter SDKをダウンロードします。
1-2. developmentフォルダの作成
ホームディレクトリ直下にdevelopment
フォルダを作成します。
~ % mkdir development
1-3. Flutter SDKの格納場所の指定
インストールしたFlutter SDKを先ほど作成したdevelopment
フォルダに格納します。
~ % unzip ~/Downloads/flutter_macos_arm64_3.24.3-stable.zip \
-d ~/development/
1-4. パスを通す
今の状態ではFlutterコマンドをターミナルで使用することができないためパスを通し、Flutterコマンドを使用できるようにします。
~ % vi ~/.zshrc
# 以下の1行を追加
export PATH=$HOME/development/flutter/bin:$PATH
~% source ~/.zshrc
2. Xcodeのインストール
2-1. Xcode Appのインストール
App Store経由でXcodeをインストールします。
2-2. コマンドラインツールでの使用許可
コマンドラインツールで、先ほどインストールしたXcode Appのバージョンを使用できるように設定します。
~ % sudo sh -c 'xcode-select -s /Applications/Xcode.app/Contents/Developer && xcodebuild -runFirstLaunch'
2-3. Xcodeの使用許可承諾
Xcodeの使用許可にサインします。
~ % sudo xcodebuild -license
2-4. iOS Simulatorのインストール
iOS開発のシミュレーターをインストールします。
~ % xcodebuild -downloadPlatform iOS
3. Android Studioのインストール
3-1. Android Studioのインストール
こちらのリンクからAndroid Studioをインストールします。
3-2. Flutterプラグインのインストール
Android StudioのプラグインからFlutterをインストールします。
3-3. Android SDK Command-line Toolsのインストール
Android SDK Command-line Toolsをインストールします。
Android Studioの「SDK Manager」から「SDK Tools」タブを選択し、「Android SDK Command-line Tools(latest)」にチェックを入れ「Apply」を実行します。
3-4. ライセンスの同意
Androidライセンスに同意します。
flutter doctor --android-licenses
4. VSCodeの拡張機能設定
拡張機能として「Flutter」と「Dart」の2つをインストールします。
ここまででFlutterの環境構築は完了です。
次の項目では実際にVSCodeでFlutterのシミュレーターを立ち上げ、開発ができるところまで進んでいきます。
開発手順
Flutterアプリケーションの作成
VSCodeで「Command + Shift + P」を打ち込み、コマンドパレッドを開き「Flutter」と入力します。「New Project」を選択し、さらに「Application」を選択します。
続いて、作成したアプリケーションを配置するフォルダの選択とアプリケーション名を入力します。ここまでの作業で新規アプリケーションのファイルが作成されます。
シミュレーターの起動
初期のサンプルアプリとしてカウンターアプリが既に実装されています。シミュレーター経由でこのカウンターアプリを起動してみます。
VSCodeの右下にある「macOS(darwin)」をクリックし、「Start iOS Simulator」を選択します。数十秒〜数分待つとiPhoneのシミュレータが起動します。
シミュレーターが起動したら、VSCodeの左のアイコンから「実行とデバッグ」アイコンを選択し、「実行とデバッグ」ボタンを押下します。こちらも数十秒〜数分待つとカウンターアプリが起動します。
カウンターアプリを修了したい場合はVSCodeの四角の赤アイコンを選択します。
軽微な改修を加えてみる
初期コード
現状の初期コードは以下のようになっています。
// 「Material」はAndroid系統のWidget
import 'package:flutter/material.dart';
// 「Cupertino」はiOS系統のWidget
// import 'package:flutter/cupertino.dart';
// void関数は「戻り値がない」ことを示す。
// もし関数が値を返す場合には、その値の型を指定する
// 整数を返す場合はint、文字列を返す場合はStringなど
// main関数はアプリケーションのエントリーポイント
// この関数が呼び出されると、アプリケーションが起動する
// runApp関数は、引数に渡されたWidgetを画面に表示する
// この場合、MyAppクラスのインスタンスを引数に渡している
// constを使ってMyAppインスタンスを生成している
// MyAppが定数インスタンスとして生成されるため、再レンダリングが不要な場合に効率的に処理される
void main() {
runApp(const MyApp());
}
// MyAppクラスはStatelessWidgetクラスを継承している
// 「状態を持たない」Widgetを作成するために使用される
// ユーザーの操作によって変化するデータを持たない場合に使用される
class MyApp extends StatelessWidget {
// constを使ってMyAppインスタンスを生成している
// {super.key}は、親クラス(StatelessWidget)のkeyパラメータを受け取る
// superは「親クラス」を指し、keyはStatelessWidgetが持つパラメータの一つ
// keyはWidgetの一意性を管理するためのIDとして使われ、ツリー構造のWidgetを識別する
// const MyApp({super.key});は、定数コンストラクタであるMyAppクラスのコンストラクタで、
// 親クラスのkeyを直接受け取り、MyAppインスタンスを一意に管理するための役割を持つ
const MyApp({super.key});
// StatelessWidgetクラスから継承されたbuildメソッドをオーバーライドしている
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo', // アプリのタイトル
theme: ThemeData(
// アプリのカラースキーム
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
// Material Design3を有効化
useMaterial3: true,
),
// homeプロパティでアプリのホーム画面を設定
// MyHomePageクラスを指定し、タイトルとして"Flutter Demo Home Page"を渡している
// MyHomePageはこのアプリが起動した際に最初に表示される画面
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
// MyHomePageクラスはStatefulWidgetクラスを継承している
// 「状態を持つ」Widgetを作成するために使用される
// ユーザーの操作によって変化するデータを持つ場合に使用される
class MyHomePage extends StatefulWidget {
// {super.key, required this.title}は、keyとtitleの2つの引数を受け取る
// super.keyは、親クラスStatefulWidgetのkeyに値を渡すために使われ、
// FlutterのWidgetツリー内でWidgetを一意に識別するために利用される
// required this.titleは、必須の引数titleを設定する
const MyHomePage({super.key, required this.title});
// titleプロパティをfinalで宣言する
// このプロパティは変更できない固定の値で、コンストラクタで一度設定されるとその後変更されない
final String title;
// State<MyHomePage>を作成するメソッドであるcreateStateをオーバーライドする
@override
// createStateメソッドはStatefulWidgetに必須のメソッド
// 対応する状態クラスである_MyHomePageStateクラス(Stateオブジェクト)を返す
// アンダーバーをつけることでそのメソッドはプライベートになる
State<MyHomePage> createState() => _MyHomePageState();
}
// State<MyHomePage>を継承することで、このクラスはMyHomePage Widgetと連動する
// StatefulWidgetであるMyHomePageの状態を保持し、必要に応じて再描画を行う
class _MyHomePageState extends State<MyHomePage> {
// _counterはint型の整数で、初期値は0に設定されている
// アンダーバーが付いているのでプライベート変数として定義されている
int _counter = 0;
// カウンターを増加させるメソッド
// アンダーバーが付いているのでプライベート変数として定義されている
void _incrementCounter() {
// setStateメソッドは状態が変化したことを通知し、Widgetを再描画するために使用する
// setStateを呼び出さずに_counterを更新した場合、変更が表示されない
setState(() {
// _counterを1ずつ増加させる
// アンダーバーが付いているのでプライベート変数として定義されている
_counter++;
});
}
@override
Widget build(BuildContext context) {
// Scaffoldは、Flutterアプリの基本的なレイアウト構造を提供するウィジェット
// appBar/body/floatingActionButtonプロパティを使って、各部分を簡単に設定できる
return Scaffold(
// AppBarはアプリ画面の上部に表示されるバー
// ここではアプリのタイトルや背景色が設定される
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
// bodyは画面の中央部分のレイアウトを構成
// Center Widgetは、指定した子Widgetを中央に配置するためのWidget
body: Center(
// Column Widgetは、複数の子Widgetを縦方向に並べるためのレイアウトWidget
child: Column(
// MainAxisAlignment.centerにより、縦方向の中央に配置する
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
// 初期表示のテキスト
const Text(
'You have pushed the button this many times:',
),
Text(
// 文字列内に変数を埋め込むため$を使用する
'$_counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
// floatingActionButtonは画面右下に表示されるボタン
floatingActionButton: FloatingActionButton(
// ボタンが押されると_incrementCounterメソッドが呼ばれ、カウンターが増加する
onPressed: _incrementCounter,
// ボタンのツールチップ(ホバーまたは長押しで表示される説明)
tooltip: 'Increment',
// ボタンにプラスアイコンを設定
child: const Icon(Icons.add),
),
);
}
}
ヘッダータイトルの変更
ヘッダータイトルを「Flutterヘッダー」に変更します。
- home: const MyHomePage(title: 'Flutter Demo Home Page'),
+ home: const MyHomePage(title: 'Flutterヘッダー'),
画面中央のテキスト変更
画面中央のテキストを「Hello Flutter!」に変更します。
- const Text(
- 'You have pushed the button this many times:',
- ),
+ const Text(
+ 'Hello Flutter!',
+ ),
全体色の変更
全体のカラーを青系統に変更します。
- colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
+ colorScheme: ColorScheme.fromSeed(seedColor: Colors.blueAccent),
ヘッダーにプラスアイコンを付与
ヘッダーにプラスアイコンを付与し、このアイコンをクリックしてもインクリメントされるように変更します。
- appBar: AppBar(
- backgroundColor: Theme.of(context).colorScheme.inversePrimary,
- title: Text(widget.title),
- ),
+ appBar: AppBar(
+ backgroundColor: Theme.of(context).colorScheme.inversePrimary,
+ title: Text(widget.title),
+ IconButton(
+ icon: const Icon(Icons.add),
+ onPressed: _incrementCounter,
+ ),
+ ),
ヘッダータイトルを左寄せ
ヘッダーのタイトルを左寄せに修正します。
- title: Text(widget.title),
+ title: Align(
+ alignment: Alignment.centerLeft,
+ child: Text(widget.title),
+ ),
画面中央にテキストを追加
画面中央部に縦並びになるようにテキストを1行追加します。
+ const Text(
+ 'カウンターが1ずつ増加します',
+ ),
Hello Flutter!のフォントサイズ修正
画面中央部に表示されている「Hello Flutter!」のフォントサイズを変更します。
- const Text(
- 'Hello Flutter!',
- ),
+ const Text(
+ 'Hello Flutter!',
+ ),
decrementのボタンを追加する
現状、インクリメントするボタンしか表示されていません。デクリメントする(カウントダウンする)ボタンを追加します。
// カウンターを減少させるメソッド
// アンダーバーが付いているのでプライベート変数として定義されている
void _decrementCounter() {
// setStateメソッドは状態が変化したことを通知し、Widgetを再描画するために使用する
// setStateを呼び出さずに_counterを更新した場合、変更が表示されない
setState(() {
// _counterを1ずつ減少させる
// アンダーバーが付いているのでプライベート変数として定義されている
_counter--;
});
}
floatingActionButton: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
FloatingActionButton(
onPressed: _decrementCounter,
tooltip: 'Decrement',
child: const Icon(Icons.remove),
),
const SizedBox(width: 10),
FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
],
),
挙動確認
ここまで修正すると以下のような画面になります。

参考
今回はMacでのFlutterの環境構築手順についてまとめました。今後はFlutter開発の記事を中心に書いていこうと思っています。