Flutter　キャッチアップ

## 前作
[Flutterを知らない人がFlutterでアプリを公開するまでにどのような情報が必要でどのようなエラーを解消したか](https://qiita.com/satoru_pripara/items/1427b8ea2ce7df3a3e85)

## Flutter 公式実装例

[All Samples](https://flutter.github.io/samples/#)

## 公式では無い実装例

- [nisrulz/flutter-examples](https://github.com/nisrulz/flutter-examples)
- [Flutter 全部俺 Advent Calendar 2019](https://adventar.org/calendars/4140)
    - [flutter_circle_color_picker](https://github.com/itome/flutter_circle_color_picker) 

## Flutter 情報集

[Solido/awesome-flutter](https://github.com/Solido/awesome-flutter)

Flutter関連ニュース、ライブラリ、実装例など関連情報を網羅しているリポジトリ。困ったらチェックするといいだろう。

## 参考になる書籍など

- Flutter実践開発 iPhone/Android両対応アプリ開発のテクニック, 渡部陽太, 技術評論者, 2023
   - 基本的なところが概ねカバーされており良書である。

- 「内側」から理解する Flutter 入門, 中條 剛（ちゅーやん）, 2021, ZENN, https://zenn.dev/chooyan/books/934f823764db62

- Flutter 大学, https://zenn.dev/flutteruniv

## 環境構築

基本的には公式ページに沿ってインストールを進めれば問題ない。
[Flutter - install flutter](https://docs.flutter.dev/get-started/install)

### Flutter, Dart SDK バージョン

Dart SDK バージョンはFlutterバージョンと関連している。リストは以下：

[flutter dev release archive](https://docs.flutter.dev/release/archive)

### Cocoapodsについて
iOS側のライブラリを集めてくれるツールCocoapodsをFlutterでは利用している。パソコンのグローバル環境にあるCocoapodsを使うようである。しかしiOSアプリ開発では、よくrbenvやbundlerを用いて、各プロジェクトごとに別バージョンのCocoapodsを指定していることがよくある。Flutterでも、各プロジェクトごとに別バージョンのCocoapodsを指定する方法はある。ただFlutter SDKそのものを書き換える必要があるので、応急処置的な対応とは言える。しかもFlutter SDKをバージョンアップするごとに対応がいるだろう。

[Zenn - Flutter の CocoaPods を rbenv と bundler で管理する](https://zenn.dev/attomicgm/articles/manage_flutter_cocoapods_used_rbenv_bundler)


## Flutter State Management とは

### Providerパッケージ
[Simple app state management - flutter 公式](https://docs.flutter.dev/development/data-and-backend/state-mgmt/simple)

[samples/provider_counter/](https://github.com/flutter/samples/tree/master/provider_counter)
[samples/provider_shopper/](https://github.com/flutter/samples/tree/master/provider_shopper)

各ウィジェット間で情報のやりとりをする際、クロージャを渡していくと言うやり方でも良いが、ちょっと複雑なアプリになるとすぐ煩雑になる。

そのため、
ChangeNotifier-ChangeNotifierProvider-Consumer
のクラスが用意されている。いわゆるリアクティブプログラミングのように、値の変化を購読し、UIを変更できる。

リアクティブプログラミング的に言えば
Observable-Observableを必要なクラスに渡すクラス-Subscribeを記述するクラス
のような関係となろうか。

2024年現在、Provider + ChangeNotifierで多くの複雑な構築もできるようになっているため、基本はこれを進める。

[FlutterのBLoC(Business Logic Component)のライフサイクルを正確に管理して提供するbloc_providerパッケージの解説](https://medium.com/flutter-jp/bloc-provider-70e869b11b2f)

#### ChangeNotifier使用例

ChangeNotifierだが、`notifyListner()`メソッドを呼ぶと、購読してるクラスへ値が通知されるようになっている。

また、Flutter公式の機能であるListenableBuilderと併用することもできる。ChangeNotifierだがが更新された際、ListenableBuilderで囲った部分のウィジェットのみをピンポイントで更新させることができる。そのため、パフォーマンス向上に役立つ。Flutterで新しいプロジェクトを作成するときに選べるテンプレアプリでも使用されている。

#### provider利用側

providerの利用側(UI, widget側)でproviderを参照する方法はいくつかある。以下AIにまとめてもらったが、ドキュメントを見たり自分で書いてみた結果からも間違ってはいないと思う: 

AIの解説: 

Flutterの`provider`パッケージを使用する際、`Provider`からデータを参照する方法はいくつかあります。それぞれの方法には特徴があり、適切な場面で使い分けることが重要です。以下に体系的に解説します。

---

### 1. **`Provider.of<T>(context)`**
`Provider.of<T>(context)`は、指定された`BuildContext`に関連付けられた`Provider`からデータを取得する最も基本的な方法です。

#### 使用例:
```dart
final myModel = Provider.of<MyModel>(context);
```

#### 特徴:
- `listen`パラメータ（デフォルトは`true`）で、リビルドの挙動を制御できます。
  - `listen: true`: プロバイダの値が変更されたときにウィジェットを再構築します。
  - `listen: false`: 値の変更を監視せず、ウィジェットを再構築しません（例えば、イベントハンドラ内で使用する場合など）。
  
#### 注意点:
- `listen: true`の場合、不要な再構築を引き起こす可能性があるため、慎重に使用する必要があります。

---

### 2. **`Consumer<T>`**
`Consumer<T>`は、`Provider.of<T>(context)`をラップしたウィジェットで、特定の部分だけを再構築したい場合に便利です。

#### 使用例:
```dart
Consumer<MyModel>(
  builder: (context, myModel, child) {
    return Text(myModel.someValue);
  },
)
```

#### 特徴:
- `builder`関数内でプロバイダの値にアクセスでき、その値に基づいてUIを構築します。
- 親ウィジェット全体を再構築する必要がなく、効率的です。

#### 注意点:
- `Consumer`を使用することで、不要な再構築を防ぐことができますが、過剰にネストするとコードが複雑になる可能性があります。

---

### 3. **`Selector<T, R>`**
`Selector<T, R>`は、`Consumer`と似ていますが、特定のプロパティのみを監視し、そのプロパティが変更された場合にのみ再構築を行います。

#### 使用例:
```dart
Selector<MyModel, String>(
  selector: (context, myModel) => myModel.someValue,
  builder: (context, someValue, child) {
    return Text(someValue);
  },
)
```

#### 特徴:
- `selector`関数で監視するプロパティを指定できるため、不要な再構築を防ぎます。
- 複雑なモデルの一部だけを監視する場合に特に有用です。

#### 注意点:
- `selector`関数の実装が誤っていると、意図しない再構築が発生する可能性があります。

---

### 4. **`context.watch<T>()`**
`context.watch<T>()`は、`Provider.of<T>(context, listen: true)`の短縮形として導入されました。

#### 使用例:
```dart
final myModel = context.watch<MyModel>();
```

#### 特徴:
- `watch`は常に`listen: true`として動作します。
- コードが簡潔になり、可読性が向上します。

#### 注意点:
- 再構築が必要ない場合は使用しないように注意してください。

---

### 5. **`context.read<T>()`**
`context.read<T>()`は、`Provider.of<T>(context, listen: false)`の短縮形です。

#### 使用例:
```dart
final myModel = context.read<MyModel>();
```

#### 特徴:
- `read`は`listen: false`として動作します。
- イベントハンドラや初期化処理などで使用する場合に便利です。

#### 注意点:
- UIの構築中に使用すると、意図しない挙動を引き起こす可能性があります。

---

### 6. **`context.select<T, R>()`**
`context.select<T, R>()`は、`Selector`ウィジェットの短縮形です。

#### 使用例:
```dart
final someValue = context.select((MyModel myModel) => myModel.someValue);
```

#### 特徴:
- `Selector`と同様に、特定のプロパティのみを監視し、そのプロパティが変更された場合にのみ再構築します。
- コードが簡潔で読みやすいです。

#### 注意点:
- 監視対象のプロパティが明確である場合に使用します。

---

### まとめ
| 方法                     | 再構築の制御 | 使用場面                                   |
|--------------------------|--------------|--------------------------------------------|
| `Provider.of<T>(context)` | 可能         | 全体的な値の取得やイベントハンドラ内での使用 |
| `Consumer<T>`            | 自動         | 特定の部分だけを再構築したい場合             |
| `Selector<T, R>`         | 部分監視     | 特定のプロパティのみを監視したい場合         |
| `context.watch<T>()`     | 自動         | 簡潔な記述が必要な場合                      |
| `context.read<T>()`      | なし         | イベントハンドラや初期化処理内での使用       |
| `context.select<T, R>()` | 部分監視     | 特定のプロパティのみを監視したい場合         |

- 以上、AIの解説。

参考: [Document/provider](https://pub.dev/documentation/provider/latest/provider/)



### RiverPod ライブラリ

[flutter_riverpod](https://pub.dev/packages/flutter_riverpod)

ConsumerWidgetもステート管理のクラスだが、デフォルトのクラスではなくRiverPodライブラリのクラスである。Providerパッケージと似てはいるが、さらに高機能となっている。

RiverpodとProviderの比較については:
[Provider vs Riverpod](https://riverpod.dev/docs/from_provider/provider_vs_riverpod)

ConsumerWidgetはProviderの変化を購読できるWidget(StatlesWidget)である。buildメソッドの中で、複数のプロバイダの値を監視できる点で描きやすいのが特徴のWidgetである。

このほかに、ConsumerというWidget(StatefulWidget)もある。こちらはパフォーマンスの点で優れている。

RiverPod ライブラリそのものの特徴としてとはコンパイルセーフ（コンパイルさえ通れば、安全に実行できる）で、Flutterには依存せず、さまざまなユースケースをサポートしており、ほぼデフォルトのProviderの上位互換である。
またProviderをグローバル定数として宣言するという特徴がある。

[ConsumerWidget class - official doc](https://pub.dev/documentation/flutter_riverpod/latest/flutter_riverpod/ConsumerWidget-class.html)
[Riverpodの基本的な使い方を整理してみる](https://zenn.dev/umatoma/articles/2026ef43bdb0f4)
[Reading a Provider - RiverPod Doc](https://riverpod.dev/docs/concepts/reading/)
[【Flutter】Providerのほぼ上位互換、Riverpodの基本的な使い方](https://techracho.bpsinc.jp/wingdoor/2020_10_08/97815)

#### const StatelessWidget({ Key? key }) : super(key: key);
これはコンストラクタである。

#### riverpod_generator, riverpod_annotation

riverpodを使う際に似たようなコードを書かなければいけない場面が多いために、コード生成でその問題を解決してくれる。特に事情がなければriverpodと一緒に必ず利用することを薦める。

[riverpod_generator](https://pub.dev/packages/riverpod_generator)
[riverpod_annotation](https://pub.dev/packages/riverpod_annotation)

使用方法

[Zenn - Riverpod Generatorで生成できるProviderの種類と書き方（1.2.0時点）]()

#### riverpod_lint
riverpod を使う際よくある間違いのコードを検出してくれる。これも使うことを推奨。

[riverpod_lint](https://pub.dev/packages/riverpod_lint)

#### riverpod おすすめ構成

※バージョン番号は任意
```yaml:pubspec.yaml
dependencies:
    flutter_riverpod: ^2.5.1
    riverpod_annotation: ^2.3.5

dev_dependencies:
    riverpod_generator: ^2.4.0
    build_runner: ^2.4.11
    custom_lint: ^0.6.4
    riverpod_lint: ^2.3.10
```



### flutter-bloc
こちらもステートマネジメントのライブラリである。ただシンプルでより使いやすい印象。blocパターン（だいたい、MVVMと同じ気がする）を実現できる。なおblocパターンそのものはこのライブラリを使わなくても、streamやrx_dartなどを使っても実現することはできる。

[flutter-bloc](https://pub.dev/packages/flutter_bloc)
[bloc documentation](https://bloclibrary.dev/bloc-concepts/)
[【Flutter】flutter_blocについてまとめる](http://skmkuma.com/【flutter】flutter_blocについてまとめる/#BlocProvider)
[Flutterのアプリ設計(Bloc)](https://itome.team/blog/2019/12/flutter-advent-calendar-day21/)

#### BlocBuilder, BlocListener, BlocConsumerの違いについて

BlocBuilderはstateが変更された時にWidgetを返すもの。BlocListenerはWidgetは関係なく、stateが変更された時に何かしたい処理を書くもの。BlocConsumerは両者の特徴を併せ持つ。

[Flutter: BlocBuilder vs BlocConsumer vs BlocListener](https://ppantaleon.medium.com/flutter-blocbuilder-vs-blocconsumer-vs-bloclistener-a4a3ce7bfa9a)

### flutter-hooks

React Hooks のようにステートマネジメントを行うためのライブラリ。

[flutter-hooks](https://pub.dev/packages/flutter_hooks/example)

riverpodと併用したい場合は[hooks-riverpod](https://pub.dev/packages/hooks_riverpod)を使う。

### flutter_redux

Reduxパターンを実現するためのライブラリ。やや更新が古いので不安があるが、FlutterでReduxを実現するためのライブラリで他にいいのがない。

Reduxパターンとは元々Reactに由来するもの。アプリ全体の状態(State)はただ一つのStoreが持つこととなっている。Stateはほかの箇所から変更不能となっている。ただしActionを送信し、ReducerがActionを受け取ることで適切な状態へと更新してくれる。一般には複雑な状態を持つアプリでもStateで明確に表すことができるので、状態を再現したり、テストしたりが簡単になる。デメリットとしては若干学習コストがかかる。

[flutter_redux](https://pub.dev/packages/flutter_redux)

更新が新しいライブラリとしては以下があるが、使用実績が少なくFavorite数は100台となっている。

[async_redux](https://pub.dev/packages/async_redux)

[Flutterのアプリ設計(Redux)](https://itome.team/blog/2019/12/flutter-advent-calendar-day22/)

### flutter_mobx

Reactに由来するMobXデザインパターンを実現するためのライブラリである。

[flutter_mobx](https://pub.dev/packages/flutter_mobx)

Reduxと少し似ており、Actionを用いてアプリの状態(Observable)を変更する。

変更された状態に基づいてアプリで動作や表示を行う際には、ObserverやReactionといった要素を利用する。

### GlobalKey

各ウィジェットで情報のやり取りをするための方法の一つ。別のウィジェット、多くは子ウィジェットのメンバーに親からアクセスできるようにする。

[GlobalKey<T extends State<StatefulWidget>> class ](https://api.flutter.dev/flutter/widgets/GlobalKey-class.html)
[FlutterのGlobalKeyについて深掘りしてみる](https://zenn.dev/flutteruniv_dev/articles/908d4069197e0c)
[Youtube - Flutter GlobalKey](https://www.youtube.com/watch?v=uvpaZGNHVdI&t=50s)

[ListenableBuilder]()

### pub.devとは

Flutter, dartのAPIが集まる公式サイト

[pub.dev](https://pub.dev)

### GetXとは

ステート管理、ルーティング管理、Dependency Injectionなどが簡潔に記述できるライブラリ。簡単なアプリであればStatefulWidgetで状態管理しても良いと思われるが、複雑なアプリではRiverPodと並び有効に使える。

https://pub.dev/packages/get#about-get

リアクティブプログラミングを使いやすいようにしてくれている。
https://github.com/jonataslaw/getx/blob/master/documentation/en_US/state_management.md#reactive-state-manager

ルーティング管理は以下。画面遷移が驚くほど使いやすくなっている。https://github.com/jonataslaw/getx/blob/master/documentation/en_US/route_management.md
[GetXの使い方(ルート管理編)](https://zenn.dev/tatsuhiko/books/b938417d5cb04d/viewer/f424b2)

その他、依存性注入、API呼び出し、多言語対応、スナックバーなど数々の機能を簡単に使えるようになっている奇跡のライブラリ。

一般論になるが、依存性注入、ルーティング管理は特に大規模なアプリでは他のウィジェットクラスとは別に管理したほうが、１ファイルの行数が減り見通しが良くなるだろう。GetXでもそのように実装することができる。分離して実装している方の参考:

[Sameera-Perera/flutter_e-commerce_item_gridview/routes](https://github.com/Sameera-Perera/flutter_e-commerce_item_gridview/tree/main/lib/routes)
[Sameera-Perera/flutter_e-commerce_item_gridview/item_bindings](https://github.com/Sameera-Perera/flutter_e-commerce_item_gridview/blob/main/lib/view/item/item_binding.dart)



#### Rx

典型的には、`Controller` （値を放出する側=購読される側）を以下のようにして各ウィジェットで初期化する。
```dart:test.dart
class Home extends StatelessWidget {
  final controller = Get.put(Controller());
}
```

購読した値が更新された時、ウィジェットも更新したい時は、そのウィジェットを`Obx`で囲むだけで良い。

```dart:test.dart
            Obx(() => Text(
                      'clicks: ${controller.count}',
                    )),

```






### Firebase core　とは

Firebaseの基本の組み込みができるFlutter ライブラリ。

[firebase_core](https://pub.dev/packages/firebase_core)

### Firebase Authenticationとは

ログイン周りを簡単に実装できるFirebaseのフレームワーク

[Firebase Authentication](https://firebase.google.com/docs/auth)

ユーザーの作成、現在のユーザー状態の取得またはユーザー状態の変更の購読、ログイン、ログアウトなど一通りのユーザー操作が簡単に実行可能。


### Firebase auth for flutter とは

flutterからFirebase authを使えるようにしてくれるライブラリ

[Firebase auth for flutter](https://pub.dev/packages/firebase_auth)

### Cloud Storage for Firebase　とは

画像・動画などユーザー作成コンテンツを保存するような場合に使用するクラウドストレージ。

Firebase Authと連携できる。
[Cloud Storage for Firebase](https://firebase.google.com/docs/storage)

### Cloud Storage for Flutter とは

Cloud Storage for FirebaseをFlutter向けに使えるようにしてくれるライブラリ。

[Cloud Storage for Flutter](https://pub.dev/packages/firebase_storage)

### Cloud Firestore とは

[Cloud Firestore](https://firebase.google.com/docs/firestore)
[Zenn - 【図で解説】Firestoreでできること・できないこと](https://zenn.dev/yucatio/articles/173f386c471398)
[The Firebase Blog - 5 tips for Firebase Storage](https://firebase.blog/posts/2016/07/5-tips-for-firebase-storage)

クラウドでのNoSQLデータベース。

flutterでの使い方は以下：
[Zenn - Firebase編5:Storage](https://zenn.dev/kazutxt/books/flutter_practice_introduction/viewer/firebase_storage#%E3%82%A2%E3%83%83%E3%83%97%E3%83%AD%E3%83%BC%E3%83%89)

Firebase公式ドキュメントにも書いてありますが、Firestore内にてdocument(具体的なデータを格納する場所)とcollection(documentを格納する場所)は交互になるようにしてください。collectionがcollectionを格納したり、documentがdocumentを格納することはありません。https://firebase.google.com/docs/firestore/data-model#dart
```dart:test.dart
final messageRef = db
    .collection("rooms")
    .doc("roomA")
    .collection("messages")
    .doc("message1");

```



### Cloud Firestore for Flutter Pluginとは

Cloud FirestoreをFlutterで使うためのライブラリ。

[Cloud Firestore for Flutter Plugin](https://pub.dev/packages/cloud_firestore)

ドキュメント https://firebase.flutter.dev/docs/firestore/usage/

### Google Ad Mob

flutterでは以下のライブラリで導入できる。
[google_mobile_ads](https://pub.dev/packages/google_mobile_ads)
ドキュメントは以下。
[Mobile Ads SDK Flutter](https://developers.google.com/admob/flutter/quick-start)

ドキュメントだけだとよく分からないところもあったが以下のCodelabはわかりやすかった。
[Codelabs - Adding an AdMob banner and native inline ads to a Flutter app](https://codelabs.developers.google.com/codelabs/admob-inline-ads-in-flutter#4)

### flutter_native_splash

ネイティブアプリのようなスプラッシュ画面をつけたい時にはこのライブラリが使える。

[flutter_native_splash](https://pub.dev/packages/flutter_native_splash)

### image_picker

画像やビデオを端末のアルバムから取得またはカメラで撮影するためのライブラリ。

[pub.dev - image_picker](https://pub.dev/packages/image_picker)

### video_player

ウィジェット上で動画を再生するためのライブラリ。
[pub.dev - video_player](https://pub.dev/packages/video_player)

### video_compress
動画を圧縮するためのライブラリ。
[video_compress](https://pub.dev/packages/video_compress)


### timeago

時間の表示について、「約１時間前」「今から45秒後」といった人間が読んでわかりやすいフォーマットに変換してくれるライブラリ。
[pub.dev - timeago](https://pub.dev/packages/timeago)

### cached network image

ネットワーク上から画像を取得し、キャッシュに貯めたりローディング表示をしたりしながら画像を表示できるウィジェットのライブラリ。


[pub.dev - cached_network_image](https://pub.dev/packages/cached_network_image)


### flutter_launcher_icons
[pub.dev - flutter_launcher_icons](https://pub.dev/packages/flutter_launcher_icons)

iOS、Androidのアプリアイコンを設定できる非常に便利なライブラリ。ymlファイルを用意するなどして設定を記載する。


### package_info_plus
[pub.dev - package_info_plus](https://pub.dev/packages/package_info_plus/example)

アプリ名、バージョン、ビルド番号などのシステム情報をコード上で手軽に取得できるようになる。


### ログ出しができるライブラリ

何種類かあるが、loggerがおすすめである。
[pub.dev - logger](https://pub.dev/packages/logger/example)
[【2022年】おすすめのロガーパッケージ4選【Flutter】](https://zenn.dev/susatthi/articles/20220413-153500-flutter-logger)

### データを端末に保存

- データベース(SQLite)に保存する[sqflite](https://pub.dev/packages/sqflite)
- 暗号化が可能でデータの読み書きが早いNoSQLデータベースである[hive](https://pub.dev/packages/hive)
- 設定などのちょっとしたデータを保存する[shared_preferences](https://pub.dev/packages/shared_preferences)

に大別される。

### HTTP リクエスト（APIクライアント）用のライブラリ

[http](https://pub.dev/packages/http)
[dio](https://pub.dev/packages/dio)
[retrofit](https://pub.dev/packages/retrofit)
[chopper](https://pub.dev/packages/chopper)
getX
などがある。一番星が多いのはhttpである。

クライアントの自動生成機能があるため、ある程度以上の規模のアプリであればretrofit+dioが良いか。簡単にいうと、自分である程度APIクライアントのクラスを書いた後、build_runnerというライブラリを用いてコードの自動生成ができる。retrofitのドキュメントに詳しく書いてある。


[Best Libraries for Making HTTP Requests in Flutter (2023)](https://www.kindacode.com/article/best-libraries-for-making-http-requests-in-flutter/#GetX_aka_Get)

dioを利用している場合、pretty_dio_logger  というリクエストやレスポンスをログに見やすく出してくれるライブラリもある。

[pretty_dio_logger](https://pub.dev/packages/pretty_dio_logger)

### URLを開く

https://pub.dev/packages/url_launcher

### display_number

数字の整形（桁数、四捨五入）ができる。

- 以下、引用

```dart:display.dart
import 'package:number_display/number_display.dart';

final display = createDisplay(length: 8);

main(List<String> args) {
  print(display(-254623933.876));    // result: -254.62M
}
```


- 以上、引用 https://pub.dev/packages/number_display より

### bezier_chart

線グラフ、円グラフなどが作れる。が、dart3には非対応。

https://pub.dev/packages/bezier_chart

### folding_cell

折り畳まれたカードが開いたり閉じたりするようなアニメーションを表現できる。

https://pub.dev/packages/folding_cell


### flutter_launcher_icons

一つpngファイルを用意さえすれば、iOS, Android, webなど各種プラットフォーム用のサイズのアプリアイコンを自動で生成してくれるライブラリ。便利すぎてデメリットも特にないのでほぼデファクトスタンダードであろう。

[flutter_launcher_icons](https://pub.dev/packages/flutter_launcher_icons#)

### リンティング

デフォルトで`flutter_lint`というライブラリが入っている。さらに厳しいルールを設けているものとして
- `lint`: https://pub.dev/packages/lint
- `very_good_analysis`: https://qiita.com/kenma/items/b085b7598875ac2222c3

がある。チーム開発では厳しいやつを使ったほうがいいかもしれない。

### Shimmerエフェクト（ローディング中、UI部品に光が左から右に流れるような画面表示を出すこと）

同名のライブラリがあり、非常に簡単に呼び出せる。
[pub.dev/shimmer](https://pub.dev/packages/shimmer)

### ライフサイクル

コードを実行する厳密なタイミングの制御が必要な場合は以下を検討してみるとよいだろう。

- Flutterのデフォルトのライフサイクル
    - [RouteObserver](https://api.flutter.dev/flutter/widgets/RouteObserver-class.html) -> ウィジェットがpush, popしたタイミングを取得できる。デフォルトの`Navigator.of(context).push<void>`や、GetXライブラリの`Get.toNamed()`などでは取得できていた。
        - ただ、無論、同一画面内である子ウィジェットを切り替え、別の子ウィジェットを表示するなどのケースでは、無論検知できない。
    - [WidgetsBindingObserver](https://api.flutter.dev/flutter/widgets/WidgetsBindingObserver-class.html) 　-> フォアグラウンド、バックグラウンドのタイミングなどを取得できる。
- ライブラリ
    - [focus_detector](https://pub.dev/packages/focus_detector) -> 2年半ほどリリースがない。
    - [visibility_detector](https://pub.dev/packages/visibility_detector) -> 1年ほど前にリリース。こちらの方が人気はありそう。

### ローカライズ

[intl](https://pub.dev/packages/intl) + [flutter localizations](https://pub.dev/packages/flutter_localizations)パッケージを使うと良い。

[「flutter_localizations」による多言語対応](https://qiita.com/tanakasoboro/items/d5631a0a29787b20041d)

### 画像操作

[image](https://pub.dev/packages/image)
png, jpg,gifといった様々な画像の拡大縮小などの操作ができる。

### SVG画像

[flutter_svg](https://pub.dev/packages/flutter_svg)を使うと良いだろう。

### コード生成

[build_runner](https://pub.dev/packages/build_runner)というパッケージを様々な他のパッケージと一緒に用いて、コード生成を行う。
`flutter pub pub run build_runner build`

というとんでもない長いコマンドを叩いてコード生成を行うことで有名。


### Flutter からiOS, AndroidなどNativeを呼び出す
[MethodChannel](https://api.flutter.dev/flutter/services/MethodChannel-class.html)を使うことで可能である。ただ、冗長であって、一つコードを書いただけで複数のプラットフォームで動くと言うFlutterの利点を殺してしまうことにもなるので、これを多用しなければならない場合はそもそもFlutterを使うこと自体あまり適切ではないだろう。

### iOS, Androidアプリに一部だけFlutterを導入
[Add-to-app](https://docs.flutter.dev/add-to-app)と言う方法で可能となる。Flutterへの移行を段階的に行う際には有効だろう。ただ、NativeとFlutterで密にやり取りをしないといけないとなると面倒なので、独立性の高い機能（画面）をFlutterで作って導入してみることを勧める。

### Flutter からiOS, Nativeの画面を表示する

[Platform View](https://docs.flutter.dev/platform-integration/android/platform-views)と呼ばれる仕組みを使うと可能ではある。が、やはりただ、冗長であって、一つコードを書いただけで複数のプラットフォームで動くと言うFlutterの利点を殺してしまうことにもなるので、これを多用しなければならない場合はそもそもFlutterを使うこと自体あまり適切ではないだろう。

また、いったんNativeで描画したものをFlutter側でコピーして映すような挙動となるので、パフォーマンス的にもよろしくない。地図やウェブビューで使用することが多いだろうが、それらについてはそれ用のパッケージがpub.devに用意されているので、Platform Viewを自分で直接使うことはそう多くないはず。

### UI部品について


#### 総論 Material Design

[Flutter doc - material package](https://api.flutter.dev/flutter/material/material-library.html)

マテリアルパッケージをインポートすることでマテリアルデザインを利用可能となる。

[Material Design - Components](https://material.io/components)

どのようなデザインの類型があるかは上記から検索できる。

[flutter doc - Widgets](https://docs.flutter.dev/development/ui/widgets)

各ウィジェット（UI部品）のリストは上記から検索できる。



#### Scaffold

主にアプリの一番基本（ウィジェットの階層の大元）に設定すべきとされるウィジェット。

appBar, backgroundColor, body, bottomNavigationBar, bottomSheet, drawer, endDrawer, floatingActionButtonなど基本となる付属部品をたくさんつけられる。また、それらの部品の見た目・振る舞いに関しても、Scaffoldのプロパティを通じてオプションが様々設定可能となっている。

[Flutter doc - Scaffold](https://api.flutter.dev/flutter/material/Scaffold-class.html)
[【Flutter】Scaffoldの使い方｜アプリのレイアウトを作成](https://flutternyumon.com/how-to-use-scaffold/)

#### Drawer

Scaffoldにセットし、画面右端または左端から出てくるドロワービューを表現するウィジェット。ScaffoldにAppBarを設定していれば、Drawerを開くためのボタンが自動的につけられる。プログラムによりDrawerを開くには、`Scaffold.of(context).openDrawer()`関数を呼べば良い。Drawerを閉じるには、`Navigator.of(context).pop()`関数を呼べば良い。Drawerの中身としては、典型的にはListViewを使い、縦にコンテンツを並べることが多い。

[Drawer class](https://api.flutter.dev/flutter/material/Drawer-class.html)


#### AppBar

主にScaffoldに設定する、アプリの最上部にあるタイトルバー。
[flutter doc - AppBar class](https://api.flutter.dev/flutter/material/AppBar-class.html)
[Flutter の AppBar で遊んだら楽しかったよ](https://zenn.dev/sugitlab/articles/e68b2fce02e50f)


#### BottomNavigationBar

画面の下部に設置する、複数のボタンを備えたタブのこと。主にアプリの基本となる画面への画面遷移に使うことが多いだろう。

[Flutter doc - BottomNavigationBar](https://api.flutter.dev/flutter/material/BottomNavigationBar-class.html)
[Flutter doc - BottomNavigationBarItem](https://api.flutter.dev/flutter/widgets/BottomNavigationBarItem-class.html)
[Zen - FlutterのBottomNavigationBarを本気で学ぶ](https://zenn.dev/urasan/articles/5bb85a54fb23fb)




#### Column

縦にウィジェットを並べたい時に使うウィジェット。ただchildが画面サイズを超えてもスクロールはできない（しかもエラーになる）。たくさんのchildを含みたいのであればListViewを使うことになるか。

[Row](https://api.flutter.dev/flutter/widgets/Row-class.html)クラスはこれの横バージョンである。

[Flutter Doc - Column](https://api.flutter.dev/flutter/widgets/Column-class.html)

#### SizedBox

子ウィジェットの縦横の長さを厳密に制限できるクラス。

子無しで使えば特定の長さの隙間を表すのにも使える。

[Flutter doc - SizedBox class](https://api.flutter.dev/flutter/widgets/SizedBox-class.html)

たとえば以下は高さ25の隙間を表すことができる。

```dart:SizedBoxTest.dart
SizedBox(
  height: 25.0
)
```



#### FloatingActionButton

 あるアプリ（または画面）において最も重要な機能などを担当させるためのボタン。影がついており、他のコンテンツから浮き上がって見え、ユーザーから目立つということが特徴。

一つの画面に二つ以上のFloatingActionButtonを付けると混乱の元になるためするべきではない。またFloatingActionButtonをdisableさせるのも避けた方がいい。

典型的にはScaffoldウィジェットに埋め込む形で利用する。

単に右下に配置することもできるほか、下部のナビゲーションばーがあればそこに埋め込む形で表示することもできる。Scaffoldクラスの[floatingActionButtonLocation](https://api.flutter.dev/flutter/material/Scaffold/floatingActionButtonLocation.html)変数を使う。

onPressed変数にはasyncキーワードをつけて非同期処理を記述することも可能。

[FlutterボタンのonPressedでasyncを使う方法](https://www.choge-blog.com/programming/flutterbutton-onpressedasync/)
[Asynchronous programming: futures, async, await](https://dart.dev/codelabs/async-await)

#### SingleChildScrollView

ListViewとは異なり、たった一つのWidgetのみchildとして持つことができるリスト。主に、通常は全体を見せることを予定しているが、端末によっては画面端をはみ出してしまうようなコンテンツについて、スクロールができるようにするために用いる。

[Flutter基礎 ~SingleChildScrollView・ListView・ListTile~](https://zenn.dev/engineerhikaru/books/ecf839ce7d0591bb203b/viewer/fa941f720f5358fa99b1)

#### Stack

Z軸方向にChildを底から積み重ねていくWidget。

子ウィジェットはpositionedとnon-positionedがあり、positionedは指定した特定の位置に積み上げられる。non-positionedはStackのalignmentプロパティの指示に従って積み上げられる。alignmentはデフォルトではtop-leftである。

Positionedは指定の仕方によってはStackの位置をはみ出すことがあるが、はみ出す部分を描画するか、それともはみ出した部分は描画しないかもoverflowプロパティにより指定できる。

[Stack class - Flutter Doc](https://api.flutter.dev/flutter/widgets/Stack-class.html)
[FlutterのStackを使ってみた](https://dev.classmethod.jp/articles/flutter_stack1/)

#### CustomPaint

図形、線分、色など自由な描画をしたい際に用いるWidget。

size, およびCUstomPainterクラスを渡して初期化する。

CustomPainterクラスでは２つのメソッドを実装する必要がある。

Painter内の描画を書き換えるかを指示するためのshouldRepaint(CustomPaiter old)メソッド、および描画の内容を指示するpaint(Canvas, Size)メソッドである。

渡されたcanvasクラスを使って、以下のように豊富な種類の描画を自由に行える。
drawLine(線)
drawRect(四角)
drawCircle(円)
drawArc(アーチ)
drawPath(パス)
drawImage(ビットマップ画像)
drawParagraph(テキスト)

[CustomPaint class - Flutter Doc](https://api.flutter.dev/flutter/widgets/CustomPaint-class.html)
[[Flutter] キャンバス上で任意の図形の描画を行えるCustomPaintを使ってみる](https://dev.classmethod.jp/articles/flutter_custom_paint/)

六角形を描くにはどうする？
-> [Drawing a Hexagon Grid in Flutter](https://bartvwezel.nl/flutter/drawing-a-hexagon-grid-in-flutter/)

#### GestureDetector

タップ、ドラッグなど様々な操作を検知できる。

childにwidgetを指定した場合はそのchildの大きさになる。一方、childがなければ、親のサイズまで広がる。

[Flutter doc - GestureDetector](https://api.flutter.dev/flutter/widgets/GestureDetector-class.html)


#### TextField

[Flutter dox - TextField](https://api.flutter.dev/flutter/material/TextField-class.html)

#### TextFormField

TextFieldと同様ユーザー入力を受け付ける。validatorという関数を受け取ることができ、ユーザーが入力した文字列のバリデーションが可能。


[TextFormField](https://api.flutter.dev/flutter/material/TextFormField-class.html)
[TextField、TextFormField、Formの概要](https://zenn.dev/heyhey1028/books/flutter-supa-gpt/viewer/supabase_auth2)


##### TextEditingController

TextField、TextFormFieldなどに設定することができる。入力された文字列の取得や、プログラムからの文字列の変更、入力された時にする動作を関数として設定するなどが可能。

使い終わった時にはdisposeが必要となるので、statefull widgetのdisposeで一緒にdisposeすると良い。

[TextEditingController](https://api.flutter.dev/flutter/widgets/TextEditingController-class.html)
[[Flutter]TextEditingControllerについて](https://zenn.dev/t_fukuyama/articles/76cb07d38d078a)

#### Icon

さまざまなアイコンがシステム側で用意されている。IconDataとしてIconクラスのコンストラクタに渡す。

[Flutter doc](https://api.flutter.dev/flutter/material/Icons-class.html)

用意されているアイコンは、マテリアルアイコンのページを参照。

[Google - Material Icons](https://fonts.google.com/icons)

#### IconButton
[Flutter doc - IconButton](https://api.flutter.dev/flutter/material/IconButton-class.html)

Iconを渡し、タップ可能なボタンを生成する。

#### Container

Widgetに対してパディング・背景色・大きさの制約などを加えたい場合はContainerでラップすると良い。decorationプロパティにBoxDecorationなどを設定することで、childの背景に装飾を追加することもできる。

[Flutter doc - Container](https://api.flutter.dev/flutter/widgets/Container-class.html)

#### InkWell

タップした時の波紋のようなエフェクト（リップルエフェクト）を出せるようにするWidget。Button系のウィジェットにもこのような効果はついていますが、InkWellは任意のウィジェットをchildとして納めることができます。

[Flutter doc - InkWell](https://api.flutter.dev/flutter/material/InkWell-class.html)
[Flutterのリップルエフェクトは一癖ある](https://qiita.com/kasa_le/items/d92845c338eb3abd1e11)

#### CircleAvatar
[Flutter doc - CircleAvatar](https://api.flutter.dev/flutter/material/CircleAvatar-class.html)

ユーザーの顔画像を丸く表示するようなUI部品。正直そんな細かい部品まで公式で用意されているとは驚いた。

典型的には、画像がない場合はユーザーのイニシャルを表示する。

#### Image
[Flutter doc - Image](https://api.flutter.dev/flutter/widgets/Image-class.html)

画像を表示する。



#### NetworkImage 
[Flutter doc - NetworkImage](https://api.flutter.dev/flutter/painting/NetworkImage-class.html)

画像のURLを渡して、画像を表示する。


#### SimpleDialog
showDialog関数を使って呼び出せる、flutterのデフォルトのダイアログ。

[flutter doc - showDialog function](https://api.flutter.dev/flutter/material/showDialog.html)
[flutter doc - SimpleDialog class](https://api.flutter.dev/flutter/material/SimpleDialog-class.html)

#### PageView


上下・左右にページを捲るような形でスワイプし、複数のウィジェットを連続で表示できるウィジェット。

[flutter doc - PageView](https://api.flutter.dev/flutter/widgets/PageView-class.html)


#### Expanded

Row, Column, FlexのchildをExpandedでラップすることで、余っているスペース全てをそのchildが占めるようにすることができる。flexプロパティを設定することで、複数のExpandedがある場合、余っているスペースをどの割合で占めるか指定することもできる。

固定サイズにしたいやつはSizedBoxでラップし、伸び縮みさせたいやつはExpandedなどでラップすると良いだろう。


[flutter doc - Expanded](https://api.flutter.dev/flutter/widgets/Expanded-class.html)

#### Flexible
Expandedとほぼ同じだが、Row, Column, Flexのchildが余っているスペースを全て埋めることを強制しない点で異なる。

[flutter doc - Flexible](https://api.flutter.dev/flutter/widgets/Flexible-class.html)

#### AspectRatio

子ウィジェットを特定の縦横比にしたいときに利用する。

[AspectRatio](https://api.flutter.dev/flutter/widgets/AspectRatio-class.html)

#### ClipRRect

画像を丸く加工して表示するためのウィジェット。Clip`Rounded`Rectの略。
[fluter doc - ClipRRect](https://api.flutter.dev/flutter/widgets/ClipRRect-class.html)


#### RotationTransition

Widgetを回転させるアニメーションを実現するクラス。

[flutter dox - RotationTransition](https://api.flutter.dev/flutter/widgets/RotationTransition-class.html)


#### Center

子ウィジェットを中央に配置する。

[flutter doc - Center](https://api.flutter.dev/flutter/widgets/Center-class.html)


#### ListView

複数の子ウィジェットをスクロール可能な形でリスト表示するウィジェット。子ウィジェットの個数は静的でも、動的でも構わない。
[flutter doc - ListView](https://api.flutter.dev/flutter/widgets/ListView-class.html)


#### ListTile

典型的にはListViewの子として使うことを想定したウィジェット。左側、右側に画像をおける場所を持つほか、中央に１〜３行の文字を置けるラベルがある。

[ListTile](https://api.flutter.dev/flutter/material/ListTile-class.html)


#### Divider

ウィジェット間の区切り線となる、横に細長いウィジェット。

[flutter doc - Divider](https://api.flutter.dev/flutter/material/Divider-class.html)



#### TextFormField

TextFieldを内蔵した入力フォーム。

[flutter doc - TextFormField](https://api.flutter.dev/flutter/material/TextFormField-class.html)
[Zen - コピペで使えるTextFormField](https://api.flutter.dev/flutter/material/TextFormField-class.html)


#### TextButton

輪郭や浮き上がった感じのないテキストそのままのような見た目のボタンを作ることができるウィジェット。

[flutter doc - TextButton](https://api.flutter.dev/flutter/material/TextButton-class.html)
[【Flutter】TextButtonの使い方｜ボーダーなしのフラットボタンを作る](https://flutternyumon.com/how-to-use-textbutton/)


#### StreamBuilder

非同期的に流れてくるデータを受け取り、特定のウィジェットを再描画するためのウィジェット。Firebase、端末のセンサー類、ネットワーク接続状況、その他自分で定義したストリームなどを受け取ることができる。

（全体ではなく）特定のウィジェットだけ更新させる、ということができるため、再描画コストの低減に役立つ。

[flutter doc - StreamBuilder<T> class](https://api.flutter.dev/flutter/widgets/StreamBuilder-class.html)
[FlutterのStreamBuilderをつかって無駄な再描画を減らそう](https://qiita.com/sgmryk/items/5b21f05f6ed2cc84e8a9)


#### SafeArea

端末のトップやボトムにあるノッチなどの障害物に子ウィジェットがかからないように十分距離を離してくれるウィジェット。


[flutter doc - SafeArea class](https://api.flutter.dev/flutter/widgets/SafeArea-class.html)
[FlutterのSafeAreaを使って上下のあいつらを気にしない方法](https://zenn.dev/captain_blue/articles/introduce-sarearea-in-flutter)


#### FittedBox

指定したBoxFit型の引数に応じて、子ウィジェットのサイズや位置を調節してくれる。
- BoxFit.fill: 子ウィジェットのアスペクト比を無視してFittedBoxに合わせる
- BoxFit.contain: 子ウィジェットのアスペクト比を保ちながら可能な限り大きくする

など。

[Flutter doc - FittedBox](https://api.flutter.dev/flutter/widgets/FittedBox-class.html)
[Flutter doc - BoxFit enum](https://api.flutter.dev/flutter/painting/BoxFit.html)

#### CircularProgressIndicator & LinearProgressIndicator

円型&線形の進行度表示ウィジェット。

Indeterminateスタイルでは単純に同じアニメーションを繰り返し続けるだけだが、Determinateスタイルでは数値を渡すことで少しずつ進行度が上昇し100パーセントへ向かうようなアニメーションが可能。

[Flutter doc - CircularProgressIndicator](https://api.flutter.dev/flutter/material/CircularProgressIndicator-class.html)
[Flutter doc - LinearProgressIndicator](https://api.flutter.dev/flutter/material/LinearProgressIndicator-class.html)


#### RefreshIndicator

スクロール可能なWidget(リストビューなど)をラップして使う。オーバースクロールさせた時に、ぐるぐる回転するインジケータを表示させ、何らかの非同期の処理を行わせ、画面を更新し、インジケータを消すという動作を行える。いわゆるpull to refresh。

[Flutter doc - RefreshIndicator](https://api.flutter.dev/flutter/material/RefreshIndicator-class.html)



#### GridView

複数の列・行を持ちうるスクロール可能なウィジェット。

[flutter - GridView](https://api.flutter.dev/flutter/widgets/GridView-class.html)

[`GridView.count`](https://api.flutter.dev/flutter/widgets/GridView/GridView.count.html)というインストラクタがあり、固定数の要素である場合にはこれを利用する。

```dart:GridViewTest.dart
return GridView.count(
    crossAxisCount: 2,
    children: <Widget>[
        Text("1")
        Text("2")
        Text("3")
        Text("4")
    ]
)
```

[`GridView.builder`](https://api.flutter.dev/flutter/widgets/GridView/GridView.builder.html)は、要素が動的で大量の要素を持ちうる場合に使用する。これだと、画面上に出現している要素に対してしか計算を行わないため、パフォーマンス的に良い。

#### FutureBuilder

非同期処理で Widget を生成したいときに使う Widget。


[【Flutter Widget of the Week #6】FutureBuilderを使ってみた](https://zenn.dev/faucon/articles/771b65ccc58b2f)

#### Card

角丸で影のある四角形の形をしているウィジェット。

Containerと何が違うのか？ という質問がStack Over Flowにあったが、Cardは角丸で影のあるなどの特性を備えた独自の部品であって、Containerは他のウィジェットをラップする目的で使われるものである。

[Card class](https://api.flutter.dev/flutter/material/Card-class.html)
[【Flutter】Card Widgetまとめ](https://qiita.com/ILTsubugai/items/6bec723133968cf13bc9)
[Flutter Card vs Container Widget](https://stackoverflow.com/questions/60412220/flutter-card-vs-container-widget)

#### Color, Colors

色を表すクラスがColorである。16進数を渡して初期化できる。

[Color](https://api.flutter.dev/flutter/dart-ui/Color-class.html)

Colorの定数を定義した集まりがColorsである。

[Colors](https://api.flutter.dev/flutter/material/Colors-class.html)

#### Builder

ある親Widgetのbuildメソッドの中で、子Widgetがあり、これが親Widgetのcontextにアクセスする場合うまく動作しなくなるのでこのような動作は禁止される。たとえば、`MediaQuery.of(context)`、`Scaffold.of(context)`などで使用されることがある。

このような場合は、子WidgetをStatelessWidgetのサブクラスとして定義し直せば良い。ただ、それが面倒な場合は、Builderでラップするだけでも良い。

[Builder](https://api.flutter.dev/flutter/widgets/Builder-class.html)

#### Flutter 様々なコマンド

[[Flutter]コマンドまとめ表](https://qiita.com/isekiryu/items/934936cdc503c491a7d8)

### Double Dot(..) カスケード記法

```
List list = [];
list.add(color1);
list.add(color2);
list.add(color3);
list.add(color4);

// with cascade

List list = [];
list
  ..add(color1)
  ..add(color2)
  ..add(color3)
  ..add(color4);
```
 
[List use of double dot (.) in dart?](https://stackoverflow.com/questions/49447736/list-use-of-double-dot-in-dart)
[A tour of the Dart language - Cascade Notation](https://dart.dev/guides/language/language-tour#cascade-notation)

#### n秒後に処理をさせる

Future<T>.delayedが利用できる。

```
await Future<void>.delayed(Duration(milliseconds: nSeconds));
```

[Future<T>.delayed constructor](https://api.flutter.dev/flutter/dart-async/Future/Future.delayed.html)

#### dynamic キーワードについて。
動的型付けができるようにする。無論多用すると型安全ではなくなることもあり、おすすめはしない。
[【Dart】【Flutter】dynamic型（動的型付け）](https://note.com/hatchoutschool/n/n767701b099b0)

#### コンストラクタ

"List Constructor", "Const Constructor", "Factory Constructor"など色々ごちゃごちゃあるようだがすぐに全部理解できる気はしなかったが、わからなくなったら公式ページに都度戻ればいいだろう。

とりあえず"Const Constructor"というのは生成したオブジェクトを一回生成して以降は定数とする（プロパティを後から変えれない）時に使う。

`Const`キーワードをコンストラクタの前につけるほか、そのクラスの変数全てにfinalマークをつけることになる。

[named-constructors - Flutter Doc](https://dart.dev/guides/language/language-tour#named-constructors)
[Dartのconstコンストラクタとは](https://zenn.dev/razokulover/articles/61380323a73e00572789)

#### Stream

非同期に連続した値を発信・購読ができるStream型がDart公式として用意されている。

https://dart.dev/libraries/async/using-streams#two-kinds-of-streams

##### 位置パラメータ、デフォルト値
曲線かっこ（{}）を用いて名前付きパラメータをコンストラクタにつけることができます。

```dart:test.dart
class Customer {
  String name;
  int age;
  String location;
  // Named optional parameters
  Customer(this.name, {this.age, this.location});
  @override
  String toString() {
    return "Customer [name=${this.name},age=${this.age},location=${this.location}]";
  }
}

var customer = Customer("bezkoder", location: "US", age: 26);
print(customer);
// Customer [name=bezkoder,age=26,location=US]
var customer1 = Customer("bezkoder", age: 26);
print(customer1);
// Customer [name=bezkoder,age=26,location=null]
var customer2 = Customer("zkoder");
print(customer2);
// Customer [name=zkoder,age=null,location=null]
```
https://www.bezkoder.com/dart-flutter-constructors/

またパラメータの後ろに`= "DefaultValue"`とすることでデフォルト値をつけることも可能です。

#### Theme

[FlutterのThemeを理解する](https://itome.team/blog/2019/12/flutter-advent-calendar-day12/)

Flutterアプリを初期作成したときに書いてある`primarySwatch`(基本となる色見本)は、設定するとさまざまなところで基本の色として使われるようになる。

[Zenn - Flutter の primarySwatch は奥が深い](https://zenn.dev/sugitlab/articles/bef3a05963680a)

#### flavorごとに設定を変えるには（develop, staging, releaseなど）

以下が参考になります。
[FlutterでDart-defineのみを使って開発環境と本番環境を分ける](https://zenn.dev/altiveinc/articles/separating-environments-in-flutter?redirected=1)
[Flutterで環境ごとにビルド設定を切り替える — iOS編](https://medium.com/flutter-jp/flavor-b952f2d05b5d)
[flutterのdart-defineは2.2以上ではbase64でエンコードされるので対応したスクリプトの紹介](https://qiita.com/mogmet/items/dd9191ddc7d43f13bd62)

#### 機密情報をソースコードにハードコーディングしたくない場合

`flutter build apk --dart-define-from-file=env.json`といった実行方法をすると、環境変数から値を読み込んでくれるので、ハードコーディングの必要がなくなります。

[【Flutter】環境変数をファイルで設定する](https://flutter.salon/flutter/dart-define-from-file/)

flutter 3.13くらいから、jsonファイルだけでなく`.env`ファイルもライブラリなしで`flutter run --dart-define-from-file=.env`で読み込めるようになった。iOS、Androidネイティブがわへそれらの設定値を伝えることも比較的簡単にできるのでおすすめである。

[Add .env file support for option --dart-define-from-file #128668](https://github.com/flutter/flutter/pull/128668)
[The Right Way to Set Environment Variables with Compile-Time Variables](https://itnext.io/secure-your-flutter-project-the-right-way-to-set-environment-variables-with-compile-time-variables-67c3163ff9f4)

アプリを実行する際に毎回`flutter run --dart-define-from-file=.env`を叩くのも面倒だと思うので、Android StudioのEdit Configuration > Additional ttach argsに`--dart-define-from-file=.env`を設定すると、デバッグ実行するごとにこのコマンドが叩かれている扱いとなる。

#### ゲッター・セッター

`get`キーワード・`set`キーワードを用いる。

#### `part` キーワード

`import`と同様に他のファイルの内容を読み込むが、`import`と違いpublicだけではなくprivateのものまで読み込む。該当ファイルらを一つのファイルにしてしまうようなものと言える。通常は使う機会がなく、自動生成系ライブラリを使うときに使うタイミングがあるようである。

[[Dart]partとimportの違い](https://zenn.dev/r0227n/articles/difference_between_part_and_import)

#### Pointクラス

二次元平面上の座標を表すクラス

'dart:math'をインポートすることで利用可能

[dart-tutorial - dart-getters-setters](https://www.w3adda.com/dart-tutorial/dart-getters-setters)

#### 画面遷移(Flutter Default)
Navigatorクラスを使って画面遷移を行う。非常に簡便である。
[Flutter doc - Navigator class](https://api.flutter.dev/flutter/widgets/Navigator-class.html)
[FlutterのNavigationとRoutingを理解する](https://itome.team/blog/2019/12/flutter-advent-calendar-day10/)

#### Guard 節
SwiftであるようなGuard節は存在しない。ifを使って早々にreturnして抜けるしかないだろう。

#### compactMap
SwiftのようなcompactMapは直接はないが、`whereType`を使えばnullではない値だけを抽出できる。

```dart.test.dart
final List<String?> hoge = [null, "a", "b", null];
final fuga = hoge.whereType<String>().toList(); // ["a", "b"]
```
[【Flutter】dartでListからnullを除外する](https://qiita.com/sekitaka_1214/items/a05383b7aa77f888bdfb)

### json変換

jsonをオブジェクトに変換、またはその逆をしたい場合は、dart:convert　パッケージのjsonDecode()を使うことが考えられる。

中規模以上のプロジェクトなどで、自動でjsonに変換したいなどの場合は、[json_serializable](https://pub.dev/packages/json_serializable), [json_annotation](https://pub.dev/packages/json_annotation)などのライブラリを使える。

[JSON and serialization](https://docs.flutter.dev/data-and-backend/json)

### 日付けの取り扱い

DateTimeクラスで特定の日付を表すことができます。日付の差の計算や、タイムゾーンの指定、何日後・何日前への移動など一通りの操作は行えます。

[flutterでDateTimeとStringの変換方法とTimeZoneとLocale](https://qiita.com/ko2ic/items/bd0d20d72c66e8231c5c)
[【Dart】【Flutter】DateTime型についてのまとめ](https://note.com/hatchoutschool/n/n8b98f036c99e)

### `<Widget>`という書き方

`<Widget>`という書き方がコードの中に出てくることがありますが、これは、配列の中の型を何にするかを指定するものです。無論`Widget`型以外でも、何でも指定できます。

```dart:test.dart
Column(
  children: <Widget>[
  // Other codes
  ]
)
```

参考: [What does <Widget> means in Flutter code?](https://stackoverflow.com/questions/68955036/what-does-widget-means-in-flutter-code)

### プログラム全体からアクセスできるよう定数を定義したい

プログラムのトップレベルに定義したり、あるクラスのStatic変数として定義するなどが考えられる。

```dart:const.dart
const rawgKey = const String.fromEnvironment('RAWG_KEY');

// or 

class Const {
    // Make constructor private to prevent instantiation
    Const._();

    static const rawgKey = const String.fromEnvironment('RAWG_KEY');
}
```

[Flutter: Defining Constants — The Right Way](https://medium.com/nerd-for-tech/flutter-defining-constants-the-right-way-321d33185b41)


### RiverPod 導入

`pubspec.yml`に下記を追加し、pub getを押す

`flutter_riverpod: ^1.0.3`

https://pub.dev/packages/flutter_riverpod

### RiverPodの利用

参考:
[RiverPod official](https://riverpod.dev/docs/getting_started/)
[Flutter State Management with Riverpod: The Essential Guide](https://codewithandrea.com/articles/flutter-state-management-riverpod/#provider-drawback-#2-getting-providers-by-type-and-runtime-exceptions)

#### main

riverPodを利用する場合は最初の`main`関数において、`runApp`に`ProviderScope`を渡す。`ProviderScope`とは、アプリの全Providerの状態を保持するWidgetである。

```
void main() {
  runApp(
      ProviderScope(child: MyApp())
  );
}
```

### 画面サイズ取得

```dart:test.dart
MediaQuery.of(context).size.width
MediaQuery.of(context).size.height
```

### 画像リソースの追加

典型的にはプロジェクトルートにassetsフォルダを作り、画像を置く。pubspec.ymlにて、以下のように追加する。

```yaml:pubspec.yaml
flutter:
  assets:
    - assets/
```

[Flutter doc - assets](https://docs.flutter.dev/ui/assets/assets-and-images)

### Flutterのバージョンの切り替えをスムーズにやりたい。

fvmがおすすめ。https://fvm.app

使用方法参考

[FVMでFlutter SDKのバージョンをプロジェクト毎に管理する](https://zenn.dev/altiveinc/articles/flutter-version-management)


## 内部設計

### Element
Flutterで利用者側にはあまり出てこないが内部で使われている要素。ドキュメントなどを読んでもあまり理解できなかったためAIによる解説を貼ることで終わりにさせていただく。：

```
もちろんです！Flutterの「Element」について、初心者にもわかりやすく解説します。

---

### **前提知識: Flutterのウィジェットツリー**
FlutterではUIは「ウィジェット（Widget）」によって構築されます。ウィジェットはUIの設計図のようなもので、どのように見えるべきかを定義します。しかし、ウィジェット自体はただの不変（immutable）なオブジェクトであり、実際のUIを描画したり状態を管理したりするわけではありません。

そのため、Flutterにはウィジェットとは別に「Element」という概念が存在します。

---

### **Elementとは何か？**
**Element**は、ウィジェットツリーに基づいて構築される「実行時のオブジェクト」です。具体的には以下のような役割を持っています：

1. **ウィジェットとレンダリングツリーをつなぐ橋渡し**  
   - ウィジェットは単なる設計図ですが、Elementはその設計図を基に実際に画面に表示されるUI要素を管理します。
   - Elementはウィジェットのインスタンスに対応し、ウィジェットのプロパティを元にUIを構築・更新します。

2. **状態（State）の保持**  
   - StatefulWidgetの場合、Elementはそのウィジェットに関連付けられた状態（State）を保持します。
   - これにより、ウィジェットが再構築されても状態が失われることなく維持されます。

3. **ライフサイクルの管理**  
   - Elementはウィジェットの追加、更新、削除といったライフサイクルを管理します。
   - 例えば、ウィジェットが更新された場合、新しいウィジェットと既存のElementを比較して、必要に応じて再構築を行います。

---

### **ウィジェット、Element、レンダリングツリーの関係**
FlutterのUI構築プロセスを理解するために、以下の3つの層を覚えておくと便利です：

1. **ウィジェットツリー（Widget Tree）**  
   - UIの設計図。すべてのウィジェットがツリー構造で表現されています。
   - ウィジェットは不変（immutable）なので、変更が必要な場合は新しいウィジェットを作成します。

2. **エレメントツリー（Element Tree）**  
   - 実行時に生成されるツリーで、ウィジェットツリーに基づいて構築されます。
   - 各Elementはウィジェットと対応しており、ウィジェットのプロパティや状態を管理します。

3. **レンダリングツリー（Render Tree）**  
   - 実際に画面に描画されるレイアウトやペイントを行うためのツリー。
   - Elementがレンダリングツリーを操作し、最終的なUIを描画します。

---

### **簡単な例で理解する**
例えば、以下のようなシンプルなコードを考えます：

dartのコード:
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text('Hello, Flutter!'),
    );
  }
}

このコードを実行すると、次のような流れでUIが構築されます：

1. **ウィジェットツリーの構築**  
   - `MyApp` → `Center` → `Text` の順でウィジェットツリーが作られます。

2. **エレメントツリーの生成**  
   - Flutterはウィジェットツリーに基づいて、それぞれのウィジェットに対応するElementを生成します。
   - 例えば、`Center`ウィジェットには`CenterElement`、`Text`ウィジェットには`TextElement`が対応します。

3. **レンダリングツリーの描画**  
   - Elementがレンダリングツリーを操作し、最終的に画面に「Hello, Flutter!」というテキストが中央揃えで表示されます。

---

### **なぜElementが必要なのか？**
ウィジェットだけでは不十分な理由は以下の通りです：

- **効率性**: ウィジェットは不変なので、毎回新しいウィジェットを作成する必要があります。一方、Elementは変更可能（mutable）なので、ウィジェットが更新された場合でも必要な部分だけを再構築できます。
- **状態管理**: StatefulWidgetの場合、Elementが状態を保持することで、ウィジェットの再構築時に状態が失われることを防ぎます。
- **ライフサイクル管理**: Elementがウィジェットの追加・更新・削除を管理することで、効率的なUI更新が可能になります。

---

### **まとめ**
- **ウィジェット**はUIの設計図で、不変（immutable）です。
- **Element**は実行時のオブジェクトで、ウィジェットとレンダリングツリーをつなぐ役割を果たします。
- **レンダリングツリー**は実際に画面に描画されるレイアウトやペイントを担当します。

FlutterのUIシステムは「ウィジェット」「Element」「レンダリングツリー」の3層で構成されており、それぞれが協力して効率的で柔軟なUIを実現しています。

もしまだ疑問点があれば、ぜひお聞かせください！
```



## エラー

#### missing_default_value_for_parameter
```
The parameter ‘{0}’ can’t have a value of ‘null’ because of its type, but the implicit default value is ‘null’.

With null safety, use the ‘required’ keyword, not the ‘@required’ annotation.
```

コンストラクタのパラメータにデフォルト値を提供しろというエラーであるので、デフォルト値を設定するか、そもそもその値をnullableにしてしまうか、あるいはそのパラメータに`@required`をつけて必須のパラメータにするかの3択となる。

See https://dart.dev/tools/diagnostic-messages?utm_source=dartdev&utm_medium=redir&utm_id=diagcode&utm_content=missing_default_value_for_parameter#missing_default_value_for_parameter




#### don't support null safety:       - package:flutter_riverpod      - package:riverpod


riverpodがnullに対応していないのにnullを使用していたのでこのエラーが出た。

null safety 対応バージョンのriverpodもあるようなので、それを代わりに用いたら解消した。

https://pub.dev/packages/riverpod/versions/0.13.0-nullsafety.1/install

#### build gradle cannot resolve symbol 'properties'

build.gradleでエラー。


https://stackoverflow.com/questions/56938436/first-flutter-app-error-cannot-resolve-symbol-properties

#### multidex

https://developer.android.com/studio/build/multidex?hl=ja#kts

#### Permission denied. Please enable Firebase Storage for your bucket by visiting the Storage tab in
the Firebase Console and ensure that you have sufficient permission to properly provision resources

Firebase Console > Storage > rules より、リクエストを許可する条件を記入していなかったので、リクエストが全て拒絶されていた。


#### Build file android/app/build.gradle line 24 A problem occurred evaluating project ':app' Android Gradle plugin requires Java 11 to run. You are currently using Java 1.8.

Android端末実機で動かそうとした時に発生。

android/build.gradle > dependenciesよりandroidビルドツールとkotlin gradleプラグインのバージョンを下げて解消。

[[Flutter] Android Gradle plugin requires Java 11 to runのエラーの直し方](https://qiita.com/iseruuuuu/items/6527667d677ebfe9d1e1)


####  [Get] the improper use of a GetX has been detected. 

```
      [Get] the improper use of a GetX has been detected. 
      You should only use GetX or Obx for the specific widget that will be updated.
      If you are seeing this error, you probably did not insert any observable variables into GetX/Obx 
      or insert them outside the scope that GetX considers suitable for an update 
      (example: GetX => HeavyWidget => variableObservable).
      If you need to update a parent widget and a child widget, wrap each one in an Obx/GetX.
```

`GetXController`クラスを使っているのに、Rxの変数を何も使っていない時に出るエラーの模様。

ウィジェットをObxで囲い忘れている時にも出ることが多い。


#### Because <MyProject> depends on cached_network_image >=3.2.2 which requires SDK version >=2.18.0 <3.0.0, version solving failed.


```
Because <MyProject> depends on cached_network_image >=3.2.2 which requires SDK version >=2.18.0 <3.0.0, version solving failed.
pub get failed (1; Because tic_tok_copy depends on cached_network_image >=3.2.2 which requires SDK version >=2.18.0 <3.0.0, version solving failed.)

```

新しいライブラリを追加しようとしたらエラーになった。

`flutter channel stable`と`flutter upgrade`を実行。その後pubspec.ymlでflutter sdkバージョンをもっと高いものに書き換えた上で、`pub get`を実行すると解消したかのように見えたが、アプリを実行する時にやはり同様のエラーが出続ける。

`podfile`のios version を13にあげる
ターミナルでiosフォルダに行き、pod repo update, pod update, pod installを実行

しても治らず。

最終的にpodfile.lockを一回削除してからアプリをビルドしたところ、エラーが解消した。

#### Specs satisfying the `Firebase/Firestore (= 8.15.0), Firebase/Firestore (= 9.4.0)` dependency were found, but they required a higher minimum deployment target.

導入しているFirestoreのバージョンが低すぎて、他のライブラリが要求するバージョンに達していなかった模様。Firestore(ここでは、cloud_firestoreライブラリ)のバージョンを最新版にしてpub getしたところ治った。

#### Columnの中にGridViewを追加したらレイアウトがメチャクチャになった。

GridViewのshrinkWrapプロパティをtrueにすると治る場合がある。
[flutter - ListView - shrinkWrap](https://api.flutter.dev/flutter/widgets/ScrollView/shrinkWrap.html)
[StackOverFlow - What does the shrinkWrap property do in Flutter?](https://stackoverflow.com/questions/54007073/what-does-the-shrinkwrap-property-do-in-flutter)

ただパフォーマンス的にはあまり良くない模様。
[Flutter アプリ開発におけるパフォーマンス改善 Tips](https://zenn.dev/xxminamixx/articles/38d8695ee0a12a)

Flexible, Expanded, LimitedBox, SizedBoxなどを使ってListViewの高さを決めてあげることでも治る。
[【Flutter】Columnの中でListViewを使う時にエラーが出る](https://qiita.com/satoru_pripara/private/31c6674fa26275136c08)

#### A RenderFlex overflowed by 32 pixels on the bottom.

ウィジェットをSingleChildScrollViewで囲む。

[flutter doc - SingleChildScrollView](https://api.flutter.dev/flutter/widgets/SingleChildScrollView-class.html)

#### flutter LoadError - dlsym(Init_ffi_c): symbol not found

pod install中にエラー

以下のflutter の公式wikiを参考にrosetta2をインストール  & rubyをインストールし直したら治った。M1 Macでのみ起こる問題なので、M1 Macを利用の方は見ておいた方が良い。

[Developing with Flutter on Apple Silicon](https://github.com/flutter/flutter/wiki/Developing-with-Flutter-on-Apple-Silicon)

#### [!] CDN: trunk URL couldn't be downloaded: https://cdn.cocoapods.org/CocoaPods-version.yml Response: URL using bad/illegal format or missing URL

pod install中にエラー

色々試したが最終的には下記Issueに従ってCocoapodsを一回アンインストールし、brewを使って再インストールしたら治った。

https://github.com/CocoaPods/CocoaPods/issues/11159


#### [!] CocoaPods could not find compatible versions for pod "Firebase/CoreOnly":


```
  In snapshot (Podfile.lock):
    Firebase/CoreOnly (= 9.4.0)

  In Podfile:
    firebase_core (from `.symlinks/plugins/firebase_core/ios`) was resolved to 1.24.0, which depends on
      Firebase/CoreOnly (= 9.6.0)


You have either:
 * out-of-date source repos which you can update with `pod repo update` or with `pod install --repo-update`.
 * changed the constraints of dependency `Firebase/CoreOnly` inside your development pod `firebase_core`.
   You should run `pod update Firebase/CoreOnly` to apply changes you've made.

```

指示通りに`pod repo update`をやったが解消しなかった。podfile.lockを削除してからもう一度`pod install`を叩くと解消した。


#### flutter CocoaPods not installed or not in valid state.

以下が参考になります。


[【Flutter】エラーCocoaPods not installed. 〜が表示されiosビルドできない](https://zenn.dev/ryouhei_furugen/articles/ace89d5796e28e)

最終的には、よくわからなかったのでCocoapodsやAndroid Studioをアンインストールし、インストールし直しました。


#### Flutter Error (Xcode) Multiple commands produce GoogleService-Info.plist'

異なるFlavor(dev, stg, prod)用にGoogle-service.info.plistを用意していたらこのようなエラーが発生してした。RunnerをXcodeで開き、target >  Build Phases の Copy Bundle Resources からGoogle-service.info.plistを削除したら治った。

参考: [FlutterでFirebaseの環境毎設定でMultiple commands produce ~が出るようになってしまった場合](https://zenn.dev/razokulover/articles/93ac8c9d7b4146)

#### Unhandled Exception: Binding has not yet been initialized. The "instance" getter on the ServicesBinding binding mixin is only available once that binding has been initialized.

```
Unhandled Exception: Binding has not yet been initialized.
The "instance" getter on the ServicesBinding binding mixin is only available once that binding has been initialized.
Typically, this is done by calling "WidgetsFlutterBinding.ensureInitialized()" or "runApp()" (the latter calls the former). Typically this call is done in the "void main()" method. The "ensureInitialized" method is idempotent; calling it multiple times is not harmful. After calling that method, the "instance" getter will return the binding.
In a test, one can call "TestWidgetsFlutterBinding.ensureInitialized()" as the first line in the test's "main()" method to initialize the binding.
If ServicesBinding is a custom binding mixin, there must also be a custom binding class, like WidgetsFlutterBinding, but that mixes in the selected binding, and that is the class that must be constructed before using the "instance" getter.

```

- awaitをmainメソッドの内部で使う場合、その前に`WidgetsFlutterBinding.ensureInitialized();`を呼んでおく必要がある。これをmainメソッドの一番最初に持って来たところエラーが解消した。

[Flutter: Unhandled Exception: ServicesBinding.defaultBinaryMessenger was accessed before the binding was initialized](https://stackoverflow.com/questions/57689492/flutter-unhandled-exception-servicesbinding-defaultbinarymessenger-was-accesse)


#### [VERBOSE-2:dart_vm_initializer.cc(41)] Unhandled Exception: [core/not-initialized] Firebase has not been correctly initialized.

```
[VERBOSE-2:dart_vm_initializer.cc(41)] Unhandled Exception: [core/not-initialized] Firebase has not been correctly initialized.

Usually this means you've attempted to use a Firebase service before calling `Firebase.initializeApp`.

View the documentation for more information: https://firebase.flutter.dev/docs/overview#initialization

```

`Firebase.initializeApp`は呼んでいるはずだが、上記のエラーが出てしまった。`GoogleService-Info.plist`が想定しているフォルダ(iOS/Runner)に置いていることを確かめた後、これをXcodeで開いたRunner.xcworkspace内へとコピーペーストを行う。これにより、Xcodeが`GoogleService-Info.plist`を参照できるようになり、エラーが解消した。

[Flutter: Firebase has not been correctly initialized](https://stackoverflow.com/questions/70627695/flutter-firebase-has-not-been-correctly-initialized)

#### The lower bound of sdk must be or higher to enable null safety

sdkのバージョンの最低を2.12.0にあげる。

```yaml:pubscpec.yml
environment:
  sdk: ">=2.12.0 <3.0.0"
```

[How to enable Null-Safety in Flutter?](https://stackoverflow.com/questions/64621051/how-to-enable-null-safety-in-flutter)

#### error The non-nullable local variable must be assigned before it can be used not_assigned_potentially_non_nullable_local_variable at

non-nullの変数については、初期化しないのであれば、`late`キーワードをつける。

```dart:.dart
late String test;
```

[error: The non-nullable local variable 'newTaskTitle' must be assigned before it can be used](https://stackoverflow.com/questions/68014437/error-the-non-nullable-local-variable-newtasktitle-must-be-assigned-before-it)

#### error The argument type Object? can't be assigned to the parameter type String argument_type_not_assignable

```dart:.dart
results = jsonDecode(snapshot.data);
```

`snapshot.data`の型がなんであるかがdartに伝わっていないようなので、型を明示するとともにnullの場合どうするのかを指示するようにした。

```dart:.dart
results = jsonDecode(snapshot.data as String ?? '');
```

[How can I resolve "The argument type 'Object?' can't be assigned to the parameter type 'String'.dart(argument_type_not_assignable)"?](https://stackoverflow.com/questions/67853012/how-can-i-resolve-the-argument-type-object-cant-be-assigned-to-the-paramete)

#### Annotation must be either a const variable reference or const constructor invocation

ライブラリのdio, retrofitを両方使っている場合、両方に`Headers`というのが定義されているので普通に使うと衝突してしまう。以下のようにdioの`Headers`を隠せば解決する。

```dart:rest_client.dart
import 'package:dio/dio.dart' hide Headers;

// 中略

    @GET("/games")
    @Headers(<String, dynamic>{
      "X-RapidAPI-Host" : "rawg-video-games-database.p.rapidapi.com"
    })
  Future<List<GamesListElement>> getGames();
```

[Stack Over Flow - Annotation must be either a const variable reference or const constructor invocation](https://stackoverflow.com/questions/67531335/annotation-must-be-either-a-const-variable-reference-or-const-constructor-invoca)

#### 環境変数を設定しているはずだが、`String.fromEnvironment('XXXXXX');`を使っても値が取れずnullになってしまう。

`String.fromEnvironment('XXXXXX');`のドキュメントにも書いてあるが、直前に`const`キーワードをつけないとうまく動作せずnullがかえってきてしまっていた。

```dart:test.dart
const apiKey = const String.fromEnvironment('X_RAPID_API_KEY');
```

[String.fromEnvironment without a const silently does the wrong thing in the VM #55870](https://github.com/flutter/flutter/issues/55870)

#### Failed to download Kotlin Compiler Maven artifact (org.jetbrains.kotlin:kotlin-dist-for-jps-meta:1.8.20-release). The search was performed in the following repos: https://repo1.maven.org/maven2 https://repository.jboss.org/nexus/content/repositories/public/ You can use Kotlin compiler which is bundled into your IDE. Select 'Bundled' version in 'File | Settings | Build, Execution, Deployment | Compiler | Kotlin Compiler | Kotlin Compiler version

Flutterよくわからなかったが、`KotlinJpsPluginSettings`というののダウンロードの設定がFlutterプロジェクトのルートにあるはずの`.idea`フォルダの中の`kotlinc.xml`の中に書いてある。これの中の`<option name="version" value="1.8.20-release" />`というのから-releaseを削除し`<option name="version" value="1.8.20" />`としたところ、エラーが消えた。

[Kotlin dist downloading failed #126248](https://github.com/flutter/flutter/issues/126248)

#### Unhandled Exception: DioException [unknown]: null Error: type '_Map<String, dynamic>' is not a subtype of type 'List<dynamic>?' in type cast

dioを使ってAPIを呼んでいた。レスポンスは`{`で始まり`}`で終わるオブジェクトの型であってオブジェクトの配列ではないのにも関わらず、APIクライアントの実装のところで`List<TestElement>`という形で配列かのような指定をしてしまっていた。`TestElement`と直したところ治った。

#### Expected to find '}'
クロージャについて、クロージャが値を返さない（Voidを返す）時は、`=>`という矢印の表記はいらない。

[flutter: Expected to find '}'. in if else condition]()

#### dart sdk is not found in the specified location

他人の作ったFlutterプロジェクトを開く時によく発生する。Dart SDKとあるが、Dartではなく、Android StudioのFlutterの設定で、Flutter SDKのパスの位置を指定してあげれば解決する。

参考 [[Flutter]Dartのプラグインをインストールしたにも関わらず「Dart SDK is not configured」が出てしまう場合の対処法](https://minpro.net/dart-sdk-is-not-configured)

#### 意図せずして、イベントトラッキングが何度も送信されてしまう。

Widgetの`build`メソッド内にイベントトラッキング送信のコードを書いてしまっていた。`build`メソッドはいつ何度呼ばれてもおかしくないので、そこに高価な処理や、厳密なタイミングが求められる処理は書くべきではない。というかUIの生成以外は書かないほうがいいのではないか。

[【Flutter】build() でやってはいけない 3 つのこと](https://qiita.com/chooyan_eng/items/976adeea8eed1b5ebad4#併せて読みたい)

#### アプリがフォアグラウンド・バックグラウンドになった時に何かを実行したい。

以下はChatGPTが出してきたコードだが、自分でも試したところ想定通りに動作していた。

```dart:MyHomePage.dart
import 'package:flutter/material.dart';

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with WidgetsBindingObserver {

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    if (state == AppLifecycleState.resumed) {
      // 画面が再表示されたときに呼ばれる
      print('viewDidAppear');
    } else if (state == AppLifecycleState.paused) {
      // 画面が非表示になったときに呼ばれる
      print('viewDidDisappear');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Demo Home Page'),
      ),
      body: Center(
        child: Text('Hello, world!'),
      ),
    );
  }
}

```

#### `fvm flutter`コマンドで、`flutter not found`と出る。

fvmによって該当フォルダでどのflutterを指定していないからそうなる。そのプロジェクトの該当フォルダでどのflutterを使うか指定すれば解消する。

#### pod install apple silicon cannot load such file -- ffi_c (LoadError)

Apple Silicon macで作業していた。rbenvでrubyを入れ、rbenvでグローバルに設定したrubyにおいてcocoapodsをインストールし、それを見に行くようにしていた。ところがグローバルのrubyが2.2.6とApple Silicon macに対応していないバージョンとなってしまっていた。

`.zprofile`に`if which rbenv > /dev/null; then eval "$(rbenv init -)"; fi`と記載し、rbenvがある場合はrbenv経由でrubyを実行するようにした。

すると、`ruby -v`と実行した時、rbenvでグローバルに設定した3.3.3が出るようになり、本エラーも解消した。

#### Include of non-modular header inside framework module 'firebase_auth.FLTAuthStateChannelStreamHandler': '/Users/xxxxxxx/ios/Pods/Headers/Public/Firebase/Firebase.h'

Xcode16で、Firebase関連のライブラリ（[firebase/flutterfire](https://github.com/firebase/flutterfire/issues/13280)）を使うと、iOS側をビルドする際にこのエラーが発生する模様。

Runner.xcworkspace　をXcodeで開き、

`Build Settings`　より　`Allow Non-modular includes in Framework Modules`をYESにすると解消する模様。


参考: [include of non-modular header inside framework module 'firebase_messaging.FLTFirebaseMessagingPlugin' #12962](https://github.com/firebase/flutterfire/issues/12962)

#### NULL is not a subtype of Map<string, dynamic>

サーバーからの戻り値jsonをオブジェクトに変換しようとした際に起きた。Nullableの値を常に得ようとしてしまっていたことが原因だった。Nullの場合は何もしないようにしたら解消した。json_annotationなどを利用して自動で変換している場合はこのような不具合は起きないだろうが、一応。

```recipe_before_change.dart
class Recipe {
  final String id;
  final String title;
  final String imageUrl;
  final List<String> ingredients;
  final String instructions;
  final NutritionInfo nutrition;

  Recipe({
    required this.id,
    required this.title,
    required this.imageUrl,
    required this.ingredients,
    required this.instructions,
    required this.nutrition,
  });

  factory Recipe.fromJson(Map<String, dynamic> json) {
    return Recipe(
      id: json['id'].toString(), 
      title: json['title'], 
      imageUrl: json['image'], 
      ingredients: [],//Handled later 
      instructions: '',//Handled later 
      nutrition: NutritionInfo.fromJson(json['nutrition']),
    );
  }
}
```

```recipe_after_change.dart
class Recipe {
  final String id;
  final String title;
  final String imageUrl;
  final List<String> ingredients;
  final String instructions;
  final NutritionInfo? nutrition;

  Recipe({
    required this.id,
    required this.title,
    required this.imageUrl,
    required this.ingredients,
    required this.instructions,
    this.nutrition
  });

  factory Recipe.fromJson(Map<String, dynamic> json) {
    return Recipe(
      id: json['id'].toString(), 
      title: json['title'], 
      imageUrl: json['image'], 
      ingredients: [],//Handled later 
      instructions: '',//Handled later 
      nutrition: json['nutrition'] == null ? null : NutritionInfo.fromJson(json['nutrition']),
    );
  }
}
```

#### Stack Overflow
sqflite使用時にこのエラーが発生した。Stack Overflowとは一般にメモリが逼迫しこれ以上プログラムを進められなくなったことを指し、何らかの無限ループが発生してしまった際などによく起こる。

ある変数から、その変数自身を誤って参照してしまっていたため、発生してしまった。

```dart:before.dart
 Future<Database> get database async {
    if (_database != null) return database!;//無限ループ
    _database = await _initDatabase();
    return _database!;
  }
```

```dart:after.dart
 Future<Database> get database async {
    if (_database != null) return _database!;//OK!
    _database = await _initDatabase();
    return _database!;
  }
```

#### FlutterError (This widget has been unmounted, so the State no longer has a context (and should be considered defunct). Consider canceling any active work during "dispose" or using the "mounted" getter to determine if the State is still active.)

ウィジェットがもう消失しているのにそのウィジェットのcontextプロパティにアクセスしようとしていることが原因であった。

一つの解決策としては`mounted`メソッドを呼び、ウィジェットがまだマウントされている間だけcontextにアクセスするようにしたところ解消した。

その他、このエラーがの解決策としては、当該ウィジェットが消えた際にdisposeメソッドなので何か購読しているものを解除する処理を入れるべき場合もあると思われる。解除すべき購読がないか確かめよう。たとえば[TextEditingControllerはウィジェット喪失時に購読解除すべきとされる](https://docs.flutter.dev/cookbook/forms/text-field-changes)。

参考: [Stack Overflow](https://stackoverflow.com/questions/68256069/flutter-error-this-widget-has-been-unmounted-so-the-state-no-longer-has-a-cont)

#### FormKeyの配下のcurrentStateがnullになってしまう。

FormKeyはForm系ウィジェットの実装の際に用いる。
- Stateful Widgetを使っていること
- その中に`Form`という親ウィジェットがあり、その配下に一つまたは複数のForm関連ウィジェット（`TextFormField`）を置く構成であること
- FormKeyを`Form`の`key`のパラメータとして渡していること

以上のような構成になっているかどうか確認しよう。

[Form](https://api.flutter.dev/flutter/widgets/Form-class.html)

#### Error: The pod "Firebase/CoreOnly" required by the plugin "firebase_auth" requires a higher minimum macOS deployment version than the plugin's reported minimum version.

ライブラリ関連のエラーのようだが、実は普段起動しているターゲットではないMacをターゲットにしてアプリを起動しようとしていたことが原因だった。ターゲットをiOS, Androidデバイスに指定して起動したら解消しt

#### 引数に基づき動的に画面遷移先を変更したい。


`main.dart`などで`MaterialApp`について、
   - 変更前: `routes`プロパティを使用して固定のルートマップを定義
   - 変更後: より柔軟な`onGenerateRoute`方式に変更

2. **パラメーター処理の追加**:
   - 以前の`routes`では単純に画面を表示するだけでしたが、`onGenerateRoute`ではルート名に応じた処理や引数の受け渡しが可能になります。
   - 特に`SaveLoadScreen`への引数（`isLoadMode`）を適切に処理できるようになります。

3. **エラーハンドリングの改善**:
   - 未定義のルートに対して適切なエラー画面を表示するようになります。


簡単に言うと、従来の静的なルーティングから、引数を処理できる動的なルーティングに変更したことで、遷移時に必要なパラメーターを正しく渡せるようになります。

onGenerateRoute でなくroutes を使って場合は、画面へ引数を渡せないということではない。


`routes`を使う場合も引数を渡すことは可能。ただし、それぞれに違いがあります：

### `routes`での引数の扱い
```dart
// 1. 引数を渡す（これは同じ）
Navigator.pushNamed(
  context, 
  AppRoutes.saveLoad,
  arguments: {'isLoadMode': false}
);

// 2. 受け取る側（SaveLoadScreen内）
@override
Widget build(BuildContext context) {
  // この方法で引数を取得する必要がある
  final args = ModalRoute.of(context)!.settings.arguments as Map<String, dynamic>?;
  final isLoadMode = args?['isLoadMode'] ?? false;
  
  // ...
}
```

### `onGenerateRoute`での引数の扱い
```dart
// 1. 引数を渡す（同じ）
Navigator.pushNamed(
  context, 
  AppRoutes.saveLoad,
  arguments: {'isLoadMode': false}
);

// 2. 受け取る処理（main.dartのonGenerateRoute内）
case AppRoutes.saveLoad:
  final args = settings.arguments as Map<String, dynamic>? ?? {};
  return MaterialPageRoute(
    builder: (_) => SaveLoadScreen(
      // 引数を事前に処理してコンストラクタに渡せる
      isLoadMode: args['isLoadMode'] ?? false,
    ),
  );
```

`onGenerateRoute`の主な利点：
1. 引数の処理をルーティング時に集中して行える
2. ウィジェットのコンストラクタで直接パラメータを受け取れる
3. 同じルート名でも引数によって異なる画面を返せる
4. 引数に基づいた動的なルート生成が容易

#### 端末の向きを取得したい。

```dart:
final isLandscape = MediaQuery.of(context).orientation == Orientation.landscape
```

### Android Studio ショートカット

#### 右クリック -> `Reformat code with dartfmt`で、コードをflutter風に改行した形へと一発で整形できる。

```dart:test.dart
Text("TokTik", style: TextStyle(fontSize: 35, color: buttonColor, fontWeight: FontWeight.w900,),),
```

↓

```dart:test.dart
            Text(
              "TokTik",
              style: TextStyle(
                fontSize: 35,
                color: buttonColor,
                fontWeight: FontWeight.w900,
              ),
            ),
```


#### option + Return(Mac)で、特定のWidgetを別のWidgetでラップさせることが一瞬でできる。

![截屏2022-06-15 17.53.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392332/57eff080-087d-5f38-5a27-32c7bd135c28.png)

`extends StatelessWidget`の上で同じ操作をすると、StatefulWidgetへの自動変換が利用できるようだ。


#### `stless`でStateless Widget, `stful`でstateful widgetを一発で作れる。

#### Command + N で様々なコード生成

https://medium.com/mindorks/11-android-studio-shortcuts-every-android-developer-must-know-a153e736e611

![截屏2022-07-26 21.03.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392332/8bf28c13-ac1e-06e8-8aee-39ca5eb77931.png)


#### Shift２連打

ファイル名、symbol名などで検索。

#### Control + Shift + F

全ファイルの中身を検索。

#### Widget Inspector

デバッグビルド中のアプリ内のウィジェットの構造を詳細に把握できる。

##### Repaint Rainbow
どの範囲のウィジェットが再描画されるかが表示される。パフォーマンスのチェックに便利。

[Repaint Rainbow](https://docs.flutter.dev/tools/devtools/inspector#highlight-repaints)

### Android 関連

#### AndroidManifest.xmlとは

アプリの重要な設定を記載するファイル。

[AndroidManifest.xml の備忘録](https://qiita.com/izuki_y/items/8cb59b12fef6727ed87b)
[AndroidManifest概要](https://developer.android.com/guide/topics/manifest/manifest-intro)

#### Android 端末を開発に使う

設定 > 端末について > バージョン > ビルド番号を7連続タップ で開発者モードがONになります。
追加設定 > 開発者オプション > USB デバッグ　をONにするとAndrdoid studioから端末へアプリを走らせることができます。
https://smartttphone.com/oppo-developer/

#### buildgradleについて

[Android developer guide - ビルドを設定する](https://developer.android.com/studio/build#module-level)

[Gradle (build.gradle) 読み書き入門](https://qiita.com/hatimiti/items/a127311d739c9d3e0045)

- defaultconfig
典型的には以下のようなものを設定する

https://developer.android.com/studio/build#module-level
```

        // Uniquely identifies the package for publishing.
        applicationId = "com.example.myapp"

        // Defines the minimum API level required to run the app.
        minSdk = 15

        // Specifies the API level used to test the app.
        targetSdk = 28

        // Defines the version number of your app.
        versionCode = 1

        // Defines a user-friendly version name for your app.
        versionName = "1.0"

```

他にも以下のような値がある。

- [`applicationIdSuffix`](https://developer.android.com/studio/build/application-id#change_the_application_id_for_build_variants): ビルドバリアント向けにアプリのIDを変更できる。

- アプリ名を環境ごとに動的に変更したい場合、ここに適当な変数を定義し、`android/app/src/main/AndroidManifest.xml`内で利用できる。

```:app/build.gradle
defaultConfig {
    // String型の変数app_nameを定義し、任意の値を入れれる。
    resValue "string", "app_name", "FlutterAT" + 
            (dartEnvironmentVariables.FLAVOR == 'prod' ? '' :".${dartEnvironmentVariables.FLAVOR}")
}
```

```:android/app/src/main/AndroidManifest.xml
android:label="@string/app_name"
```

## テスト

[Testing Flutter apps](https://docs.flutter.dev/testing/overview)

[codelabs - Flutter アプリのテスト方法](https://codelabs.developers.google.com/codelabs/flutter-app-testing?hl=ja#4)

テストは単純な順にUnit Tests, Widget Tests, Integration Testsが存在。

以下はデフォルトであるWidget Testsの例。日本語コメントは筆者。

```test/widget_test.dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

import 'package:my_app/main.dart';

void main() {
  testWidgets('Counter increments smoke test', (WidgetTester tester) async {
    // アプリを起動
    await tester.pumpWidget(MyApp());

    // カウンターアプリで、最初にカウントが0となっているTextウィジェットがあることを確認
    expect(find.text('0'), findsOneWidget);
    expect(find.text('1'), findsNothing);

    // +ボタン（アイコン）を検索し、タップする
    await tester.tap(find.byIcon(Icons.add));
    // 少し時間の待受をし、画面が変化し終わるまで待つ。
    await tester.pump();

    // カウントが0から1になっていることを確認。
    expect(find.text('0'), findsNothing);
    expect(find.text('1'), findsOneWidget);
  });
}

```


## CI/CD

[Continuous integration services](https://docs.flutter.dev/testing/overview#continuous-integration-services)

[GitHub Actions で Automatically manage signing を使って Flutter の ipa ビルドする](https://zenn.dev/yorifuji/articles/build-automatically-manage-singin-on-ci#app-store-connect-api-の-private-key-の配置)

### デプロイ前の注意点(チェックポイント)

- Android: [Build and release an Android app](https://docs.flutter.dev/deployment/android)
    - [Google Play Store Policy](https://support.google.com/googleplay/android-developer/topic/9858052?hl=en&sjid=14907708344136828705-AP)
    - [【2022年最新】Flutter製AndroidアプリをPlayストアにリリースするまでの手順を徹底解説！](https://gakogako.com/flutter_android_release/#keystoreファイルを作成する)
- iOS: [Build and release an iOS app](https://docs.flutter.dev/deployment/ios)

### iOS

自動でApp Store Conectにアップロードする場合や、Automatically manage signingを利用してビルドする場合はApp Store ConnectよりPrivate Keys(.p8 ファイル)を作成し、ダウンロードすることとなる。

参考: [Uploading an App Store Connect API Key to Appcircle](https://www.youtube.com/watch?v=A0OgvrX5L-U)

そうでない場合はプロビジョニングプロファイルなどを使うこととなるがこれは割愛する。