学生の個人開発にもFlutterがオススメな理由（リリース例あり）

![logo_lockup_flutter_horizontal.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164020/92eead15-c4fe-d938-17ba-400538029524.png)


## はじめに
[Flutter #2 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/flutter-2)の6日目の記事です。

[大学生向け学習用マッチングアプリ「スタマチ」](https://twitter.com/matchingstudy)開発チームの [TetsuFe](https://twitter.com/tetsufe_) です。

【追記】 2020年10/14日にオープンソースになりました↓

https://github.com/noriHanda/study_matching_flutter

2019年10-12月に実際に本アプリをリリースした経験をもとに、学生の個人（小規模チーム）開発にFlutterがオススメな理由を紹介していきます。

- リリースしたアプリ
- 開発効率の高さ
- 学習リソースも充実、初心者の敷居も高くない
- UIの作りやすさ
- 審査の緩めなAndroidだけ先行配信できる
- Flutterを使うデメリット
- おまけとして、状態管理パターン・CI・利用したライブラリ


## 注意
- React Nativeなどの類似クロスプラットフォーム開発フレームワークとの差異については触れません。実際React Nativeなどもある程度同じようなメリット/デメリットがあるんじゃないかと思います。


## リリースしたアプリ
- 「スタマチ 大学生限定の学習用マッチングアプリ」
    - [Android版 (10/15-)](https://play.google.com/store/apps/details?id=com.hufurima.study_matching)
    - [iOS版 (12/3-)](https://apps.apple.com/jp/app/id1480122846)

<img width=600 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164020/e19466e3-dcd5-b37a-0c75-44ed9699a3b8.png">

Android版リリースまでの **開発期間は3ヶ月弱。(追記:プログラマは当時2人)**
恋人を見つけたい人向けではなく、主に勉強仲間を見つけるためのマッチングアプリです。

また、大学生限定と書かれていますが、現状は僕の所属する北海道大学（北大）のみで使えるアプリとなっています。


## 開発効率が高い
Flutterを使えば、以下のような特徴から、**講義や研究、バイト等で 時間のない学生や、仕事で忙しい個人開発者でも効率よくiOS/Android 両方でアプリをリリースできます。**

- **ひとつのコードでiOS/Androidアプリができる**
- **[Hot Reload](https://flutter.dev/docs/development/tools/hot-reload)**
    - **リビルドが数秒で終わります。** iOS/Androidネイティブよりも時間効率が良い！

Flutterはクロスプラットフォームフレームワークであるため、iOS/Androidで別別のコードをほとんど書く必要なく両OS対応のアプリを開発していくことができます。


また、Hot Reload・Hot Restart機能により、ネイティブ開発では時間のかかるビルドに苦しまされることなく、細かいUIの調整や状態変数のリセットなどがスムーズにできます。

<img src="https://buildflutter-com.cdn.ampproject.org/i/s/buildflutter.com/wp-content/uploads/2018/04/UIChange.gif">
以下リンクより引用：https://buildflutter-com.cdn.ampproject.org/i/s/buildflutter.com/wp-content/uploads/2018/04/UIChange.gif




## 学習リソースも充実
新しいフレームワークですが、意外と学習リソースが充実しているのもFlutterの良いところで、 **公式チュートリアルやドキュメントの数が豊富で説明も分かりやすいです。** Flutter初学者のメンバーは以下で実際に学習しました。

- [FLutter公式ガイド](https://flutter.dev/docs/get-started/install)
- [Udacityのチュートリアル（日本語字幕あり）](https://www.udacity.com/course/build-native-mobile-apps-with-flutter--ud905)

上記のリソースを選ぶ際、monoさんの[「Flutterの効率良い学び方」](https://medium.com/flutter-jp/flutter-learning-c5640c5f05b9)を参考にさせていただきました。新しい記事の [Flutter はじめの一歩](https://medium.com/flutter-jp/first-step-9b7f2c74fb08) もよさそうです。

チームメンバーは特にUdacityのチュートリアルにしっかり取り組んでいました(僕は公式のチュートリアルをやりました)。いろんな定番Widgetに触れるようなので、初心者以外でも学びがありそうです。


## UIの作りやすさ
- **全てDartのみで書ける**
  - **Storyboard, XML, CSSを触る必要がありません**
- **宣言的UI**
  - ロジックと分離しやすく、UIのパーツが再利用しやすい
  - 現行のメインのiOS, Android開発では手続き的な記述がほとんど。宣言的記述ができるSwiftUIもiOS13以上でないと使えず主流になるのはまだ先です
- Material Design系の標準ライブラリで **いい感じのUIがすぐ作れる**

例を一つだけ示します。

<img width="375" alt="Simulator Screen Shot - iPhone 8 - 2019-07-15 at 03.24.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164020/b0265ecd-bd99-02aa-8822-bc68f65e0f6e.png">

このUIを作るには以下のようなコードになります（一部省略）。

_MyHomePageState.build(BuildContext context) のreturn中に

- appBar（上の「Flutter Demo Home Page」の部分）
- body（中央の「５」など）
- floatingActionButton（右下のボタン）

などを宣言的に指定してUIを作っていきます。

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

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

```


## 審査の緩めなAndroidだけ先行配信できる
10月に申請を出した結果、iOS版はリジェクトされてしまったのですが、 **審査の緩めなAndroid版のみは先にリリースすることができました。**

これも Flutter が iOS/Android のクロスプラットフォーム対応であったからこそできたことだと思います。先にAndroid版でユーザの反応を見て、iOS版リリースまでに対策・修正ができたのもよかったです。

### iOS版のリリース
開発者の都合もあり一ヶ月以上後にはなりましたが、無事にiOS版もリリースできました。また、主なリジェクトの理由はFlutterに関係するものではありません（UserGeneratedContent等の理由）が、iOSの設定ファイル(info.plistなど)には注意した方が良いですね。AndroidとiOSで設定が必要な項目が違ったりするので。

UserGeneratedContentに関しては、こちらの記事を参考にリジェクト後の対応を行いました。
http://staff.feedtailor.jp/2014/11/17/627/

## Flutterを使うデメリット
- 新しいフレームワークなので、 **ライブラリがたまに不安定** なことがある
  - 端末からの画像取得ライブラリでGoogle Driveから取得したときクラッシュすることがありました(対策不明)
- ネイティブの機能を活用したい際は **ネイティブコードを書かなければならない場合も**
  - 今回のアプリではネイティブコード(Swift, Kotlin)は1行も書いていませんが、カメラやヘルスケアデータなどをフル活用する際はネイティブコードを書く必要があるらしいです
- ほぼ誰も扱ったことがない言語・フレームワークである可能性が高い
  - Flutterをやったことがないメンバーは嫌う可能性があるかも
  - （ネイティブに比べると）スタンダードな書き方がわからず迷いやすいかも


## おまけ

### 状態管理
状態管理は **BLoCパターン** を使いました。 **サーバーサイドとの通信を行うところはほぼ全てBLoCを利用しました。** 最近ではBLoCを使わない方が良い場合についても議論が活発になってきている印象もありますが、今回は敢えて使い分けはしませんでした。主な理由は統一感が出て実装に迷いが少なくなること、初心者のメンバーが多いためBLoC以外（ValueListenableなど）の学習コストが重く受け止められやすかったことです。

BLoCパターンについては以下の記事が新しくかつわかりやすいと思います。

Flutterの実践導入で用いるBloc Patternの全体像と押さえておくポイント
https://note.com/yamarkz/n/n7f9106e53179

また、僕自身も記事を投稿しています。
Stream/RxDart初心者のためのBLoC入門（Flutter）
https://qiita.com/tetsufe/items/521014ddc59f8d1df581


### CI
[Codemagic](https://codemagic.io/)を利用しました。iOSの証明書管理も簡単にできてオススメです。Bitriseとも迷うところかと思いますが、ビルド時間の制限が長いCodemagicを個人的にオススメします。

Slack通知でビルドしたファイルの配布もできるので、 **プログラミングができないメンバーにも簡単にテストアプリを配布でき、複数人開発がより円滑になります。**

<img width="743" alt="スクリーンショット 2019-12-05 15.52.40.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164020/ebbd1a69-7cd5-ad22-a28f-60a2879af8e2.png">


以下の記事がSlack連携などにも詳しく書かれていて参考にさせていただきました。

CodemagicでFlutterアプリのビルド・配信をする — iOS編
https://medium.com/flutter-jp/codemagic-a0f494c6244a

### 利用したライブラリ
- 画像表示: cached_network_image
- 状態管理 Provider, rxdart
- push通知 firebase messaging
- WebView（利用規約など）: webview_flutter
- HTTP通信: http
- ローカルデータ保存: shared_preferences
- 不揃いグリッドビュー: flutter_staggered_grid_view
- フォトライブラリからの画像取得: image_picker
- firebase_messaging


### Flutter以外の構成
バックエンドは Nginx/Django/PostgreSQL と Firebase Cloud Messaging の構成でした。**FirebaseはFlutterと同じく開発がGoogleなので、ライブラリの開発も活発で、相性がいいです。**Firebase以外はおそらく特にFlutterと相性のいい構成等はなく、得意な組み合わせを使うので問題ないと思います。


## 最後に
もし同じようにFlutterで個人開発等を行っている方で質問等ありましたら、ここのコメントもしくは [僕のTwitter](https://twitter.com/tetsufe_) までご連絡ください。また、現在就活中です。