【Swift, Firebase】究極の瞑想アプリを作った話

マツコの知らない世界で有名になった **「瞑想」** ですが、
今回、ヨガ教室をやっている [yoggy inc.](https://www.yoggy.co.jp/) さんの新規事業ということで、
瞑想スタジオと合わせた[瞑想アプリ](https://itunes.apple.com/jp/app/muon-%E7%9E%91%E6%83%B3-%E3%83%9E%E3%82%A4%E3%83%B3%E3%83%89%E3%83%95%E3%83%AB%E3%83%8D%E3%82%B9/id1362966765?mt=8)を製作し公開しました。

<img width="991" alt="スクリーンショット 2018-08-17 10.39.11.png" src="https://qiita-image-store.s3.amazonaws.com/0/62822/e7d61d63-dea6-0423-b320-6ef67b7390f0.png">


また、先日クリエイティブの専門誌である **「ブレーン」** にもこのアプリが取り上げられました。

![Dj645qSUUAAsQTF.jpg](https://qiita-image-store.s3.amazonaws.com/0/62822/8c9c5a33-8785-a5df-664e-4b0084cfd460.jpeg)


## 主要機能
- 瞑想のガイダンスを流す
- 瞑想を続けるための進捗管理やカレンダー機能、心測定機能など
- アプリのサブスクリプション
	- 無料期間あり
	- 月々または年額
- HealthKitとの連携

## 動作
![meditation_start.gif](https://qiita-image-store.s3.amazonaws.com/0/62822/bfeffca2-cf44-5557-3f11-9fb214881f2b.gif)![breath.gif](https://qiita-image-store.s3.amazonaws.com/0/62822/ff55f663-fd37-9e05-55a1-3ae818b020ee.gif)![calendar.gif](https://qiita-image-store.s3.amazonaws.com/0/62822/9810626f-22a0-bcf4-193e-e29c916b84aa.gif)




## 環境
- XCode 9.2~
- Swift 4.0.3~
- Carthage 0.27.0 ~
- Cocoapods 1.4.0 ~

## 開発期間
- 3/12 ～4/23 開発
- 4/23 ~ 4/27 テスト
- 4/27 ~ バグ修正、チケット対応


## 開発体制
- iOSメイン: おかむー + 実装サポート数名
- サーバー: おかむー

### 進捗管理
- Google Docsのスプレッドシート
- github issue

### プロトタイプ
- prott

### ソースコード管理
- github


## 作戦
- サーバーサイドとアプリの開発が両方必要だったため、スピードとコスパ重視のFirebaseを使いました
    - ライブラリにもたくさんお世話になりました
- あとあとややこしくなりそうなのは極力使わない
    - UIWindowはつかわない
    - UserDefaultも極力使わない、もし使うのであればkeyChainを利用するが、極力使わない

## 主な技術や構成、使用したライブラリ
- MVVMを採用
    - DataSourceを分離しテストしやすい構造にする
- Firebase
    - 本番環境とstg環境を用意
- Lottie(旧BodyMovin)
    - コアなアニメーションはAfter Effectsで書き出してもらう


<details>
<summary>`Gemfileで管理するもの`</summary>
<pre>
- cocoapods
- fastlane
<pre>
</details>

<details>
<summary>`podfileで管理するもの`</summary>
<pre>
- swiftDate
- firebase
- fbloginkit
- fabric
<pre>
</details>


<details>
<summary>`cartfile(なるべくcarthageに寄せた)で管理するもの`</summary>
<pre>
- json
    - github “SwiftyJSON/SwiftyJSON”
- reactive
    - github “SwiftBond/Bond”
- setting
    - github “nickoneill/PermissionScope” ~> 1.0
- ui
    - github “ninjaprox/NVActivityIndicatorView”
    - github “SVProgressHUD/SVProgressHUD”
    - github “airbnb/lottie-ios”
    - github “xmartlabs/Eureka” ~> 4.0
    - github “danielgindi/Charts” ~> 3.0.5
    - github “kaandedeoglu/KDCircularProgress”
    - github “ChiliLabs/CHIPageControl” ~> 0.1.3
- cache
    - github “rs/SDWebImage”
- DB
    - github “realm/realm-cocoa”
- scrollView
    - github “dzenbot/DZNEmptyDataSet”
    - github “eggswift/pull-to-refresh”
- network
    - github “ashleymills/Reachability.swift” ~> 3.0
    - github “Alamofire/Alamofire”
- storekit
    - github “bizz84/SwiftyStoreKit”
- calendar
    - github “WenchaoD/FSCalendar”
- secret
    - github “evgenyneu/keychain-swift” ~> 10.0
<pre>
</details>


## 管理画面やデータ更新
- Firebaseを使用するので、管理画面は開発せずGoogle Sheetを管理画面としました

### 瞑想コンテンツの更新
- GoogleSheetはjson形式でexportできるので、それをFirebase Storageに置いてもらうオペレーションをしてもらう
- 音声や画像ファイルなどは、あらかじめFirebase Storageにuploadしておき、downloadURLをGoogle Sheetの管理画面へ記入してもらう

### push通知
- FCMは使わず、Cloud Messagingを利用して手動でpushします

### ユーザーのDataの管理
- Realmは、encryptionKeyで暗号化して使用する
- ログインはFirebaseAuthenticationにまかせる
  - Email
  - Facebook
  - 匿名
- 個人情報でないその他の情報は、Realtime Databaseにputして、Cloud Storage バケットへ定期的にバックアップする

## 品質管理・規約
- お互いにプルリクを送り合う
- 今回SwiftLintは使わなかった
- finalとprivate修飾子の徹底
    - 三項演算子と??アンラップは今回は、使用を許可
- interfaceはextensionにつける
- 強制アンラップは禁止
- Windowはつかわない
- UserDefaultも極力使わない、もし使うのであればkeyChainを利用するが、極力使わない

などなど、まあSwifterにとっては当たりまえなことは多い


## アニメーション
### 瞑想画面
- 瞑想中の映像は、AfterEffectで動画として書き出して再生させる
- 波形部分は、UIViewで毎秒drawする
- 瞑想開始待ちローディングは、AfterEffectでSVGで書き出してもらい、Lottieで実装する

![meditation_start.gif](https://qiita-image-store.s3.amazonaws.com/0/62822/100e726d-5641-aa34-48a3-706cbae44db3.gif)![meditation_end.gif](https://qiita-image-store.s3.amazonaws.com/0/62822/5afe9844-9bc2-4de6-0009-b722fc5f217e.gif)



### ホーム画面
- 瞑想進捗 CABasicAnimationで実装
- 画面遷移 CustomTransitionで実装

![progress.gif](https://qiita-image-store.s3.amazonaws.com/0/62822/0d6f0b22-0156-e5da-c10c-fcf494430f28.gif)


### ツール画面
- 呼吸カウント AfterEffectでSVGで書き出してもらい、Lottieで実装する
- タイマー KDCircularProgressを使用して実装
- 心測定 AfterEffectでSVGで書き出してもらい、Lottieで実装する

![breath.gif](https://qiita-image-store.s3.amazonaws.com/0/62822/db70821a-ad0d-bf1e-2c65-4a7692399547.gif)![timer.gif](https://qiita-image-store.s3.amazonaws.com/0/62822/eb113b73-e6b5-7dfe-dc7f-26ec8da8bddd.gif)![cocololo.gif](https://qiita-image-store.s3.amazonaws.com/0/62822/a3fa38c1-d7c2-ac31-3894-7ddd162afed5.gif)


## テストコード
- XCTest
- XCUITest

## 構造について
- Clean Architectureを採用したかったが、開発期間的に慣れているMVVMにしました

## めんどくさかったところ
- 外部と提携したSDKが、x86_64に対応していなかった
    - targetをdev,stg,prodを作成し、devのみコンパイルフラグを使って、排除することでローカルでの開発できるようにした（ふつうではある）

## 難しかったところ
- このアプリは、背景が有機的に動いている演出があるため、全ての画面が透明背景で、いろいろ問題があった
    - デフォルトのトランジションを使うと、背面とかぶるのでカスタムトランジションやアニメーションを工夫して書く必要があった

- 設定画面などはEurekaを使用していたが、透明がゆえに、Eurekaも限界がきて最後は、ほとんど自前に書き換えた

## 大変だったところ
- 開発期間が短く、いろいろ犠牲になった
  - 食事、自分のコミット、技術の切り売りなど
  - 将来のためにも、しっかりと時間のある案件をやりたい or 5倍のスピードで実装できるようになりたい

## 感想
- まずは周りの人に感謝です。ありがとうございました。
- 業務や趣味でもFirebaseは結構使っていたのでハマる事なく実装できた
- アンドロイド対応などもあればチャレンジしたい
- サブスクリプションの設定で、明らかにAppleの翻訳ミスを見つけてしまった(今後記事にする)


## さいごに

- [結婚式アプリで30万ゲットした後、実際に式場に導入した時の話](https://note.mu/okamu_/n/n1c61d9b8b30d)
- [合コンアプリを作って1.3のDLを稼いだ話](https://note.mu/okamu_/n/nbd3dbd455279)

[![rectangle_large_type_2_16f3c7118afccf85c7baac3bcebfb64b.png](https://qiita-image-store.s3.amazonaws.com/0/62822/8d3407e3-1ed6-97bc-0f86-03d0c8189632.png)](https://note.mu/okamu_/n/n1c61d9b8b30d)[![rectangle_large_type_2_1d8e5847e845492d608aee545f735bda.png](https://qiita-image-store.s3.amazonaws.com/0/62822/392b5482-f21f-a2da-c589-8c379959360e.png)](https://note.mu/okamu_/n/nbd3dbd455279)



などを書いています。

過去の作品などはこちら
https://www.okamu.ro/

- またTwitterもやっているのでフォローして欲しいです
    - https://twitter.com/okamu_ro