【Flutter×Firebse】非エンジニアがパワーリフター向けアプリをリリースした話【個人開発】

# はじめに

最近、パワーリフター向けBIG3記録アプリ「LifterLog」をリリースしました。

[iOS版はこちら](https://t.co/AOEoEIMyEy?amp=1)
[android版はこちら](https://play.google.com/store/apps/details?id=jp.co.freadteam.lifterlog)

以前、Swiftで開発したアプリをFlutterで完全リニューアルしたのですが、
今回の開発→リリースまでの過程や得られた知見を共有したいと思います。

特にこれからアプリ開発やFlutterを始めようとしている人の参考になれば幸いです。
![lifterlog_screenshot_アートボード 1-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200520/7459183b-28bb-ad45-48a4-50a10ee6fe88.png)
※因みにパワリフターとは
[パワーリフティング](https://ja.wikipedia.org/wiki/%E3%83%91%E3%83%AF%E3%83%BC%E3%83%AA%E3%83%95%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0)（バーベルを持ち上げ、その重さを競うスポーツ by Wikipedia）を行う選手のこと。

# 自己紹介
ITベンチャーに勤務する社会人２年目の非エンジニア。
筋トレと椎名林檎/東京事変とアメフトが好き。

プログラミング経験は３年ほど。
独学を中心にSwiftやReactを触っていて、今年の５月頃からFlutterを始めました。 

# 開発背景
完全に自分が使いたかったからです笑。
既存のトレーニング記録系のアプリに自分が必要としている機能を満たしたものがなく、「無いなら自分で作るか〜」と勢いで始めました。

当初はSwiftで開発し、昨年リリースもしたのですが

- androidでもリリースしたい。
- Flutterに興味があった。

以上の理由でFlutterで完全リニューアルを始めました。

自分が作りたいものを自分好みに作れることって、個人開発の素晴らしい美徳だと思います。

# 使用ツール・技術
- Flutter 
- Firebase（Firestore / Firebase Authentication / Cloud Functions）
- Git / Github（バージョン管理, issue管理）
- Adobe XD（モック作成）
- Adobe Photoshop（モック作成）
- Adobe Illustrator（スクショ、アイコン作成）
- Googleスプレッドシート（DB設計など）
- Googleフォーム（アンケートや問い合わせフォームとして利用）
- Slack（メモ、issue管理、アンケート確認等）

#リリースまでの流れ
1. 必要機能洗い出し
2. UIUX設計
3. DB設計
4. スケジュール作成
5. 開発
6. リリース申請

ざっとこんな流れで仕事のない土日祝日を中心にコツコツと進めていきました。
以下、各過程でやったことを説明したいと思います。

### 1. 必要機能の洗い出し
まずアプリに必要となる機能を思いつく限り書き出し、その後本当に必要な機能のみをピックアップしてアプリ機能を固めました。（スプレッドシートにまとめた。）

機能をピックアップする際に意識したのは
**「このアプリを一言で表すと？」**
です。

今回なら、「BIG3のトレーニングボリュームが記録できるアプリ」。
こちらを念頭に機能を選定しました。

あれもこれも機能をつけようとすると結局何のためのアプリかわからなくなったり、開発がままならくなることも。。。
特に個人開発では必要最低限の機能で開発・リリースし、徐々にアップデートしていくことが大事だと思っています。

### 2. UIUX設計
自分がトレーニングしている状況を想定し、画面遷移等を決めAdobe XDにてモックを作成しました。
やはり、モックがあると開発がグッと楽になりますね。

### 3. DB設計
設計にあたっては主にこちらの記事を参考に致しました。
[Cloud Firestoreの勘所 パート2 — データ設計](https://medium.com/google-cloud-jp/firestore2-920ac799345c)
[Firestore Database Design](https://speakerdeck.com/1amageek/firestore-database-design)

必要な機能や拡張性を考慮しつつ慎重に。。。
ここが一番気を使ったところでしたが、同時に楽しいものでもありました。

### 4. スケジュール作成
スプレッドシートに開発する機能をまとめ、優先順位をつけざっくりとした開発日程を作成。
個人開発といえど、今回のように限られた開発時間でリリースまで最速でまでもっていくには特に必須な工程かと思っています。
地図のない旅行は無駄な回り道が増えますからね。（まぁ、往々にして予定通りにはいかなかったのですが。）

また、開発する機能ごとにGithubのissueを立て、完了次第closeするという流れで進めました。
関連する記事などを逐次コメントでき、後々振り返る時にも便利です。
また、バグ等が発生した場合も同様にissueを立て管理しています。

### 5. 開発
いよいよ開発スタートです。
Flutterの状態管理はprovider + ChangeNotifierを利用。
とにかくリリースすることを最優先に掲げて開発しました。

ここで大事なのは以下の3点かな、と思います。

**1. なんか動くぞ！を許容する。**
→最初から100%理解することは不可能だ割り切ってとりあえず動く状態を作り先に進まないと時間がいくらあっても足りません。
モチベが下がってしまう危険性もありますし、そのうち理解できる時は必ずくるのでとりあえず進むことを優先しましょう。

**2. 妥協と追求の繰り返す。**
→実装していく中でどうしても上手くいかない・思った通りに動かないことがでてくるかと思います。
そんな時は期限を決め、期限内に解決しなければ機能を簡潔にする・削る・代替するなどどうにかして前に進むことが大事！（もちろん、全力で調べることが前提ですが）
個人開発の良さはステークホルダーが存在せず、自分の思いのままに開発ができること。
リリースするために柔軟に対応してくことをお勧めします。

**3. 公式ドキュメントを読もう。**
→原理原則は全てここにある、といっても過言でないでしょう。とっつきにくいですがこちらも繰り返し読んでいればそのうちなんとなーくわかってきます笑。

![Ck9_MOJWYAAR_Rm.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200520/b7415cb2-d9fc-d92e-42e3-a55c60c0a937.jpeg)
**この精神大事。**

### 6. リリース
ストアのスクショやアイコン等はIllustratorで作成し、公式ドキュメントにそってリリース作業を行いました。
[iOSリリース](https://flutter.dev/docs/deployment/ios)
[androidリリース](https://flutter.dev/docs/deployment/android)
審査に提出後、iOS・android共に約二日後に審査結果がでて、晴れてリリース！🎉
開発を決めてから約４ヶ月程度。
やっぱり、リリースされる瞬間は嬉しいです。💪

# 7. 開発ではまった点

### 7_1. 本番/開発環境の切り替え
多分一番苦労した。。。
そもそもflavorってなんぞや？ってところからスタートし、あれこれ記事を読んで何とかできました。
特にiOS側の設定が複雑かつ、自分にほとんど知見のない領域だったのが要因。
こちらの記事を主に参考にいたしました。

[Flutterで環境ごとにビルド設定を切り替える — iOS編](https://medium.com/flutter-jp/flavor-b952f2d05b5d)
[flutterで本番/ステージング/開発を切り替える](https://qiita.com/ko2ic/items/53f97bb7c28632268b5a)
[【Flutter】Flavorの設定~buildまで(Android編)](https://qiita.com/hiromasa-fun/items/c79c99535f6f1db2a6a9)
[Creating flavors for Flutter](https://flutter.dev/docs/deployment/flavors)

### 7_2. スクロールして画面外となったListView内のTextFieldの値がリセットされる。
トレーニングを記録する画面で入力した値が消える現状に遭遇。
最初はロジックエラーかと思いましたが、思い当たる節があり調べてみるとこちらがヒット。

[[Flutter]スクロール可能なFormFieldの取り扱い](https://medium.com/@shiba1014/flutter-%E3%82%B9%E3%82%AF%E3%83%AD%E3%83%BC%E3%83%AB%E5%8F%AF%E8%83%BD%E3%81%AAformfield%E3%81%AE%E5%8F%96%E3%82%8A%E6%89%B1%E3%81%84-42684beaaa2a)

>非表示にされたり、ListViewの要素が画面外にスクロールされたりした時、つまりInvisibleな状態になると、そのwidgetはdisposeされます。再び表示される際には初期化されるため、それまでの値が書き換えられてしまいます

あーあるある、こういうの。
SwiftでいうTableViewCellの再利用的な話かなぁ、と目星がついていたので検索もスムーズにできました。
このように、**わからないことを他の言語に置き換えて考えてみる**、というのはとても有効な考え方だなと改めて感じました。

### 7_4. 今後の展望
今回のリリースでは切り捨てた機能の実装、UIの見直しを直近の動きと捉えています。
<dl>
  <dt>今回切り捨てた機能</dt>
  <dd>・スプラッシュ画面</dd>
<dd>・強制アップデート機能（Firebase Remote Config）</dd>
<dd>・ダークモード</dd>
<dd>・androidのGoogleログイン</dd>
</dl>
ざっとこんなもんでしょうか。
リリースを最優先に考えた結果、実装が後回しになりましたが確実に今後必要となってくる機能ばかりなので確実に実装していきたい。
<br>
**UIの見直し**
ここもしっかり基礎から学んで反映させたい、切実に！
今は完全にノリと勢いに任せてます。苦笑。
学ぶにあたっては、ドキュメント等だけでなく、いろいろなアプリを触っていくことも大事にしたい。

### ~~8. 未解決問題（どなたかお力添えを。。。🙏）~~
~~今回、どうしても解決できなかった問題。
**リリース環境のandroidでGoogleログインができない！**~~

~~ログインしようとするとこんなエラーが。。。~~
>  ~~(PlatformException(sign_in_failed, com.google.android.gms.common.api.ApiException: 12500: , null))~~

~~調べてみるといろいろ記事はでてきますがどれもすでに対処済み&効果なし。。。
サポートメールの設定、Firebaseにrelease用のSHA1のキーの入力、Google API ConsoleのOAuth同意画面の設定も全部やってるけど効果なし。
開発環境だと問題なく作動するのに。。。~~

~~参考記事~~
~~https://stackoverflow.com/questions/56188338/platformexception-platformexceptionsign-in-failed-com-google-android-gms-comm
https://github.com/flutter/flutter/issues/25640
https://qiita.com/hiraski/items/c5fb20da4a8862ec72ea~~

~~本当にここは妥協したくなかったのですがとりあえずメールとパスワード認証に代替して一時撤退。。。~~
~~同じような現象に遭遇して解決した方いたらどんな方法とったか教えてい頂けると嬉しいです...!~~

~~全くわからん！笑。~~

# 9. まとめ
以上、リリースまでの流れをまとめてみました。

やはり、個人開発で大切なのは

**・必要最低限の機能に絞る。
・妥協と追求を繰り返しとにかく前進する。**

ことかと思います。

まだまだ、できないこと・知らないことがたくさんありますが、やはり自分のアプリをリリースできるのは本当に楽しい。
これからも少しずつ問題を解消していき、学んでいきたいと思います。

にしても、Flutter、楽しいなぁ。

# 10.追記
## 2021/5/2_リリース環境のandroidでGoogleログインができない！が解決！！
原因はAPIキーをAndroidのみで動作するように制限していたためでした。
![API_キーの制限と名前変更_–_API_とサービス_–_LifterLog_–_Google_Cloud_Platform.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200520/3edd011e-2e04-de1e-2c2a-1fa41c9ea26c.png)


詳しくはこの[issue](https://github.com/firebase/firebase-android-sdk/issues/1757#issuecomment-665084985)を。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Debug環境はできてProduction環境でできなかった理由もこれではっきした。<br><br>Production環境にだけAPIの制限かけてたからだとは。。。</p>&mdash; パンジーRyo@BIG3と自宅懸垂（減量中） (@panzee54) <a href="https://twitter.com/panzee54/status/1388747450156863498?ref_src=twsrc%5Etfw">May 2, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>