【個人開発】FlutterとFirebaseでサボり防止アプリを作った

# (2022年6月追記)

2022年6月現在、この記事にあるアプリよりも、ほぼ同じコンセプトのReact+NextJS製webサービス「みんなで作業場」に滞在していることが多いです。

是非お越しください！

https://sagyoba.oka-ryunoske.work/

# アプリ

先日、個人開発アプリをリリースしました！やったね！！！

審査も通りまして、現在App StoreとPlay Storeで配信されております。

[App Store](https://apps.apple.com/jp/app/%E7%9B%A3%E8%A6%96%E3%81%97%E5%90%88%E3%81%86%E4%BC%9A/id1507154418)

[Play Store](https://play.google.com/store/apps/details?id=work.oka_ryunoske.procrastinators_watch_mutually)

せっかくなので、利用した技術のメリットと注意点をまとめておこうと思います。

# 作ったアプリ

これです。

広報用ページも作ってみたのでリンクを貼っておきます。

広報用ページはスマホで見る用にレイアウトしてます。

[監視し合う会 〜お互いサボらないようにみんなで作業しよう〜](https://kanshi-shiau-kai-app.web.app/)

英語名: Procrastinators Watch Mutually

![kanshi_feature_1024_500.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85139/23774597-120a-15dc-2a0e-808fe874427a.png)


## 解決したい課題

やらなきゃいけないことがあるのに、なかなか取り組めずにグダグダしてしまう経験がみなさんあると思います。

でも、会社や学校で「今はこれをやる時間です」と管理されたり、誰かと一緒に「今からやるぞ！」って決めると、取り組めますよね。

そういう「誰かと一緒」「時間を管理される」という状況をアプリ上で再現して、作業に取り組みやすくするためのアプリです。

## 解決方法

 - 一緒に作業してるメンバーと作業内容が表示される
 - タイマーで全員同時に作業時間と休憩時間を指定される(49分作業12分休憩)
 - ちゃんと取り組めたかどうか自己申告し、それに対して褒めたり罰したりできる
    - 褒められたいし、自分に嘘をつきたくないので、作業に取り組むモチベーションアップ
 - 罰された人は社会貢献活動で償うまでアプリを利用できない
    - 社会貢献活動とは動画広告視聴のことで、広告主・広告配信業者・アプリ制作者に貢献できる
    - サボりに対し、有意義な軽い「罰」を用意することで、作業に取り組むモチベーションアップ

そんなアプリです。

[監視し合う会 〜お互いサボらないようにみんなで作業しよう〜](https://kanshi-shiau-kai-app.web.app/)


ということは、広告の実装が必要ですね。

また、ユーザーの入力した内容が他者から見えるので、プライバシーポリシーや利用規約で不適切な入力を防止し、違反者にはミュートやBANをできるようにする必要があります。

そのためにはログイン機能でユーザーを識別する必要もありそうですね。

では技術方面を見ていきましょう。

# Flutter

フロントエンドはFlutterを使います。

https://flutter.dev/

## Flutterのメリット

最大のメリットはなんと言っても、AndroidとiOSの両アプリをそれぞれ作らなくて済むことです。

また、同じメリットを持つフレームワークは他にもありますが、Flutterが今最も勢いがあるフレームワークと言えると思います。コミュニティも活発で情報が得やすいです。

<img width="749" alt="スクリーンショット 2020-07-27 15.01.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85139/877edf05-1a0a-ac9b-e7bd-65ad2a912f91.png">

あのGoogleがかなり力を入れて作っているという安心感もありますね。

今後はWebや、Mac、Windows用のネイティブアプリも作れるようになるということで、スマホアプリに限らず広範囲にわたるクロスプラットフォーム開発が可能になっていくようです。

Webは2020年7月27日現在、既にかなりのレベルでアプリが作れます。


## 開発環境

Flutterの開発環境はAndroid Studioを使いました。

VSCodeでもいいと思います。

Flutter Inspectorの見やすさや新規プロジェクトの作りやすさでAndroid Studioを選びましたが、それも半年以上前のことなので、今のVSCodeと比較するとどうかわかりません。

### 静的解析

Flutter開発をする際は静的解析を有効にするようにしましょう。

これはほぼ必須だと思います。

行儀がよく見やすい、ルールの統一されたコードを書くことが出来ます。

詳しくはこちら。

https://dart.dev/guides/language/effective-dart

https://medium.com/flutter-jp/analysis-b8dbb19d3978

## 状態管理手法

Provider + ChangeNotifier パターンを採用しました。

2020年7月27日現在、Flutter公式が最もおすすめしている方法です。

Flutter開発を始めると状態管理手法に悩むことになると思いますが、まずはこれでいいと思います。

他の方法については、こちらの記事を参考にしてもらえると嬉しいです。

[Flutterの状態管理いろいろ比較 〜グローバル変数StateからBLoCパターンまで〜](https://qiita.com/agajo/items/50d5d7497d28730de1d3)

なお、リンク先記事を書いた後で登場した

 - StateNotifier
 - Riverpod
 - Cubit

などの方法については記事内で触れていません。興味ある方はお調べください。

筆者自身の次のアプリはRiverpod+ChangeNotifierパターンで作ろうと思っています。

## 多言語対応

英語・日本語・中国語の3言語に対応させました。

多言語対応の方法はこちらの公式解説の[An alternative class for the app’s localized resources](An alternative class for the app’s localized resources)を参考にしつつ、オレオレ手法でやってます。

公式オススメの方法は、自動コード生成を含んでおり、それと静的解析ツールがバッティングして警告を吐きまくり、静的解析の例外設定をしてみたらそこにバグがあり例外設定が効かず…というトラブルに見舞われたので、それ以来オレオレでやってます。今はどうなんでしょう。

筆者のオレオレ手法は、自動コード生成がなく、コード補完も効いて
`L10n.of(context).title`
のように欲しい文言を得られるので、悪くないと思ってます。

ここでは詳しく解説しませんが、そのうち記事にするかもしれません。

なお、もちろん、後述のプライバシーポリシーやスクリーンショット、ストア上のタイトルや説明文も全て3言語分用意してます。ちょっと大変。


# Firebase

バックエンドにはFirebaseを使っています。

ログイン・データベース・サーバーサイドロジック・広告・プライバシーポリシーページの用意を全てFirebaseに頼っています。様様ですね。

下記に出てくるfirebase関係のパッケージを使うには[firebase_core](https://pub.dev/packages/firebase_core)パッケージが必要になるのでご注意ください。

## Authentication

Google、Facebookアカウントを使ったログインを実装しました。



[firebase_authパッケージ](https://pub.dev/packages/firebase_auth)を使います。

ただし、iOSアプリの場合はサードパーティログインにAppleを加えることが必須なので、iOS版に限りAppleログインも実装しました。

Appleに関してはこちらの記事が大変参考になりました。

[[Flutter] Sign in with Apple を Cloud Functions 無しで実装する](https://qiita.com/sensuikan1973/items/3e1a10668d71e0701724)



Androidアプリの方は、Androidのapkファイルの署名に使った証明書のハッシュをFirebaseやFacebookに伝えておく必要があるのでご注意ください。

デバッグ時にデバッグ用証明書のハッシュを渡していても、リリース時にはリリースに使った鍵の証明書のハッシュを伝える必要があります。筆者はこれを忘れていて、リリース直後にAndroid版で一切ログインできない事故を起こしました。


## Firestore

[cloud_firestoreパッケージ](https://pub.dev/packages/cloud_firestore)を使います。

Firestoreの使い方・考え方についてはこちらの動画シリーズがとてもわかりやすいので一通り見ておくといいと思います。

[Get to know Cloud Firestore](https://www.youtube.com/playlist?list=PLl-K7zZEsYLluG5MCVEzXAQ7ACZBCuZgZ)

従来のRDBMSとは結構異なる考え方が推奨されてます。

「データの正規化を頑張るより、重複を許した方が良い」とか「リアルタイム接続をデフォルトにして一件ずつフェッチするのを例外的な場合に限定しよう」とか。

「クエリ一回でも、読み込んだドキュメントの件数に応じて料金がかかる」なんかは結構重要です。


### セキュリティルールとテスト

Firestoreで重要になるのがセキュリティルールです。

アクセス権限の管理だけではなく、**サーバーサイドバリデーション**もセキュリティルールを使って行います。

筆者はセキュリティルールとそのテストはAndroid StudioではなくVSCodeで書いています。

テストコードをTypeScriptで書いているのですが、Android Studioではシンタックスハイライトや補完が効かないので。

セキュリティルールだけ書いていくとゴチャゴチャしてきて管理が大変なので、やはりテストとセットで書いていくのが良いと思います。

その際はこちらの記事を参考にしてもらえたらとても嬉しいです。

[VSCodeデバッガを使ってCloud FunctionsとFirestoreの連携テスト(TypeScript)](https://qiita.com/agajo/items/621812e35bf1abd9a797)

2020年6月のバージョンで、セキュリティルール内で一時変数が使えるようになったりして、どんどん便利になっていますね。

[New improvements to Firestore Security Rules](https://firebase.googleblog.com/2020/06/new-firestore-security-rules-features.html)

## Functions

Firestoreの中身を**どうしても**サーバーサイドから操作したい時は、Cloud Functionsを使います。

「どうしても」と書いたのは、Firestoreの操作をする時はまず第一にクライアントのSDKから操作することを考えるべきだからです。

Firestore SDKはオフラインサポートなどいろいろうまいことやってくれるので、積極的に利用しましょう。

先程の動画シリーズの一つですが、これが参考になります。

https://www.youtube.com/watch?v=oDvdAFP6OhQ



また、Functionsを使う必然性がある場合でも、呼び出し可能関数を作るのはできるだけ避けましょう。

理由はこちらの記事が参考になります。

[CQRSを学ぶついでにCloud FunctionsとFirestoreを連動させる時の小技も学ぶ](https://engineer.dena.com/posts/2019.12/follow-up-on-firebase-meetup-15/)

Web APIの操作に慣れているとつい同様にAPIを作って叩きたくなりますが、耐えましょう。クライアントからの操作で完結するものは完結させます。

じゃあどうするかというと、Cloud Functionsには、さまざまな「トリガー」が用意されています。

 - Firebase Analyticsに新しいイベントが送られた時
 - Firebase Authentication で新しいユーザーが作られた時
 - Firestore上でドキュメントが削除されたとき

などなど、たくさんあります。

これらに応答してFunctionsが起動するようにしましょう。

ただし、Functions上の各関数は一回のトリガーに対して複数回起動することがあるので、「冪等」にしておくといいです。「冪等」というのは、「2回以上実行しても結果が変わらない」ということです。

今回のアプリでは、ユーザーがきちんと退室せずに放置した場合に退室処理を走らせるためにFunctionsを利用しています。

## hosting

サーバー上にファイルを置いておき、特定のURLでアクセスできるようになります。

一昔前だったらレンタルサーバーを有料で借りないとこういうことはできませんでしたが、便利な時代になりました。

今回は、プライバシーポリシーを掲載したページや、広報用ページを置くために利用しています。

### 開発環境

FunctionsもVSCodeで書いています。TypeScriptで書いているのですが、Android Studioだと補完やシンタックスハイライトが効かないからです。

### Functionsのテスト

公式記事が大いに参考になります。

[Cloud Functions の単体テスト
](https://firebase.google.com/docs/functions/unit-testing?hl=ja)

また、こちらは上に既に貼ったのと同じ私の記事ですが、再掲します。参考にしてもらえると嬉しいです。

[VSCodeデバッガを使ってCloud FunctionsとFirestoreの連携テスト(TypeScript)
](https://qiita.com/agajo/items/621812e35bf1abd9a797)


## AdMob

このアプリは広告が出るので、[firebase_admob](https://pub.dev/packages/firebase_admob)パッケージを使って広告を出しています。

ただ、このパッケージは何かと使いにくいので、色々注意が必要です。

筆者がこのパッケージについてあれこれ嘆いている様子がわかるツイッター検索結果がこちらです。

[ツイッター検索](https://twitter.com/search?q=from%3Aagajo_tech%20firebase_admob&src=typed_query&f=live)

# ストア申請のために

アプリが動くようになったら、ストアで配信したいですよね。

ここでもいろいろ障壁があります。

## ミュート機能・通報機能

このアプリはユーザーが入力した表示名やタスク内容が他人から見えるため、「ユーザー生成コンテンツ」に該当すると思われます。

この場合、少なくともApp Storeに掲載されるためには、不適切な内容を投稿するユーザーに対して対策を施しておく必要があります。Play Storeについては未調査ですが、おそらく同様だと思います。

具体的には、ユーザーをミュートや報告する機能が必要です。

詳しくはApple公式のこちらが参考になります。

[App Store Reviewガイドライン - 1.2 ユーザー生成コンテンツ](https://developer.apple.com/jp/app-store/review/guidelines/#user-generated-content)

## プライバシーポリシー

個人情報をどう扱うか、というものです。

すべてのアプリで必須のはずです。一切情報収集しない場合でもその旨を記述したプライバシーポリシーが必要だと思われます。

Firebase Analyticsを使っている場合は情報収集していることになるので、その旨の記述が必要ですね。

AdMobを使っている場合はユーザーに合わせた広告を出すために情報収集してますので、それについても記述が必要です。

詳しくはこちらを御覧ください。

[App Store Reviewガイドライン - 5.法的事項](https://developer.apple.com/jp/app-store/review/guidelines/#legal)

とはいえプライバシーポリシーなんてどう書いたら良いかよくわからないものです。

検索すると書き方の解説や雛形がヒットしますので、参考にするといいと思います。


## 申請用スクショ撮影

ストアで申請するためにはアプリのスクリーンショットが必須です。

これが案外面倒です。スクショとして欲しい画面が、アプリを実際に操作して簡単に作れるとは限らないからです。

それが複数端末分必要になります。

また、多言語対応している場合はその数だけ必要になります。

4画面*4端末*3言語とすると48枚必要になりますね。手動で撮っては結構な手間です。

これについては私のこちらの記事を参考にしてもらえると嬉しいです。

[Flutterアプリのスクショを(極力)自動で撮る on AndroidStudio
](https://qiita.com/agajo/items/2d2d57561b5880618966)

## 署名について

署名周りも、アプリ配信時の結構なハードルになると思います。

これも自分の記事で恐縮ですが、概要をまとめておりますので参考にしてもらえたら嬉しいです。

[Android・iOSアプリを配信する時の署名について整理する](https://qiita.com/agajo/items/0f0449ee1a7f0eb3b284)



# 終わりに

技術周りをまとめておこうと思って書いてみたら、自分の過去記事へのリンクが多くなってしまいました。

まあ、難所を突破するたびにその結果を記事にまとめるようにしていたので、それらへのリンクが多くなるのは必然か……。。。。

ということで、皆様、アプリ開発ライフを楽しみましょう！

サボり防止アプリもよろしくおねがいします！これで時間管理しながらアプリ開発してくれたらメチャクチャ嬉しいです！

[監視し合う会 〜お互いサボらないようにみんなで作業しよう〜](https://kanshi-shiau-kai-app.web.app/)

[App Store](https://apps.apple.com/jp/app/%E7%9B%A3%E8%A6%96%E3%81%97%E5%90%88%E3%81%86%E4%BC%9A/id1507154418)

[Play Store](https://play.google.com/store/apps/details?id=work.oka_ryunoske.procrastinators_watch_mutually)