2021-08-23に投稿

Flutterでアプリを作る時に使っている僕の定番パッケージ

この2年でFlutterアプリを5つリリースしました。最初はよく分からない感じで適当に作っていましたが、やっているうちにだんだんわかってきたのと、あとは諸々の便利なライブラリなども出てきてそれらをキャッチアップして開発するようにしていて、最近なんとなくだんだん自分のアプリの作り方が固まって来ました。せっかくなので一度まとめて紹介したいと思います。

おすすめ

Flutter Hooks

https://pub.dev/packages/flutter_hooks

FlutterでReactのようなHooksを使って書けるパッケージです。StatefulWidgetを使わず、代わりにHookWidgetというものを使います。setStateを使わず、Hooks独自の値の見方、更新の仕方で処理を書いていきます。

僕もWebメインなので同様にWebでReactとかNext.jsを使っている人には直感的で使いやすいのではないかと思います。Reactとほぼ同様のものが使えます。useState, useEffect, useCallback, useMemoizedなど。

他にもFlutterで使うのに必要な~~Controller系もだいたいHooksが用意されています。例えばuseTextEditingControllerなど。

例えばsetStateの代わりに使うuseStateは下記のような感じで使えます。

  @override
  Widget build(BuildContext context) {
    final isImageDeleted = useState(false);

    void toggle() {
      if (isImageDeleted.value) {
        isImageDeleted.value = false;
      }
    }

ここまでなら好みで使うかくらいのレベルですが、後述するRiverpodというパッケージでこのflutter_hooksを使って書くことができるため、両方合わせて使うと便利になっています。

Riverpod

https://pub.dev/packages/riverpod

異なるウィジェット間にまたがった共通のstateを扱いたい時に便利なパッケージです。これまたWebのReactでいうとReduxとかRecoilとかのイメージです(使い方は全然違います)

いろいろな書き方があり、先程のFlutter Hooksと組み合わせて使うこともできます。

たとえば下記のようにデータを定義し

class ChatEditState {
  late Chat chat;
  int editingMessageKey = -1;
  int insertingMessageKey = -1;
  int insertingPersonId = -1;
  int personId = -1;
}

こんな感じで値を更新処理を定義したりして

class ChatEdit extends StateNotifier<ChatEditState> {
  ChatEdit() : super(ChatEditState());

  void setChat(Chat chat) {
    state = state..chat = chat;
  }

こんな感じで更新して

chatEdit.setChat(chat);

こんな感じで参照したりします。(バージョンによって書き方が違います)

  Widget build(BuildContext context) {
    final state = useProvider(chatEditProvider);

    return Text(state.chat.name);

便利なのですが、バージョンアップも頻繁で、そろそろv1になるところで同時に破壊的変更もちょっと続いてるので、直近で利用するにはキャッチアップも必要になっています。あと調べて出てくるサンプルがcounterのようなシンプルすぎるものが多かったりするので情報を見つけるのにちょっと苦労する時もあります。

Hive

https://pub.dev/packages/hive

アプリ内のデータベースです。端末内で完結するため、ネットワークと接続する必要がなくオフラインで利用できるアプリの開発に役立ちます。僕はせっかくアプリということであまり外部のデータベースを使いたくないためいつもこれを使ってアプリを作っています。

データベースと言うと他にもSQLiteがありますが、それに比べて下記のような点が優れています。

  • 定義したクラスからわざわざMap型に変換して保存したりデータを取り出してparseしたりする必要がない
  • 型も基本的なものは一通り使える
  • リレーションもできる
  • 速い(らしい(多分))

とにかく一番上のですね、開発がとても楽です。

ただ独自のデータ処理のため、今のところ問題は出ていないのですが、何か問題があった時にどういう対処が必要なのか、そもそも対処が可能なのか、というのがよくわからない部分もありますので、個人アプリでしか使っていません。仕事ではSQLiteを使っています。この辺は自己判断になっていきそうです。

boxという箱からデータを取ってきます。

  static Box<Person> getBox() {
    return Hive.box<Person>('people');
  }

  static Person get(dynamic key) {
    return getBox().get(key)!;
  }

  static List<Person> getAll() {
    return getBox().values.toList();
  }

検索はSQLのwhereみたいなのとか特別なものは特になく、十分速いから普通にListのwhereでデータを取る、みたいな感じみたいです。

仕組みとしては、build_runnerというパッケージを用いて、コマンドを使ってデータ管理部分はコードを自動生成してくれるようになっています。そのため面倒なコードを書かなくても開発ができるという感じです。このbuild_runnerは他のパッケージでもちょいちょい使われるので慣れておくと良いと思います。

その他詳細は以前記事を書いているのでそちらをどうぞ。
https://crieit.net/posts/Flutter-Hive

Freezed

https://pub.dev/packages/freezed

これはイミュータブルなオブジェクトを簡単に扱うことができるようにしてくれるパッケージです。

例えば下記のように値を更新して新たなオブジェクトとして生成します。

final cloned = original.copyWith(name: 'aiueo');

まあこれはこれで良いのですが、個人的にはやはりJSONやMap型のオブジェクトをエンティティの形に相互変換できる機能がすごく便利です。json_serializableというパッケージと組み合わせて使います。

これにより、SQLiteやAPIで取得したデータなどオブジェクトに変換する処理を書かなくてもデータを扱うことができるようになり、とても楽です。

例えば下記のようなコードを書いてbuild_runnerを実行すればコードが生成されてあとはもう使うだけです。

import 'package:anyone_composer/models/cloud/cloud_record_stroke.dart';
import 'package:freezed_annotation/freezed_annotation.dart';

part 'cloud_record.freezed.dart';
part 'cloud_record.g.dart';

@freezed
abstract class CloudRecord implements _$CloudRecord {
  factory CloudRecord({
    required String id,
    required String uid,
    @JsonKey(name: 'user_id') required String userId,
    required List<CloudRecordStroke> recordStrokes,
  }) = _CloudRecord;
  const CloudRecord._();

  factory CloudRecord.fromJson(Map<String, dynamic> json) =>
      _$CloudRecordFromJson(json);
}

下記のような感じで変換してくれます。

final entity = CloudRecord.fromJson(json);

僕はHiveを使うのであまり使いませんが、仕事でAPIを使う場合や、あとはFirestoreからデータを取るときとかは便利です。

Flutter EasyLoading

https://pub.dev/packages/flutter_easyloading

ローディング表示を行ってくれるパッケージです。なんかもうこんな感じで簡単です。

EasyLoading.show();

EasyLoading.dismiss();

他にもメッセージ出したり、デザインも設定できたりします。デモサイトで実際に動作を見てみることもできます。通信などで時間がかかる処理がある場合に使いましょう。いちいちボタン用にstateを設定して表示切り替えたりするよりもだいぶ楽です。

基本的なやつ

google_mobile_ads

これは公式のAdMobパッケージです。サードパーティのものや、古い公式の別ライブラリがあったりして紛らわしいかもですが、これが最新です。ちゃんとウィジェットとして画面内に埋め込むことができます。

とはいえまだ時々よくわからない問題が出たりすることもあるのでシンプルな使い方をするほうが良さそうです。僕はだいたい下の方に表示するだけにしています。まだまだ改善してほしいなと思う部分は多いです。

あとはapp_tracking_transparencyもあわせつつ

Flutter Launcher Icons

https://pub.dev/packages/flutter_launcher_icons

大きい画像を一つ作っておけばあとはAndroid、iOS用のアイコンサイズをぶわっと作ってくれるやつです。便利です。

app_review

レビューリクエストをしてくれるライブラリです。とても簡単に使えるのでリリース時から入れておきましょう。

まとめ

あくまでも僕の定番です。みなさんも自分のお気に入りを探しましょう。

実際に作ったやつは下記のポートフォリオにの「アプリ」というグループでまとめてあります。(Flutterじゃないゲームも混じってますが)
https://www.alphabrend.co.jp/portfolio

ツイッターでシェア
みんなに共有、忘れないようにメモ

だら@Crieit開発者

Crieitの開発者です。 Webエンジニアです(在宅)。大体10年ちょい。 記事でわかりにくいところがあればDMで質問していただくか、案件発注してください。 業務依頼、同業種の方からのコンタクトなどお気軽にご連絡ください。 業務経験有:PHP, MySQL, Laravel, React, Flutter, Vue.js, Node, RoR 趣味:Elixir, Phoenix, Nuxt, Express, GCP, AWS等色々 PHPフレームワークちいたんの作者

Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

有料記事を販売できるようになりました!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?

コメント