SwiftUIを使ってリモートでの孤独感を埋めるアプリの0→1開発
プロジェクトの詳細
話したい人とすぐ話せるアプリStayONの開発 https://prtimes.jp/main/html/rd/p/000000012.000049339.html
使用技術
- Firebase:
- RealtimeDatabase
- Firestore
- Auth
- Cloud Messaging
- Analytics
- Crashlytics
- Extensions
- AppCheck
- Performance Monitoring
- バックエンド
- Firebase CloudFunction
- クライアント
- SwiftUI
- 通話、画面共有
- Agora
- 管理データ操作
- FirebaseAdminSDK
参加期間
- 2021年11月〜2022年11月
開発規模
- 5人 アバター画面担当エンジニアが別途ひとり参加でそれ以外の部分を担当
プロジェクトでの課題
技術者がいない状態でメタバースに絡めたコミュニケーションアプリの実現とアプリのアイデアを考える。
主な取り組み
- アイデアからプロダクト決め
- 検証(Discord運用・Bot導入・調査)
- アプリ開発
- SNS運用(宣伝)
- アプリの審査・デプロイ
- 2Dアイコンの作成プレゼン資料作成
- アップデート文のGithub Discussion管理
アイデアと検証
このプロダクトを作るきっかけは、コロナ禍で人とのコミュニケーションがオンラインになるなかで起きた課題をメタバースで解決できるのではないかと考えたのが始まりです。
メタバースを体験する中で一番課題に感じていたことは、アバターや世界それ自体がよりも如何にコミュニケーションをとりやすくするかだという点でした。まずは身近でない人とのコミュニケーションをもっと楽に、偏見を持たず気軽に話せる必要があると考え、課題の定義とその課題をどうすれば解決できそうかの検証をしました。
いきなりアプリを作り始めるのではなく、まずは小さいコミュニティで検証しながら進めていくことにし、Discordでのサーバー運営を始めました。Discordを選択した理由としては、ゲームと親和性が高かったこと、チャットや通話などサービスを運営する際のプラットフォームとして近い形で検証できると考えたためです。
サーバー運営には他の運営サーバーの構成を参考にして自分のサーバーに適用しながら雛形を決め集客を行いました。話す目的を「趣味やゲーム」に設定し、同じゲームをやっている人や同じ趣味を持つ人たちが沢山集まれる場所を用意しました。
集まった方に話を聞いていると実は話したいと思って参加したけど話せない人が何人かいたため、コミュニケーションにおける当初の課題は各々感じている問題なのだと考えていました。
また、人が増えるにつれコミュニケーション問題への解決に少しでも繋がるかと思い、SpeechToTextを使って文字起こしを行ったり、リアクションロールや自動返信Botを導入しました。 検証した際の結果がどう変わったか分かりづらかったため、サーバーのメトリクスを取るBotを入れることで確認できるようにしていました。
【わかったことと課題】
チャットは動くが通話はあまり動かないということがわかりました。なぜ通話が動かないのか、メタバースにおいても重要な要素だと考えていたため、通話の課題を深掘りをしました。
一番の課題は自分が「最初の一人目」になることが参加しずらい原因と考えました。そのため、自分がまずは先陣を切り、通話に参加してみました。初めは一人でしたが、ずっといると気になった人が入ってきてくれるという状況が作れました。
次に DiscordではなくSpacialChatを使った検証をしました。同じ部屋で近づくと話せる状態で会話の可視化ができ、他の人に近づいて話したり離れて違う人と話したりとリアルな会話を体験できました。 そして、それらの結果から以下のようにアプリの概要や機能の草案を作成しました。
- アプリを開けばすぐ話せる状態で参加
- 近くに行くと声が聞こえる体験をアプリでできるようにする
- 1グループ6人で他の会話も聞きながら会話ができるようにする
そしてその実現に必要な機能を話し合いながらアプリの作成を始めました。
アプリケーション開発
チームで相談し、SwiftUIを採用することに決めました。アプリ開発は初めてで、本を一冊を終えただけでは知識不足でしたが、一通りSwiftUIの使い方を学べたため実装しながら技術を身につけていくことができました。
インフラやサーバーをゼロから立てると時間がかかり、できる限りスピーディーにアプリを仕上げるため全てが1つでできるFirebaseを使用しました。一人で開発することを加味するとあまり時間をかけるよりも形にする方が大事だと判断しました。 FirebaseではEmulatorを使うことで本番環境と開発環境を切り替えて動作確認できるようにしました。
タスク管理はGithub Projectを使用しました。Githubでタスク管理するとissue、 PRの紐づけやタスク管理が簡単にでき、開発タスクが頻繁に変わる中でRedmineやBacklogなどのチケットツールよりスイッチングコストが低いと考えたためです。Webhookを設定し、社内のDiscordに変更や修正点の通知を送り確認できるようにしています。
通話および画面共有のライブラリとしてAgoraを採用しました。採用理由は、Twilioやその他のライブラリと比較して豊富なサンプルコードやチュートリアルがあること、画面共有機能など拡張性も高いことです。また、ClubhouseでもAgoraが採用されており参考にできると考えたのも理由の1つです。
通話に必要なトークンを生成するサーバーは公式のサンプルをコードに落としてGoとHerokuで作成しました。Herokuはサーバーへのデプロイが簡単でトークンを返すサーバーと簡素な機能で足りたため採用しました。
【実装した機能】
-
チャンネル機能
チャンネル機能ではユーザーがアプリを開いた時に、参加して通話ができる機能として実装しました。RealtimeDatabaseを使用してプレゼンス確認をトリガーにして、CloudFunctionのバックグラウンド関数でFirestoreのユーザードキュメントを更新し、オンライン状態を管理しました。アプリを開いているオンラインのユーザーをチャンネル内に表示することで、今話せるユーザーは誰なのかがわかるようになりました。
話すのが苦手な人のために通話だけでなく、投稿したつぶやきをアイコンの上に表示することで通話しながら、今いる人達がチャット同士として話せるようにしました。
-
タイムライン機能
つぶやき投稿の返信時、ドキュメントの返信数をインクリメントするバックグラウンド関数を設定しました。その関数内で返信時に返信されたユーザーのfcmTokenを取得しプッシュ通知を送れるようにしました。返信したユーザーの一覧がアイコンで見えるようにするため、ドキュメントにユーザーのアイコンをハードコーディングすることで毎度読み取らずに1つのドキュメントで表示できるようにしました。タイムラインではその世界のログが掲示板になっているイメージで作成しました。
-
ログイン、ログアウト機能(SignInWithApple使用)
ログイン後ユーザー情報をリアルタイム取得し、取得したデータをViewからアクセスできるようにFirebaseFirestoreSwiftパッケージを使用してユーザー構造体に変換し使いました。 退会機能はFirebaseのドキュメントにはなかった為、Flutter用に書かれていた退会処理をCloudFunctionで書き直しクライアントからリクエスト出来るようにしています。
-
通話機能
AgoraのサンプルコードやExampleプロジェクトを試していたため、通話機能に必要な機能は比較的容易に実装できました。 通話をグループごとに分けるため、Agoraから生成される部屋IDや話者をFirebaseのドキュメントに登録し、通話に参加する側が参加している通話部屋の情報を取得してグループ通話を実装しました。 実装する際、Xcodeで定義されている処理がサジェストで表示されるため、Agoraの通話機能に適した処理で使えそうなdelegateメソッドがあればドキュメントで仕様を調べAgoraの機能でできないかを調べました。 通話に参加したイベントなどはアプリ側の実装ではなく、delegateメソッドで検出するなど無駄なコードを書かずに開発できるように心がけました。
【リリースにあたって】
-
デザインのリニューアル
デザイナーと元のデザインをリニューアルしながら、合わせて実装のブラッシュアップも並行して行いました。設計から見直す必要があったりリリース期限も2ヶ月と決められていましたが、初期時より実装力が少しついてきていたためスピード感を持って作ることができました。どうしても開発タスクがかさみ間に合わない場合は、タスクの優先度を決め期限に間に合うことができました。
-
Firebaseのルール作成、AppCheckによるセキュリティ強化
誰でもリクエストできてしまうため、Firestoreのルールを作成して登録できる人、情報を制限しました。ルール内ではScheme検証、許可するパラメーターのバリデーションをかける関数を作成し、リクエストされるパラメータの検証をしました。 Firestoreのルールはどの部分でエラーになるのか詳細が出ないため、実装時にデバッグがしづらく苦労しましたが、適宜ルールを緩くしたり厳しくしたりしながら差分を確認して原因を特定しながらルールを作成しました。これにより、今も未検証なリクエストは全て弾かれていてセキュリティを万全にできています。
-
アプリの審査・デプロイ
審査ではAnalyticsのトラッキングの許可モーダルを出していないこと、タイムラインでユーザーのコンテンツをフィルター機能実装、退会機能がないなどさまざまな理由でリジェクトされたため修正しました。
-
リリース
リリースの間隔を細かくし、バグや新規開発など常にアップデートしていく必要もあり、他の部分の修正対応でパッチが出せない状況にならないように気をつけました。
-
画面共有機能
通話中アバターでできることが少なく暇になってしまうことが課題で、画面共有ができると表現の幅が広がると考えAgoraのライブラリを使用して導入しました。共有ができることによって、通話時間が格段に伸びていました。
-
Twitterのアカウント運用
アプリの使い方を説明した画像を作成して紹介したり、アップデートの通知や取り止めもないつぶやきをしたりしながらアプリを露出するタイミングを増やせるようにしました。 ユーザーに知ってもらえる機会が増え、StayONの登録ユーザーも増えました。
改善点と結果
開発側の意見しか取り入れてなかった為、ユーザーに何の説明もなく始まる点が使いにくいとのレビューを頂きました。その為、躓く点や使いにくい点などアプリ利用者にインタビューし、フィードバックをもらった上で出た課題やユーザーの動向をmiroを使い、チームで整理しました。
新規登録するといきなりホーム画面に遷移してしまうため、オンボーディングページを作成してユーザーのセットアップ画面を作成しました。 この機能を追加したことによってユーザーから「使いやすい」との声を頂きました。
また、アニメーションを設定し画面の切り替えを実装しました。画面の切り替えは遷移ビューでは行わず、sectionの番号を保持してswitchでviewを出し分けることでオンボーディングページを切り替えました。そうすることで、StayONの世界観を表現し、入り込めるようにしました。
初めてのアプリ開発で技術者が1人という環境でしたが、自分では安易に始めることのできないアプリ開発に挑戦良かったと考えています。0から1を作っていく上で、アイデアを出したりデザインを形にしていくことの難しさをしり、エンジニアの技術はもちろんのことチームで仕事をする力、自分でどのタスクを優先的に実装しスケジュールを組んでいく力がつきました。