Firebase 云函数

1. 概述

在此 Codelab 中,您将学习如何使用适用于 Google Cloud Functions 的 Firebase SDK 来改进聊天网络应用,以及如何使用 Cloud Functions 向聊天应用的用户发送通知。

3b1284f5144b54f6.png

你会学到什么

  • 使用 Firebase SDK 创建 Google Cloud Functions。
  • 根据 Auth、Cloud Storage 和 Cloud Firestore 事件触发 Cloud Functions。
  • 将 Firebase 云消息传递支持添加到您的 Web 应用程序。

你需要什么

  • 一张信用卡。 Cloud Functions for Firebase 需要 Firebase Blaze 计划,这意味着您必须使用信用卡对 Firebase 项目启用计费。
  • 您所选择的IDE /文本编辑器如WebStorm原子崇高
  • 在安装了 NodeJS v8 的情况下运行 shell 命令的终端。
  • Chrome 等浏览器。
  • 示例代码。请参阅下一步。

2.获取示例代码

克隆GitHub的库在命令行:

git clone https://github.com/firebase/friendlychat

导入入门应用

使用您的 IDE,打开或导入android_studio_folder.png cloud-functions-start从样本代码目录的目录。该目录包含代码实验室的起始代码,该代码实验室由功能齐全的聊天 Web 应用程序组成。

3. 创建 Firebase 项目并设置您的应用

创建项目

火力地堡控制台单击添加项目,并调用它FriendlyChat。

单击创建项目

升级到 Blaze 计划

为了使用云功能的火力地堡,你将不得不upgade你的火力地堡计划的火焰计费计划。这将要求您将信用卡或其他结算方式添加到您的 Google Cloud 帐户。

所有 Firebase 项目,包括 Blaze 计划中的项目,仍然可以访问 Cloud Functions 的免费使用配额。此 Codelab 中概述的步骤将在免费套餐使用限制范围内。但是你会看到小的费用(约$ 0.03 ,从云存储),它是用来承载您的云功能构建的图像。

如果你没有获得一张信用卡或不舒服与火焰计划继续进行,考虑使用火力地堡模拟器套房,这将让你模仿你的本地计算机上的免费云功能。

启用 Google 身份验证

为了让用户登录应用程序,我们将使用需要启用的 Google 身份验证。

在火力地堡控制台打开开发部>验证>登录方法选项卡(或点击这里去那里),你需要启用谷歌登录的提供者,然后单击保存。这将允许用户使用他们的 Google 帐户登录 Web 应用程序。

还随意设置你的应用程序,以友好的交谈的面向公众的名称:

8290061806aacb46.png

启用云存储

该应用程序使用云存储上传图片。要在火力地堡项目能够访问云存储的存储部分,然后点击开始使用按钮。然后点击了它,当你收到有关安全规则的免责声明。

842ad84821323ef5.png

4. 安装 Firebase 命令行界面

Firebase 命令行界面 (CLI) 将允许您在本地提供 Web 应用程序并部署您的 Web 应用程序和 Cloud Functions。

要安装或升级 CLI,请运行以下 npm 命令:

npm -g install firebase-tools

要验证 CLI 是否已正确安装,请打开控制台并运行:

firebase --version

确保火力地堡CLI的版本是4.0.0以上,使其拥有所有必需的最新云功能特征。如果没有,运行npm install -g firebase-tools如上图所示升级。

通过运行以下命令授权 Firebase CLI:

firebase login

请确保你在cloud-functions-start目录,然后建立了火力地堡CLI使用您的火力地堡项目:

firebase use --add

然后选择您的项目 ID 并按照说明进行操作。出现提示时,你可以选择任何别名,如codelab的实例。

5. 部署并运行 Web 应用程序

现在您已经导入并配置了您的项目,您已准备好首次运行 Web 应用程序。在打开控制台cloud-functions-start文件夹,运行firebase deploy --except functions这样只会部署Web应用火力地堡托管:

firebase deploy --except functions

这是您应该看到的控制台输出:

i deploying database, storage, hosting
✔  database: rules ready to deploy.
i  storage: checking rules for compilation errors...
✔  storage: rules file compiled successfully
i  hosting: preparing ./ directory for upload...
✔  hosting: ./ folder uploaded successfully
✔ storage: rules file compiled successfully
✔ hosting: 8 files uploaded successfully
i starting release process (may take several minutes)...

✔ Deploy complete!

Project Console: https://console.firebase.google.com/project/friendlychat-1234/overview
Hosting URL: https://friendlychat-1234.firebaseapp.com

打开网络应用

最后一行应显示主机URL。现在应从此 URL 提供 Web 应用程序,该 URL 的格式应为 https://<project-id>.firebaseapp.com。打开它。您应该会看到聊天应用程序的运行 UI。

登录到应用程序使用的登录与Google按钮,随意添加一些消息和发表图片:

3b1284f5144b54f6.png

如果您首次在新浏览器上登录该应用程序,请确保在出现提示时允许通知: 8b9d0c66dc36153d.png

我们需要您稍后启用通知。

如果您不小心点击了,你可以在左边在Chrome Omnibar的URL,并选择通知🔒安全按钮,点击更改此设置>始终在本网站允许

e926868b0546ed71.png

现在,我们将使用 Firebase SDK for Cloud Functions 添加一些功能。

6. 函数目录

Cloud Functions 允许您轻松拥有在云中运行的代码,而无需设置服务器。我们将向您展示如何构建对 Firebase 身份验证、云存储和 Firebase 实时数据库事件做出反应的函数。让我们从 Auth 开始。

当使用SDK火力地堡的云功能,你的函数代码将住在functions目录(默认)。你的函数代码也是一个Node.js的应用程序,因此需要package.json ,让你的应用程序,并列出了相关的一些信息。

为了让您更容易,我们已经创建了functions/index.js文件在您的代码会。在继续之前,请随时检查此文件。

cd functions
ls

如果你不熟悉的Node.js这将有助于更多地了解它继续代码实验室之前。

该文件的package.json已经列出了两个需要的依赖:在火力地堡SDK云功能火力地堡管理员SDK 。要安装它们在本地运行npm installfunctions文件夹:

npm install

现在让我们来看看index.js文件:

索引.js

/**
 * Copyright 2017 Google Inc. All Rights Reserved.
 * ...
 */

// TODO(DEVELOPER): Import the Cloud Functions for Firebase and the Firebase Admin modules here.

// TODO(DEVELOPER): Write the addWelcomeMessage Function here.

// TODO(DEVELOPER): Write the blurImages Function here.

// TODO(DEVELOPER): Write the sendNotification Function here.

我们将首先导入所需的模块,然后编写三个函数来代替 TODO。首先让我们导入所需的 Node 模块。

7. 导入 Cloud Functions 和 Firebase 管理模块

两个模块将本程式码实验室中是必需的,在firebase-functions模块允许我们编写云功能触发规则,而firebase-admin模块允许我们使用火力地堡平台管理员权限的服务器上,例如写入Cloud Firestore 或发送 FCM 通知。

index.js文件,替换第一个TODO有以下情况:

索引.js

/**
 * Copyright 2017 Google Inc. All Rights Reserved.
 * ...
 */

// Import the Firebase SDK for Google Cloud Functions.
const functions = require('firebase-functions');
// Import and initialize the Firebase Admin SDK.
const admin = require('firebase-admin');
admin.initializeApp();

// TODO(DEVELOPER): Write the addWelcomeMessage Function here.

// TODO(DEVELOPER): Write the blurImages Function here.

// TODO(DEVELOPER): Write the sendNotification Function here.

Firebase Admin SDK 在 Cloud Functions 环境或其他 Google Cloud Platform 容器上部署时可以自动配置。这是我们做的时候调用上面admin.initializeApp();

现在让我们添加一个在用户第一次登录您的聊天应用程序时运行的函数,我们将添加一条聊天消息来欢迎用户。

8. 欢迎新用户

聊天消息结构

发布到 FriendlyChat 聊天源的消息存储在 Cloud Firestore 中。让我们看看我们用于消息的数据结构。为此,请在聊天中发布一条新消息,上面写着“Hello World”:

11f5a676fbb1a69a.png

这应该显示为:

fe6d1c020d0744cf.png

在你的火力地堡的应用程序控制台单击数据库下的开发部分。您应该会看到消息集合和一个包含您所写消息的文档:

442c9c10b5e2b245.png

正如你所看到的,聊天消息存储在云公司的FireStore与该文档nameprofilePicUrltexttimestamp属性添加到messages收集。

添加欢迎信息

第一个云功能补充说,欢迎新用户在聊天的消息。为此,我们可以使用触发器functions.auth().onCreate ,用户的迹象,为您的火力地堡的应用程序在第一时间每次运行的功能。添加addWelcomeMessages功能到您的index.js文件:

索引.js

// Adds a message that welcomes new users into the chat.
exports.addWelcomeMessages = functions.auth.user().onCreate(async (user) => {
  console.log('A new user signed in for the first time.');
  const fullName = user.displayName || 'Anonymous';

  // Saves the new welcome message into the database
  // which then displays it in the FriendlyChat clients.
  await admin.firestore().collection('messages').add({
    name: 'Firebase Bot',
    profilePicUrl: '/images/firebase-logo.png', // Firebase logo
    text: `${fullName} signed in for the first time! Welcome!`,
    timestamp: admin.firestore.FieldValue.serverTimestamp(),
  });
  console.log('Welcome message written to database.');
});

添加此功能的特殊exports目标是使当前文件的功能来访问外部节点的方式和所需的云功能。

在上面的函数中,我们将“Firebase Bot”发布的新欢迎消息添加到聊天消息列表中。我们通过这样add的方法messages在云公司的FireStore采集是聊天的信息的存储位置。

由于这是一个异步操作,我们需要返回的承诺表明,当云计算公司的FireStore写入完成后,使功能不会太早退出执行。

部署函数

该功能仅在您部署后才处于活动状态。在命令行中运行firebase deploy --only functions

firebase deploy --only functions

这是您应该看到的控制台输出:

i  deploying functions
i  functions: ensuring necessary APIs are enabled...
⚠  functions: missing necessary APIs. Enabling now...
i  env: ensuring necessary APIs are enabled...
⚠  env: missing necessary APIs. Enabling now...
i  functions: waiting for APIs to activate...
i  env: waiting for APIs to activate...
✔  env: all necessary APIs are enabled
✔  functions: all necessary APIs are enabled
i  functions: preparing functions directory for uploading...
i  functions: packaged functions (X.XX KB) for uploading
✔  functions: functions folder uploaded successfully
i  starting release process (may take several minutes)...
i  functions: creating function addWelcomeMessages...
✔  functions[addWelcomeMessages]: Successful create operation. 
✔  functions: all functions deployed successfully!

✔  Deploy complete!

Project Console: https://console.firebase.google.com/project/friendlypchat-1234/overview

测试功能

成功部署该功能后,您需要有一个首次登录的用户。

  1. 打开你的应用程序使用托管URL浏览器(以下形式https://<project-id>.firebaseapp.com )。
  2. 随着新的用户,请登录使用登录按钮在你的应用程序中的第一次。

262535d1b1223c65.png

  1. 登录后,应自动显示欢迎消息:

1c70e0d64b23525b.png

9. 图片审核

用户可以在聊天中上传所有类型的图片,并且缓和令人反感的图片总是很重要的,尤其是在公共社交平台上。在FriendlyChat正在发布到聊天的图象存储到谷歌云存储

随着云计算的功能,可以检测使用新的图像上传functions.storage().onFinalize触发。每次在 Cloud Storage 中上传或修改新文件时,这都会运行。

要审核图像,我们将经历以下过程:

  1. 检查图像是使用或标记为成人暴力云愿景API
  2. 如果图像已被标记,则将其下载到正在运行的 Functions 实例上
  3. 利用模糊图像的ImageMagick
  4. 将模糊的图像上传到 Cloud Storage

启用 Cloud Vision API

由于我们将在此函数中使用 Google Cloud Vision API,因此您必须在 Firebase 项目中启用该 API。按照此链接,选择您的火力地堡项目并启用该API:

5c77fee51ec5de49.png

安装依赖

为了调整图像,我们需要一些 Node.js 包:

  • 谷歌的云计算愿景客户端库Node.js的: @谷歌云/视觉运行通过云愿景API的图像来检测不良的图像。
  • 使Node.js库使我们能够运行的进程:子进程,承诺自ImageMagick的命令行工具来运行ImageMagick的自带的所有功能实例预装。

这两个软件包安装到您的云功能应用,运行以下npm install --save命令。请确保您从做这个functions目录。

npm install --save @google-cloud/vision@0.12.0 child-process-promise@2.2.1

这将在本地安装两个包,并将其添加为你声明的依赖性package.json文件。

导入和配置依赖

要导入已安装的两个依赖和Node.js的一些核心模块( pathos以及fs ),我们就需要在本节中添加以下行到顶部index.js文件:

索引.js

const Vision = require('@google-cloud/vision');
const vision = new Vision();
const spawn = require('child-process-promise').spawn;

const path = require('path');
const os = require('os');
const fs = require('fs');

由于您的函数将在 GCP 环境中运行,因此无需配置 Cloud Storage 和 Cloud Vision 库:它们将自动配置为使用您的项目。

检测不当图像

您将使用functions.storage.onChange其作为创建或在云端存储修改的文件或文件夹,一旦运行代码的云功能触发。添加blurOffensiveImages功能到您的index.js文件:

索引.js

// Checks if uploaded images are flagged as Adult or Violence and if so blurs them.
exports.blurOffensiveImages = functions.runWith({memory: '2GB'}).storage.object().onFinalize(
    async (object) => {
      const image = {
        source: {imageUri: `gs://${object.bucket}/${object.name}`},
      };

      // Check the image content using the Cloud Vision API.
      const batchAnnotateImagesResponse = await vision.safeSearchDetection(image);
      const safeSearchResult = batchAnnotateImagesResponse[0].safeSearchAnnotation;
      const Likelihood = Vision.types.Likelihood;
      if (Likelihood[safeSearchResult.adult] >= Likelihood.LIKELY ||
          Likelihood[safeSearchResult.violence] >= Likelihood.LIKELY) {
        console.log('The image', object.name, 'has been detected as inappropriate.');
        return blurImage(object.name);
      }
      console.log('The image', object.name, 'has been detected as OK.');
    });

请注意,我们添加了云功能实例的一些配置将运行功能,具有.runWith({memory: '2GB'})我们请求的情况下获得2GB的内存,而不是默认的,这将有助于为这函数是内存密集型的。

当该功能被触发时,图像会通过 Cloud Vision API 运行以检测它是否被标记为成人或暴力。如果图像是基于这些标准检测为不恰当我们模糊这是在做形象blurImage功能,我们将在下面看到。

图像模糊

添加以下blurImage功能在您的index.js文件:

索引.js

// Blurs the given image located in the given bucket using ImageMagick.
async function blurImage(filePath) {
  const tempLocalFile = path.join(os.tmpdir(), path.basename(filePath));
  const messageId = filePath.split(path.sep)[1];
  const bucket = admin.storage().bucket();

  // Download file from bucket.
  await bucket.file(filePath).download({destination: tempLocalFile});
  console.log('Image has been downloaded to', tempLocalFile);
  // Blur the image using ImageMagick.
  await spawn('convert', [tempLocalFile, '-channel', 'RGBA', '-blur', '0x24', tempLocalFile]);
  console.log('Image has been blurred');
  // Uploading the Blurred image back into the bucket.
  await bucket.upload(tempLocalFile, {destination: filePath});
  console.log('Blurred image has been uploaded to', filePath);
  // Deleting the local file to free up disk space.
  fs.unlinkSync(tempLocalFile);
  console.log('Deleted local file.');
  // Indicate that the message has been moderated.
  await admin.firestore().collection('messages').doc(messageId).update({moderated: true});
  console.log('Marked the image as moderated in the database.');
}

在上述函数中,图像二进制文件是从 Cloud Storage 下载的。然后,该图像是使用ImageMagick的模糊convert工具和模糊的版本是重新上载于存储桶。然后我们删除 Cloud Functions 实例上的文件以释放一些磁盘空间,我们这样做是因为可以重复使用相同的 Cloud Functions 实例,如果不清理文件,它可能会耗尽磁盘空间。最后,我们向聊天消息添加一个布尔值,指示图像已被审核,这将触发客户端上的消息刷新。

部署函数

该功能仅在您部署后才处于活动状态。在命令行中运行firebase deploy --only functions

firebase deploy --only functions

这是您应该看到的控制台输出:

i  deploying functions
i  functions: ensuring necessary APIs are enabled...
✔  functions: all necessary APIs are enabled
i  functions: preparing functions directory for uploading...
i  functions: packaged functions (X.XX KB) for uploading
✔  functions: functions folder uploaded successfully
i  starting release process (may take several minutes)...
i  functions: updating function addWelcomeMessages...
i  functions: creating function blurOffensiveImages...
✔  functions[addWelcomeMessages]: Successful update operation.
✔  functions[blurOffensiveImages]: Successful create operation.
✔  functions: all functions deployed successfully!

✔  Deploy complete!

Project Console: https://console.firebase.google.com/project/friendlychat-1234/overview

测试功能

成功部署函数后:

  1. 打开你的应用程序使用托管URL浏览器(以下形式https://<project-id>.firebaseapp.com )。
  2. 登录应用程序后上传图像: 4db9fdab56703e4a.png
  3. 选择你最好的进攻要上传的图片(或者你可以使用这个食肉僵尸!),并在一段时间后,你应该看到您的帖子刷新与图像的模糊版本: 83dd904fbaf97d2b.png

10. 新消息通知

在本节中,您将添加一个云功能,该功能在发布新消息时向聊天参与者发送通知。

使用火力地堡云端通讯(FCM),您可以发送通知给用户在跨平台的和可靠的方式。要向用户发送通知,您需要他们的 FCM 设备令牌。当用户在新浏览器或设备上第一次打开应用程序时,我们正在使用的聊天网络应用程序已经从用户那里收集设备令牌。这些令牌被存储在云公司的FireStore在fcmTokens集合。

如果您想了解如何获得一个Web应用程序,你可以去通过FCM设备令牌火力地堡网页程式码实验室

发送通知

为了检测当新邮件,你将使用张贴functions.firestore.document().onCreate ,当在云公司的FireStore的给定路径创建一个新的对象上运行代码的云功能触发。添加sendNotifications功能到您的index.js文件:

索引.js

// Sends a notifications to all users when a new message is posted.
exports.sendNotifications = functions.firestore.document('messages/{messageId}').onCreate(
  async (snapshot) => {
    // Notification details.
    const text = snapshot.data().text;
    const payload = {
      notification: {
        title: `${snapshot.data().name} posted ${text ? 'a message' : 'an image'}`,
        body: text ? (text.length <= 100 ? text : text.substring(0, 97) + '...') : '',
        icon: snapshot.data().profilePicUrl || '/images/profile_placeholder.png',
        click_action: `https://${process.env.GCLOUD_PROJECT}.firebaseapp.com`,
      }
    };

    // Get the list of device tokens.
    const allTokens = await admin.firestore().collection('fcmTokens').get();
    const tokens = [];
    allTokens.forEach((tokenDoc) => {
      tokens.push(tokenDoc.id);
    });

    if (tokens.length > 0) {
      // Send notifications to all tokens.
      const response = await admin.messaging().sendToDevice(tokens, payload);
      await cleanupTokens(response, tokens);
      console.log('Notifications have been sent and tokens cleaned up.');
    }
  });

在上面我们从云数据库的FireStore收集所有用户的装置凭证和发送通知到每个这些使用功能admin.messaging().sendToDevice功能。

清理令牌

最后,我们要删除不再有效的令牌。当浏览器或设备不再使用我们曾经从用户那里获得的令牌时,就会发生这种情况。例如,如果用户撤销了其浏览器会话的通知权限,就会发生这种情况。要做到这一点添加以下cleanupTokens在你的函数index.js文件:

索引.js

// Cleans up the tokens that are no longer valid.
function cleanupTokens(response, tokens) {
 // For each notification we check if there was an error.
 const tokensDelete = [];
 response.results.forEach((result, index) => {
   const error = result.error;
   if (error) {
     console.error('Failure sending notification to', tokens[index], error);
     // Cleanup the tokens that are not registered anymore.
     if (error.code === 'messaging/invalid-registration-token' ||
         error.code === 'messaging/registration-token-not-registered') {
       const deleteTask = admin.firestore().collection('fcmTokens').doc(tokens[index]).delete();
       tokensDelete.push(deleteTask);
     }
   }
 });
 return Promise.all(tokensDelete);
}

部署函数

该功能仅在您部署后才处于活动状态。在命令行中运行firebase deploy --only functions

firebase deploy --only functions

这是您应该看到的控制台输出:

i  deploying functions
i  functions: ensuring necessary APIs are enabled...
✔  functions: all necessary APIs are enabled
i  functions: preparing functions directory for uploading...
i  functions: packaged functions (X.XX KB) for uploading
✔  functions: functions folder uploaded successfully
i  starting release process (may take several minutes)...
i  functions: updating function addWelcomeMessages...
i  functions: updating function blurOffensiveImages...
i  functions: creating function sendNotifications...
✔  functions[addWelcomeMessages]: Successful update operation.
✔  functions[blurOffensiveImages]: Successful updating operation.
✔  functions[sendNotifications]: Successful create operation.
✔  functions: all functions deployed successfully!

✔  Deploy complete!

Project Console: https://console.firebase.google.com/project/friendlychat-1234/overview

测试功能

  1. 一旦功能已成功部署,使用托管的网址在浏览器中打开应用(在形式https://<project-id>.firebaseapp.com )。
  2. 如果您是第一次登录应用程序,请确保在出现提示时允许通知: 8b9d0c66dc36153d.png
  3. 关闭聊天应用程序选项卡或显示不同的选项卡:仅当应用程序在后台时才会显示通知。如果你想学习如何当你的应用程序是在前台收到的消息看一下我们的文档
  4. 使用不同的浏览器(或隐身窗口),登录应用程序并发布消息。您应该会看到第一个浏览器显示的通知: 45282ab12b28b926.png

11. 恭喜!

您已使用 Firebase SDK for Cloud Functions 并将服务器端组件添加到聊天应用程序。

我们涵盖的内容

  • 使用 Firebase SDK for Cloud Functions 创作 Cloud Functions。
  • 根据 Auth、Cloud Storage 和 Cloud Firestore 事件触发 Cloud Functions。
  • 将 Firebase 云消息传递支持添加到您的 Web 应用程序。
  • 使用 Firebase CLI 部署了 Cloud Functions。

下一步

了解更多