שליחת התראות לאפליקציית אינטרנט באמצעות Cloud Messaging ו-Cloud Functions

1. סקירה כללית

ב-Codelab הזה תלמדו איך להשתמש ב-Cloud Functions for Firebase כדי להוסיף פונקציונליות לאפליקציית אינטרנט של Chat, על ידי שליחת התראות למשתמשים באפליקציית Chat.

3b1284f5144b54f6.png

מה תלמדו

  • יצירת Google Cloud Functions באמצעות Firebase SDK.
  • הפעלת Cloud Functions על סמך אירועי Auth, Cloud Storage ו-Cloud Firestore.
  • הוספת תמיכה ב-Cloud Messaging לאפליקציית האינטרנט.

מה צריך להכין

  • כרטיס אשראי. כדי להשתמש ב-Cloud Functions for Firebase נדרשת תוכנית Firebase Blaze, כלומר עליך להפעיל את החיוב בפרויקט Firebase באמצעות כרטיס אשראי.
  • סביבת הפיתוח המשולבת (IDE) או עורך הטקסט שבחרתם, כמו WebStorm,‏ Atom או Sublime.
  • טרמינל להרצת פקודות מעטפת שמותקן בו NodeJS v9.
  • דפדפן כמו Chrome.
  • הקוד לדוגמה. לשם כך, יש לפעול לפי השלבים הבאים.

2. קבלת קוד לדוגמה

משכפלים את מאגר ה-GitHub משורת הפקודה:

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

ייבוא האפליקציה למתחילים

בסביבת הפיתוח המשולבת (IDE), פותחים או מייבאים את ספריית android_studio_folder.pngcloud-functions-start מספריית הקוד לדוגמה. הספרייה הזו מכילה את קוד ההתחלה של Codelab, שמורכב מ-Chat Web App שפועל באופן מלא.

3. יצירת פרויקט Firebase והגדרת האפליקציה

יצירת פרויקט

במסוף Firebase, לוחצים על הוספת פרויקט וקוראים לפרויקט ידידותי ל-Chat.

לוחצים על Create Project.

שדרוג לתוכנית Blaze

כדי להשתמש ב-Cloud Functions for Firebase וב-Cloud Storage for Firebase, פרויקט Firebase צריך להיות בתוכנית התמחור 'תשלום לפי שימוש' (Blaze), כלומר הוא צריך להיות מקושר לחשבון לחיוב ב-Cloud.

אם אין לכם גישה לכרטיס אשראי או שלא מתאים לכם להמשיך עם תוכנית התמחור והתשלומים של Blaze, מומלץ להשתמש בחבילת האמולטור של Firebase, שתאפשר לכם ליצור אמולציה של Cloud Functions בחינם במחשב שלכם.

לכל הפרויקטים ב-Firebase, כולל אלה בתוכנית התמחור Blaze, עדיין יש גישה למכסות שימוש ללא עלות ב-Cloud Functions. השלבים שמפורטים ב-codelab הזה יהיו במסגרת מגבלות השימוש של תוכנית 'חינם תמיד'. עם זאת, יהיו חיובים קטנים (כ-$0.03) מ-Cloud Storage שמשמשים לאירוח קובצי אימג' של ה-build של Cloud Functions.

כדי לשדרג את הפרויקט לתוכנית Blaze, יש לפעול לפי השלבים הבאים:

  1. במסוף Firebase, בוחרים באפשרות שדרוג התוכנית.
  2. בוחרים את תוכנית Blaze. פועלים לפי ההוראות במסך כדי לקשר חשבון לחיוב ב-Cloud לפרויקט.
    אם נדרשת יצירת חשבון לחיוב ב-Cloud כחלק מהשדרוג, יכול להיות שתצטרכו לחזור לתהליך השדרוג במסוף Firebase כדי להשלים את השדרוג.

הפעלת Google Auth

כדי לאפשר למשתמשים להיכנס לאפליקציה, נשתמש באימות של Google שצריך להפעיל.

במסוף Firebase, פותחים את הקטע Build > Authentication (אימות) > הכרטיסייה Sign-in method (שיטת הכניסה או לוחצים כאן כדי להיכנס לשם). לאחר מכן, מפעילים את האפשרות 'ספק הכניסה של Google' ולוחצים על שמירה. כך המשתמשים יוכלו להיכנס לאפליקציית האינטרנט באמצעות חשבונות Google שלהם.

בנוסף, אתם יכולים להגדיר את השם של האפליקציה שגלוי לכולם כידידותי ל-Chat:

8290061806aacb46.png

הגדרה של Cloud Storage for Firebase

האפליקציה משתמשת ב-Cloud Storage כדי להעלות תמונות.

כך מגדירים את Cloud Storage for Firebase בפרויקט Firebase:

  1. בחלונית הימנית של מסוף Firebase, מרחיבים את Build ובוחרים באפשרות Storage.
  2. לוחצים על תחילת העבודה.
  3. בוחרים מיקום לקטגוריית ברירת המחדל של האחסון.
    קטגוריות ב-US-WEST1, ב-US-CENTRAL1 וב-US-EAST1 יכולות ליהנות מהתוכנית 'תמיד בחינם' ב-Google Cloud Storage. קטגוריות בכל המיקומים האחרים כפופות לתמחור ולשימוש ב-Google Cloud Storage.
  4. לוחצים על הפעלה במצב בדיקה. קוראים את כתב הוויתור לגבי כללי האבטחה.
    לא תפיץ או תחשוף אפליקציה באופן ציבורי בלי להוסיף כללי אבטחה לקטגוריית האחסון.
  5. לוחצים על יצירה.

הוספה של אפליקציית אינטרנט

מוסיפים אפליקציית אינטרנט במסוף Firebase. כדי לעשות זאת, עוברים אל Project Settings (הגדרות הפרויקט) וגוללים למטה אל Add app (הוספת האפליקציה). בוחרים את האתר כפלטפורמה, ומסמנים את התיבה של הגדרת האירוח ב-Firebase. לאחר מכן רושמים את האפליקציה ולוחצים על Next (הבא) עד שאר השלבים, ולבסוף לוחצים על Continue to console.

4. התקנת ממשק שורת הפקודה של Firebase

ממשק שורת הפקודה (CLI) של Firebase יאפשר לכם להציג את אפליקציית האינטרנט באופן מקומי ולפרוס את אפליקציית האינטרנט ו-Cloud Functions.

כדי להתקין או לשדרג את ה-CLI, מריצים את פקודת ה-npm הבאה:

npm -g install firebase-tools

כדי לוודא שה-CLI הותקן בצורה תקינה, פותחים מסוף ומריצים את הפקודה הבאה:

firebase --version

כדי שהגרסה של ה-CLI של Firebase היא יותר מ-4.0.0, צריך לוודא שהיא כוללת את כל התכונות העדכניות ביותר שנדרשות ל-Cloud Functions. אם לא, מריצים את npm install -g firebase-tools כדי לשדרג כפי שמתואר למעלה.

נותנים הרשאה ל-Firebase CLI על ידי הפעלת הפקודה:

firebase login

מוודאים שנמצאים בספרייה cloud-functions-start ומגדירים את Firebase CLI לשימוש בפרויקט Firebase:

firebase use --add

בשלב הבא, בוחרים את מזהה הפרויקט ופועלים לפי ההוראות. כשמוצגת בקשה, אפשר לבחור כל כינוי, למשל codelab.

5. פריסה והפעלה של אפליקציית האינטרנט

אחרי שמייבאים את הפרויקט ומגדירים אותו, אפשר להריץ את אפליקציית האינטרנט בפעם הראשונה. פותחים חלון טרמינל, עוברים לתיקייה cloud-functions-start ופורסים את אפליקציית האינטרנט באירוח 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 הזו, שאמורה להיות בפורמט https://<project-id>.firebaseapp.com. פותחים אותה. אתם אמורים לראות את ממשק המשתמש של אפליקציית Chat.

נכנסים לאפליקציה באמצעות הלחצן כניסה באמצעות חשבון Google, ומוסיפים הודעות ומפרסמים תמונות:

3b1284f5144b54f6.png

אם נכנסים לאפליקציה בפעם הראשונה בדפדפן חדש, צריך להקפיד לאשר התראות כשמוצגת בקשה לעשות זאת: 8b9d0c66dc36153d.png

נצטרך להפעיל את ההתראות בשלב מאוחר יותר.

אם לחצתם בטעות על חסימה, תוכלו לשנות את ההגדרה הזו על ידי לחיצה על הלחצן 🔒 Secure מימין לכתובת ה-URL בסרגל הכלים של Chrome והחלפת המצב של הסרגל שלצד התראות:

e926868b0546ed71.png

עכשיו נוסיף פונקציונליות מסוימת באמצעות Firebase SDK ל-Cloud Functions.

6. ספריית הפונקציות

בעזרת Cloud Functions תוכלו להשתמש בקלות בקוד שרץ בענן, בלי שתצטרכו להגדיר שרת. נסביר לך איך ליצור פונקציות שמגיבות לאירועים של Firebase Auth, Cloud Storage ו-Firebase Firestore. נתחיל עם אימות.

כשמשתמשים ב-Firebase SDK ל-Cloud Functions, קוד Functions נמצא בתיקייה functions (כברירת מחדל). קוד הפונקציות הוא גם אפליקציית Node.js ולכן נדרש package.json שמספק מידע מסוים על האפליקציה ומפרט יחסי התלות.

כדי להקל עליך, כבר יצרנו את הקובץ functions/index.js שאליו יועבר הקוד. אפשר לבדוק את הקובץ הזה לפני שממשיכים.

cd functions
ls

אם אתם לא מכירים את Node.js, מומלץ לקרוא מידע נוסף עליה לפני שתמשיכו בקודלאב.

בקובץ package.json כבר מפורטות שתי יחסי תלות נדרשים: Firebase SDK for Cloud Functions ו-Firebase Admin 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.

אנחנו נייבא את המודולים הנדרשים ואז נכתוב שלוש פונקציות במקום המשימות לביצוע. נתחיל בייבוא של המודולים הנדרשים של Node.

7. ייבוא המודולים של Cloud Functions ו-Firebase Admin

במהלך הקודלאב הזה נשתמש בשני מודולים: 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.

ניתן להגדיר באופן אוטומטי את ה-SDK של Firebase Admin כשפורסים אותו בסביבת Cloud Functions או בקונטיינרים אחרים של Google Cloud Platform. ההגדרה הזו מתבצעת כשאנחנו קוראים לפונקציה admin.initializeApp() ללא ארגומנטים.

עכשיו נוסיף פונקציה שתופעל כשמשתמש ייכנס לחשבון בפעם הראשונה באפליקציית הצ'אט, ונוסיף הודעת צ'אט כדי לברך את המשתמש.

8. מקבלים משתמשים חדשים

מבנה ההודעות ב-Chat

ההודעות שמפרסמים בפיד הצ'אט של WonderChat מאוחסנות ב-Cloud Firestore. נבחן את מבנה הנתונים שבו אנחנו משתמשים להודעה. כדי לעשות את זה, צריך לפרסם בצ'אט הודעה חדשה עם הכיתוב 'Hello World' (שלום עולם):

11f5a676fbb1a69a.png

זה אמור להופיע כך:

fe6d1c020d0744cf.png

במסוף Firebase, לוחצים על Firestore Database בקטע Build. אתם אמורים לראות את אוסף ההודעות ומסמך אחד שמכיל את ההודעה שכתבתם:

442c9c10b5e2b245.png

כפי שאפשר לראות, הודעות צ'אט מאוחסנות ב-Cloud Firestore כמסמך עם מאפייני name,‏ profilePicUrl,‏ text ו-timestamp שנוספו לאוסף messages.

הוספת הודעות פתיחה

הפונקציה הראשונה ב-Cloud Functions מוסיפה לצ'אט הודעה שמקבלת את פני משתמשים חדשים. לשם כך, אפשר להשתמש בטריגר 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) => {
  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 היא הדרך של Node להפוך את הפונקציה לנגישה מחוץ לקובץ הנוכחי, והיא נדרשת ל-Cloud Functions.

בפונקציה שלמעלה, אנחנו מוסיפים לרשימת ההודעות בצ'אט הודעת פתיחה חדשה שפורסמה על ידי 'Firebase Bot'. אנחנו עושים זאת באמצעות השיטה add באוסף messages ב-Cloud Firestore, שבו מאוחסנים ההודעות בצ'אט.

מכיוון שזו פעולה אסינכררונית, אנחנו צריכים להחזיר את ה-Promise שמציין מתי Cloud Firestore סיים לכתוב, כדי ש-Cloud Functions לא יפעל מוקדם מדי.

פריסת Cloud Functions

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. עם משתמש חדש, נכנסים לאפליקציה בפעם הראשונה באמצעות הלחצן כניסה.
  • אם כבר נכנסתם לאפליקציה, אתם יכולים לפתוח את האימות במסוף Firebase ולמחוק את החשבון מרשימת המשתמשים. לאחר מכן, נכנסים שוב לחשבון.

262535d1b1223c65.png

  1. אחרי שתיכנסו, הודעת הפתיחה אמורה להופיע באופן אוטומטי:

1c70e0d64b23525b.png

9. ניהול תמונות

המשתמשים יכולים להעלות כל סוג של תמונות בצ'אט, ותמיד חשוב לנהל תמונות פוגעניות, במיוחד בפלטפורמות חברתיות ציבוריות. ב-FriendlyChat, התמונות שפורסמו בצ'אט מאוחסנות בקטגוריות של Cloud Storage.

עם Cloud Functions, אפשר לזהות העלאות של תמונות חדשות באמצעות הטריגר functions.storage().onFinalize. הפקודה הזו תרוץ בכל פעם שיועלה קובץ חדש או שיתבצע שינוי בקובץ ב-Cloud Storage.

כדי לנהל את התמונות, אנחנו פועלים לפי התהליך הבא:

  1. בודקים אם התמונה סומנה כתוכן למבוגרים או כתוכן אלים באמצעות Cloud Vision API.
  2. אם התמונה סומנה, מורידים אותה במכונה שפועלת של Functions.
  3. מטשטשים את התמונה באמצעות ImageMagick.
  4. מעלים את התמונה המטושטשת ל-Cloud Storage.

הפעלה של Cloud Vision API

אנחנו נשתמש ב-Google Cloud Vision API בפונקציה הזו, ולכן צריך להפעיל את ה-API בפרויקט firebase. לוחצים על הקישור הזה, בוחרים את הפרויקט ב-Firebase ומפעילים את ה-API:

5c77fee51ec5de49.png

תלות בהתקנות

על מנת לנהל תמונות, נשתמש בספריית הלקוח של Google Cloud Vision עבור Node.js, @google-cloud/vision, כדי להריץ תמונות דרך Cloud Vision API ולאתר תמונות לא הולמות.

כדי להתקין את החבילה הזו באפליקציית Cloud Functions, מריצים את הפקודה הבאה של npm install --save. חשוב לוודא שאתם מבצעים את הפעולה הזו מהספרייה functions.

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

הפקודה הזו תתקין את החבילה באופן מקומי ותוסיף אותה כיחס תלות מוצהר בקובץ package.json.

ייבוא והגדרה של יחסי תלות

כדי לייבא את יחסי התלות שהותקנו ואת חלק ממודולי הליבה של Node.js‏ (path,‏ os ו-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 של 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 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. לאחר מכן התמונה מטושטשת באמצעות הכלי convert של ImageMagick, והגרסה המטושטשת תועלה מחדש לקטגוריית האחסון. בשלב הבא אנחנו מוחקים את הקובץ במכונה של 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. התראות על הודעות חדשות

בקטע הזה נוסיף פונקציה של Cloud Functions ששולחת התראות למשתתפים בצ'אט כשמפרסמים הודעה חדשה.

באמצעות העברת הודעות בענן ב-Firebase (FCM), אפשר לשלוח למשתמשים התראות בפלטפורמות שונות בצורה אמינה. כדי לשלוח הודעה למשתמש, נדרש אסימון מכשיר ב-FCM שלו. אפליקציית הצ'אט לאינטרנט שבה אנחנו משתמשים כבר אוספת אסימוני מכשירים ממשתמשים כשהם פותחים את האפליקציה בפעם הראשונה בדפדפן או במכשיר חדשים. האסימונים האלה מאוחסנים ב-Cloud Firestore באוסף fcmTokens.

רוצים לדעת איך מקבלים אסימוני מכשיר של FCM באפליקציית אינטרנט? אתם יכולים לעיין בCodelab של Firebase לאינטרנט.

שליחת התראות

כדי לזהות מתי מתפרסמות הודעות חדשות, תשתמשו בטריגר 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);
      functions.logger.log('Notifications have been sent and tokens cleaned up.');
    }
  });

בפונקציה שלמעלה, אנחנו אוספים את כל אסימוני המכשירים של המשתמשים ממסד הנתונים של Cloud 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. לאחר שהפונקציה נפרסת בהצלחה, פותחים את האפליקציה בדפדפן באמצעות כתובת ה-URL של האירוח (בפורמט https://<project-id>.firebaseapp.com).
  2. אם נכנסים לאפליקציה בפעם הראשונה, צריך להקפיד לאשר קבלת התראות כשמוצגת ההודעה: 8b9d0c66dc36153d.png
  3. סגירת הכרטיסייה של אפליקציית הצ'אט או הצגת כרטיסייה אחרת: ההתראות מופיעות רק אם האפליקציה פועלת ברקע. כדי ללמוד איך לקבל הודעות בזמן שהאפליקציה בחזית, אפשר לעיין בתיעוד שלנו.
  4. נכנסים לאפליקציה בדפדפן אחר (או בחלון פרטי) ומפרסמים הודעה. אמורה להופיע התראה בדפדפן הראשון: 45282ab12b28b926.png

11. כל הכבוד!

השתמשתם ב-Firebase SDK ל-Cloud Functions והוספתם רכיבים בצד השרת לאפליקציית צ'אט.

אילו נושאים דיברנו?

  • כתיבת פונקציות של Cloud Functions באמצעות Firebase SDK for Cloud Functions.
  • הפעלת פונקציות של Cloud Functions על סמך אירועים של Auth,‏ Cloud Storage ו-Cloud Firestore.
  • הוספת תמיכה ב-Cloud Messaging לאפליקציית האינטרנט.
  • פריסת Cloud Functions באמצעות ה-CLI של Firebase.

השלבים הבאים

מידע נוסף