在此代碼實驗室中,您將學習如何使用Firebase SDK for Google Cloud Functions來改進聊天Web應用程序,以及如何使用Cloud Functions將通知發送給聊天應用程序用戶。
你會學到什麼
- 使用Firebase SDK創建Google Cloud Functions。
- 根據Auth,Cloud Storage和Cloud Firestore事件觸發Cloud Functions。
- 將Firebase Cloud Messaging支持添加到您的Web應用程序。
你需要什麼
從命令行克隆GitHub存儲庫:
git clone https://github.com/firebase/friendlychat
導入入門應用
使用您的IDE,打開或導入示例代碼目錄中的
cloud-functions-start
目錄。該目錄包含代碼實驗室的起始代碼,該代碼實驗室由功能全面的Chat Web App組成。
建立專案
在Firebase控制台中,單擊“添加項目”,並將其命名為FriendlyChat 。
單擊創建項目。
啟用Google身份驗證
為了讓用戶登錄該應用,我們將使用需要啟用的Google身份驗證。
在Firebase控制台中,打開“開發”部分>“身份驗證” >“登錄方法”標籤(或單擊此處轉到此處),您需要啟用Google登錄提供程序,然後單擊“保存” 。這將允許用戶使用其Google帳戶登錄Web應用。
也可以隨時將您應用的公開名稱設置為“友好聊天” :
啟用雲存儲
該應用程序使用Cloud Storage上傳圖片。要在Firebase項目上啟用Cloud Storage,請訪問“存儲”部分,然後單擊“入門”按鈕。當您收到有關安全規則的免責聲明時,請單擊“得到它” 。
Firebase命令行界面(CLI)允許您在本地提供Web應用程序並部署Web應用程序和Cloud Functions。
要安裝或升級CLI,請運行以下npm命令:
npm -g install firebase-tools
要驗證CLI是否已正確安裝,請打開控制台並運行:
firebase --version
確保Firebase CLI的版本高於4.0.0 ,以使其具有Cloud Functions所需的所有最新功能。如果沒有,請運行npm install -g firebase-tools
進行升級,如上所示。
通過運行以下命令授權Firebase CLI:
firebase login
確保您位於cloud-functions-start
目錄中,然後將Firebase CLI設置為使用Firebase項目:
firebase use --add
然後選擇您的項目ID,然後按照說明進行操作。出現提示時,您可以選擇任何別名,例如codelab
。
現在,您已經導入並配置了項目,就可以開始運行Web應用程序了。在cloud-functions-start
文件夾中打開一個控制台,然後運行firebase deploy --except functions
這只會將Web應用程序部署到Firebase託管:
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登錄”按鈕登錄該應用,並隨時添加一些消息和發布圖片:
如果您是第一次使用新的瀏覽器登錄該應用,請確保在出現提示時允許通知:
我們需要您稍後啟用通知。
如果您不小心單擊了阻止,則可以通過以下方法更改此設置:單擊Chrome Omnibar中URL左側的🔒安全按鈕,然後選擇“通知”>“始終在此站點上允許” :
現在,我們將使用Firebase SDK for Cloud Functions添加一些功能。
雲功能使您可以輕鬆地在雲中運行代碼,而無需設置服務器。我們將向您展示如何構建對Firebase Auth,Cloud Storage和Firebase Realtime Database事件做出反應的功能。讓我們從Auth開始。
在將Firebase SDK用於Cloud Functions時,您的Functions代碼將位於functions
目錄下(默認情況下)。您的Functions代碼也是Node.js應用程序,因此需要package.json
來提供有關您的應用程序的一些信息並列出依賴項。
為了使您更輕鬆,我們已經創建了functions/index.js
文件,您可以在該文件中找到代碼。在繼續前進之前,請隨時檢查此文件。
cd functions
ls
如果您不熟悉Node.js ,它將有助於在繼續進行代碼實驗室之前進一步了解它。
package.json文件已經列出了兩個必需的依賴項:用於Cloud Functions的Firebase SDK和Firebase Admin SDK 。要在本地安裝它們, npm install
從functions
文件夾運行npm install
:
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.
我們將首先導入所需的模塊,然後編寫三個Function代替TODO。首先,讓我們導入所需的Node模塊。
在此代碼實驗室期間,將需要兩個模塊, firebase-functions
模塊允許我們編寫Cloud Functions觸發規則,而firebase-admin
模塊允許我們在具有管理員訪問權限的服務器上使用Firebase平台,例如寫入Cloud 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.
當部署在Cloud Functions環境或其他Google Cloud Platform容器上時,可以自動配置Firebase Admin SDK。這是我們在調用admin.initializeApp();
時admin.initializeApp();
現在,讓我們添加一個功能,該功能在用戶首次登錄您的聊天應用程序時運行,並且我們將添加一個聊天消息來歡迎用戶。
聊天消息結構
發佈到FriendlyChat聊天供稿的消息存儲在Cloud Firestore中。讓我們看一下用於消息的數據結構。為此,將新消息發佈到聊天室中,並顯示“ Hello World”:
它應顯示為:
在Firebase應用程序控制台中,單擊“開發”部分下的“數據庫”。您應該看到消息集合和一個包含所寫消息的文檔:
如您所見,聊天消息作為文檔存儲在Cloud Firestore中, name
, profilePicUrl
, text
和timestamp
屬性添加到了messages
集合中。
添加歡迎信息
第一個Cloud Function添加一條消息,歡迎新用戶加入聊天。為此,我們可以使用觸發器functions.auth().onCreate
,該觸發器在用戶每次首次登錄Firebase應用程序時運行該函數。將addWelcomeMessages
函數添加到index.js
文件中:
index.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
像是Node使該功能可在當前文件之外訪問的方式,並且對於Cloud Functions是必需的。
在上面的功能中,我們將“ Firebase Bot”發布的新歡迎消息添加到聊天消息列表中。我們通過在Cloud Firestore中的messages
集合上使用add
方法來執行此操作,該方法是存儲聊天消息的位置。
由於這是異步操作,因此我們需要返回Promise,以指示Cloud Firestore寫入何時完成,以便Functions不會過早退出執行。
部署功能
該功能僅在部署後才處於活動狀態。在命令行上運行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
測試功能
功能成功部署後,您將需要有一個首次登錄的用戶。
- 使用託管URL(以
https://<project-id>.firebaseapp.com
的形式)在瀏覽器中打開您的應用程序。 - 對於新用戶,請使用“登錄”按鈕首次在您的應用程序中登錄。
- 如果您已經登錄了該應用程序,則可以打開Firebase控制台身份驗證部分,然後從用戶列表中刪除您的帳戶。然後再次登錄。
- 登錄後,將自動顯示歡迎消息:
用戶可以在聊天中上載所有類型的圖像,並且適度冒犯性圖像始終很重要,尤其是在公共社交平台中。在FriendlyChat中,將發佈到聊天室中的圖像存儲到Google Cloud Storage中。
使用Cloud Functions,您可以使用functions.storage().onFinalize
觸發器來檢測新的圖像上傳。每當在Cloud Storage中上傳或修改新文件時,此操作就會運行。
要審核圖像,我們將執行以下過程:
- 使用Cloud Vision API檢查圖像是否標記為成人或暴力
- 如果圖像已被標記,則將其下載到正在運行的Functions實例上
- 使用ImageMagick模糊圖像
- 將模糊的圖像上傳到Cloud Storage
啟用Cloud Vision API
由於我們將在此功能中使用Google Cloud Vision API,因此您必須在Firebase項目上啟用該API。點擊此鏈接,選擇您的Firebase項目並啟用API:
安裝依賴項
要審核圖像,我們需要一些Node.js包:
- 適用於Node.js的Google Cloud Vision客戶端庫: @ google-cloud / vision ,可通過Cloud Vision API運行圖像以檢測不適當的圖像。
- 一個Node.js庫,允許我們運行進程:子進程承諾運行ImageMagick,因為ImageMagick命令行工具已預先安裝在所有Functions實例上。
要將這兩個軟件包安裝到您的Cloud Functions應用中,請運行以下npm install --save
命令。確保您從functions
目錄執行此操作。
npm install --save @google-cloud/vision@0.12.0 child-process-promise@2.2.1
這將在本地安裝這兩個軟件包,並將它們作為已聲明的依賴項添加到package.json
文件中。
導入和配置依賴項
要導入已安裝的兩個依賴項以及本節中需要的一些Node.js核心模塊( path
, os
和fs
),請在index.js
文件頂部添加以下幾行:
index.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');
由於您的功能將在Google Cloud環境中運行,因此無需配置Cloud Storage和Cloud Vision庫:它們將自動配置為使用您的項目。
檢測不合適的圖像
您將使用functions.storage.onChange
Cloud Functions觸發器,該觸發器將在Cloud Storage存儲桶中創建或修改文件或文件夾後立即運行代碼。將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 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.');
});
請注意,我們添加了將運行該函數的Cloud Functions實例的一些配置,我們使用.runWith({memory: '2GB'})
請求該實例獲取2GB的內存而不是默認的內存,這將有所幫助函數是佔用大量內存的。
觸發該功能後,將通過Cloud Vision API運行該圖像,以檢測該圖像是否標記為成人或暴力。如果根據這些標準將圖像檢測為不適當的圖像,我們將對圖像進行模糊處理,這將在blurImage
函數中完成,我們將在下面看到。
圖像模糊
在index.js
文件中添加以下blurImage
函數:
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});
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
工具對圖像進行模糊處理,然後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
測試功能
功能成功部署後:
- 使用託管URL(以
https://<project-id>.firebaseapp.com
的形式)在瀏覽器中打開您的應用程序。 - 登錄應用後,上傳圖片:
- 選擇要上傳的最佳進攻圖像(或者您可以使用這張吃殭屍的肉!),過一會兒,您應該會看到圖像模糊不清,您的帖子會刷新:
在本部分中,您將添加一個Cloud Function,該功能會在發布新消息時向聊天參與者發送通知。
使用Firebase Cloud Messaging (FCM),您可以跨平台且可靠的方式向用戶發送通知。要將通知發送給用戶,您需要他們的FCM設備令牌。當用戶首次在新的瀏覽器或設備上打開應用程序時,我們正在使用的聊天網絡應用程序已從用戶那裡收集設備令牌。這些令牌存儲在fcmTokens
集合中的Cloud Firestore中。
如果您想學習如何在Web應用程序上獲取FCM設備令牌,可以通過Firebase Web Codelab 。
發送通知
要檢測何時發布新消息,您將使用functions.firestore.document().onCreate
Cloud Functions觸發器,該觸發器在Cloud 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);
console.log('Notifications have been sent and tokens cleaned up.');
}
});
在上面的函數中,我們從Cloud Firestore數據庫收集所有用戶的設備令牌,並使用admin.messaging().sendToDevice
函數向每個令牌發送通知。
清理令牌
最後,我們要刪除不再有效的令牌。當我們曾經從用戶那裡獲得的令牌不再被瀏覽器或設備使用時,就會發生這種情況。例如,如果用戶已撤銷其瀏覽器會話的通知權限,則會發生這種情況。為此,在index.js
文件中添加以下cleanupTokens
函數:
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) {
console.error('Failure sending notification to', tokens[index], error);
// Cleanup the tokens who 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
測試功能
- 功能成功部署後,使用託管URL(以
https://<project-id>.firebaseapp.com
的形式)在瀏覽器中打開您的應用程序。 - 如果您是首次登錄應用,請確保在出現提示時允許通知:
- 關閉聊天應用程序選項卡或顯示其他選項卡:僅當應用程序在後台時,才會顯示通知。如果您想了解如何在前台運行應用程序時接收消息,請查看我們的文檔。
- 使用其他瀏覽器(或隱身窗口),登錄應用並發布消息。您應該看到第一個瀏覽器顯示的通知:
您已使用Firebase SDK for Cloud Functions並將服務器端組件添加到聊天應用程序中。
我們涵蓋的內容
- 使用Firebase SDK for Cloud Functions創作Cloud Functions。
- 根據Auth,Cloud Storage和Cloud Firestore事件觸發Cloud Functions。
- 將Firebase Cloud Messaging支持添加到您的Web應用程序。
- 使用Firebase CLI部署的雲功能。
下一步
- 了解其他Cloud Function觸發器類型。
- 將Firebase和Cloud Functions與您自己的應用一起使用。