Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spring Boot + Flutter Push Notification #304

Open
uniquejava opened this issue Apr 27, 2020 · 1 comment
Open

Spring Boot + Flutter Push Notification #304

uniquejava opened this issue Apr 27, 2020 · 1 comment
Labels

Comments

@uniquejava
Copy link
Owner

uniquejava commented Apr 27, 2020

有三个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

@uniquejava uniquejava changed the title Spring Boot + Flutter Messaging + Push Notification Spring Boot + Flutter Push Notification Apr 27, 2020
@uniquejava
Copy link
Owner Author

测试(device token || topic )

通过REST API在线发: https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages/send
(topic 和 token都行!)
image

通过firebase console发 (topic 和 token和user segment!)

image

@uniquejava uniquejava added the FCM label May 17, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant