NodeJS通过Firebase将APN发送到应用程序

嗨,我想发送APN到我的应用程序。 我成功地能够生成通知,并将其发送到我的应用程序。

我的问题是,服务器在一个块中相当频繁地发送通知。 我猜测我的脚本algorithm有问题。

我想做的事:

每次在post中发表评论时,我都希望将通知发送到设备。 我想从Firebase数据库显式获取用户名和注释。

我正在附加服务器脚本:

var firebase = require("firebase"); var once = require("once"); const apn = require('apn'); var config = { apiKey: "<key>", authDomain: "<domain>", databaseURL: "<url>", projectId: "<id>", storageBucket: "<bucket>", messagingSenderId: "<ID>" }; firebase.initializeApp(config); let options = { token: { key: "<p8 file>", keyId: "<key>", teamId: "<team>" }, production: false }; let apnProvider = new apn.Provider(options); // Prepare the notifications let notification = new apn.Notification(); notification.expiry = Math.floor(Date.now() / 1000) + 24 * 3600; // will expire in 24 hours from now notification.badge = 3; notification.sound = "default"; notification.topic = "<My bundle ID>"; notification.payload = {'messageFrom': 'me'}; var author; var dtoken; var spotter; var comment; var database = firebase.database(); var postref = database.ref("posts").orderByChild("gen_notif").equalTo("yes").on("value", function (snapshot) { var key; var deviceToken; console.log("-------------------Post Ids----------------------") snapshot.forEach(function (childSnapshot) { key = childSnapshot.key author = childSnapshot.val()["author"]; console.log(key) var newref = database.ref("posts/" + childSnapshot.key + "/comment").on('child_added', function(snapy){ console.log(snapy.val()) console.log("-----------------comment Keys----------------------") snapy.forEach(function(s){ var spotuserkey = s.key comment = s.val() console.log(spotuserkey) var spotuser = database.ref("users/"+ spotuserkey +"/credentials/name").on('value', function(spottersnap){ console.log("-----------------User Key-----------------------") spotuser = spottersnap.val() console.log(spotuser) var tokenref = database.ref("device/"+author+"/token").once('value', function(snap){ console.log("-----------------device token---------------------") deviceToken = snap.val() console.log(deviceToken) notification.alert = { "title": "You Got Spotted", "body": spotuser + " Spot you " + comment }; apnProvider.send(notification, deviceToken).then( result => { console.log(result["failed"][0]["response"]); }); })//tokenref end })//spotteref end }); //snapy forEach end })//newref end }); //snapshot forEach end }); //postref end apnProvider.shutdown(); 

要初始化您的应用程序,我认为最好使用您可以通过Firebase控制台下载的serviceAccountKey文件,而不是直接在您的代码中编写密钥:

 const functions = require('firebase-functions'); var admin = require('firebase-admin'); var serviceAccount = require("./serviceAccountKey.json"); admin.initializeApp({ credential: admin.credential.cert(serviceAccount), databaseURL: "YOUR_DATABASE_URL_GOES_HERE" }); 

当然,你需要在这里用你自己的数据库url来replace,并且确保你的serviceAccountKey.json文件在你的functions文件夹中。

不过,我认为你需要重新调整你的数据库,以便更容易地在服务器端检索你的ID,例如它可能看起来像这样:

 root/ | .... | | |___ posts/ |   |___ postID |       |___ authorId : ... |       |___ caption : ... |       |___ comments |         |___ commentID | |___ senderId: ... |      |___ text: ... |      ... | | |___ users/ |   |___ userID |       |___ name : ... |       |___ email : ... |       |___ notificationTokens |            |___ token1 : true           | |___ token2 : true |            ... 

然后,您可以创build使用函数来在通知节点内写入通知对象,只要注释节点中有新的写入事件:

 exports.createPostCommentedNotification = functions.database.ref('/posts/{postID}/comments/{commentID}').onWrite(event => { const data = event.data; if(data == undefined || !data.val()) { return; } const postID = event.params.postID; const commentID = event.params.commentID; const getCommentSender = admin.database().ref(`/posts/${postID}/comments/${commentID}`).once('value'); const getPostAuthor = admin.database().ref(`/posts/${postID}`).once('value'); return Promise.all([getCommentSender, getPostAuthor]).then(results => { const commentSenderData = results[0]; const postAuthorData = results[1]; const commentSenderId = commentSenderData.val().senderId; const postAuthorId = postAuthorData.val().authorId; if(commentSenderId == postAuthorId) { return; }; const notificationID = admin.database().ref().push().key; const timestamp = Date.now() const getSenderProfilePromise = admin.auth().getUser(commentSenderId); return Promise.all([getSenderProfilePromise]).then(results => { // Note that when you create a user account you would need to set the displayName of the user using the updateProfile() method, otherwise you would need to retrieve the senderName in a different way:) const senderData = results[0] const senderName = senderData.providerData[0].displayName var notificationData = { senderName: senderName, notificationTimestamp: timestamp }; var updates = {}; updates['/notifications/' + postAuthorId + '/' + notificationID] = notificationData; admin.database().ref().update(updates); }); }); }); 

然后,只要有一个新的通知对象添加到通知节点,就可以使用用户令牌创build另一个函数来实际发送推送通知,如下所示:

 exports.sendPushNotifications = functions.database.ref('/notifications/{receiverId}/{notificationId}').onWrite(event => { const data = event.data; if(data == undefined || !data.val()) { return; } const receiverId = event.params.receiverId; const notificationId = event.params.notificationId; const getDeviceTokensPromise = admin.database().ref(`/users/${receiverId}/notificationTokens`).once('value'); const getMessageContentPromise = admin.database().ref(`/notifications/${receiverId}/${notificationId}/notificationType`).once('value'); const getSenderPromise = admin.database().ref(`/notifications/${receiverId}/${notificationId}/senderName`).once('value'); return Promise.all([getDeviceTokensPromise, getSenderPromise]).then(results => { const tokensSnapshot = results[0]; const senderSnapshot = results[1]; const sender = senderSnapshot.val() if (!tokensSnapshot.hasChildren()) { return console.log('There are no notification tokens to send to.'); } const payload = { notification: { title: `${sender}`, body: 'Someone commented on your post', badge: '1' } }; var options = { priority: "high", timeToLive: 60 * 60 * 24, mutable_content : true, content_available : true, category : 'reminder' }; const tokens = Object.keys(tokensSnapshot.val()); return admin.messaging().sendToDevice(tokens, payload, options).then(response => { const tokensToRemove = []; response.results.forEach((result, index) => { const error = result.error; if (error) { console.error('Failure sending notification to', tokens[index], error); if (error.code === 'messaging/invalid-registration-token' || error.code === 'messaging/registration-token-not-registered') { tokensToRemove.push(tokensSnapshot.ref.child(tokens[index]).remove()); } } }); return Promise.all(tokensToRemove); }); }); }); 

那么让我知道,如果你有任何问题!