Firebase 云函数

一、概述

在此 Codelab 中,您将了解如何使用 Firebase SDK for Google Cloud Functions 来改进 Chat Web 应用,以及如何使用 Cloud Functions 向 Chat 应用的用户发送通知。

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 v9 的终端来运行 shell 命令。
  • 浏览器,例如 Chrome。
  • 示例代码。请参阅下一步。

2.获取示例代码

克隆GitHub的库在命令行:

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

导入入门应用

使用您的 IDE,打开或导入android_studio_folder.png cloud-functions-start从样本代码目录的目录。此目录包含 codelab 的起始代码,其中包含一个功能齐全的 Chat Web App。

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

创建项目

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

单击创建项目

升级到 Blaze 计划

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

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

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

启用谷歌身份验证

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

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

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

8290061806aacb46.png

启用云存储

该应用程序使用云存储上传图片。要在火力地堡项目实现云存储,访问存储部分,然后点击开始使用按钮。完成那里的步骤,对于 Cloud Storage 位置,将使用一个默认值。点击之后完成

添加网络应用

在 Firebase 控制台上,添加一个 Web 应用。要做到这一点,去项目设置和向下滚动添加应用程序。挑选网络为平台,查看包装盒上设置火力地堡主机,然后注册应用程序,然后单击下一步的步骤剩余部分,最后点击继续安慰

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的文件夹,并部署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 应用程序,其格式应为 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 Auth、Cloud Storage 和 Firebase Firestore 数据库事件做出反应的函数。让我们从 Auth 开始。

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

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

cd functions
ls

如果你不熟悉Node.js的,以前更多地了解它继续代码实验室将是有益的。

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

npm install

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

index.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能够使用火力地堡平台与服务器上的管理员权限来做,比如写入云公司的FireStore或发送FCM通知的操作。

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

index.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.

在火力地堡管理员SDK可以在部署到云环境的功能或其他谷歌云平台集装箱进行自动配置,而出现这种情况时,我们称之为admin.initializeApp()不带参数。

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

8. 欢迎新用户

聊天消息结构

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

11f5a676fbb1a69a.png

这应该显示为:

fe6d1c020d0744cf.png

在火力地堡控制台,点击公司的FireStore数据库下的Build部分。您应该看到消息集合和一个包含您编写的消息的文档:

442c9c10b5e2b245.png

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

添加欢迎信息

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

index.js

// Adds a message that welcomes new users into the chat.
exports.addWelcomeMessages = functions.auth.user().onCreate(async (user) => {
  functions.logger.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(),
  });
  functions.logger.log('Welcome message written to database.');
});

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

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

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

部署云功能

Cloud 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的, @谷歌云/远景,通过云愿景API运行图像检测不当图片。

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

npm install --save @google-cloud/vision@2.4.0

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

导入和配置依赖项

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

index.js

const Vision = require('@google-cloud/vision');
const vision = new Vision.ImageAnnotatorClient();
const {promisify} = require('util');
const exec = promisify(require('child_process').exec);

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

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

检测不当图像

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

index.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 imageUri = `gs://${object.bucket}/${object.name}`;
      // Check the image content using the Cloud Vision API.
      const batchAnnotateImagesResponse = await vision.safeSearchDetection(imageUri);
      const safeSearchResult = batchAnnotateImagesResponse[0].safeSearchAnnotation;
      const Likelihood = Vision.protos.google.cloud.vision.v1.Likelihood;
      if (Likelihood[safeSearchResult.adult] >= Likelihood.LIKELY ||
          Likelihood[safeSearchResult.violence] >= Likelihood.LIKELY) {
        functions.logger.log('The image', object.name, 'has been detected as inappropriate.');
        return blurImage(object.name);
      }
      functions.logger.log('The image', object.name, 'has been detected as OK.');
    });

请注意,我们添加了将运行该函数的 Cloud Functions 实例的一些配置。随着.runWith({memory: '2GB'})我们请求的情况下获得的记忆,而不是默认的2GB,因为这个功能需要占用大量内存。

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

模糊图像

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

index.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});
  functions.logger.log('Image has been downloaded to', tempLocalFile);
  // Blur the image using ImageMagick.
  await exec(`convert "${tempLocalFile}" -channel RGBA -blur 0x24 "${tempLocalFile}"`);
  functions.logger.log('Image has been blurred');
  // Uploading the Blurred image back into the bucket.
  await bucket.upload(tempLocalFile, {destination: filePath});
  functions.logger.log('Blurred image has been uploaded to', filePath);
  // Deleting the local file to free up disk space.
  fs.unlinkSync(tempLocalFile);
  functions.logger.log('Deleted local file.');
  // Indicate that the message has been moderated.
  await admin.firestore().collection('messages').doc(messageId).update({moderated: true});
  functions.logger.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 设备令牌。我们使用的聊天 Web 应用程序在用户首次在新浏览器或设备上打开应用程序时已经从用户那里收集了设备令牌。这些令牌被存储在云公司的FireStore在fcmTokens集合。

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

发送通知

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

index.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);
      functions.logger.log('Notifications have been sent and tokens cleaned up.');
    }
  });

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

清理令牌

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

index.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) {
     functions.logger.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

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

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。

下一步

学到更多