Gửi thông báo cho ứng dụng web bằng giải pháp Gửi thông báo qua đám mây và Chức năng đám mây

1. Tổng quan

Trong lớp học lập trình này, bạn sẽ tìm hiểu cách sử dụng Cloud Functions cho Firebase để thêm chức năng vào một ứng dụng web trò chuyện bằng cách gửi thông báo cho người dùng ứng dụng trò chuyện.

3b1284f5144b54f6.png

Kiến thức bạn sẽ học được

  • Tạo Google Cloud Functions bằng Firebase SDK.
  • Kích hoạt Cloud Functions dựa trên các sự kiện Auth, Cloud Storage và Cloud Firestore.
  • Thêm tính năng hỗ trợ Giải pháp gửi thông báo qua đám mây của Firebase vào ứng dụng web của bạn.

Bạn cần có

  • Thẻ tín dụng. Cloud Functions cho Firebase yêu cầu gói Blaze của Firebase. Điều này có nghĩa là bạn sẽ phải bật tính năng thanh toán cho dự án Firebase của mình bằng thẻ tín dụng.
  • IDE/trình chỉnh sửa văn bản mà bạn chọn, chẳng hạn như WebStorm, Atom hoặc Sublime.
  • Một cửa sổ dòng lệnh để chạy các lệnh shell khi đã cài đặt NodeJS phiên bản 9.
  • Một trình duyệt như Chrome.
  • Mã mẫu. Xem bước tiếp theo cho việc này.

2. Nhận mã mẫu

Sao chép kho lưu trữ GitHub từ dòng lệnh:

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

Nhập ứng dụng khởi đầu

Bằng cách sử dụng IDE, hãy mở hoặc nhập thư mục android_studio_folder.pngcloud-functions-start từ thư mục mã mẫu. Thư mục này chứa đoạn mã khởi đầu cho lớp học lập trình, bao gồm một Ứng dụng trò chuyện trên web có đầy đủ chức năng.

3. Tạo dự án Firebase và thiết lập ứng dụng

Tạo dự án

  1. Đăng nhập vào bảng điều khiển của Firebase bằng Tài khoản Google của bạn.
  2. Nhấp vào nút này để tạo một dự án mới, rồi nhập tên dự án (ví dụ: FriendlyChat).
  3. Nhấp vào Tiếp tục.
  4. Nếu được nhắc, hãy xem xét và chấp nhận các điều khoản của Firebase, rồi nhấp vào Tiếp tục.
  5. (Không bắt buộc) Bật tính năng hỗ trợ của AI trong bảng điều khiển của Firebase (còn gọi là "Gemini trong Firebase").
  6. Đối với lớp học lập trình này, bạn không cần Google Analytics, vì vậy hãy tắt lựa chọn Google Analytics.
  7. Nhấp vào Tạo dự án, đợi dự án được cấp phép rồi nhấp vào Tiếp tục.

Nâng cấp lên gói Blaze

Để sử dụng Cloud Functions cho Firebase và Cloud Storage cho Firebase, dự án Firebase của bạn cần phải sử dụng gói giá trả theo mức sử dụng (Blaze). Tức là dự án đó phải được liên kết với một Tài khoản thanh toán trên đám mây.

Nếu bạn không có thẻ tín dụng hoặc không muốn tiếp tục sử dụng gói giá Linh hoạt, hãy cân nhắc sử dụng Firebase Emulator Suite. Bộ công cụ này sẽ cho phép bạn mô phỏng Cloud Functions miễn phí trên máy cục bộ.

Tất cả dự án Firebase, kể cả những dự án sử dụng gói giá linh hoạt, vẫn có hạn mức sử dụng Cloud Functions không mất phí. Các bước được trình bày trong lớp học lập trình này sẽ nằm trong hạn mức sử dụng của gói miễn phí. Tuy nhiên, bạn sẽ thấy các khoản phí nhỏ (khoảng 0,03 USD) từ Cloud Storage.Đây là dịch vụ được dùng để lưu trữ các hình ảnh bản dựng Cloud Functions.

Để nâng cấp dự án lên gói Blaze, hãy làm theo các bước sau:

  1. Trong bảng điều khiển của Firebase, hãy chọn nâng cấp gói.
  2. Chọn gói Blaze. Làm theo hướng dẫn trên màn hình để liên kết một tài khoản thanh toán trên Cloud với dự án của bạn.
    Nếu cần tạo một tài khoản thanh toán trên Cloud trong quá trình nâng cấp này, bạn có thể cần quay lại quy trình nâng cấp trong bảng điều khiển Firebase để hoàn tất quá trình nâng cấp.

Bật tính năng Uỷ quyền của Google

Để cho phép người dùng đăng nhập vào ứng dụng, chúng ta sẽ dùng tính năng xác thực của Google và cần bật tính năng này.

Trong Bảng điều khiển Firebase, hãy mở mục Tạo > Xác thực > thẻ Phương thức đăng nhập (hoặc nhấp vào đây để chuyển đến thẻ này). Sau đó, hãy bật Nhà cung cấp dịch vụ đăng nhập bằng Google rồi nhấp vào Lưu. Thao tác này sẽ cho phép người dùng đăng nhập vào ứng dụng web bằng Tài khoản Google của họ.

Ngoài ra, bạn có thể đặt tên công khai của ứng dụng thành Friendly Chat:

8290061806aacb46.png

Thiết lập Cloud Storage cho Firebase

Ứng dụng này sử dụng Cloud Storage để tải ảnh lên.

Sau đây là cách thiết lập Cloud Storage cho Firebase trong dự án Firebase:

  1. Trong bảng điều khiển bên trái của bảng điều khiển Firebase, hãy mở rộng Tạo rồi chọn Bộ nhớ.
  2. Nhấp vào Bắt đầu.
  3. Chọn một vị trí cho bộ chứa lưu trữ mặc định.
    Các bộ chứa ở US-WEST1, US-CENTRAL1US-EAST1 có thể tận dụng cấp"Luôn miễn phí" của Google Cloud Storage. Các bộ chứa ở tất cả những vị trí khác đều tuân theo mức giá và mức sử dụng của Google Cloud Storage.
  4. Nhấp vào Bắt đầu ở chế độ thử nghiệm. Đọc tuyên bố từ chối trách nhiệm về các quy tắc bảo mật.
    Không phân phối hoặc công khai ứng dụng mà không thêm Quy tắc bảo mật cho vùng lưu trữ của bạn.
  5. Nhấp vào Tạo.

Thêm ứng dụng web

Trên Bảng điều khiển Firebase, hãy thêm một ứng dụng web. Để làm như vậy, hãy chuyển đến phần Cài đặt dự án rồi di chuyển xuống phần Thêm ứng dụng. Chọn web làm nền tảng và đánh dấu vào hộp để thiết lập tính năng Lưu trữ Firebase, sau đó đăng ký ứng dụng và nhấp vào Tiếp theo cho các bước còn lại, cuối cùng nhấp vào Tiếp tục đến bảng điều khiển.

4. Cài đặt Giao diện dòng lệnh của Firebase

Giao diện dòng lệnh (CLI) của Firebase sẽ cho phép bạn phân phát ứng dụng web cục bộ và triển khai ứng dụng web cũng như Cloud Functions.

Để cài đặt hoặc nâng cấp CLI, hãy chạy lệnh npm sau:

npm -g install firebase-tools

Để xác minh rằng bạn đã cài đặt CLI đúng cách, hãy mở một bảng điều khiển và chạy:

firebase --version

Đảm bảo phiên bản Firebase CLI là 4.0.0 trở lên để có tất cả các tính năng mới nhất cần thiết cho Cloud Functions. Nếu không, hãy chạy npm install -g firebase-tools để nâng cấp như minh hoạ ở trên.

Uỷ quyền cho Giao diện dòng lệnh (CLI) của Firebase bằng cách chạy:

firebase login

Đảm bảo bạn đang ở trong thư mục cloud-functions-start, sau đó thiết lập Giao diện dòng lệnh (CLI) của Firebase để sử dụng Dự án Firebase của bạn:

firebase use --add

Tiếp theo, hãy chọn Mã dự án rồi làm theo hướng dẫn. Khi được nhắc, bạn có thể chọn một Biệt hiệu bất kỳ, chẳng hạn như codelab.

5. Triển khai và chạy ứng dụng web

Sau khi nhập và định cấu hình dự án, bạn đã sẵn sàng chạy ứng dụng web lần đầu tiên! Mở cửa sổ dòng lệnh, chuyển đến thư mục cloud-functions-start rồi triển khai ứng dụng web lên dịch vụ lưu trữ Firebase bằng cách sử dụng:

firebase deploy --except functions

Đây là kết quả đầu ra của bảng điều khiển mà bạn sẽ thấy:

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

Mở ứng dụng web

Dòng cuối cùng phải hiển thị URL lưu trữ. Giờ đây, ứng dụng web sẽ được phân phát từ URL này, có dạng https://<project-id>.firebaseapp.com. Hãy mở URL này. Bạn sẽ thấy giao diện người dùng đang hoạt động của một ứng dụng trò chuyện.

Đăng nhập vào ứng dụng bằng cách sử dụng nút ĐĂNG NHẬP BẰNG GOOGLE và thoải mái thêm một số tin nhắn cũng như đăng ảnh:

3b1284f5144b54f6.png

Nếu bạn đăng nhập vào ứng dụng lần đầu tiên trên một trình duyệt mới, hãy nhớ cho phép thông báo khi được nhắc: 8b9d0c66dc36153d.png

Sau này, bạn sẽ cần bật thông báo.

Nếu vô tình nhấp vào Chặn, bạn có thể thay đổi chế độ cài đặt này bằng cách nhấp vào nút 🔒 An toàn ở bên trái URL trong Omnibar của Chrome rồi bật/tắt thanh bên cạnh Thông báo:

e926868b0546ed71.png

Bây giờ, chúng ta sẽ thêm một số chức năng bằng Firebase SDK cho Cloud Functions.

6. Thư mục Hàm

Cloud Functions giúp bạn dễ dàng chạy mã trong Cloud mà không cần thiết lập máy chủ. Chúng ta sẽ cùng tìm hiểu cách tạo các hàm phản hồi các sự kiện của Firebase Auth, Cloud Storage và cơ sở dữ liệu Firebase Firestore. Hãy bắt đầu với Auth.

Khi sử dụng Firebase SDK cho Cloud Functions, mã Functions của bạn sẽ nằm trong thư mục functions (theo mặc định). Mã Functions của bạn cũng là một ứng dụng Node.js và do đó cần có một package.json cung cấp một số thông tin về ứng dụng của bạn và liệt kê các phần phụ thuộc.

Để giúp bạn dễ dàng hơn, chúng tôi đã tạo tệp functions/index.js nơi mã của bạn sẽ được đặt. Bạn có thể kiểm tra tệp này trước khi chuyển sang bước tiếp theo.

cd functions
ls

Nếu chưa quen với Node.js, bạn nên tìm hiểu thêm về nền tảng này trước khi tiếp tục lớp học lập trình.

Tệp package.json đã liệt kê 2 phần phụ thuộc bắt buộc: Firebase SDK cho Cloud FunctionsFirebase Admin SDK. Để cài đặt cục bộ, hãy chuyển đến thư mục functions rồi chạy:

npm install

Bây giờ, hãy xem tệp 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.

Chúng ta sẽ nhập các mô-đun cần thiết rồi viết 3 hàm thay cho các TODO. Hãy bắt đầu bằng cách nhập các mô-đun Node bắt buộc.

7. Nhập các mô-đun Cloud Functions và Firebase Admin

Bạn sẽ cần 2 mô-đun trong lớp học lập trình này: firebase-functions cho phép ghi các trình kích hoạt và nhật ký của Cloud Functions, còn firebase-admin cho phép sử dụng nền tảng Firebase trên một máy chủ có quyền truy cập của quản trị viên để thực hiện các thao tác như ghi vào Cloud Firestore hoặc gửi thông báo FCM.

Trong tệp index.js, hãy thay thế TODO đầu tiên bằng nội dung sau:

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.

Bạn có thể tự động định cấu hình Firebase Admin SDK khi triển khai vào môi trường Cloud Functions hoặc các vùng chứa Google Cloud Platform khác. Điều này xảy ra khi chúng ta gọi admin.initializeApp() mà không có đối số.

Bây giờ, hãy thêm một Hàm chạy khi người dùng đăng nhập lần đầu vào ứng dụng trò chuyện và chúng ta sẽ thêm một tin nhắn trò chuyện để chào mừng người dùng.

8. Chào mừng người dùng mới

Cấu trúc của tin nhắn trong cuộc trò chuyện

Tin nhắn được đăng vào ô trò chuyện FriendlyChat sẽ được lưu trữ trong Cloud Firestore. Hãy xem cấu trúc dữ liệu mà chúng ta sử dụng cho một thông báo. Để làm việc này, hãy đăng một tin nhắn mới vào cuộc trò chuyện có nội dung "Hello World":

11f5a676fbb1a69a.png

Thẻ này sẽ xuất hiện như sau:

fe6d1c020d0744cf.png

Trong Bảng điều khiển của Firebase, hãy nhấp vào Cơ sở dữ liệu Firestore trong mục Tạo. Bạn sẽ thấy bộ sưu tập messages và một tài liệu chứa thông báo mà bạn đã viết:

442c9c10b5e2b245.png

Như bạn thấy, tin nhắn trò chuyện được lưu trữ trong Cloud Firestore dưới dạng một tài liệu có các thuộc tính name, profilePicUrl, texttimestamp được thêm vào tập hợp messages.

Thêm thư chào mừng

Cloud Function đầu tiên sẽ thêm một thông báo chào mừng người dùng mới vào cuộc trò chuyện. Để làm việc này, chúng ta có thể sử dụng trình kích hoạt functions.auth().onCreate. Trình kích hoạt này sẽ chạy hàm mỗi khi người dùng đăng nhập lần đầu vào ứng dụng Firebase. Thêm hàm addWelcomeMessages vào tệp 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.');
});

Việc thêm hàm này vào đối tượng exports đặc biệt là cách Node giúp hàm có thể truy cập bên ngoài tệp hiện tại và là điều kiện bắt buộc đối với Cloud Functions.

Trong hàm trên, chúng ta đang thêm một thông báo chào mừng mới do "Firebase Bot" đăng vào danh sách tin nhắn trò chuyện. Chúng ta thực hiện việc này bằng cách sử dụng phương thức add trên tập hợp messages trong Cloud Firestore. Đây là nơi lưu trữ các tin nhắn của cuộc trò chuyện.

Vì đây là một thao tác không đồng bộ, nên chúng ta cần trả về Promise cho biết thời điểm Cloud Firestore đã hoàn tất việc ghi để Cloud Functions không thực thi quá sớm.

Triển khai Cloud Functions

Cloud Functions sẽ chỉ hoạt động sau khi bạn triển khai chúng. Để thực hiện việc này, hãy chạy lệnh sau trên dòng lệnh:

firebase deploy --only functions

Đây là kết quả đầu ra của bảng điều khiển mà bạn sẽ thấy:

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

Kiểm thử hàm

Sau khi triển khai thành công hàm này, bạn sẽ cần có một người dùng đăng nhập lần đầu tiên.

  1. Mở ứng dụng trong trình duyệt bằng URL lưu trữ (dưới dạng https://<project-id>.firebaseapp.com).
  2. Với một người dùng mới, hãy đăng nhập lần đầu vào ứng dụng bằng nút Đăng nhập.
  • Nếu đã đăng nhập vào ứng dụng, bạn có thể mở Xác thực bằng Firebase Console rồi xoá tài khoản của mình khỏi danh sách người dùng. Sau đó, hãy đăng nhập lại.

262535d1b1223c65.png

  1. Sau khi bạn đăng nhập, một tin nhắn chào mừng sẽ tự động xuất hiện:

1c70e0d64b23525b.png

9. Kiểm duyệt hình ảnh

Người dùng có thể tải mọi loại hình ảnh lên cuộc trò chuyện. Điều quan trọng là bạn phải luôn kiểm duyệt những hình ảnh phản cảm, đặc biệt là trên các nền tảng xã hội công khai. Trong FriendlyChat, những hình ảnh được xuất bản lên cuộc trò chuyện sẽ được lưu trữ trong các bộ chứa Cloud Storage.

Với Cloud Functions, bạn có thể phát hiện các tệp hình ảnh mới được tải lên bằng cách sử dụng trình kích hoạt functions.storage().onFinalize. Thao tác này sẽ chạy mỗi khi một tệp mới được tải lên hoặc sửa đổi trong Cloud Storage.

Để kiểm duyệt hình ảnh, chúng tôi sẽ thực hiện quy trình sau:

  1. Kiểm tra xem hình ảnh có bị gắn cờ là Nội dung người lớn hoặc Bạo lực hay không bằng cách sử dụng Cloud Vision API.
  2. Nếu hình ảnh đã bị gắn cờ, hãy tải hình ảnh đó xuống phiên bản Functions đang chạy.
  3. Làm mờ hình ảnh bằng ImageMagick.
  4. Tải hình ảnh bị làm mờ lên Cloud Storage.

Bật Cloud Vision API

Vì chúng ta sẽ sử dụng Google Cloud Vision API trong hàm này, nên bạn phải bật API này trên dự án Firebase của mình. Truy cập vào đường liên kết này, sau đó chọn dự án Firebase của bạn và bật API:

5c77fee51ec5de49.png

Cài đặt các phần phụ thuộc

Để kiểm duyệt hình ảnh, chúng ta sẽ dùng Thư viện ứng dụng Google Cloud Vision cho Node.js, @google-cloud/vision, để chạy hình ảnh thông qua Cloud Vision API nhằm phát hiện hình ảnh không phù hợp.

Để cài đặt gói này vào ứng dụng Cloud Functions, hãy chạy lệnh npm install --save sau. Hãy nhớ thực hiện thao tác này trong thư mục functions.

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

Thao tác này sẽ cài đặt gói cục bộ và thêm gói đó làm phần phụ thuộc đã khai báo trong tệp package.json.

Nhập và định cấu hình các phần phụ thuộc

Để nhập các phần phụ thuộc đã cài đặt và một số mô-đun cốt lõi của Node.js (path, osfs) mà chúng ta sẽ cần trong phần này, hãy thêm các dòng sau vào đầu tệp 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');

Vì hàm của bạn sẽ chạy trong môi trường Google Cloud, nên bạn không cần định cấu hình các thư viện Cloud Storage và Cloud Vision: các thư viện này sẽ được tự động định cấu hình để sử dụng dự án của bạn.

Phát hiện hình ảnh không phù hợp

Bạn sẽ sử dụng trình kích hoạt functions.storage.onChange Cloud Functions. Trình kích hoạt này sẽ chạy mã của bạn ngay khi một tệp hoặc thư mục được tạo hoặc sửa đổi trong một vùng lưu trữ Cloud Storage. Thêm hàm blurOffensiveImages vào tệp 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.');
    });

Xin lưu ý rằng chúng tôi đã thêm một số cấu hình của phiên bản Cloud Functions sẽ chạy hàm này. Với .runWith({memory: '2GB'}), chúng ta đang yêu cầu phiên bản này nhận được 2 GB bộ nhớ thay vì bộ nhớ mặc định, vì hàm này sử dụng nhiều bộ nhớ.

Khi hàm này được kích hoạt, hình ảnh sẽ được chạy thông qua Cloud Vision API để phát hiện xem hình ảnh đó có bị gắn cờ là nội dung người lớn hoặc bạo lực hay không. Nếu hệ thống phát hiện hình ảnh không phù hợp dựa trên các tiêu chí này, chúng tôi sẽ làm mờ hình ảnh. Việc này được thực hiện trong hàm blurImage như chúng ta sẽ thấy tiếp theo.

Làm mờ hình ảnh

Thêm hàm blurImage sau đây vào tệp 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.');
}

Trong hàm trên, tệp nhị phân hình ảnh được tải xuống từ Cloud Storage. Sau đó, hình ảnh sẽ bị làm mờ bằng công cụ convert của ImageMagick và phiên bản bị làm mờ sẽ được tải lại lên Storage Bucket. Tiếp theo, chúng ta sẽ xoá tệp trên phiên bản Cloud Functions để giải phóng một số dung lượng đĩa. Chúng ta làm việc này vì có thể sử dụng lại cùng một phiên bản Cloud Functions và nếu không dọn dẹp các tệp, phiên bản này có thể hết dung lượng đĩa. Cuối cùng, chúng ta thêm một giá trị boolean vào tin nhắn trò chuyện để cho biết hình ảnh đã được kiểm duyệt. Điều này sẽ kích hoạt quá trình làm mới tin nhắn trên ứng dụng.

Triển khai hàm

Hàm sẽ chỉ hoạt động sau khi bạn triển khai. Trên dòng lệnh, hãy chạy firebase deploy --only functions:

firebase deploy --only functions

Đây là kết quả đầu ra của bảng điều khiển mà bạn sẽ thấy:

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

Kiểm thử hàm

Sau khi triển khai thành công hàm:

  1. Mở ứng dụng trong trình duyệt bằng URL lưu trữ (dưới dạng https://<project-id>.firebaseapp.com).
  2. Sau khi đăng nhập vào ứng dụng, hãy tải hình ảnh lên: 4db9fdab56703e4a.png
  3. Chọn hình ảnh phản cảm nhất để tải lên (hoặc bạn có thể dùng hình ảnh zombie ăn thịt này!) và sau vài giây, bạn sẽ thấy bài đăng của mình được làm mới bằng một phiên bản mờ của hình ảnh: 83dd904fbaf97d2b.png

10. Thông báo về tin nhắn mới

Trong phần này, bạn sẽ thêm một Cloud Function để gửi thông báo cho những người tham gia cuộc trò chuyện khi có tin nhắn mới được đăng.

Khi sử dụng Giải pháp gửi thông báo qua đám mây của Firebase (FCM), bạn có thể gửi thông báo một cách đáng tin cậy cho người dùng trên nhiều nền tảng. Để gửi thông báo cho người dùng, bạn cần có mã thông báo thiết bị FCM của họ. Ứng dụng web trò chuyện mà chúng tôi đang sử dụng đã thu thập mã thông báo thiết bị của người dùng khi họ mở ứng dụng lần đầu tiên trên một trình duyệt hoặc thiết bị mới. Các mã thông báo này được lưu trữ trong Cloud Firestore trong bộ sưu tập fcmTokens.

Nếu muốn tìm hiểu cách lấy mã thông báo thiết bị FCM trên một ứng dụng web, bạn có thể tham gia Lớp học lập trình Firebase Web.

Gửi thông báo

Để phát hiện thời điểm có tin nhắn mới được đăng, bạn sẽ sử dụng trình kích hoạt functions.firestore.document().onCreate Cloud Functions. Trình kích hoạt này sẽ chạy mã của bạn khi một đối tượng mới được tạo tại một đường dẫn nhất định của Cloud Firestore. Thêm hàm sendNotifications vào tệp 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.');
    }
  });

Trong hàm ở trên, chúng ta đang thu thập mã thông báo thiết bị của tất cả người dùng từ cơ sở dữ liệu Cloud Firestore và gửi thông báo đến từng mã thông báo này bằng hàm admin.messaging().sendToDevice.

Dọn dẹp mã thông báo

Cuối cùng, chúng ta muốn xoá những mã thông báo không còn hợp lệ. Điều này xảy ra khi trình duyệt hoặc thiết bị không còn sử dụng mã thông báo mà chúng tôi đã nhận được từ người dùng nữa. Ví dụ: điều này xảy ra nếu người dùng đã thu hồi quyền nhận thông báo cho phiên trình duyệt. Để thực hiện việc này, hãy thêm hàm cleanupTokens sau đây vào tệp 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);
}

Triển khai hàm

Hàm này sẽ chỉ hoạt động sau khi bạn triển khai. Để triển khai, hãy chạy lệnh sau trong dòng lệnh:

firebase deploy --only functions

Đây là kết quả đầu ra của bảng điều khiển mà bạn sẽ thấy:

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

Kiểm thử hàm

  1. Sau khi triển khai thành công hàm này, hãy mở ứng dụng trong trình duyệt bằng URL lưu trữ (dưới dạng https://<project-id>.firebaseapp.com).
  2. Nếu bạn đăng nhập vào ứng dụng lần đầu tiên, hãy nhớ cho phép thông báo khi được nhắc: 8b9d0c66dc36153d.png
  3. Đóng thẻ ứng dụng trò chuyện hoặc hiển thị một thẻ khác: Thông báo chỉ xuất hiện nếu ứng dụng ở chế độ nền. Nếu bạn muốn tìm hiểu cách nhận thông báo trong khi ứng dụng đang chạy trên nền trước, hãy xem tài liệu của chúng tôi.
  4. Dùng một trình duyệt khác (hoặc cửa sổ ẩn danh), đăng nhập vào ứng dụng rồi đăng một tin nhắn. Bạn sẽ thấy một thông báo do trình duyệt đầu tiên hiển thị: 45282ab12b28b926.png

11. Xin chúc mừng!

Bạn đã sử dụng Firebase SDK cho Cloud Functions và thêm các thành phần phía máy chủ vào một ứng dụng trò chuyện.

Nội dung đã đề cập

  • Tạo Cloud Functions bằng Firebase SDK cho Cloud Functions.
  • Kích hoạt Cloud Functions dựa trên các sự kiện Auth, Cloud Storage và Cloud Firestore.
  • Thêm tính năng hỗ trợ Giải pháp gửi thông báo qua đám mây của Firebase vào ứng dụng web của bạn.
  • Triển khai Cloud Functions bằng Firebase CLI.

Các bước tiếp theo

Tìm hiểu thêm