いくつか作りたい2Dゲームがあり地道に制作中。
複数タイトルとなると中長期的には認証周りや汎用的なAPIを先に用意した方が楽なので、その辺りを実装していました。
というわけで、今回はバックエンドとアプリ側(Godot)の連携部分で得た知見を書いていきます。
システム的な概要
まず、配信プラットフォームをWebとiOSの2つに絞ります。2つに絞るのは後述するプラットフォーム毎のネイティブ実装がネックになるため、アプリは最低限1種類をまず作ります。
GodotでWebエクスポートするとHTMLやJS、WASM、アセットなどの静的ファイルが出力されます。つまりCDN配信が可能なので、例えばこのような構成が可能です。

もしゲームのアクセス自体にきめ細かい制御を行いたい場合はNext.jsのpublicディレクトリに配置してサーバーサイド(use serverの層)で判定を追加します。またはNginxのauth_request_moduleを使えばNext.jsとGodotのファイルを物理的に分けるので、そっちの方が見た目は綺麗ですね。
バックエンドの実装は一般的なWebの機能が揃っていれば何でもいいんですが、モダンかつ直近の仕事でもよく扱っているNext.jsにします。
認証はFirebase Authenticationを採用。ただし認証画面はゲーム毎に用意したくないのでWeb側に画面を作ります。すなわちiOS版のゲームでもNext.jsのログイン画面を開いて認証し、ゲームアプリに戻るということです。ここが今回のポイントとなる部分。
認証のあれこれ
前述の構成を実現するためにいくつか検討事項があります。
まずWebの方。Firebaseを使うことは決まったものの、セッションCookieを使うかクライアントサイドのIDトークンを使うか?という2択問題があります。
先ほどの構成の場合、セッションCookieの恩恵はとても大きいです。何故なら一度ログインしてしまえば他のゲームでも認証を維持できるからです。ドメイン同じですからね。しかもJWTと違って明示的にAuthorizationにトークン付与する必要もありません。
デメリットは有効期限が最大2週間で切れることです。リフレッシュのような機能がないので必要なら自前で似たような実装が必要ですが、まあ利点が大きいので問題じゃない気がします。
次にクライアントサイドのIDトークン、つまりFirebaseのSDKを使ってフロント側で認証する方法です。こっちもなかなか魅力的です。実装が楽、リフレッシュも楽、ユーザーの基本情報をSDK経由で取れるので楽。
→しかし、こっちは難しい問題が一つあります。
それはNext.jsのFirebase SDKが管理しているIDトークンやリフレッシュトークンをGodotのゲーム側からどうやって取得するのだろう?という点です。この時点でWeb版ではCookieを使うことが本線になりました。ここは他にも手段がありそうなんですが、話が逸れるので後述。
はい、Web版のGodotアプリはセッションCookieでいけそうです。iOSアプリではどうでしょうか。先ほど書いたように2週間経つと再ログインが必要になり、個人的にそれは結構不快です。特にゲームは横向き表示も十分にありえるので、横→縦→横みたいな変化は避けたいのです。また、ブラウザ(Next.js)でログインした際のCookieの値をアプリ側で保持してHTTPリクエストに乗っけるみたいな実装をあまりしたくありません。Cookieの有効期限をアプリ側で管理しないといけないですし。
よってアプリ版ではクライアントサイドのIDトークンを使うことに決定。
しかし・・・またしても気になる懸念材料が出てきました。ログインやアカウント登録はNext.js側で行うので、アプリ側ではリフレッシュとログアウトだけできれば良いのです。そのためだけにiOSの重たいFirebaseのライブラリを入れるのは適切なんだろうか?という問いです。今後ゲームを複数作るならそのアプリに全て入れていかないといけないですし、Androidや他プラットフォームも対応するならそっちも必要です。
当初は汎用的な機能をサクッと作って〜と気楽に考えていましたが、考慮することが増えてきて何だか大きい決断が迫られてしまいました。
結論はこうです。アプリ版ではSDKを使わずにFirebaseに直接HTTPリクエストを実行します。idTokenに有効期限が含まれているので、GDScriptでJWTをパースして期限判定してリフレッシュすれば重たいSDKを入れずに複数プラットフォームにも対応できます。
Web版はセッションCookie、アプリ版はクライアントのIDトークンを使うわけで、バックエンドはそれぞれ2つずつAPIが必要か?いや、それはさすがになし。Next.jsのproxy(旧middleware)で共通化がんばります。
この辺まで一度図にしました。

"ユーザー取得"はフロントのSDK(アプリからは不可)とバックエンドからそれぞれログインユーザーの情報を取れるのであえて2つ記載。ひとまず認証に関する全体のイメージはこんな感じです。
Godot(iOS)とWebのログイン画面を連携
続いて認証の流れ。
GodotではモバイルのWebViewが標準で容易されておらず。今回の要件にマッチするプラグインがあるのか、この辺りの情報があまり見つからずGDExtensionで自作する結論に至ります。Unityだと結構出てくるんですが。広義のWebView(つまりWKWebView)というよりASWebAuthenticationSessionを使いたかったのです。
イメージとしては、
①ゲーム上のログインボタンをタップ
②GDScriptからSwiftコード呼び出し
③ASWebAuthenticationSessionを使ってNext.jsのログイン画面開く
④ログイン
⑤Swiftで特定コールバックURIをハンドリング
⑥Webの画面閉じる
⑦SwiftからGDScriptにURIのパラメータ渡す
という流れになります。
GDScriptからiOSのネイティブAPIを直接呼べないのでSwift Package ManagerでiOS/Mac向けにビルドしたframeworkをGodotプロジェクト上に配置してGDExtensionで連携します。
*.gdextensionファイルの説明はこちら
できたもの
動画はGodotをiOSエクスポートしたアプリをiPhoneに入れたもの。
LOGINボタンタップ→Next.jsのログイン画面→Googleログインボタンタップ→完了したらウィンドウを閉じてアプリ側に戻っています。これでFirebase SDKをアプリ側に入れずに済みました。
この辺りはハマりどころが多く長くなるので、また別の記事で具体的なコードを含め解説したいと思います。
GodotからJavaScriptのFirebaseを(強引に)使う
先ほど話が出た、Next.jsのフロント側で持っているFirebase SDKの認証情報をGodotのWeb版で利用できないか?という件。
実際に動作確認まで出来てないので何とも言えませんが、一応アイディアが2つ。
まず1つ目、GodotでブラウザJavaScriptを書いてGDScriptと連携する方法。GodotのWebエクスポートにはCustom HTML Shellという設定があり、出力するHTMLファイルのテンプレートとなるHTMLを自分で用意することができます。

godot/misc/dist/html/full-size.html at master · godotengine/godot · GitHub
テンプレートは上記リンクにあり、こちらを編集してブラウザJavaScriptのFirebaseをモジュールとして利用すれば、同じオリジンなのでログイン情報を共有できるのでは?という考え。
もう一つの方法は、GodotアプリにNext.js側の画面を表示したiframe(目に見えない小さいサイズ)を追加し、GDScriptからJavaScriptを通してpostMessageでやりとりする方法です。iframeはさっきと同じようにHTMLのテンプレート編集で可能で、JavaScriptもJavaScriptBridgeを通して実行できるので、こっちのが方が実現性は高そう。ただ、機密情報を扱うのでオリジンの設定やデータのやりとりに暗号化するなど工夫が必要です。
この記事を書いていて、AIはこれらの方法を教えてくれるだろうか?と気になりましたが、残念ながらAIは答えてくれませんでした。
iframeのpostMessageはクロスオリジンで使うケースが多いためか、同じオリジンで異なるアプリケーションでやりとりをするという発想にならなかったのかもしれません。まあ単に聞き方が悪いのかも( ´Д`)y━・~~
まとめ
色々長くなってしまいましたが、今後アプリを複数作るにあたって必要なプラットフォーム(土台)を作ることができました。他にも課金やメッセージチャットのような機能を拡充していけたらいいなと夢を見つつ、そろそろ本格的にゲームを作っていこうと思います。
私が小学生の時に流行ったハンゲームに一歩近づけたような気がします。かれこれ20年ちょっと前か・・。