Flutter + Firebaseでアプリを作っていく中で調べたことのメモ
新規に開発中のアプリで調べたことについて雑に書いていこうと思います。
Flutter(Dart)、Firebase共にほぼ初心者です。
ただ、すでにある程度進めてしまっている状態でこのスクラップを作ったので、完全に1からではありません。
UserAccountsDrawerHeader
超ニッチな感じもするけど、Material Designにしっかり定義されてるので、そういう意味ではあって然るべきクラスなのかもしれない。
↓こういうコードを書くだけで、
Drawer(
child: ListView(
children: [
UserAccountsDrawerHeader(
currentAccountPicture: Icon(Icons.account_circle, size: 64),
accountName: Text("name"),
accountEmail: Text("test@example.com"),
),
],
),
);
↓こうなる。便利。
Dartにはinterface
的なもの(Swiftで言うprotocol
)は存在しないらしい。
ただ全てのクラスは暗黙的にインタフェースも定義しており、クラスの定義時にimplements
で指定すると、そのクラスのインタフェースを実装出来るとのこと。
class A {
void funcA() {
print("A");
}
}
class B implements A {
@override
void funcA() {
print("B");
}
}
ここで、class B
のfuncA()
をコメントアウトすると、↓のようなエラーが発生する。
Missing concrete implementation of 'A.funcA'.
Try implementing the missing method, or make the class abstract.
デフォルト実装が不要な場合はabstract class
にして全て抽象メソッドにすれば良さそう。
abstract class A {
void funcA();
}
freezedでプロパティを追加したりした時、何故かVScodeで.freezed.dart
ファイルを一度開いてやらないとずっと反映されないままビルドエラーになったりするんだけど何だろう...
Riverpod、なんとなく状態管理専用のパッケージに見えてたけど、こんな感じにするとDIにも使えそう。
class FooService {
...
}
class BarService {
final FooService fooService;
BarService(this.fooService);
...
}
final fooServiceProvider = Provider<FooService>((ref) {
return FooService();
});
final barServiceProvider = Provider<BarService>((ref) {
final fooService = ref.watch(fooServiceProvider);
return BarService(fooService);
});
まだ試してないけど、Providerの中身を書き換えることも出来るようでテスト時のモック化も大丈夫そう。
というか公式サイトでも言及されてた。
Providers are a complete replacement for patterns like Singletons, Service Locators, Dependency Injection or InheritedWidgets.
SnackBarの表示方法
ScaffoldMessenger.of(context).showSnackBar(snackBar)
を使う。
final snackBar = SnackBar(content: Text('Yay! A SnackBar!'));
// Find the ScaffoldMessenger in the widget tree
// and use it to show a SnackBar.
ScaffoldMessenger.of(context).showSnackBar(snackBar);
以前はScaffold.of(context)
だったが非推奨になり、ScaffoldMessengerを使うようにとのこと。
Scaffoldの時は画面遷移等で現在のScaffoldが破棄(BuildContextが無効化)された状態でSnackBarを表示しようとした時にエラーになったりしていたが、ScaffoldMessengerにすることでそういったエラーも無くなるらしい。
詳細は以下。
そもそもSnackBarって?
画面下に一時的に短いメッセージを表示する通知領域みたいなもの。
似たようなものにAndroidのToastがあるが、こちらはメッセージのみなのに対し、SnackBarはテキストボタンを置くことも出来る。
Firebase App Distribution
アプリ側にSDK入れたりは全く必要なし。
ただ配信される側として、iOSにプロファイルのインストールを要求されるのが若干気になったけど、インストールしてしまえば簡単だった。
※2021年5月27日時点でまだベータ版らしいので、仕様が変わる可能性はあります。
AdHoc配布用IPA作成
(プロビジョニングプロファイルの作成等は完了している前提)
初回のみ
-
flutter build ipa
コマンドでxcarchiveを作成。 -
build/ios/archive/XXX.xcarchive
に作成されているので、これを開く。(Xcodeが開くはず) - 普段のiOS開発と同じように
Distribute App
からIPAをExportする。
2回目以降
- 初回でExportした、IPAが入っているディレクトリと同じ場所にある
ExportOptions.plist
をどこかにコピーする。 -
flutter build ipa --export-options-plist="path/to/ExportOptions.plist"
(path/to/
はコピー先のディレクトリ)実行。 -
build/ios/ipa
内にIPAが作成される。
2回目以降はXcodeを開く必要が無くなる。
参考
Firestore Security Rules編集補助プラグイン for VScode
VScodeでRuleを記述するにあたって、せめてシンタックスハイライトは欲しいと思い探してみたところ、
インストールしてみてパッと見は良い感じ。
こちらの方がダウンロード数は多く、以前はおすすめされたりしていたようだが、Archivedされて更新が完全に止まっている模様。
Firestore Security Rulesを記述するときに参考にした情報
他にも色々な優良情報があるかもしれませんが、現時点で参考にした情報。
何はともあれまずは公式。
ここに貼られている著者様の他記事も要参照。
シンプルなTODOアプリを作りながらFirestoreのデータ設計やSecurity Rulesの書き方を解説されています。
前述のシンプルなTODOアプリの応用編。
簡単な家計簿アプリを開発する想定でSecurity Rulesの書き方や考え方について解説されています。
基本的にどの記事(動画)も、ただ書き方を説明するだけではなく「何故そう書くのか」を細かく説明して下さっているので非常に参考になりました。
[Dart]NullableなListのnullを取り除き、Non-NullableなListにする方法
SwiftではcompactMap()でやっていたこと。
List<int?>をList<int>に変換するには:
List<int?> a = [null,2,null];
final List<int> b = a.whereType<int>().toList();
whereType<XXX>で指定した型(ここではint)にマッチする要素のみを抽出、その型のIterableを返してくれるらしい。
これはNullableに限らず色々応用出来そう。
参考:
アプリアイコンの設定
flutter_launcher_icons
パッケージを使用し、ベースとなる画像から各プラットフォーム毎のアイコン画像を生成します。
flutter_launcher_icons のインストール
$ flutter pub add -d flutter_launcher_icons
投稿時点では0.9.0
dev_dependencies:
flutter_launcher_icons: ^0.9.0
pubspec.yaml
に設定を追記
flutter_icons:
android: true
ios: true
image_path_ios: "assets/app_icon_ios.png"
image_path_android: "assets/app_icon_android.png"
adaptive_icon_background: "#ffffff"
adaptive_icon_foreground: "assets/app_icon_android_foreground.png"
-
android
/ios
:true
/false
でそのプラットフォームの画像を生成するか否かを指定。true
の場合はプロジェクト生成時にデフォルトで作られているFlutterアイコンを上書きする形で画像を生成する。また画像パスを文字列で指定することもでき、その場合はその名前で画像が新たに生成される。 -
image_path_ios
: iOSで使用するベース画像を指定 -
image_path_android
: Androidで使用するベース画像を指定 -
adaptive_icon_background
: Android 8.0(API Level 26) 以降で使用されるAdaptive Iconのバックグラウンドレイヤを指定する。色("#ffffff")もしくは画像パスを指定。 -
adaptive_icon_foreground
: Android 8.0(API Level 26) 以降で使用されるAdaptive Iconのフォアグラウンドレイヤを指定する。画像パスを指定。
Android 8.0(API Level 26)以降はadaptive_icon_xxx
のAdaptive Iconを、それ以前はimage_path_android
に指定した画像が使用されるものと思われます。
(前者はmipmap-anydpi-v26
にリソースが作られ、後者はmipmap-hdpi
〜mipmap-xxxhdpi
にリソースが作られる。)
画像の生成
$ flutter pub run flutter_launcher_icons:main
ベース画像に大きめの画像を用意しておけば、あとはよしなにリサイズしてくれるようです。
ここまでの簡単な設定をしておけば、後はコマンド一発でアイコン画像が設定された状態で出来上がるので便利ですね。
参考:
- https://pub.dev/packages/flutter_launcher_icons
- https://www.virment.com/how-to-generate-icon-for-flutter-app/
- https://developer.android.com/guide/practices/ui_guidelines/icon_design_adaptive?hl=ja
- https://qiita.com/takahirom/items/696fb5ecaa230fa8f755
- https://developer.android.com/guide/topics/resources/providing-resources.html#AlternativeResources
画面の空白部分をタップした時のTextFieldのフォーカスの外し方
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
FocusManager.instance.primaryFocus?.unfocus();
},
child: Scaffold(
...
)
);
}
以下の1行でフォーカスが外れ、キーボードが閉じるようです。
// ⭕️
FocusManager.instance.primaryFocus?.unfocus();
これに関してググると、
// ❌
FocusScope.of(context).unfocus();
こういった実装や、
// ❌
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus) {
currentFocus.unfocus();
}
こういったものが出てくるのですが、私のアプリではおかしな挙動になってしまいダメでした。(あまりちゃんと理解が出来ていません)
参考:
複数のStreamを1つのStreamにまとめる
List<Stream<T>>
を Stream<List<T>>
にして、各々のStreamの最新値をリストにしたStreamを作成する方法。
残念ながらバニラDartでは簡単には出来なさそうなので、RxDartを使用し、Rxではお馴染みのcombineLatest
を使用します。
RxDartのインストール
$ flutter pub get rxdart
サンプルコード
import 'package:rxdart/rxdart.dart';
...
final List<Stream<XXX>> xxxStreams = ...
final Stream<List<XXX>> combinedStream = CombineLatestStream.list(xxxStreams).toList())
RxDartは独自にObservable型等を作らずに、Dart標準のStreamクラスを拡張する形で実装されているようなので、若干導入の敷居が下がって良さそうですね。