שלח הודעות לנושאים בפלטפורמות של אפל

בהתבסס על מודל הפרסום/הרשמה, העברת הודעות בנושא FCM מאפשרת לך לשלוח הודעה למספר מכשירים שהצטרפו לנושא מסוים. אתה מחבר הודעות נושא לפי הצורך, ו-FCM מטפל בניתוב ומסירת ההודעה בצורה מהימנה למכשירים הנכונים.

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

כמה דברים שכדאי לזכור לגבי נושאים:

  • העברת הודעות בנושא מתאימה ביותר לתוכן כגון מזג אוויר או מידע זמין לציבור אחר.
  • הודעות נושא מותאמות לתפוקה ולא לאחזור . למסירה מהירה ומאובטחת למכשירים בודדים או לקבוצות קטנות של מכשירים, מקד הודעות לאסימוני רישום , לא לנושאים.
  • אם אתה צריך לשלוח הודעות למספר מכשירים לכל משתמש , שקול לשלוח הודעות קבוצת מכשירים עבור מקרי שימוש אלה.
  • העברת הודעות נושא תומכת בהרשמות ללא הגבלה לכל נושא. עם זאת, FCM אוכפת מגבלות בתחומים הבאים:
    • ניתן להירשם למופע אחד של אפליקציה ללא יותר מ-2000 נושאים.
    • אם אתה משתמש בייבוא ​​אצווה כדי להירשם למופעי אפליקציה, כל בקשה מוגבלת ל-1000 מופעי אפליקציה.
    • תדירות המנויים החדשים מוגבלת בתעריף לפרויקט. אם תשלח יותר מדי בקשות מנוי בפרק זמן קצר, שרתי FCM יגיבו בתגובה של 429 RESOURCE_EXHAUSTED ("חריגה מהמכסה"). נסה שוב עם גיבוי אקספוננציאלי.

הירשם לאפליקציית הלקוח לנושא

אפליקציות לקוח יכולות להירשם לכל נושא קיים, או שהן יכולות ליצור נושא חדש. כאשר אפליקציית לקוח נרשמת לשם נושא חדש (כזה שלא קיים כבר עבור פרויקט Firebase שלך), נושא חדש בשם זה נוצר ב-FCM וכל לקוח יכול להירשם אליו לאחר מכן.

כדי להירשם לנושא, התקשר לשיטת המנוי מהשרשור הראשי של היישום שלך (FCM אינו בטוח לשרשור). אם בקשת המנוי נכשלת בתחילה, FCM מנסה שוב באופן אוטומטי. במקרים שבהם לא ניתן להשלים את המנוי, המנוי זורק שגיאה שתוכל לתפוס במטפל השלמה כפי שמוצג:

מָהִיר

Messaging.messaging().subscribe(toTopic: "weather") { error in
  print("Subscribed to weather topic")
}

Objective-C

[[FIRMessaging messaging] subscribeToTopic:@"weather"
                                completion:^(NSError * _Nullable error) {
  NSLog(@"Subscribed to weather topic");
}];

שיחה זו מבצעת בקשה אסינכרונית ל-FCM העורפי ומרשימה את הלקוח לנושא הנתון. לפני שתתקשר ל- subscribeToTopic:topic , ודא שמופע אפליקציית הלקוח כבר קיבל אסימון רישום דרך ה-callback didReceiveRegistrationToken .

בכל פעם שהאפליקציה מתחילה, FCM מוודא שכל הנושאים המבוקשים נרשמו. כדי לבטל את הרישום, התקשר unsubscribeFromTopic:topic , ו-FCM תבטל את הרישום לנושא ברקע.

נהל מנויים לנושאים בשרת

Firebase Admin SDK מאפשר לך לבצע משימות ניהול נושא בסיסיות מצד השרת. בהתחשב באסימוני הרישום שלהם, אתה יכול להירשם ולבטל את הרישום של מופעי אפליקציות לקוח בכמות גדולה באמצעות לוגיקה של שרת.

אתה יכול להירשם למופעי אפליקציה של לקוח לכל נושא קיים, או שאתה יכול ליצור נושא חדש. כאשר אתה משתמש ב-API כדי להירשם לאפליקציית לקוח לנושא חדש (כזה שלא קיים כבר עבור פרויקט Firebase שלך), נושא חדש בשם זה נוצר ב-FCM וכל לקוח יכול להירשם אליו לאחר מכן.

אתה יכול להעביר רשימה של אסימוני רישום לשיטת המנוי של Firebase Admin SDK כדי להירשם למכשירים המתאימים לנושא:

Node.js

// These registration tokens come from the client FCM SDKs.
const registrationTokens = [
  'YOUR_REGISTRATION_TOKEN_1',
  // ...
  'YOUR_REGISTRATION_TOKEN_n'
];

// Subscribe the devices corresponding to the registration tokens to the
// topic.
getMessaging().subscribeToTopic(registrationTokens, topic)
  .then((response) => {
    // See the MessagingTopicManagementResponse reference documentation
    // for the contents of response.
    console.log('Successfully subscribed to topic:', response);
  })
  .catch((error) => {
    console.log('Error subscribing to topic:', error);
  });

Java

// These registration tokens come from the client FCM SDKs.
List<String> registrationTokens = Arrays.asList(
    "YOUR_REGISTRATION_TOKEN_1",
    // ...
    "YOUR_REGISTRATION_TOKEN_n"
);

// Subscribe the devices corresponding to the registration tokens to the
// topic.
TopicManagementResponse response = FirebaseMessaging.getInstance().subscribeToTopic(
    registrationTokens, topic);
// See the TopicManagementResponse reference documentation
// for the contents of response.
System.out.println(response.getSuccessCount() + " tokens were subscribed successfully");

פִּיתוֹן

# These registration tokens come from the client FCM SDKs.
registration_tokens = [
    'YOUR_REGISTRATION_TOKEN_1',
    # ...
    'YOUR_REGISTRATION_TOKEN_n',
]

# Subscribe the devices corresponding to the registration tokens to the
# topic.
response = messaging.subscribe_to_topic(registration_tokens, topic)
# See the TopicManagementResponse reference documentation
# for the contents of response.
print(response.success_count, 'tokens were subscribed successfully')

ללכת

// These registration tokens come from the client FCM SDKs.
registrationTokens := []string{
	"YOUR_REGISTRATION_TOKEN_1",
	// ...
	"YOUR_REGISTRATION_TOKEN_n",
}

// Subscribe the devices corresponding to the registration tokens to the
// topic.
response, err := client.SubscribeToTopic(ctx, registrationTokens, topic)
if err != nil {
	log.Fatalln(err)
}
// See the TopicManagementResponse reference documentation
// for the contents of response.
fmt.Println(response.SuccessCount, "tokens were subscribed successfully")

C#

// These registration tokens come from the client FCM SDKs.
var registrationTokens = new List<string>()
{
    "YOUR_REGISTRATION_TOKEN_1",
    // ...
    "YOUR_REGISTRATION_TOKEN_n",
};

// Subscribe the devices corresponding to the registration tokens to the
// topic
var response = await FirebaseMessaging.DefaultInstance.SubscribeToTopicAsync(
    registrationTokens, topic);
// See the TopicManagementResponse reference documentation
// for the contents of response.
Console.WriteLine($"{response.SuccessCount} tokens were subscribed successfully");

ממשק ה-API של Admin FCM מאפשר לך גם לבטל את הרישום של מכשירים לנושא על ידי העברת אסימוני רישום לשיטה המתאימה:

Node.js

// These registration tokens come from the client FCM SDKs.
const registrationTokens = [
  'YOUR_REGISTRATION_TOKEN_1',
  // ...
  'YOUR_REGISTRATION_TOKEN_n'
];

// Unsubscribe the devices corresponding to the registration tokens from
// the topic.
getMessaging().unsubscribeFromTopic(registrationTokens, topic)
  .then((response) => {
    // See the MessagingTopicManagementResponse reference documentation
    // for the contents of response.
    console.log('Successfully unsubscribed from topic:', response);
  })
  .catch((error) => {
    console.log('Error unsubscribing from topic:', error);
  });

Java

// These registration tokens come from the client FCM SDKs.
List<String> registrationTokens = Arrays.asList(
    "YOUR_REGISTRATION_TOKEN_1",
    // ...
    "YOUR_REGISTRATION_TOKEN_n"
);

// Unsubscribe the devices corresponding to the registration tokens from
// the topic.
TopicManagementResponse response = FirebaseMessaging.getInstance().unsubscribeFromTopic(
    registrationTokens, topic);
// See the TopicManagementResponse reference documentation
// for the contents of response.
System.out.println(response.getSuccessCount() + " tokens were unsubscribed successfully");

פִּיתוֹן

# These registration tokens come from the client FCM SDKs.
registration_tokens = [
    'YOUR_REGISTRATION_TOKEN_1',
    # ...
    'YOUR_REGISTRATION_TOKEN_n',
]

# Unubscribe the devices corresponding to the registration tokens from the
# topic.
response = messaging.unsubscribe_from_topic(registration_tokens, topic)
# See the TopicManagementResponse reference documentation
# for the contents of response.
print(response.success_count, 'tokens were unsubscribed successfully')

ללכת

// These registration tokens come from the client FCM SDKs.
registrationTokens := []string{
	"YOUR_REGISTRATION_TOKEN_1",
	// ...
	"YOUR_REGISTRATION_TOKEN_n",
}

// Unsubscribe the devices corresponding to the registration tokens from
// the topic.
response, err := client.UnsubscribeFromTopic(ctx, registrationTokens, topic)
if err != nil {
	log.Fatalln(err)
}
// See the TopicManagementResponse reference documentation
// for the contents of response.
fmt.Println(response.SuccessCount, "tokens were unsubscribed successfully")

C#

// These registration tokens come from the client FCM SDKs.
var registrationTokens = new List<string>()
{
    "YOUR_REGISTRATION_TOKEN_1",
    // ...
    "YOUR_REGISTRATION_TOKEN_n",
};

// Unsubscribe the devices corresponding to the registration tokens from the
// topic
var response = await FirebaseMessaging.DefaultInstance.UnsubscribeFromTopicAsync(
    registrationTokens, topic);
// See the TopicManagementResponse reference documentation
// for the contents of response.
Console.WriteLine($"{response.SuccessCount} tokens were unsubscribed successfully");

השיטות subscribeToTopic() ו- unsubscribeFromTopic() גורמות לאובייקט המכיל את התגובה מ-FCM. לסוג ההחזרה אותו פורמט ללא קשר למספר אסימוני הרישום שצוינו בבקשה.

במקרה של שגיאה (כשלי אימות, אסימון או נושא לא חוקי וכו') שיטות אלו גורמות לשגיאה. לרשימה מלאה של קודי שגיאה, כולל תיאורים ושלבי פתרון, ראה Admin FCM API Errors .

קבלה וטיפול בהודעות בנושא

FCM מעביר הודעות נושא באותו אופן כמו הודעות אחרות במורד הזרם.

יישם את application(_:didReceiveRemoteNotification:fetchCompletionHandler:) כפי שמוצג:

מָהִיר

func application(_ application: UIApplication,
                 didReceiveRemoteNotification userInfo: [AnyHashable: Any]) async
  -> UIBackgroundFetchResult {
  // If you are receiving a notification message while your app is in the background,
  // this callback will not be fired till the user taps on the notification launching the application.
  // TODO: Handle data of notification

  // With swizzling disabled you must let Messaging know about the message, for Analytics
  // Messaging.messaging().appDidReceiveMessage(userInfo)

  // Print message ID.
  if let messageID = userInfo[gcmMessageIDKey] {
    print("Message ID: \(messageID)")
  }

  // Print full message.
  print(userInfo)

  return UIBackgroundFetchResult.newData
}

Objective-C

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
    fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
  // If you are receiving a notification message while your app is in the background,
  // this callback will not be fired till the user taps on the notification launching the application.
  // TODO: Handle data of notification

  // With swizzling disabled you must let Messaging know about the message, for Analytics
  // [[FIRMessaging messaging] appDidReceiveMessage:userInfo];

  // ...

  // Print full message.
  NSLog(@"%@", userInfo);

  completionHandler(UIBackgroundFetchResultNewData);
}

בנה בקשות לשלוח

לאחר שיצרת נושא, על ידי הרשמה למופעי אפליקציית לקוח לנושא בצד הלקוח או באמצעות ממשק API של השרת , תוכל לשלוח הודעות לנושא. אם זו הפעם הראשונה שאתה בונה בקשות שליחה עבור FCM, עיין במדריך לסביבת השרת שלך ול-FCM לקבלת מידע חשוב על רקע והגדרה.

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

Node.js

// The topic name can be optionally prefixed with "/topics/".
const topic = 'highScores';

const message = {
  data: {
    score: '850',
    time: '2:45'
  },
  topic: topic
};

// Send a message to devices subscribed to the provided topic.
getMessaging().send(message)
  .then((response) => {
    // Response is a message ID string.
    console.log('Successfully sent message:', response);
  })
  .catch((error) => {
    console.log('Error sending message:', error);
  });

Java

// The topic name can be optionally prefixed with "/topics/".
String topic = "highScores";

// See documentation on defining a message payload.
Message message = Message.builder()
    .putData("score", "850")
    .putData("time", "2:45")
    .setTopic(topic)
    .build();

// Send a message to the devices subscribed to the provided topic.
String response = FirebaseMessaging.getInstance().send(message);
// Response is a message ID string.
System.out.println("Successfully sent message: " + response);

פִּיתוֹן

# The topic name can be optionally prefixed with "/topics/".
topic = 'highScores'

# See documentation on defining a message payload.
message = messaging.Message(
    data={
        'score': '850',
        'time': '2:45',
    },
    topic=topic,
)

# Send a message to the devices subscribed to the provided topic.
response = messaging.send(message)
# Response is a message ID string.
print('Successfully sent message:', response)

ללכת

// The topic name can be optionally prefixed with "/topics/".
topic := "highScores"

// See documentation on defining a message payload.
message := &messaging.Message{
	Data: map[string]string{
		"score": "850",
		"time":  "2:45",
	},
	Topic: topic,
}

// Send a message to the devices subscribed to the provided topic.
response, err := client.Send(ctx, message)
if err != nil {
	log.Fatalln(err)
}
// Response is a message ID string.
fmt.Println("Successfully sent message:", response)

C#

// The topic name can be optionally prefixed with "/topics/".
var topic = "highScores";

// See documentation on defining a message payload.
var message = new Message()
{
    Data = new Dictionary<string, string>()
    {
        { "score", "850" },
        { "time", "2:45" },
    },
    Topic = topic,
};

// Send a message to the devices subscribed to the provided topic.
string response = await FirebaseMessaging.DefaultInstance.SendAsync(message);
// Response is a message ID string.
Console.WriteLine("Successfully sent message: " + response);

מנוחה

POST https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send HTTP/1.1

Content-Type: application/json
Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA
{
  "message":{
    "topic" : "foo-bar",
    "notification" : {
      "body" : "This is a Firebase Cloud Messaging Topic Message!",
      "title" : "FCM Message"
      }
   }
}

פקודת cURL:

curl -X POST -H "Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA" -H "Content-Type: application/json" -d '{
  "message": {
    "topic" : "foo-bar",
    "notification": {
      "body": "This is a Firebase Cloud Messaging Topic Message!",
      "title": "FCM Message"
    }
  }
}' https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send HTTP/1.1

כדי לשלוח הודעה לשילוב של נושאים, ציין תנאי , שהוא ביטוי בוליאני המציין את נושאי היעד. לדוגמה, התנאי הבא ישלח הודעות למכשירים המנויים על TopicA ועל TopicB או TopicC :

"'TopicA' in topics && ('TopicB' in topics || 'TopicC' in topics)"

FCM מעריך תחילה תנאים בסוגריים, ולאחר מכן מעריך את הביטוי משמאל לימין. בביטוי הנ"ל, משתמש שנרשם לאף נושא בודד אינו מקבל את ההודעה. כמו כן, משתמש שאינו נרשם ל- TopicA אינו מקבל את ההודעה. השילובים האלה אכן מקבלים את זה:

  • TopicA ונושא TopicB
  • TopicA ו- TopicC

אתה יכול לכלול עד חמישה נושאים בביטוי המותנה שלך.

כדי לשלוח לתנאי:

Node.js

// Define a condition which will send to devices which are subscribed
// to either the Google stock or the tech industry topics.
const condition = '\'stock-GOOG\' in topics || \'industry-tech\' in topics';

// See documentation on defining a message payload.
const message = {
  notification: {
    title: '$FooCorp up 1.43% on the day',
    body: '$FooCorp gained 11.80 points to close at 835.67, up 1.43% on the day.'
  },
  condition: condition
};

// Send a message to devices subscribed to the combination of topics
// specified by the provided condition.
getMessaging().send(message)
  .then((response) => {
    // Response is a message ID string.
    console.log('Successfully sent message:', response);
  })
  .catch((error) => {
    console.log('Error sending message:', error);
  });

Java

// Define a condition which will send to devices which are subscribed
// to either the Google stock or the tech industry topics.
String condition = "'stock-GOOG' in topics || 'industry-tech' in topics";

// See documentation on defining a message payload.
Message message = Message.builder()
    .setNotification(Notification.builder()
        .setTitle("$GOOG up 1.43% on the day")
        .setBody("$GOOG gained 11.80 points to close at 835.67, up 1.43% on the day.")
        .build())
    .setCondition(condition)
    .build();

// Send a message to devices subscribed to the combination of topics
// specified by the provided condition.
String response = FirebaseMessaging.getInstance().send(message);
// Response is a message ID string.
System.out.println("Successfully sent message: " + response);

פִּיתוֹן

# Define a condition which will send to devices which are subscribed
# to either the Google stock or the tech industry topics.
condition = "'stock-GOOG' in topics || 'industry-tech' in topics"

# See documentation on defining a message payload.
message = messaging.Message(
    notification=messaging.Notification(
        title='$GOOG up 1.43% on the day',
        body='$GOOG gained 11.80 points to close at 835.67, up 1.43% on the day.',
    ),
    condition=condition,
)

# Send a message to devices subscribed to the combination of topics
# specified by the provided condition.
response = messaging.send(message)
# Response is a message ID string.
print('Successfully sent message:', response)

ללכת

// Define a condition which will send to devices which are subscribed
// to either the Google stock or the tech industry topics.
condition := "'stock-GOOG' in topics || 'industry-tech' in topics"

// See documentation on defining a message payload.
message := &messaging.Message{
	Data: map[string]string{
		"score": "850",
		"time":  "2:45",
	},
	Condition: condition,
}

// Send a message to devices subscribed to the combination of topics
// specified by the provided condition.
response, err := client.Send(ctx, message)
if err != nil {
	log.Fatalln(err)
}
// Response is a message ID string.
fmt.Println("Successfully sent message:", response)

C#

// Define a condition which will send to devices which are subscribed
// to either the Google stock or the tech industry topics.
var condition = "'stock-GOOG' in topics || 'industry-tech' in topics";

// See documentation on defining a message payload.
var message = new Message()
{
    Notification = new Notification()
    {
        Title = "$GOOG up 1.43% on the day",
        Body = "$GOOG gained 11.80 points to close at 835.67, up 1.43% on the day.",
    },
    Condition = condition,
};

// Send a message to devices subscribed to the combination of topics
// specified by the provided condition.
string response = await FirebaseMessaging.DefaultInstance.SendAsync(message);
// Response is a message ID string.
Console.WriteLine("Successfully sent message: " + response);

מנוחה

POST https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send HTTP/1.1

Content-Type: application/json
Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA
{
   "message":{
    "condition": "'dogs' in topics || 'cats' in topics",
    "notification" : {
      "body" : "This is a Firebase Cloud Messaging Topic Message!",
      "title" : "FCM Message",
    }
  }
}

פקודת cURL:

curl -X POST -H "Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA" -H "Content-Type: application/json" -d '{
  "notification": {
    "title": "FCM Message",
    "body": "This is a Firebase Cloud Messaging Topic Message!",
  },
  "condition": "'dogs' in topics || 'cats' in topics"
}' https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send HTTP/1.1

הצעדים הבאים