推送通知的实现:后端

Avatar of Pascal Klau (@pascalaoms)
Pascal Klau (@pascalaoms)

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 200 美元的免费额度!

在本系列的第一部分中,我们使用服务工作者、`manifest.json` 文件设置了前端,并初始化了 Firebase。现在我们需要创建我们的数据库和观察者函数。

文章系列

  1. 设置和 Firebase
  2. 后端(您当前所在位置)

创建数据库

登录 Firebase,然后在导航中点击数据库。在数据下,您可以手动添加数据库引用并查看实时发生的更改。

确保在规则下调整规则集,这样您在测试期间就不必费心进行身份验证。

{
  "rules": {
    ".read": true,
    ".write": true
  }
}

使用 Cloud Functions 监视数据库更改

请记住,所有这一切的目的是在您发布新博文时发送推送通知。因此,我们需要一种方法来监视这些保存博文的数据分支中的数据库更改。

使用 Firebase Cloud Functions,我们可以自动运行后端代码以响应由 Firebase 功能触发的事件。

设置并初始化 Cloud Functions 的 Firebase SDK

要开始创建这些函数,我们需要安装 Firebase CLI。它需要 Node v6.11.1 或更高版本。

npm i firebase-tools -g

初始化项目

  1. 运行 firebase login
  2. 验证您的身份
  3. 转到您的项目目录
  4. 运行 firebase init functions

已创建名为 `functions` 的新文件夹。在其中,我们有一个 `index.js` 文件,我们在其中定义我们的新函数。

导入所需的模块

我们需要在 `index.js` 中导入Cloud FunctionsAdmin SDK 模块并初始化它们。

const admin     = require('firebase-admin'),
      functions = require('firebase-function')

admin.initializeApp(functions.config().firebase)

Firebase CLI 将自动安装这些依赖项。如果您希望添加自己的依赖项,请修改 `package.json`,运行 npm install,并像往常一样引入它们。

设置观察者

我们定位数据库并创建我们要观察的引用。在我们的例子中,我们保存到一个包含帖子 ID 的 `posts` 分支。每当添加或删除新的帖子 ID 时,我们都可以对此做出反应。

exports.sendPostNotification = functions.database.ref('/posts/{postID}').onWrite(event => {
  // react to changes    
}

导出的名称 `sendPostNotification` 用于区分 Firebase 后端中的所有函数。

所有其他代码示例都将在 `onWrite` 函数内发生。

检查帖子删除

如果帖子被删除,我们可能不应该发送推送通知。因此,我们记录一条消息并退出函数。这些日志可以在 Firebase 控制台中找到,位于函数 → 日志下。

首先,我们获取帖子 ID 并检查标题是否存在。如果不存在,则表示帖子已被删除。

const postID    = event.params.postID,
      postTitle = event.data.val()

if (!postTitle) return console.log(`Post ${postID} deleted.`)

获取要向其显示通知的设备

在上一篇文章中,我们在 `updateSubscriptionOnServer` 函数中将设备令牌保存到名为 `device_ids` 的分支中的数据库中。现在我们需要检索这些令牌才能向它们发送消息。我们接收所谓的快照,这些快照基本上是包含令牌的数据引用。

如果无法检索快照,因此也无法检索设备令牌,请记录一条消息并退出函数,因为我们没有可以发送推送通知的人。

const getDeviceTokensPromise = admin.database()
  .ref('device_ids')
  .once('value')
  .then(snapshots => {

      if (!snapshots) return console.log('No devices to send to.')

      // work with snapshots  
}

创建通知消息

如果有快照可用,我们需要遍历它们并为每个快照运行一个函数,该函数最终会发送通知。但首先,我们需要使用标题、正文和图标填充它。

const payload = {
  notification: {
    title: `New Article: ${postTitle}`,
    body: 'Click to read article.',
    icon: 'https://mydomain.com/push-icon.png'
  }
}

snapshots.forEach(childSnapshot => {
  const token = childSnapshot.val()

  admin.messaging().sendToDevice(token, payload).then(response => {
    // handle response
  }
}

处理发送响应

如果我们发送失败或令牌无效,我们可以将其删除并记录一条消息。

response.results.forEach(result => {
  const error = result.error

  if (error) {
    console.error('Failed delivery to', token, error)

  if (error.code === 'messaging/invalid-registration-token' ||
      error.code === 'messaging/registration-token-not-registered') {

      childSnapshot.ref.remove()
      console.info('Was removed:', token)

  } else {
    console.info('Notification sent to', token)
  }

}

部署 Firebase Functions

要将您的 `index.js` 上传到云端,我们运行以下命令。

firebase deploy --only functions

结论

现在,当您添加新帖子时,已订阅的用户将收到推送通知,引导他们返回您的博客。

GitHub 仓库 演示网站

文章系列

  1. 设置和 Firebase
  2. 后端(您当前所在位置)