Skip to content

Spring Boot + Flutter Push Notification #304

Description

@uniquejava

有三个topic要谈:

  1. sending push notification to a topic
  2. directly to the users’ device
  3. sending messages with additional data payload.

消息格式: https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages

pom.xml

<dependency>
<groupId>com.google.firebase</groupId>
<artifactId>firebase-admin</artifactId>
<version>6.13.0</version>
</dependency>

最新版本请参见: https://firebase.google.com/docs/admin/setup#add-sdk

Authenticate a service account and authorize it to access Firebase services

you must generate a private key file in JSON format.

To generate a private key file for your service account:

In the Firebase console, open Settings > Service Accounts.
Click Generate New Private Key, then confirm by clicking Generate Key.
Securely store the JSON file containing the key.

使用以上json文件初始化FCM Admin SDK

FileInputStreamserviceAccount =
newFileInputStream("path/to/serviceAccountKey.json");
FirebaseOptionsoptions = newFirebaseOptions.Builder()
.setCredentials(GoogleCredentials.fromStream(serviceAccount))
.setDatabaseUrl("https://<DATABASE_NAME>.firebaseio.com")
.build();
FirebaseApp.initializeApp(options);

如果是通过设置环境变量 GOOGLE_APPLICATION_CREDENTIALS

指定json文件的位置, 则以上代码修改为:

FirebaseOptionsoptions = newFirebaseOptions.Builder()
.setCredentials(GoogleCredentials.getApplicationDefault())
.setDatabaseUrl("https://<DATABASE_NAME>.firebaseio.com/")
.build();
FirebaseApp.initializeApp(options);

例子: export GOOGLE_APPLICATION_CREDENTIALS="/home/user/Downloads/service-account-file.json"

或者使用以上json文件得到一个short-lived JWT token

privatestaticStringgetAccessToken() throwsIOException {
GoogleCredentialgoogleCredential = GoogleCredential
.fromStream(newFileInputStream("service-account.json"))
.createScoped(Arrays.asList(SCOPES));
googleCredential.refreshToken();
returngoogleCredential.getAccessToken();
}

如果要使用FCM service, SCOPES的值必须为 https://www.googleapis.com/auth/firebase.messaging

使用JWT Token

headers: {'Authorization': 'Bearer ' + accessToken}

以上整理自: https://firebase.google.com/docs/cloud-messaging/auth-server

搭建FCM Server的要求

https://firebase.google.com/docs/cloud-messaging/server#role

搭建FCM Server的两种方式

  1. FCM HTTP v1 API
  2. Firebase Admin SDK for FCM (封装了FCM HTTP v1 API)

发送消息 (cyper实战)

publicinterfaceFcmService {
/** * 发送消息到指定设备. *  * @param deviceToken 设备Token * @param title 标题 * @param body 内容 * @param payload 其他额外参数 * @throws FirebaseMessagingException */voidsendTokenMessage(StringdeviceToken, Stringtitle, Stringbody, Map<String, String> payload)
throwsFirebaseMessagingException;
/** * 发送topic. *  * @param topic 主题 * @param title 标题 * @param body 内容 * @param payload 其他额外参数 * @throws FirebaseMessagingException */voidsendTopicMessage(Stringtopic, Stringtitle, Stringbody, Map<String, String> payload)
throwsFirebaseMessagingException;
/** * 群发消息到多个设备 *  * @param deviceTokens 多个设备的Token * @param title 标题 * @param body 内容 * @param payload 其他额外参数 * @throws FirebaseMessagingException */voidsendMessage2MultiDevices(List<String> deviceTokens, Stringtitle, Stringbody, Map<String, String> payload)
throwsFirebaseMessagingException;
}
@Service@Slf4jpublicclassFcmServiceImplimplementsFcmService {
@OverridepublicvoidsendTokenMessage(StringdeviceToken, Stringtitle, Stringbody, Map<String, String> payload)
throwsFirebaseMessagingException {
sendMessage(deviceToken, title, body, payload, false);
}
@OverridepublicvoidsendTopicMessage(Stringtopic, Stringtitle, Stringbody, Map<String, String> payload)
throwsFirebaseMessagingException {
sendMessage(topic, title, body, payload, true);
}
privatevoidsendMessage(StringtopicOrToken, Stringtitle, Stringbody, Map<String, String> payload,
booleanisTopic) throwsFirebaseMessagingException {
// See documentation on defining a message payload.Builderbuilder = Notification.builder();
builder.setTitle(title);
builder.setBody(body);
Notificationnotification = builder.build();
Message.BuildermessageBuilder = Message.builder().setNotification(notification);
if (payload != null) {
messageBuilder.putAllData(payload);
}
if (isTopic) {
messageBuilder.setTopic(topicOrToken);
} else {
messageBuilder.setToken(topicOrToken);
}
// Send a message to the device corresponding to the provided registration// token.Stringresponse = FirebaseMessaging.getInstance().send(messageBuilder.build());
if (log.isInfoEnabled()) {
log.info(response);
}
}
@OverridepublicvoidsendMessage2MultiDevices(List<String> deviceTokens, Stringtitle, Stringbody,
Map<String, String> payload) throwsFirebaseMessagingException {
Builderbuilder = Notification.builder();
builder.setTitle(title);
builder.setBody(body);
Notificationnotification = builder.build();
// @formatter:offMulticastMessage.BuildermessageBuilder = MulticastMessage.builder()
.setNotification(notification)
.addAllTokens(deviceTokens);
if(payload != null) {
messageBuilder.putAllData(payload);
}
// @formatter:onBatchResponseresponse = FirebaseMessaging.getInstance().sendMulticast(messageBuilder.build());
if (log.isInfoEnabled()) {
log.info(response.getSuccessCount() + " messages were sent successfully");
}
}
}

App端 用到的 Dart package (pub spec)

Pub Spec: firebase_messaging 6.0.13

References

Spring Boot: Send push notifications from Spring Boot server-side application using FCM

新鲜出炉的:Flutter Push Notifications using flutter firebase messaging with example

Concise: FCM Push Notifications for Flutter

FilledStacks: Push Notifications in Flutter using Firebase

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions