個人で作ったiOSアプリを公開した ~マッハリーダー~
5月くらいから暇な時にコツコツ作っていたアプリを公開した。コメントやハイライトができるPDFリーダーで、そのコメントやハイライトは他のユーザからも見れる、というもの。 PDFをアップロードして、他のユーザも同じものを見ていると、他のユーザのアクションが見れるのだ。 (以下のアイコンからダウンロードできます)
ソースコードも全部公開しています。Firebaseの設定ファイルはコミットしていないので欲しい方いらっしゃれば個別に連絡ください。
なぜ作ったのか
本の著者と読者のコミュニケーションはあまりに一方通行 なのが気になっていた。ウェブサービスだと、サービスプロバイダとユーザは双方向のコミュニケーションが当然のように行なうことができ、もしサービスにバグがあれば、サービスプロバイダは速攻で修正し修正版をユーザにすぐに届けることが可能だ。ところが、「本」に関しては、本を読んだ感想だったり疑問に思ったことを読者が著者にフィードバックする方法が特にないし、もし本に誤りがあった場合、それを読者に届けるには買い直してもらう必要がある。たしかに、電子書籍であれば修正版をすぐに届けることは可能だが、コミュニケーションはそれでも一方通行だ。 思うことをコメントしてそれを他のユーザが読めたり、著者が簡単にフィードバックを得る場があればいいな と思ったので作ることにした。
少し前までは本を書くのは素人には難しかったが、今なら誰でも簡単に書くことができるようになってきた。もちろん紙の本は今でもそう簡単ではないが、電子書籍であれば誰でも出版可能だ。まだまだ電子書籍を出すのも一部の人に限られているが、もっと増えてくればいいと思い、それに合わせたリーダーも作れればいいと思っている。
なぜPDFにしたのか
電子書籍のデファイアントスタンダードの形式はPDFではなく、 ePub である。iOSのePubリーダーを出しているOSSもあり、それを採用するつもりで、実はこのOSSにコメント機能を実装してPRも出したりもしたのだが、ePub描画はWebviewでゴリゴリ実装する必要があったり、機能要件を考慮するとこのePubのOSSを流用するのではなく0から作る必要がありそうだったり、PDFならiOS標準でビューワーが提供されている、といった理由から一旦PDFで出してみることにした。
どう実装しているのか
アプリ側のアーキテクチャ
アプリはSwiftでMVVM (Model・View・ViewModel)で書いたつもり。View(ViewController)は描画やユーザからの入力だけを意識しており、Viewに1対1対応でViewModelも作った。ViewModelにはModelを整形したり、そのViewに依存するModelの処理を書き、Modelはデータベースの利用を表現している。
サーバレスなバックエンド
バックエンドの実装にはFirebaseを最大限利用した。
- Firebase Authentication
- 匿名ログインを利用している
- Firebase Cloud Messaging
- プッシュ通知用のトークンを取得する
- Cloud Firestore
- データベースにFirestoreを採用した
- データ更新があった時にリアルタイムでViewの更新ができる
- データベースアクセスをサーバレスで実現できる
- Cloud Functions
- 認証周りやデータベースアクセスは以外の部分を担う
- データベースの更新があった時にプッシュ通知を送るなど
- Cloud Storage
- ユーザのプロフィール画像やPDFデータを格納している
- 匿名ログインしていないとアクセスができないようにしている
- Firebase Analytics
- Firebase Crashlytics
Firestoreの利用にはPringというモデルフレームワークを利用した。これを使うとModelを定義して、そのまま model.save
をするとFirestoreにいい感じにオブジェクトが保存される。また、リレーションシップにも対応しているのでモデル間の関係性も表現できる。Firestoreはクエリ検索が貧弱なので、データ構造はViewに依存する形にしている。
Firebaseまわりで完全にバックエンドを作っているサービスはまだ少なく、情報が少ないのでFirestoreまわりで結構苦戦した。このアプリのリポジトリは公開しているので是非参考にしていただけると嬉しい(間違いも指摘していただけるとなお嬉しいです)。
アプリ間のやりとり
他のアプリでPDFを開いている時に、シェアアクションの中からこのアプリを選択して保存しておく、だったりアプリを起動して読む、ということも実装しようとした。結論から言えばShareExtensionで前者は実装したが、後者は具体的な方法がわからず未実装になっている。
まとめ
ePubに対応する、PDFの更新に対応する、他のアプリがいい感じで起動する、といった機能は未実装なので今後実装していきたい。もし手伝ってくれる方がいらっしゃればぜひ手伝ってください🙇♂️。