发送消息

准备工作

要使用 Admin FCM API,您必须先按照将 Firebase Admin SDK 添加到您的服务器中所述的步骤操作。此外,您还需要使用 Firebase 项目 ID 初始化 Admin SDK。这可以通过以下三种方式之一来实现:

  • 明确指定 projectId Firebase 应用选项。
  • 使用服务帐号凭据初始化该 SDK
  • 设置 GCLOUD_PROJECT 环境变量。

    export GCLOUD_PROJECT='my-project-id'
    

本指南提供了 Admim FCM API 支持的所有语言(Node、Java、Python 和 Go)的代码示例。如需了解各个 API 的详细信息,请参阅各自对应的参考:

向个别设备发送消息

通过 Admin FCM API,您可以向个别设备发送消息,只需为目标设备指定注册令牌即可。注册令牌是客户端 FCM SDK 为每个最终用户客户端应用实例生成的字符串。

每个 Firebase 客户端 SDK 都能够生成适用于以下平台的注册令牌:iOSAndroid网页C++Unity

您可以在消息有效负载中添加注册令牌并将其传递给 Admin SDK 的 send() 方法:

Node.js

// This registration token comes from the client FCM SDKs.
var registrationToken = 'YOUR_REGISTRATION_TOKEN';

// See documentation on defining a message payload.
var message = {
  data: {
    score: '850',
    time: '2:45'
  },
  token: registrationToken
};

// Send a message to the device corresponding to the provided
// registration token.
admin.messaging().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

// This registration token comes from the client FCM SDKs.
String registrationToken = "YOUR_REGISTRATION_TOKEN";

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

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

Python

# This registration token comes from the client FCM SDKs.
registration_token = 'YOUR_REGISTRATION_TOKEN'

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

# Send a message to the device corresponding to the provided
# registration token.
response = messaging.send(message)
# Response is a message ID string.
print('Successfully sent message:', response)

Go

// Obtain a messaging.Client from the App.
ctx := context.Background()
client, err := app.Messaging(ctx)

// This registration token comes from the client FCM SDKs.
registrationToken := "YOUR_REGISTRATION_TOKEN"

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

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

在成功完成后,send() 方法会返回 projects/{project_id}/messages/{message_id} 格式的消息 ID 字符串。否则,它会生成错误。如需错误代码的完整列表(包括说明和解决步骤),请参阅 Admin FCM API 错误

向主题发送消息

在发布/订阅模式下,利用 FCM 主题消息传递,您可以将消息发送至已经选择加入特定主题的多台设备。您根据需要撰写主题消息,FCM 将处理消息路由并将消息可靠地传送至正确的设备。

例如,某个本地天气预报应用的用户可选择加入“恶劣天气警报”主题,并接收威胁特定区域的风暴的通知。体育应用的用户可以订阅他们心仪球队的实时比分自动更新。

关于主题,请注意以下事项:

  • 主题消息传递不限制每个应用拥有的主题和订阅数。
  • 主题消息传递最适合传递新闻、天气或其他可通过公开途径获得的信息等内容。
  • 主题消息针对吞吐量(而非延迟)进行了优化。要将消息快速安全地传送到单台设备或小规模设备组,应将消息定位至注册令牌,而非主题。
  • 如果您需要向一位用户的多台设备发送消息,可考虑针对这些使用场景进行设备组消息传递

使用 send() 方法,您可以通过指定主题名称来向相关主题发送消息:

Node.js

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

// See documentation on defining a message payload.
var message = {
  data: {
    score: '850',
    time: '2:45'
  },
  topic: topic
};

// Send a message to devices subscribed to the provided topic.
admin.messaging().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);

Python

# 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)

Go

// 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)

根据条件发送消息

有时,您需要向主题组合发送消息,方法是:指定一个条件,即指定目标主题的布尔表达式。例如,以下条件会将消息发送至已订阅 TopicA 以及 TopicBTopicC 的设备:

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

FCM 首先对括号中的所有条件求值,然后从左至右对表达式求值。在上述表达式中,只订阅某个单一主题的用户将不会接收到消息。同样地,未订阅 TopicA 的用户也不会接收到消息。下列组合将会接收到消息:

  • TopicATopicB
  • TopicATopicC

通过 Admin FCM API,您可以在调用 send() 方法时指定条件,以定位已订阅某个主题组合的设备:

Node.js

// 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 = {
  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.
admin.messaging().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(new Notification(
        "$GOOG up 1.43% on the day",
        "$GOOG gained 11.80 points to close at 835.67, up 1.43% on the day."))
    .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);

Python

# 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)

Go

// 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)

以测试模式发送

Firebase Admin SDK 支持以测试模式发送 FCM 消息。SDK 和 FCM 服务会对以此模式发送的消息执行所有常规验证,但它们实际上并未传送到目标设备。因此,该功能可用于检查 SDK 和 FCM 服务是否会接受某条消息以便发送。

Node.js

// Send a message in the dry run mode.
var dryRun = true;
admin.messaging().send(message, dryRun)
  .then((response) => {
    // Response is a message ID string.
    console.log('Dry run successful:', response);
  })
  .catch((error) => {
    console.log('Error during dry run:', error);
  });

Java

// Send a message in the dry run mode.
boolean dryRun = true;
String response = FirebaseMessaging.getInstance().send(message, dryRun);
// Response is a message ID string.
System.out.println("Dry run successful: " + response);

Python

# Send a message in the dry run mode.
response = messaging.send(message, dry_run=True)
# Response is a message ID string.
print('Dry run successful:', response)

Go

// Send a message in the dry run mode.
response, err := client.SendDryRun(ctx, message)
if err != nil {
	log.Fatalln(err)
}
// Response is a message ID string.
fmt.Println("Dry run successful:", response)

定义消息

Admin SDK 的 send() 方法接受 Message 对象。下表概述了可以在 Message 中添加的所有字段。除非明确说明,否则所有字段都是选填的。

顶层消息参数

参数 说明
data 键值对映射,其中所有键和值都是字符串。
notification 一个包含 titlebody 字段的对象。
android 一个由 Android 消息专用字段组成的对象。要了解详情,请参阅 Android 专用字段
apns 一个由 Apple 推送通知服务 (APNS) 专用字段组成的对象。要了解详情,请参阅 APNS 专用字段
webpush 一个由 WebPush 协议专用字段组成的对象。要了解详情,请参阅 WebPush 专用字段
token 一个用于标识消息的收件人设备的注册令牌。
topic 要将消息发送至的主题名称。该主题名称不能包含 /topics/ 前缀。
condition 发送消息时所依据的条件,例如 "foo" in topics && "bar" in topics

您可以在同一条消息中设置 androidapnswebpushnotification 字段。FCM 服务会考虑所有指定参数并针对每个平台定制消息。但是,消息只能包含 tokentopiccondition 字段中的一个。指定其中的零个或多个字段均会出错。

在将消息传递给 FCM 服务之前,Admin SDK 会在本地执行各种验证。任何验证失败都会立即导致异常,且这些异常会说明问题的确切性质。

Android 专用字段

Node.js

var message = {
  android: {
    ttl: 3600 * 1000, // 1 hour in milliseconds
    priority: 'normal',
    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.',
      icon: 'stock_ticker_update',
      color: '#f45342'
    }
  },
  topic: 'industry-tech'
};

Java

Message message = Message.builder()
    .setAndroidConfig(AndroidConfig.builder()
        .setTtl(3600 * 1000) // 1 hour in milliseconds
        .setPriority(AndroidConfig.Priority.NORMAL)
        .setNotification(AndroidNotification.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.")
            .setIcon("stock_ticker_update")
            .setColor("#f45342")
            .build())
        .build())
    .setTopic("industry-tech")
    .build();

Python

message = messaging.Message(
    android=messaging.AndroidConfig(
        ttl=datetime.timedelta(seconds=3600),
        priority='normal',
        notification=messaging.AndroidNotification(
            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.',
            icon='stock_ticker_update',
            color='#f45342'
        ),
    ),
    topic='industry-tech',
)

Go

oneHour := time.Duration(1) * time.Hour
message := &messaging.Message{
	Android: &messaging.AndroidConfig{
		TTL:      &oneHour,
		Priority: "normal",
		Notification: &messaging.AndroidNotification{
			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.",
			Icon:  "stock_ticker_update",
			Color: "#f45342",
		},
	},
	Topic: "industry-tech",
}

您可以在消息的 android 部分中使用以下字段:

参数 说明
collapseKey 一组消息的标识符,这组消息可以折叠,以便当恢复传送时只发送最后一条消息。在任意给定时间最多允许 4 个不同的折叠键。
priority 消息优先级。必须是 normalhigh 中的一个。
ttl 消息的生存时间。这是当目标设备离线时消息在 FCM 存储空间中保留的时长。允许的最长时间是 4 周,这也是默认设置。设为 0 可立即发送消息(发后即忘)。在 Node.js 和 Java 中,此时长是以毫秒为单位设置的。在 Python 中,可以将其指定为“datimetime.timedelta”值。在 Go 中,它被指定为“time.Duration”。
restrictedPackageName 应用的软件包名称,其注册令牌必须匹配才能接收消息。
data 键值对映射,其中所有键和值都是字符串。此参数在指定后会替换顶层消息中设置的 data 字段。
notification 一个由 Android 通知专用字段组成的对象。如需受支持字段的列表,请参阅下表。

Android notification 对象可能包含以下字段:

参数 说明
title 通知的标题。此参数在设置后会替换顶层消息通知中设置的 title 字段。
body 通知的正文。此参数在设置后会替换顶层消息通知中设置的 body 字段。
icon 通知图标。如果未指定此参数,FCM 将会显示您的应用清单文件中指定的启动器图标。
color 通知的图标颜色,以 #rrggbb 格式来表示。
sound 设备收到通知时要播放的声音。支持 default 或应用中绑定的声音资源的文件名。声音文件必须位于 /res/raw/. 中。
tag 用于替换抽屉式通知栏中现有通知的标识符。如果未指定此参数,则每次请求均会创建一条新的通知。如果已指定此参数,且已显示带有相同标记的通知,则新通知将替换抽屉式通知栏中的现有通知。
clickAction 与用户点击通知相关的操作。如果指定了此参数,则当用户点击通知时,将会启动带有匹配 intent 过滤器的 Activity。
bodyLocKey 应用的字符串资源中正文字符串的键,用于将正文文字本地化为用户当前的本地化设置语言。
bodyLocArgs 将用于替换 bodyLocKey(用来将正文文字本地化为用户当前的本地化设置语言)中的格式说明符的字符串值列表。
titleLocKey 应用的字符串资源中标题字符串的键,用于将标题文字本地化为用户当前的本地化设置语言。
titleLocArgs 将用于替换 titleLocKey(用来将标题文字本地化为用户当前的本地化设置语言)中的格式说明符的字符串值列表。

APNS 专用字段

Node.js

var message = {
  apns: {
    header: {
      'apns-priority': '10'
    },
    payload: {
      aps: {
        alert: {
          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.',
        },
        badge: 42,
      }
    }
  },
  topic: 'industry-tech'
};

Java

Message message = Message.builder()
    .setApnsConfig(ApnsConfig.builder()
        .putHeader("apns-priority", "10")
        .setAps(Aps.builder()
            .setAlert(ApsAlert.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())
            .setBadge(42)
            .build())
        .build())
    .setTopic("industry-tech")
    .build();

Python

message = messaging.Message(
    apns=messaging.APNSConfig(
        headers={'apns-priority': '10'},
        payload=messaging.APNSPayload(
            aps=messaging.Aps(
                alert=messaging.ApsAlert(
                    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.',
                ),
                badge=42,
            ),
        ),
    ),
    topic='industry-tech',
)

Go

badge := 42
message := &messaging.Message{
	APNS: &messaging.APNSConfig{
		Headers: map[string]string{
			"apns-priority": "10",
		},
		Payload: &messaging.APNSPayload{
			Aps: &messaging.Aps{
				Alert: &messaging.ApsAlert{
					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.",
				},
				Badge: &badge,
			},
		},
	},
	Topic: "industry-tech",
}

您可以在消息的 apns 部分中使用以下字段:

参数 说明
headers 在 Apple 推送通知服务中定义的 HTTP 请求标头。要了解受支持的标头,请参阅 APNS 请求标头
payload 包含 aps 字典和其他自定义键值对的 APNS 有效负载。要了解受支持的字段,请参阅 APNS 有效负载键参考。Admin SDK 为常用的 APNS 有效负载字段提供了类型化 setter 方法。

WebPush 专用字段

Node.js

var message = {
  webpush: {
    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.',
      icon: 'https://my-server/icon.png'
    }
  },
  topic: 'industry-tech'
};

Java

Message message = Message.builder()
    .setWebpushConfig(WebpushConfig.builder()
        .setNotification(new WebpushNotification(
            "$GOOG up 1.43% on the day",
            "$GOOG gained 11.80 points to close at 835.67, up 1.43% on the day.",
            "https://my-server/icon.png"))
        .build())
    .setTopic("industry-tech")
    .build();

Python

message = messaging.Message(
    webpush=messaging.WebpushConfig(
        notification=messaging.WebpushNotification(
            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.',
            icon='https://my-server/icon.png',
        ),
    ),
    topic='industry-tech',
)

Go

message := &messaging.Message{
	Webpush: &messaging.WebpushConfig{
		Notification: &messaging.WebpushNotification{
			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.",
			Icon:  "https://my-server/icon.png",
		},
	},
	Topic: "industry-tech",
}

您可以在消息的 webpush 部分中使用以下字段:

参数 说明
headers 在 WebPush 协议中定义的 HTTP 请求标头。要了解受支持的标头,请参阅 WebPush 规范
data 键值对映射,其中所有键和值都是字符串。此参数在指定后会替换顶层消息中设置的 data 字段。
notification 一个包含 titlebodyicon 字段的对象。标题和正文会替换顶层消息通知中的相应字段。

综合应用

一条消息可能包含针对多个设备平台的配置参数。这意味着同一条消息中可以同时包含 androidapnswebpush 字段。FCM 服务会在传递消息时针对每个目标平台自定义消息。以下示例展示了如何针对 Android 和 iOS 平台自定义通知:

Node.js

var message = {
  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.',
  },
  android: {
    ttl: 3600 * 1000,
    notification: {
      icon: 'stock_ticker_update',
      color: '#f45342',
    },
  },
  apns: {
    payload: {
      aps: {
        badge: 42,
      },
    },
  },
  topic: 'industry-tech'
};

Java

Message message = Message.builder()
    .setNotification(new Notification(
        "$GOOG up 1.43% on the day",
        "$GOOG gained 11.80 points to close at 835.67, up 1.43% on the day."))
    .setAndroidConfig(AndroidConfig.builder()
        .setTtl(3600 * 1000)
        .setNotification(AndroidNotification.builder()
            .setIcon("stock_ticker_update")
            .setColor("#f45342")
            .build())
        .build())
    .setApnsConfig(ApnsConfig.builder()
        .setAps(Aps.builder()
            .setBadge(42)
            .build())
        .build())
    .setTopic("industry-tech")
    .build();

Python

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.',
    ),
    android=messaging.AndroidConfig(
        ttl=datetime.timedelta(seconds=3600),
        priority='normal',
        notification=messaging.AndroidNotification(
            icon='stock_ticker_update',
            color='#f45342'
        ),
    ),
    apns=messaging.APNSConfig(
        payload=messaging.APNSPayload(
            aps=messaging.Aps(badge=42),
        ),
    ),
    topic='industry-tech',
)

Go

oneHour := time.Duration(1) * time.Hour
badge := 42
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.",
	},
	Android: &messaging.AndroidConfig{
		TTL: &oneHour,
		Notification: &messaging.AndroidNotification{
			Icon:  "stock_ticker_update",
			Color: "#f45342",
		},
	},
	APNS: &messaging.APNSConfig{
		Payload: &messaging.APNSPayload{
			Aps: &messaging.Aps{
				Badge: &badge,
			},
		},
	},
	Topic: "industry-tech",
}

同样,同一条消息中可以同时包含 datanotification 字段。

旧版发送操作

除了上面讨论的 send() 方法之外,Admin Node.js SDK 还支持另外四个发送操作:

  • sendToDevice()
  • sendToDeviceGroup()
  • sendToTopic()
  • sendToCondition()

要详细了解如何及何时使用这些 API,请参阅旧版 FCM API

发送以下问题的反馈:

此网页
需要帮助?请访问我们的支持页面