ð¥Firebaseð¥ã§ã²ãŒã å ã«ç°¡æSNSãäœã
ã«ãžã¥ã¢ã«ã²ãŒã ãäœã£ãŠãããšãã®ãç°¡åãªäº€æµèŠçŽ ãå ¥ããããã©ããµãŒããŒãéçšããã®ã¯ã¡ãã£ãšâŠâŠããšããèŠä»¶ã«ã¯mBaaSã䟿å©ã§ãããã®èšäºã§ã¯å æãªãªãŒã¹ãããåè ã27æ³ãç¬èº«ãã®äºäŸãå ã«ãFirebaseã§Unity補ã²ãŒã ã«ç°¡æSNSãå®çŸããæ¹æ³ã玹ä»ããŸãã
ã²ãŒã ã¯ä»¥äžã®ãªã³ã¯ããããŠã³ããŒãã§ããŸãã tavern-ad9b4.firebaseapp.com
- çžè«æ©èœã®çŽ¹ä»
- DBã®éžæ
- ããŒã¿æ§é ã®å®çŸ©
- ãªãã¹ãåçãã€ããŠãªãçžè«ãæ¢ã
- Cloud Functionsã§åŠçãæã
- pushéç¥ãéã
- ãŸãšã
çžè«æ©èœã®çŽ¹ä»
åè ã27æ³ãç¬èº«ã¯é å Žã«ããåè ã®æ©ã¿ãèãã²ãŒã ã§ãããã«ãŠã³ã¿ãŒã®äžã«ããé»ç«ã«è©±ãããããšãã¬ã€ã€èªä¿¡ã®æ©ã¿ãèããŠãããŸãã
ãŸããé£ã«ããçœç«ã¯ä»ã®ãã¬ã€ã€ãæçš¿ããæ©ã¿ãæã£ãŠããŠãããŸãã
å¿åã§ã¡ãã»ãŒãžãæçš¿ãããšèª°ããããè¿ä¿¡ããŠããããããããããã«ã¡ãŒã«ç³»ã®ãµãŒãã¹ã§ããä»æ©ã®ç®ç«ãã人éé¢ä¿ãŸã§ãæ§ã ãªæ©ã¿ãæçš¿ãããŠããŸãã
é¡äŒŒãµãŒãã¹ãããã€ãåèã«ããã®ã§ããããªãã¹ããæ°è»œãªæ°æã¡ã§ç°¡åã«æçš¿ã§ããããµãŒãã¹ã«ããããšæããç¹ã«ä»¥äžã®ãããªç¹ãæèããŸããã
- äŒè©±ãæç«ããªã
- ãªã³ã©ã€ã³äžã§å¿åã®è°è«ããããšå€§æµã®å Žåèããã®ã§ãããããèšãåããèµ·ããåŸãªããããæ©ã¿ãçžè«ããŠèª°ããåçããã以éã®ãããšããã§ããªãããŸããã
- èŠè¿ããç¡ã
- äŸãã°ãæ©ã¿ã«çãããšã²ãŒã å ã®ã³ã€ã³ãè²°ããããšãã£ãããšãã§ããã®ã§ããããããŸã§ã³ãã¥ãã±ãŒã·ã§ã³èªäœã楜ããã§ãããããããããã£ãèŠè¿ãã¯ç¡ãããŸããã
- å±¥æŽãæ®ããªã
- æšä»ã®ãtwitterã§éå»ã®çºèšãåŒçšãããŠçäžãããSnapchatãå§ããšããããæ¶ããç³»ã®ãµãŒãã¹ã人æ°ããšãã£ããã¥ãŒã¹ãããæ°è»œãªã³ãã¥ãã±ãŒã·ã§ã³ã«ãããŠéå»ã®æçš¿ãå šãŠæ®ãæå³ã¯ãã»ã©ç¡ãã®ã§ã¯ãªãããšä»®å®ããåæã«æçš¿ã§ããæ©ã¿ã1ã€ãŸã§ã«ããŸããã
ãã¬ã€ã€ã®æ¹ãããããå±¥æŽãèŠããããè¿ä¿¡ãããããšãã£ãèŠæãããã ãã®ã§ããããšã«ããæ°è»œããéèŠèŠããŠãããæµæãæªæãæã£ãŠæçš¿ããã¢ãããŒã·ã§ã³ããªãã¹ãæé€ããããšããæå³ãããã®ã§ããããã®èŠæã«ã¯å¿ããããŸããã
DBã®éžæ
ã§ã¯å®è£ ã玹ä»ããŸãããŸãDBã§ãããFirebaseã«ã¯Realtime DatabaseïŒä»¥äžrtdbïŒãšFirestoreãšããéžæè¢ããããŸããåºæ¬çã«ã¯Firestoreã®æ¹ãæ°ããDBã§ãrtdbã§ã¯æžããªããããªè€éãªã¯ãšãªãæžãããšãã§ããŸããå ¬åŒã§ããβçã§ããããšã蚱容ã§ãããªãFirestoreã䜿ãã¹ãããšæžãããŠããŸãã
Choose a Database: Cloud Firestore or Realtime Database | Firebase
ã§ãããä»åã¯Unityã®SDKãæäŸãããŠããrtdbãæ¡çšããŸãããFirestoreã®UnitySDKã¯å ¬åŒã«æäŸãããŠãããïŒ2018/04/05çŸåšïŒèªåã§æžãã®ã¯å€§å€ãªã®ãšãä»åã®èŠä»¶ãªãrtdbã§ãå åããšè¶³ããã ãããšããæå³ã§ãã
ããŒã¿æ§é ã®å®çŸ©
次ã«ããŒã¿æ§é ãå®çŸ©ããŸããrtdbã¯RDBã®ããã«ããŒãã«ãã¬ã³ãŒããšãã£ãæŠå¿µã¯ç¡ãã1ã€ã®å€§ããªJSONããªãŒã§DBå
šäœãè¡šçŸããŸããä»åã¯çžè«ãè¡šçŸãã/post
ãšãããããã¬ãã«ã®ããŒããäœãã/post/{userID}
以äžã«ãŠãŒã¶ãŒããšã®çžè«ãäœããŸããã
{ "post": { "taro": { "question": "転è·ãããããªâŠâŠ", "answers": { "one": "ããã¡ãã£ãšé 匵ãã", "two": "å ¬åå¡ãããã" } } "jiro": { ... }, "hanako": { ... } } }
äžèšã®äŸã§ã¯taro
ãhanako
ãšãã£ãæååã§è¡šããŠããŸãããããã¯FirebaseAuthçã§çæãããŠãŒã¶ãŒããšã«ãŠããŒã¯ãªæååãæ³å®ããŠããŸãã
å/post/{userID}
以äžã«ã¯çžè«å
容ãè¡šãquestion
ãåçãè¡šãanswers
ããããŸãã1ã€ã®çžè«ã«è€æ°ã®åçãä»ãå Žåãããããanswers
ã¯æŽã«åããŒããæã£ãŠããŸãã
ããã«çžè«ãæžã蟌ãã§ãããŸããã³ãŒãã¯ãããªæãã§ãã
class Post { public string question = ""; public Dictionary<string, Answer> answers; } class Answer { public string body = ""; } void sendPost(string text) { var rootRef = FirebaseDatabase.DefaultInstance.RootReference; var postRef = rootRef.Child("post").Child(FirebaseAuth.DefaultInstance.CurrentUser.UserId); var post = new Post(); post.question = text; postRef.SetRawJsonValueAsync(JsonUtility.ToJson(post)).ContinueWith(_ => { // done }); } void sendAnswer(string text, string target) { var rootRef = FirebaseDatabase.DefaultInstance.RootReference; var answerRef = rootRef.Child("post").Child(target).Child("answers").Push(); var answer = new Answer(); answer.body = text; answerRef.SetRawJsonValueAsync(JsonUtility.ToJson(answer)).ContinueWith(_ => { // done }); }
ä»åã¯ããŠãŒã¶ãŒãåæã«æçš¿ã§ããçžè«ã¯1åããšããå¶çŽããããããæ°ããçžè«ãæçš¿ãããšãã¯setã§äžæžãããŠããŸãããããŠãŒã¶ãŒããšã«è€æ°ã®çžè«ãæçš¿ã§ããããã«ããå Žåã¯ãããã«/post/{userID}/{postID}
ã®ããã«äžæ®µæ·±ããã¹ããããŠpushããŠããæãã«ãªããšæããŸãã
ãªãã¹ãåçãã€ããŠãªãçžè«ãæ¢ã
çžè«ã«åçãããšãã¯ãpostã®äžããããŸã ããŸãåçãéãŸã£ãŠãããããªãã¹ãå€ãæçš¿ããæ¢ããŠããŸããããããããšã§ãã©ããªçžè«ãæçš¿ããŠã誰ãããããã¯è¿äºãæ¥ãç¶æ³ãå®çŸããŠããŸããããã¯ãå šãŠã®postãâ åçæ°æé â¡æçš¿æéæé ã§ãœãŒãããŠãã®å é ã衚瀺ãããŸãã
ãããå®çŸããããããœãŒãçšã®ããŒã¿æ§é ãå®çŸ©ããŸã
{ "postQueue": { "taro": { "mtime": 1000, "answer": 1, "sortKey": 11000 }, "jiro": { ... }, "hanako": { ... } } }
ãããã¬ãã«ã«/postQueue
ãäœããŸãããã®äžã«userIDããšã«æŽæ°æå»ãåçæ°ããœãŒãçšã®ãã£ãŒã«ããå®çŸ©ããŸãïŒrtdbã§ã¯è€æ°ã®ãã£ãŒã«ãã§ãœãŒãããããšãã§ããªããããœãŒãçšã®ãã£ãŒã«ããå¥éå¿
èŠã§ãããã¯åã«åçæ°ãšæŽæ°æå»ãã€ãªãåãããå€ã§ãïŒã
æ€çŽ¢ããåŠçã¯ä»¥äžã®ãããªæãã§ãã
void fetchPostQueue() { var postQueueRef = FirebaseDatabase.DefaultInstance.RootReference.Child("postQueue"); postQueueRef.OrderByChild("sortKey").LimitToFirst(10).GetValueAsync().ContinueWith(task => { foreach (var postQueue in task.Result.Children) { // do something } }); }
ã¡ãªã¿ã«ãããããœãŒãçšã®ãã£ãŒã«ãã¯/post/{userID}
ã«ä»¥äžã«çŽæ¥å®çŸ©ããŠãããã®ã§ããããã£ã±ãè€æ°çžè«ãæçš¿ããããªã£ãŠ/post/{userID}/{postID}
ãšãªã£ãå Žåãªã©ã¯ãã®ããã«ãœãŒãçšã®ããŒããå¿
èŠã§ãããŸããrtdbã§ã¯ç¹å®ã®ããŒã以äžãäžæ¬ããŠæã£ãŠããããšããã§ããªããããpost1ã€ã®ããŒã¿éã倧ããã£ãå Žåäœèšãªè»¢éãå¢ããŠããŸããšããç¹ããããŸããä»åã¯ã©ã¡ããåé¡ã§ã¯ç¡ãã®ã§ãããæ€çŽ¢çšã®ããŒããå¥éäœããšããã®ã¯rtdbã§ã¯ãã䜿ãææ³ã§ãã
indexãå¿ããã«å®çŸ©ããŠãããŸãããã
{ "rules": { "postQueue": { ".indexOn": [ "sortKey" ] } } }
Cloud Functionsã§åŠçãæã
ããŠåŸã¯åçã«åãããŠãã®/postQueue
ãæŽæ°ããã°okã§ããä»åã®ã¢ããªã§ã¯åçåŸ
ã¡ã®postã®ãœãŒãé ã¯å
šãŠãŒã¶ãŒéããŠäžå®ãªã®ã§ãè€æ°ã®ãŠãŒã¶ãŒãåæã«åã質åã«çããå¯èœæ§ããããŸããåçæ°ã®å€ãäžæŽåãèµ·ãããªãããã«ãããããã©ã³ã¶ã¯ã·ã§ã³ã®åŠçãå
¥ããŠãããã®ã§ããããã£ãããªã®ã§Cloud Functionsã䜿ã£ãŠãµãŒããŒåŽã§åŠçããŠã¿ãŸãããã
Cloud Functionsã¯Firebase補åã®1ã€ã§ããµãŒããŒåŽã®åŠçãæžããŸãã端æ«ããšã«å ±éã®ããžãã¯ããã»ãã¥ãªãã£äžã®éœåã§ã¯ã©ã€ã¢ã³ãã«çœ®ããããªãåŠçãæžããªã©ã®çšéã«äŸ¿å©ã§ããHTTPSã§ãªã¯ãšã¹ããæããŠçŽæ¥å®è¡ãããããŠãŒã¶ãŒãç»é²ããã¿ã€ãã³ã°ã§å®è¡ãããã§ããã®ã§ãããä»åã¯rtdbã®æžã蟌ã¿ãç£èŠããŠå®è¡ããããã«ããŸãã
exports.noticeAnswer = functions.database.ref('/post/{uid}').onUpdate((data, context) => { const prevAnswers = data.before.child("answers").val() const newAnswers = data.after.child("answers").val() const prevNum = prevAnswers ? Object.keys(prevAnswers).length : 0 const newNum = newAnswers ? Object.keys(newAnswers).length : 0 if (newNum > prevNum) { const now = Math.floor(new Date().getTime() / 1000) return admin.database().ref('/postQueue/' + context.params.uid).update({ answer: newNum, mtime: now, sortKey: newNum > 0 ? Number(newNum + '' + now) : now }) } return null })
onUpdateã¯æå®ãããã¹ä»¥äžãç£èŠããæŽæ°ãããã°å®è¡ãããŸããdata.before
ããå€æŽåã®ããŒã¿ã«ã¢ã¯ã»ã¹ã§ããã®ã§ãããæŽæ°åŸã®ããŒã¿ãšæ¯èŒããå·®åãããã°/postQueue/{userID}
ãæŽæ°ããŸãã
pushéç¥ãéã
æåŸã«ãåçãæçš¿ããããpushéç¥ãéãããã«ããŸãããããFirebase補åã®Messagingã䜿ãã°ä»ãŸã§ã®ã³ãŒããšçµã¿åãããŠç°¡åã«å®çŸã§ããŸãã蚌ææžãªã©ã®èšå®ã¯æžãã§ãããã®ãšããŠããŸãã¯ã©ã€ã¢ã³ãåŽã¯ãã®ããã«ãªããŸã
FirebaseMessaging.TokenReceived += (_, args) => { var token = args.Token; postRef.UpdateChildrenAsync(new Dictionary<string, object>() { { "postBy", token } }); };
FCM tokenãååŸããŠpostã«ä»äžããŠããŸããããã§ã/post
ã®ããŒã¿æ§é ã¯æ¬¡ã®ããã«ãªããŸãã
{ "post": { "taro": { "question": "転è·ãããããªâŠâŠ", "postBy": "{fcmToken}", "answers": { "one": "ããã¡ãã£ãšé 匵ãã", "two": "å ¬åå¡ãããã" } } "jiro": { ... }, "hanako": { ... } } }
ãã®tokenå®ã«éç¥ãéãã°ãçžè«ãæçš¿ãããŠãŒã¶ãŒã«åçãå±ããŸããã¡ããã©å çšFunctionsã§åçãæçš¿ããããšãã®åŠçãæžããã®ã§ãpushéç¥ãéãã³ãŒããæžãå ããŸãããã
exports.noticeAnswer = functions.database.ref('/post/{uid}').onUpdate((data, context) => { const prevAnswers = data.before.child("answers").val() const newAnswers = data.after.child("answers").val() const prevNum = prevAnswers ? Object.keys(prevAnswers).length : 0 const newNum = newAnswers ? Object.keys(newAnswers).length : 0 if (newNum > prevNum) { const news = Object.keys(newAnswers).filter(e => !prevAnswers || !prevAnswers[e]) const now = Math.floor(new Date().getTime() / 1000) return Promise.all(news.map(e => admin.messaging().sendToDevice(data.after.val().postBy, { notification: { title: 'åçãå±ããŸãã', body: newAnswers[e].body } })).concat(admin.database().ref('/postQueue/' + context.params.uid).update({ answer: newNum, mtime: now, sortKey: newNum > 0 ? Number(newNum + '' + now) : now }))) } return null })
sendToDeviceãå®éã«éä¿¡ããŠããåŠçã§ããFunctionsã§ã¯éåæãªåŠçã®çµäºãåŸ ã€å Žåãpromiseãè¿ãå¿ èŠãããã®ã§ãå ã®postQueueæŽæ°ãšåãããŠallã§è¿ããŸããããã§ã端æ«åŽã«pushéç¥ãå±ããŸãã
ãŸãšã
ãšããæãã§ããä»ã«ããäžèšãçµã¿åãããã°æªèªç®¡çãšãã®éç¥ãªã©ãå®è£ ã§ããŸããFirebaseã¯ä»ã«ããŠãŒã¶ãŒèªèšŒãéçwebãµã€ãã®ãã¹ãã£ã³ã°ãªã©ãã²ãŒã ãäœã£ãŠããšãã«æ¬²ãããªããµãŒãã¹ãäžéãæã£ãŠããŸããå°èŠæš¡ã§ããã°ç¡ææ ã«åãŸãç¯å²ã§äœ¿ããã®ã§ãæ¯éäžåºŠå°å ¥ããŠã¿ãŠã¯ãããã§ããããã