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

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

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

3b1284f5144b54f6.png

מה תלמדו

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

מה צריך

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

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

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

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

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

באמצעות סביבת הפיתוח המשולבת, פותחים או מייבאים את התיקייה android_studio_folder.pngcloud-functions-start מתיקיית הקוד לדוגמה. הספרייה הזו מכילה את קוד ההתחלה של סדנת הקוד, שמכיל אפליקציית אינטרנט פונקציונלית של Chat.

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

יצירת פרויקט

במסוף Firebase, לוחצים על Add Project (הוספת פרויקט) ומזינים את השם FriendlyChat.

לוחצים על Create Project.

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

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

  • בחשבון לחיוב ב-Cloud נדרש אמצעי תשלום, כמו כרטיס אשראי.
  • אם אתם משתמשים חדשים ב-Firebase וב-Google Cloud, כדאי לבדוק אם אתם זכאים לקרדיט בסך 300$ולחשבון לחיוב ב-Cloud בתקופת ניסיון בחינם.
  • אם אתם מבצעים את הקודלאב הזה כחלק מאירוע, כדאי לשאול את המארגן אם יש זיכויים ב-Cloud שזמינים.

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

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

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

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

הפעלת אימות Google

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

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

בנוסף, אפשר להגדיר את השם הגלוי לכולם של האפליקציה כ-Friendly 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 (הוספת אפליקציה). בוחרים באפשרות web (אינטרנט) כפלטפורמה ומסמנים את התיבה להגדרת אירוח ב-Firebase. לאחר מכן רושמים את האפליקציה ולוחצים על Next (הבא) כדי לבצע את שאר השלבים, ולבסוף לוחצים על Continue to console (המשך למסוף).

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

ממשק שורת הפקודה (CLI) של Firebase יאפשר לכם להציג את אפליקציית האינטרנט באופן מקומי ולפרוס את אפליקציית האינטרנט ו-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

לאחר מכן, בוחרים את מזהה הפרויקט ופועלים לפי ההוראות. כשמוצגת בקשה, אפשר לבחור כל כינוי, למשל 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. פותחים אותה. אמורה להופיע ממשק משתמש פעיל של אפליקציית צ'אט.

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

3b1284f5144b54f6.png

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

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

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

e926868b0546ed71.png

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

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

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

כשמשתמשים ב-Firebase SDK ל-Cloud Functions, קוד 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.

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

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

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

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

ההודעות שפורסמו בפיד הצ'אט של FriendlyChat מאוחסנות ב-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 Console Authentication ולמחוק את החשבון שלכם מרשימת המשתמשים. לאחר מכן, נכנסים שוב לחשבון.

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 ששולחת התראות למשתתפי הצ'אט כשמתפרסמת הודעה חדשה.

בעזרת העברת הודעות בענן ב-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.
  • מוסיפים לאפליקציית האינטרנט תמיכה בהעברת הודעות בענן ב-Firebase.
  • פריסת Cloud Functions באמצעות CLI של Firebase.

השלבים הבאים

מידע נוסף