「Unity/Firebase/CloudFunctions」の版間の差分
提供: 初心者エンジニアの簡易メモ
(→"The type initializer for 'Firebase.FirebaseApp' threw an exception."エラー) |
|||
| (同じ利用者による、間の25版が非表示) | |||
| 行17: | 行17: | ||
==サンプル== | ==サンプル== | ||
<pre> | <pre> | ||
| − | + | ScorePostInit score = new ScorePostInit(); | |
AddScore(score); | AddScore(score); | ||
| − | + | GetTopScores(); | |
</pre> | </pre> | ||
<pre> | <pre> | ||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||
| − | class | + | using System; // [Serializable]用 |
| − | public string | + | public class ScorePostInit { |
| − | public int | + | public string userName = "taro"; |
| − | public string | + | public int point = 100; |
| + | public string userId = "12341234"; | ||
} | } | ||
| − | async Task<object> AddScoreAsync( | + | async Task<object> AddScoreAsync(ScorePostInit score) |
{ | { | ||
object data = new Dictionary<object, object> | object data = new Dictionary<object, object> | ||
{ | { | ||
| − | { " | + | { "userName", score.userName }, |
| − | { "point", score. | + | { "point", score.point }, |
| − | { " | + | { "userId", score.userId }, |
}; | }; | ||
return await functions.GetHttpsCallable("addScore").CallAsync(data) | return await functions.GetHttpsCallable("addScore").CallAsync(data) | ||
| 行42: | 行43: | ||
}); | }); | ||
} | } | ||
| − | void AddScore( | + | public void AddScore(ScorePostInit score) |
{ | { | ||
AddScoreAsync(score).ContinueWith(task => | AddScoreAsync(score).ContinueWith(task => | ||
| 行57: | 行58: | ||
}, TaskScheduler.FromCurrentSynchronizationContext()); | }, TaskScheduler.FromCurrentSynchronizationContext()); | ||
} | } | ||
| + | async Task<object> ReplaceScoreByUserIdAsync(ScorePostInit score, string userId) | ||
| + | { | ||
| + | object data = new Dictionary<object, object> | ||
| + | { | ||
| + | { "userName", score.userName }, | ||
| + | { "userId", userId }, | ||
| + | { "point", score.point }, | ||
| + | }; | ||
| + | return await functions.GetHttpsCallable("replaceScore").CallAsync(data) | ||
| + | .ContinueWith(task => | ||
| + | { | ||
| + | return task.Result.Data; | ||
| + | }); | ||
| + | } | ||
| + | public void ReplaceScoreByUserId(ScorePostInit score, string userId) | ||
| + | { | ||
| + | ReplaceScoreByUserIdAsync(score, userId).ContinueWith(task => | ||
| + | { | ||
| + | if (task.IsFaulted) | ||
| + | { | ||
| + | // onError | ||
| + | } | ||
| + | else | ||
| + | { | ||
| + | // onComplete | ||
| + | Debug.Log("task.Result=" + task.Result); // OK | ||
| + | } | ||
| + | }, TaskScheduler.FromCurrentSynchronizationContext()); | ||
| + | } | ||
[Serializable] | [Serializable] | ||
class ResData | class ResData | ||
| 行69: | 行99: | ||
{ | { | ||
public int point = 0; | public int point = 0; | ||
| − | public string | + | public string userName = ""; |
| + | public string userId = ""; | ||
} | } | ||
| − | async Task<object> | + | async Task<object> GetTopScoresAsync() |
{ | { | ||
object data = new Dictionary<object, object> | object data = new Dictionary<object, object> | ||
| 行77: | 行108: | ||
{ "count", 3 }, | { "count", 3 }, | ||
}; | }; | ||
| − | return await functions.GetHttpsCallable(" | + | return await functions.GetHttpsCallable("getTopScores").CallAsync(data) |
.ContinueWith(task => | .ContinueWith(task => | ||
{ | { | ||
| 行83: | 行114: | ||
}); | }); | ||
} | } | ||
| − | void | + | public void GetTopScores() |
{ | { | ||
| − | + | GetTopScoresAsync().ContinueWith(task => | |
{ | { | ||
if (task.IsFaulted) | if (task.IsFaulted) | ||
| 行101: | 行132: | ||
foreach (ResUser user in resData.users) | foreach (ResUser user in resData.users) | ||
{ | { | ||
| − | Debug.Log("user.name=" + user. | + | Debug.Log("user.name=" + user.userName); |
| + | Debug.Log("user.id=" + user.userId); | ||
Debug.Log("user.point=" + user.point); | Debug.Log("user.point=" + user.point); | ||
} | } | ||
| + | } | ||
| + | }, TaskScheduler.FromCurrentSynchronizationContext()); | ||
| + | } | ||
| + | async Task<object> ReplaceUserNameByUserIdAsync(string userName, string userId) | ||
| + | { | ||
| + | object data = new Dictionary<object, object> | ||
| + | { | ||
| + | { "name", userName }, | ||
| + | { "id", userId }, | ||
| + | }; | ||
| + | return await functions.GetHttpsCallable("replaceUserNameByUserId").CallAsync(data) | ||
| + | .ContinueWith(task => | ||
| + | { | ||
| + | return task.Result.Data; | ||
| + | }); | ||
| + | } | ||
| + | public void ReplaceUserNameByUserId(string userName, string userId) | ||
| + | { | ||
| + | ReplaceUserNameByUserIdAsync(userName, userId).ContinueWith(task => | ||
| + | { | ||
| + | if (task.IsFaulted) | ||
| + | { | ||
| + | // onError | ||
| + | } | ||
| + | else | ||
| + | { | ||
| + | // onComplete | ||
| + | Debug.Log("task.Result=" + task.Result); // OK | ||
} | } | ||
}, TaskScheduler.FromCurrentSynchronizationContext()); | }, TaskScheduler.FromCurrentSynchronizationContext()); | ||
| 行116: | 行176: | ||
const admin = require('firebase-admin'); | const admin = require('firebase-admin'); | ||
admin.initializeApp(); | admin.initializeApp(); | ||
| − | // | + | // スコア追加 |
exports.addScore = functions | exports.addScore = functions | ||
.region('asia-northeast1') | .region('asia-northeast1') | ||
| 行122: | 行182: | ||
{ | { | ||
const score = { | const score = { | ||
| − | + | userName : data.userName, | |
| − | point : data.point | + | point : data.point, |
| + | userId : data.userId | ||
}; | }; | ||
return admin.firestore().collection('scores') | return admin.firestore().collection('scores') | ||
| 行132: | 行193: | ||
}); | }); | ||
}); | }); | ||
| − | // | + | // スコア更新 |
exports.replaceScore = functions | exports.replaceScore = functions | ||
.region('asia-northeast1') | .region('asia-northeast1') | ||
| 行140: | 行201: | ||
point : data.point | point : data.point | ||
}; | }; | ||
| + | if (data.userName != null) { | ||
| + | score.userName = data.userName; | ||
| + | } | ||
| + | if (data.userId != null) { | ||
| + | score.userId = data.userId; | ||
| + | } | ||
| + | console.log('data.userId=' + data.userId); | ||
return admin.firestore().collection('scores') | return admin.firestore().collection('scores') | ||
| − | .doc(data. | + | .doc(data.userId).set(score) |
.then((snapshot) => | .then((snapshot) => | ||
{ | { | ||
| 行148: | 行216: | ||
}); | }); | ||
// トップcount件のScoreを取得 | // トップcount件のScoreを取得 | ||
| − | exports. | + | exports.getTopScores = functions |
.region('asia-northeast1') | .region('asia-northeast1') | ||
.https.onCall((data, context) => | .https.onCall((data, context) => | ||
| 行168: | 行236: | ||
}); | }); | ||
}); | }); | ||
| + | // ユーザ更新 | ||
| + | exports.replaceUserNameByUserId = functions.region('asia-northeast1').https.onCall((data, context) => { | ||
| + | const user = { | ||
| + | name : data.name, | ||
| + | }; | ||
| + | if (data.id != null) { | ||
| + | user.id = data.id; | ||
| + | } | ||
| + | return admin.firestore().collection('users') | ||
| + | .doc(data.id).set(user) | ||
| + | .then((snapshot) => | ||
| + | { | ||
| + | return 'OK'; | ||
| + | }); | ||
| + | }) | ||
</pre> | </pre> | ||
| + | |||
| + | =="The type initializer for 'Firebase.FirebaseApp' threw an exception."エラー == | ||
| + | 2018.4.8f1から2019.2.12f1に更新すると以下エラーが起こったが、functionsを最新にすると治った。 | ||
| + | Rethrow as TypeInitializationException: The type initializer for 'Firebase.FirebaseApp' threw an exception. | ||
==参考== | ==参考== | ||
2020年2月6日 (木) 21:04時点における最新版
目次
準備
Gcp/Firebase/CloudFunctions [ショートカット]
準備(dbを使う場合)
Gcp/Firebase/Firestore [ショートカット]
import
FirebaseFunctions.unitypackage をunityのAssets/ImportPackage/CustomPackageからImportする
初期化
using Firebase.Functions; FirebaseFunctions functions = FirebaseFunctions.DefaultInstance;
東京リージョンの場合こちらを記述
using Firebase.Functions;
FirebaseFunctions functions = FirebaseFunctions.GetInstance("asia-northeast1");
サンプル
ScorePostInit score = new ScorePostInit(); AddScore(score); GetTopScores();
using System.Threading.Tasks;
using System; // [Serializable]用
public class ScorePostInit {
public string userName = "taro";
public int point = 100;
public string userId = "12341234";
}
async Task<object> AddScoreAsync(ScorePostInit score)
{
object data = new Dictionary<object, object>
{
{ "userName", score.userName },
{ "point", score.point },
{ "userId", score.userId },
};
return await functions.GetHttpsCallable("addScore").CallAsync(data)
.ContinueWith(task =>
{
return task.Result.Data;
});
}
public void AddScore(ScorePostInit score)
{
AddScoreAsync(score).ContinueWith(task =>
{
if (task.IsFaulted)
{
// onError
}
else
{
// onComplete
Debug.Log("task.Result=" + task.Result); // OK
}
}, TaskScheduler.FromCurrentSynchronizationContext());
}
async Task<object> ReplaceScoreByUserIdAsync(ScorePostInit score, string userId)
{
object data = new Dictionary<object, object>
{
{ "userName", score.userName },
{ "userId", userId },
{ "point", score.point },
};
return await functions.GetHttpsCallable("replaceScore").CallAsync(data)
.ContinueWith(task =>
{
return task.Result.Data;
});
}
public void ReplaceScoreByUserId(ScorePostInit score, string userId)
{
ReplaceScoreByUserIdAsync(score, userId).ContinueWith(task =>
{
if (task.IsFaulted)
{
// onError
}
else
{
// onComplete
Debug.Log("task.Result=" + task.Result); // OK
}
}, TaskScheduler.FromCurrentSynchronizationContext());
}
[Serializable]
class ResData
{
public string status = "ok";
public string notice = "";
public List<ResUser> users;
}
[Serializable]
class ResUser
{
public int point = 0;
public string userName = "";
public string userId = "";
}
async Task<object> GetTopScoresAsync()
{
object data = new Dictionary<object, object>
{
{ "count", 3 },
};
return await functions.GetHttpsCallable("getTopScores").CallAsync(data)
.ContinueWith(task =>
{
return task.Result.Data;
});
}
public void GetTopScores()
{
GetTopScoresAsync().ContinueWith(task =>
{
if (task.IsFaulted)
{
// onError
}
else
{
// onComplete
string json = task.Result.ToString();
Debug.Log("json=" + json); // {"status":"ok","notice":"","users":[{"point":140,"name":"siro"},{"point":130,"name":"saburo"},{"point":120,"name":"jiro"}]}
ResData resData = JsonUtility.FromJson<ResData>(json);
Debug.Log("status=" + resData.status);
Debug.Log("notice=" + resData.notice);
foreach (ResUser user in resData.users)
{
Debug.Log("user.name=" + user.userName);
Debug.Log("user.id=" + user.userId);
Debug.Log("user.point=" + user.point);
}
}
}, TaskScheduler.FromCurrentSynchronizationContext());
}
async Task<object> ReplaceUserNameByUserIdAsync(string userName, string userId)
{
object data = new Dictionary<object, object>
{
{ "name", userName },
{ "id", userId },
};
return await functions.GetHttpsCallable("replaceUserNameByUserId").CallAsync(data)
.ContinueWith(task =>
{
return task.Result.Data;
});
}
public void ReplaceUserNameByUserId(string userName, string userId)
{
ReplaceUserNameByUserIdAsync(userName, userId).ContinueWith(task =>
{
if (task.IsFaulted)
{
// onError
}
else
{
// onComplete
Debug.Log("task.Result=" + task.Result); // OK
}
}, TaskScheduler.FromCurrentSynchronizationContext());
}
firebaseのサーバー側変更
functions.https.onCall を使ってシリアル&認証トークンで接続するようにする
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
// スコア追加
exports.addScore = functions
.region('asia-northeast1')
.https.onCall((data, context) =>
{
const score = {
userName : data.userName,
point : data.point,
userId : data.userId
};
return admin.firestore().collection('scores')
.add(score)
.then((snapshot) =>
{
return 'OK';
});
});
// スコア更新
exports.replaceScore = functions
.region('asia-northeast1')
.https.onCall((data, context) =>
{
const score = {
point : data.point
};
if (data.userName != null) {
score.userName = data.userName;
}
if (data.userId != null) {
score.userId = data.userId;
}
console.log('data.userId=' + data.userId);
return admin.firestore().collection('scores')
.doc(data.userId).set(score)
.then((snapshot) =>
{
return 'OK';
});
});
// トップcount件のScoreを取得
exports.getTopScores = functions
.region('asia-northeast1')
.https.onCall((data, context) =>
{
const count = data.count;
return admin.firestore().collection('scores')
.orderBy('point', 'desc')
.limit(count)
.get()
.then((snapshot) =>
{
var obj = {
status: 'ok',
notice: 'Processing succeeded.',
users: snapshot.docs.map(x => x.data()),
}
var json=JSON.stringify(obj);
return json;
});
});
// ユーザ更新
exports.replaceUserNameByUserId = functions.region('asia-northeast1').https.onCall((data, context) => {
const user = {
name : data.name,
};
if (data.id != null) {
user.id = data.id;
}
return admin.firestore().collection('users')
.doc(data.id).set(user)
.then((snapshot) =>
{
return 'OK';
});
})
"The type initializer for 'Firebase.FirebaseApp' threw an exception."エラー
2018.4.8f1から2019.2.12f1に更新すると以下エラーが起こったが、functionsを最新にすると治った。
Rethrow as TypeInitializationException: The type initializer for 'Firebase.FirebaseApp' threw an exception.
参考
https://firebase.google.com/docs/functions/callable?hl=ja
https://devlog.hassaku.blue/2019/03/unity-firebase-firebase.html
https://firebase.google.com/docs/reference/unity/class/firebase/functions/firebase-functions
