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

FileInputStream serviceAccount =
  new FileInputStream("path/to/serviceAccountKey.json");

FirebaseOptions options = new FirebaseOptions.Builder()
  .setCredentials(GoogleCredentials.fromStream(serviceAccount))
  .setDatabaseUrl("https://<DATABASE_NAME>.firebaseio.com")
  .build();

FirebaseApp.initializeApp(options);

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

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

FirebaseOptions options = new FirebaseOptions.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

private static String getAccessToken() throws IOException {
  GoogleCredential googleCredential = GoogleCredential
      .fromStream(new FileInputStream("service-account.json"))
      .createScoped(Arrays.asList(SCOPES));
  googleCredential.refreshToken();
  return googleCredential.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实战)

public interface FcmService {

    /**
     * 发送消息到指定设备.
     * 
     * @param deviceToken 设备Token
     * @param title       标题
     * @param body        内容
     * @param payload     其他额外参数
     * @throws FirebaseMessagingException
     */
    void sendTokenMessage(String deviceToken, String title, String body, Map<String, String> payload)
            throws FirebaseMessagingException;

    /**
     * 发送topic.
     * 
     * @param topic   主题
     * @param title   标题
     * @param body    内容
     * @param payload 其他额外参数
     * @throws FirebaseMessagingException
     */
    void sendTopicMessage(String topic, String title, String body, Map<String, String> payload)
            throws FirebaseMessagingException;

    /**
     * 群发消息到多个设备
     * 
     * @param deviceTokens 多个设备的Token
     * @param title        标题
     * @param body         内容
     * @param payload      其他额外参数
     * @throws FirebaseMessagingException
     */
    void sendMessage2MultiDevices(List<String> deviceTokens, String title, String body, Map<String, String> payload)
            throws FirebaseMessagingException;

}

@Service
@Slf4j
public class FcmServiceImpl implements FcmService {
    @Override
    public void sendTokenMessage(String deviceToken, String title, String body, Map<String, String> payload)
            throws FirebaseMessagingException {
        sendMessage(deviceToken, title, body, payload, false);
    }

    @Override
    public void sendTopicMessage(String topic, String title, String body, Map<String, String> payload)
            throws FirebaseMessagingException {

        sendMessage(topic, title, body, payload, true);
    }

    private void sendMessage(String topicOrToken, String title, String body, Map<String, String> payload,
            boolean isTopic) throws FirebaseMessagingException {
        // See documentation on defining a message payload.
        Builder builder = Notification.builder();
        builder.setTitle(title);
        builder.setBody(body);
        Notification notification = builder.build();

        Message.Builder messageBuilder = 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.

        String response = FirebaseMessaging.getInstance().send(messageBuilder.build());

        if (log.isInfoEnabled()) {
            log.info(response);
        }
    }

    @Override
    public void sendMessage2MultiDevices(List<String> deviceTokens, String title, String body,
            Map<String, String> payload) throws FirebaseMessagingException {
        Builder builder = Notification.builder();
        builder.setTitle(title);
        builder.setBody(body);
        Notification notification = builder.build();

        // @formatter:off
 
        MulticastMessage.Builder messageBuilder = MulticastMessage.builder()
                .setNotification(notification)
                .addAllTokens(deviceTokens);
        
        if(payload != null) {
            messageBuilder.putAllData(payload);
        }
        
        // @formatter:on

        BatchResponse response = 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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions