Unityから Firebase Functions を使う - UnityでSDKなしでFirebaseを使う
サーバー側で何か処理させたい場合にAPIを作成しますが、FirebaseではFunctionsというAPIを簡単に作成できる機能があります。FunctionsにはSDK向けのonCall
とより一般的なAPIを作成するonRequest
という2つの関数があるのでそれらの違いと使い方について解説します。
この投稿はUnityでSDKなしでFirebaseを使うの一部です。
途中で出てくるソースコードの全体は以下にあります。
Firebase側:
Unity側:
onCallとonRequestの違い
functions.https.onCall
はFirebase SDK向けのFunctionでFirebase、SDK両方で連携して認証などを行ってくれるので、SKDの利用者はFunctionsを安全で簡単に利用する事ができます。
また、onCallはプロトコル仕様が公開されているのでクライアント側を自分で実装することでSDK以外からも呼び出すことができます。
functions.https.onRequest
はより一般的なWebAPIを作成するFunctionでFirebase SDKからは呼び出せないもののhttpが使えるクライアントであれば環境を選ばず使用することができます。また、onCallはPOSTメソッドしか作成できないためRESTfulなAPIを作成する場合はonRequestを使用する必要があります。欠点としてonCallで自動的に行ってくれていた認証などは自前で実装する必要があります。
まとめると以下の通りです。
次の項では実際の実装方法について解説していきますが、Unity SDKからFunctionsを呼び出す方法は公式ドキュメントやネット上に様々な紹介記事があるので省略します。
Functionsを利用する準備
Firebasseプロジェクト作成とFirebasseローカル開発環境作成を実施します。
また、前述の通りonCallは認証が必要なので、いずれかの方法で認証を行ってidTokenが取得できるようにおく必要があります。
Firebasseローカル開発環境のfunctionsフォルダ配下に後述するFunctions用のtsファイルを作成して プロジェクトのルードディレクトリ(functionsフォルダの一つ上のフォルダ)でfirebase deploy --only functions
コマンドを実行することでAPIを作成することができます。
またAPIのエンドポイントのURLはFirebaseのWebの管理画面のサイドメニューのFunctionsから確認することができます。
SDKを使わずonCallのFunctionを呼び出す
サンプルとしてメッセージを送ると「!」をつけてメッセージを返してくるstrongEchoOnCall
APIを作成しUnityから呼び出す方法を解説します。
Firebasse Functions側
Firebaseのローカル開発環境のfunctions/src配下のtsファイルににAPIを実装します。
index.tsにAPIの処理内容を直接書くこともできますが、複数のAPIを作る際にはindex.tsに全てのエンドポイントを書く必要があるので、コードの見通しをよくするため、処理本体は別のファイルにhandlerとして実装してindex.tsではhandlerを呼び出すだけにします。
import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
const strongEchoOnCall = require("./handlers/strong-echo-on-call");
admin.initializeApp();
exports.strongEchoOnCall = functions
.region("asia-northeast1").https.onCall(strongEchoOnCall.handler);
前述の通りonCallの場合は認証部分は自分で実装する必要がないので、受け取ったリクエスト中からmessageプロパティからメッセージを取り出して!
を付けた文字列をechoMessageとして返す処理を実装します。
import {CallableContext} from "firebase-functions/lib/providers/https";
exports.handler = (requestData: any, context: CallableContext) => {
if (context.auth) { // 認証済みであれば認証情報がcontext内に存在する
return {echoMessage: requestData.message + "!"};
} else {
return {errorMessage: "auth error"};
}
};
onCallのhandlerの実装のポイントは以下の2点です。
- requestDataにクライアントが送ってきたjsonが渡ってくる
- returnでクライアントに送り返すjsonを返す
実装でできたらfirebase deploy --only functions
でデプロイします。
Unity側
Unity側ではメッセージを送って、帰ってきたエコーメッセージをログに出力する処理を実装をします。
url
はFirebaseのWeb管理画面のFuncitonsから確認できます。
idToken
はこの投稿を参考に取得してください。
void StrongEchoOnCall()
{
var url = "https://asia-northeast1-[プロジェクトID].cloudfunctions.net/strongEchoOnCall";
var idToken = "****";
WebClient wc = new WebClient();
wc.Headers[HttpRequestHeader.ContentType] = "application/json";
wc.Headers[HttpRequestHeader.Authorization] = $"Bearer {idToken}";
var requestJson = new StrongEchoOnCallRequest("おはようございます").ToJson();
var responseJson = wc.UploadString(new Uri(url), requestJson);
var response = JsonUtility.FromJson<StrongEchoOnCallResponse>(responseJson);
Debug.Log(response.result.echoMessage);
}
// 以下Jsonの変換用クラス
[Serializable]
class StrongEchoOnCallRequest
{
public StrongEchoOnCallRequestData data;
public StrongEchoOnCallRequest(string message)
{
this.data = new StrongEchoOnCallRequestData(message);
}
public String ToJson()
{
return JsonUtility.ToJson(this);
}
}
[Serializable]
class StrongEchoOnCallRequestData
{
public string message;
public StrongEchoOnCallRequestData(string message)
{
this.message = message;
}
public String ToJson()
{
return JsonUtility.ToJson(this);
}
}
[Serializable]
class StrongEchoOnCallResponse
{
public StrongEchoOnCallResponseResult result;
public static StrongEchoOnCallResponse FromJson(string json)
{
return JsonUtility.FromJson<StrongEchoOnCallResponse>(json);
}
}
[Serializable]
class StrongEchoOnCallResponseResult
{
public string echoMessage;
}
Unity側の実装のポイントは以下の3点です
- 認証に使うidTokenはAuthorizationヘッダーに設定する
- リクエストはFunctionsに送りたい情報をjsonの
data
プロパティーの値にする - レスポンスはFunctionsから受け取りたい情報をjsonの
result
プロパティーの値にする
SDKを使わずonRequestのFunctionを呼び出す
onCallの場合と同様にメッセージを送ると「!」をつけてメッセージを返してくるstrongEchoOnCallAPIを作成しUnityから呼び出す方法を解説します。
Firebasse Functions側
index.tsの実装方針についてはonCallと同様です。
import * as functions from "firebase-functions";
import * as express from "express";
import * as admin from "firebase-admin";
const strongEchoOnRequest = require("./handlers/strong-echo-on-request");
admin.initializeApp();
const expressApp = express();
expressApp.post("/", strongEchoOnRequest.handler);
exports.strongEchoOnRequest = functions
.region("asia-northeast1").https.onRequest(expressApp);
以下がhandlerの実装です。
前述の通りonRequestは自動的に認証されないため、もし認証が必要な場合は何らかの方法で認証の処理を行います。今回のサンプルではクライアントからのリクエストにidTokenを含めてもらいadmin.auth().verifyIdToken()
を使って認証しています。
認証が不要なAPIの場合はres.status(200).json({echoMessage: strongEcho});
の部分だけ実装すれば良いです。
import * as express from "express";
import * as admin from "firebase-admin";
exports.handler = async (req: express.Request, res: express.Response) => {
admin
.auth().verifyIdToken(req.body.idToken).then((decodedIdToken) => {
console.log("uid: ", decodedIdToken.uid);
const strongEcho = req.body.message + "!";
res.status(200).json({echoMessage: strongEcho});
}).catch((error) => {
console.log("error: ", error);
res.status(400).json({message: "auth error"});
});
};
onRequestのhandlerの実装のポイントは以下の2点です。
- req.bodyにクライアントが送ってきたjsonが渡ってくる
- クライアントへのレスポンスはresにstatusとjsonで設定する
実装でできたらfirebase deploy --only functions
でデプロイします。
Unity側
Unity側ではメッセージを送って、帰ってきたエコーメッセージをログに出力する処理を実装をします。
url
とidToken
についてはonCallと同様です。
Unity側ではonCallと違いonRequestはより一般的なAPIを扱うためdataやreulstに包まずに送受信したいjsonを直接扱います。
void StrongEchoOnRequest()
{
var url = "https://asia-northeast1-[プロジェクトID].cloudfunctions.net/strongEchoOnCall";
var idToken = "****";
WebClient wc = new WebClient();
wc.Headers[HttpRequestHeader.ContentType] = "application/json";
var requestJson = new StrongEchoOnRequestRequest("おはようございます", idToken).ToJson();
var responseJson = wc.UploadString(new Uri(url), requestJson);
var response = JsonUtility.FromJson<StrongEchoOnRequestResponse>(responseJson);
Debug.Log(response.echoMessage);
}
// 以下Jsonの変換用クラス
[Serializable]
class StrongEchoOnRequestRequest
{
public string message;
public string idToken;
public StrongEchoOnRequestRequest(string message, string idToken)
{
this.message = message;
this.idToken = idToken;
}
public String ToJson()
{
return JsonUtility.ToJson(this);
}
}
[Serializable]
class StrongEchoOnRequestResponse
{
public string echoMessage;
public static StrongEchoOnRequestResponse FromJson(string json)
{
return JsonUtility.FromJson<StrongEchoOnRequestResponse>(json);
}
}
参考
Discussion