בהתאם למצב המכשיר, הודעות נכנסות מטופלות בצורה שונה. כדי להבין את התרחישים הללו וכיצד לשלב את FCM באפליקציה שלך, תחילה חשוב לקבוע את המצבים השונים שבהם מכשיר יכול להיות:
מדינה | תיאור |
---|---|
חֲזִית | כאשר האפליקציה פתוחה, בתצוגה ובשימוש. |
רקע כללי | כאשר האפליקציה פתוחה, אך ברקע (ממוזער). זה מתרחש בדרך כלל כאשר המשתמש לחץ על כפתור "הבית" במכשיר, עבר לאפליקציה אחרת באמצעות מחליף האפליקציות, או שהאפליקציה פתוחה בכרטיסייה אחרת (אינטרנט). |
הסתיים | כאשר המכשיר נעול או שהאפליקציה לא פועלת. |
ישנם מספר תנאים מוקדמים שחייבים לעמוד בהם לפני שהאפליקציה תוכל לקבל מטענים של הודעות באמצעות FCM:
- האפליקציה חייבת להיפתח לפחות פעם אחת (כדי לאפשר רישום ב-FCM).
- ב-iOS, אם המשתמש מחליק את האפליקציה ממחליף האפליקציות, יש לפתוח אותה מחדש באופן ידני כדי שהודעות רקע יתחילו לפעול שוב.
- באנדרואיד, אם המשתמש עוזב את האפליקציה בכוח מהגדרות המכשיר, יש לפתוח אותה מחדש באופן ידני כדי שההודעות יתחילו לעבוד.
- באינטרנט, עליך לבקש אסימון (באמצעות
getToken()
) עם אישור ה-Push האינטרנט שלך.
בקש הרשאה לקבל הודעות (אפל ואינטרנט)
ב-iOS, ב-macOS ובאינטרנט, לפני שניתן יהיה לקבל עומסי FCM במכשיר שלך, תחילה עליך לבקש רשות מהמשתמש.
חבילת firebase_messaging
מספקת API פשוט לבקשת הרשאה באמצעות שיטת requestPermission
. ממשק API זה מקבל מספר ארגומנטים בעלי שם שמגדירים את סוג ההרשאות שברצונך לבקש, כגון האם הודעות המכילות עומסי הודעות יכולות להפעיל צליל או לקרוא הודעות דרך Siri. כברירת מחדל, השיטה מבקשת הרשאות ברירת מחדל הגיוניות. ה-Reference API מספק תיעוד מלא על מה מיועדת כל הרשאה.
כדי להתחיל, קרא לשיטה מהאפליקציה שלך (ב-iOS יוצג מודאל מקורי, באינטרנט תופעל זרימת ה-API המקורית של הדפדפן):
FirebaseMessaging messaging = FirebaseMessaging.instance;
NotificationSettings settings = await messaging.requestPermission(
alert: true,
announcement: false,
badge: true,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: true,
);
print('User granted permission: ${settings.authorizationStatus}');
ניתן להשתמש במאפיין authorizationStatus
של אובייקט NotificationSettings
שהוחזר מהבקשה כדי לקבוע את ההחלטה הכוללת של המשתמש:
-
authorized
: המשתמש העניק הרשאה. -
denied
: המשתמש דחה את ההרשאה. -
notDetermined
: המשתמש עדיין לא בחר אם להעניק הרשאה. -
provisional
: המשתמש העניק הרשאה זמנית
המאפיינים האחרים ב- NotificationSettings
מחזירים אם הרשאה מסוימת מופעלת, מושבתת או לא נתמכת במכשיר הנוכחי.
לאחר שניתנה ההרשאה והסוגים השונים של מצב המכשיר הובנו, היישום שלך יכול כעת להתחיל לטפל במטעני FCM הנכנסים.
טיפול בהודעות
בהתבסס על המצב הנוכחי של האפליקציה שלך, עומסים נכנסים מסוגים שונים של הודעות דורשים יישומים שונים כדי לטפל בהם:
הודעות חזית
כדי לטפל בהודעות בזמן שהאפליקציה שלך נמצאת בחזית, האזן לזרם onMessage
.
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
print('Got a message whilst in the foreground!');
print('Message data: ${message.data}');
if (message.notification != null) {
print('Message also contained a notification: ${message.notification}');
}
});
הזרם מכיל RemoteMessage
, המפרט מידע שונה על המטען, כמו מאיפה הוא הגיע, המזהה הייחודי, זמן הנשלחה, האם הוא מכיל הודעה ועוד. מכיוון שההודעה אוחזרה בזמן שהאפליקציה שלך נמצאת בחזית, אתה יכול לגשת ישירות למצב ולהקשר של אפליקציית Flutter שלך.
הודעות חזית והודעות
הודעות התראה שמגיעות בזמן שהאפליקציה נמצאת בחזית לא יציגו התראה גלויה כברירת מחדל, הן באנדרואיד והן ב-iOS. עם זאת, ניתן לעקוף התנהגות זו:
- באנדרואיד, עליך ליצור ערוץ הודעות "בעדיפות גבוהה".
- ב-iOS, אתה יכול לעדכן את אפשרויות המצגת עבור האפליקציה.
הודעות רקע
תהליך הטיפול בהודעות רקע שונה בפלטפורמות מקוריות (אנדרואיד ואפל) ובפלטפורמות מבוססות אינטרנט.
פלטפורמות אפל ואנדרואיד
טפל בהודעות רקע על ידי רישום של מטפל onBackgroundMessage
. כאשר הודעות מתקבלות, נוצר איזול (אנדרואיד בלבד, iOS/macOS אינו דורש איזול נפרד) המאפשר לך לטפל בהודעות גם כשהאפליקציה שלך לא פועלת.
יש כמה דברים שכדאי לזכור לגבי המטפל בהודעות הרקע שלך:
- אסור שזו תהיה פונקציה אנונימית.
- זה חייב להיות פונקציה ברמה העליונה (למשל לא שיטת מחלקה הדורשת אתחול).
- בעת שימוש ב-Flutter גרסה 3.3.0 ומעלה, יש לציין את מטפל ההודעות ב-
@pragma('vm:entry-point')
ממש מעל הצהרת הפונקציה (אחרת היא עשויה להיות מוסרת במהלך ניעור עצים למצב שחרור).
@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
// If you're going to use other Firebase services in the background, such as Firestore,
// make sure you call `initializeApp` before using other Firebase services.
await Firebase.initializeApp();
print("Handling a background message: ${message.messageId}");
}
void main() {
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
runApp(MyApp());
}
מכיוון שהמטפל פועל בבידוד משלו מחוץ להקשר של היישומים שלך, לא ניתן לעדכן את מצב היישום או לבצע לוגיקה משפיעה על ממשק המשתמש. עם זאת, אתה יכול לבצע לוגיקה כמו בקשות HTTP, לבצע פעולות IO (למשל עדכון אחסון מקומי), לתקשר עם תוספים אחרים וכו'.
כמו כן, מומלץ להשלים את ההיגיון בהקדם האפשרי. הפעלת משימות ארוכות ואינטנסיביות משפיעה על ביצועי המכשיר ועלולה לגרום למערכת ההפעלה להפסיק את התהליך. אם משימות פועלות יותר מ-30 שניות, המכשיר עשוי להרוג את התהליך באופן אוטומטי.
אינטרנט
באינטרנט, כתוב JavaScript Service Worker שפועל ברקע. השתמש ב-Service Worker כדי לטפל בהודעות רקע.
כדי להתחיל, צור קובץ חדש בספריית web
שלך וקרא לו firebase-messaging-sw.js
:
importScripts("https://www.gstatic.com/firebasejs/8.10.0/firebase-app.js");
importScripts("https://www.gstatic.com/firebasejs/8.10.0/firebase-messaging.js");
firebase.initializeApp({
apiKey: "...",
authDomain: "...",
databaseURL: "...",
projectId: "...",
storageBucket: "...",
messagingSenderId: "...",
appId: "...",
});
const messaging = firebase.messaging();
// Optional:
messaging.onBackgroundMessage((message) => {
console.log("onBackgroundMessage", message);
});
על הקובץ לייבא הן את האפליקציה והן את ערכות ה-SDK להעברת הודעות, לאתחל את Firebase ולחשוף את משתנה messaging
.
לאחר מכן, על העובד להיות רשום. בתוך קובץ הכניסה, לאחר טעינת הקובץ main.dart.js
, רשום את העובד שלך:
<html>
<body>
...
<script src="main.dart.js" type="application/javascript"></script>
<script>
if ('serviceWorker' in navigator) {
// Service workers are supported. Use them.
window.addEventListener('load', function () {
// ADD THIS LINE
navigator.serviceWorker.register('/firebase-messaging-sw.js');
// Wait for registration to finish before dropping the <script> tag.
// Otherwise, the browser will load the script multiple times,
// potentially different versions.
var serviceWorkerUrl = 'flutter_service_worker.js?v=' + serviceWorkerVersion;
// ...
});
}
</script>
לאחר מכן הפעל מחדש את אפליקציית Flutter שלך. העובד יירשם וכל הודעות רקע יטופלו באמצעות קובץ זה.
טיפול באינטראקציה
מכיוון שהתראות הן רמז גלוי, נפוץ שמשתמשים מתקשרים איתן (על ידי לחיצה). התנהגות ברירת המחדל הן באנדרואיד והן ב-iOS היא פתיחת האפליקציה. אם הבקשה תסתיים היא תופעל; אם הוא ברקע הוא יובא לקדמת הבמה.
בהתאם לתוכן של הודעה, ייתכן שתרצה לטפל באינטראקציה של המשתמש בעת פתיחת האפליקציה. לדוגמה, אם הודעת צ'אט חדשה נשלחת באמצעות התראה והמשתמש לוחץ עליה, ייתכן שתרצה לפתוח את השיחה הספציפית עם פתיחת האפליקציה.
חבילת firebase-messaging
מספקת שתי דרכים לטפל באינטראקציה זו:
-
getInitialMessage()
: אם האפליקציה נפתחת ממצב סיום יוחזרFuture
המכילRemoteMessage
. לאחר צריכתו, ה-RemoteMessage
יוסר. -
onMessageOpenedApp
:Stream
שמפרסםRemoteMessage
כאשר האפליקציה נפתחת ממצב רקע.
מומלץ לטפל בשני התרחישים כדי להבטיח UX חלק עבור המשתמשים שלך. דוגמת הקוד שלהלן מתארת כיצד ניתן להשיג זאת:
class Application extends StatefulWidget {
@override
State<StatefulWidget> createState() => _Application();
}
class _Application extends State<Application> {
// It is assumed that all messages contain a data field with the key 'type'
Future<void> setupInteractedMessage() async {
// Get any messages which caused the application to open from
// a terminated state.
RemoteMessage? initialMessage =
await FirebaseMessaging.instance.getInitialMessage();
// If the message also contains a data property with a "type" of "chat",
// navigate to a chat screen
if (initialMessage != null) {
_handleMessage(initialMessage);
}
// Also handle any interaction when the app is in the background via a
// Stream listener
FirebaseMessaging.onMessageOpenedApp.listen(_handleMessage);
}
void _handleMessage(RemoteMessage message) {
if (message.data['type'] == 'chat') {
Navigator.pushNamed(context, '/chat',
arguments: ChatArguments(message),
);
}
}
@override
void initState() {
super.initState();
// Run code required to handle interacted messages in an async function
// as initState() must not be async
setupInteractedMessage();
}
@override
Widget build(BuildContext context) {
return Text("...");
}
}
האופן שבו אתה מטפל באינטראקציה תלוי בהגדרת היישום שלך. הדוגמה שלמעלה מציגה איור בסיסי באמצעות StatefulWidget.
התאמה של הודעות
אתה יכול לשלוח מחרוזות מקומיות בשתי דרכים שונות:
- אחסן את השפה המועדפת של כל אחד מהמשתמשים שלך בשרת שלך ושלח הודעות מותאמות אישית לכל שפה
- הטמע מחרוזות מקומיות באפליקציה שלך ועשה שימוש בהגדרות המקומיות המקוריות של מערכת ההפעלה
הנה איך להשתמש בשיטה השנייה:
דְמוּי אָדָם
ציין את הודעות ברירת המחדל שלך ב-
resources/values/strings.xml
:<string name="notification_title">Hello world</string> <string name="notification_message">This is a message</string>
ציין את ההודעות המתורגמות בספריית
values- language
. לדוגמה, ציין הודעות בצרפתית ב-resources/values-fr/strings.xml
:<string name="notification_title">Bonjour le monde</string> <string name="notification_message">C'est un message</string>
במטען השרת, במקום להשתמש
title
,message
ומפתחותbody
, השתמשtitle_loc_key
וב-body_loc_key
עבור ההודעה המותאמת לך, והגדר אותם לתכונתname
של ההודעה שברצונך להציג.מטען ההודעה ייראה כך:
{ "data": { "title_loc_key": "notification_title", "body_loc_key": "notification_message" } }
iOS
ציין את הודעות ברירת המחדל שלך ב-
Base.lproj/Localizable.strings
:"NOTIFICATION_TITLE" = "Hello World"; "NOTIFICATION_MESSAGE" = "This is a message";
ציין את ההודעות המתורגמות בספריית
language .lproj
. לדוגמה, ציין הודעות בצרפתית ב-fr.lproj/Localizable.strings
:"NOTIFICATION_TITLE" = "Bonjour le monde"; "NOTIFICATION_MESSAGE" = "C'est un message";
מטען ההודעה ייראה כך:
{ "data": { "title_loc_key": "NOTIFICATION_TITLE", "body_loc_key": "NOTIFICATION_MESSAGE" } }
אפשר ייצוא נתוני מסירת הודעות
אתה יכול לייצא את נתוני ההודעות שלך ל-BigQuery לניתוח נוסף. BigQuery מאפשרת לך לנתח את הנתונים באמצעות BigQuery SQL, לייצא אותם לספק ענן אחר, או להשתמש בנתונים עבור מודלים ML המותאמים אישית שלך. ייצוא ל-BigQuery כולל את כל הנתונים הזמינים עבור הודעות, ללא קשר לסוג ההודעה או אם ההודעה נשלחת דרך ה-API או מחבר ההודעות.
כדי לאפשר את הייצוא, בצע תחילה את השלבים המתוארים כאן , ולאחר מכן בצע את ההוראות הבאות:
דְמוּי אָדָם
אתה יכול להשתמש בקוד הבא:
await FirebaseMessaging.instance.setDeliveryMetricsExportToBigQuery(true);
iOS
עבור iOS, עליך לשנות את AppDelegate.m
עם התוכן הבא.
#import "AppDelegate.h"
#import "GeneratedPluginRegistrant.h"
#import <Firebase/Firebase.h>
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[GeneratedPluginRegistrant registerWithRegistry:self];
// Override point for customization after application launch.
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
[[FIRMessaging extensionHelper] exportDeliveryMetricsToBigQueryWithMessageInfo:userInfo];
}
@end
אינטרנט
עבור אינטרנט, עליך לשנות את ה-Service Worker שלך כדי להשתמש בגרסת v9 של SDK. גרסת v9 צריכה להיות מאגדת, אז אתה צריך להשתמש באנדלר כמו esbuild
למשל כדי לגרום ל-service worker לעבוד. עיין באפליקציה לדוגמה כדי לראות כיצד להשיג זאת.
לאחר המעבר ל-v9 SDK, תוכל להשתמש בקוד הבא:
import {
experimentalSetDeliveryMetricsExportedToBigQueryEnabled,
getMessaging,
} from 'firebase/messaging/sw';
...
const messaging = getMessaging(app);
experimentalSetDeliveryMetricsExportedToBigQueryEnabled(messaging, true);
אל תשכח להפעיל yarn build
כדי לייצא את הגרסה החדשה של ה-Service Worker שלך לתיקיית web
.
הצג תמונות בהתראות ב-iOS
במכשירי אפל, כדי שהודעות FCM נכנסות יציגו תמונות ממטען ה-FCM, עליך להוסיף תוסף נוסף לשירות התראות ולהגדיר את האפליקציה שלך להשתמש בה.
אם אתה משתמש באימות טלפון של Firebase, עליך להוסיף את תרמיל Firebase Auth ל-Podfile שלך.
שלב 1 - הוסף תוסף לשירות התראות
- ב-Xcode, לחץ על קובץ > חדש > יעד...
- מודל יציג רשימה של יעדים אפשריים; גלול מטה או השתמש במסנן כדי לבחור בהרחבת שירות התראות . לחץ על הבא .
- הוסף שם מוצר (השתמש ב-"ImageNotification" כדי לעקוב אחר המדריך הזה), הגדר את השפה ל-Objective-C ולחץ על סיום .
- הפעל את הסכימה על ידי לחיצה על הפעל .
שלב 2 - הוסף יעד ל-Podfile
ודא שלתוסף החדש שלך יש גישה לתרמיל Firebase/Messaging
על ידי הוספתו ב-Podfile:
מהנווט, פתח את ה-Podfile: Pods > Podfile
גלול מטה לתחתית הקובץ והוסף:
target 'ImageNotification' do use_frameworks! pod 'Firebase/Auth' # Add this line if you are using FirebaseAuth phone authentication pod 'Firebase/Messaging' end
התקן או עדכן את הפודים שלך באמצעות
pod install
מספרייתios
אוmacos
.
שלב 3 - השתמש בעוזר ההרחבה
בשלב זה, הכל אמור עדיין לפעול כרגיל. השלב האחרון הוא הפעלת עוזר ההרחבה.
מהנווט, בחר בתוסף ImageNotification שלך
פתח את הקובץ
NotificationService.m
.בחלק העליון של הקובץ, ייבא את
FirebaseMessaging.h
מיד אחרי ה-NotificationService.h
כפי שמוצג להלן.החלף את התוכן של
NotificationService.m
ב:#import "NotificationService.h" #import "FirebaseMessaging.h" #import "FirebaseAuth.h" // Add this line if you are using FirebaseAuth phone authentication #import <UIKit/UIKit.h> // Add this line if you are using FirebaseAuth phone authentication @interface NotificationService () @property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver); @property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent; @end @implementation NotificationService /* Uncomment this if you are using Firebase Auth - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options { if ([[FIRAuth auth] canHandleURL:url]) { return YES; } return NO; } - (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts { for (UIOpenURLContext *urlContext in URLContexts) { [FIRAuth.auth canHandleURL:urlContext.URL]; } } */ - (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler { self.contentHandler = contentHandler; self.bestAttemptContent = [request.content mutableCopy]; // Modify the notification content here... [[FIRMessaging extensionHelper] populateNotificationContent:self.bestAttemptContent withContentHandler:contentHandler]; } - (void)serviceExtensionTimeWillExpire { // Called just before the extension will be terminated by the system. // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used. self.contentHandler(self.bestAttemptContent); } @end
שלב 4 - הוסף את התמונה למטען
במטען ההתראות שלך, כעת תוכל להוסיף תמונה. עיין בתיעוד של iOS כיצד לבנות בקשת שליחת . זכור שגודל תמונה מקסימלי של 300KB נאכף על ידי המכשיר.