This blog is about to send push notifications with spring boot and FCM. I will tell you how to send push notifications from the server.
What is FCM?
Firebase Cloud Messaging (FCM) is a cross-platform messaging solution that lets you reliably send messages at no cost.
How FCM work
- Registration: When application gets installed it registers with FCM.
- Token: FCM returns token to app.
- Receive token: Frontend send token information to backend and backend save token in database.
- Trigger FCM service layer : Trigger the REST API from backend to this particular service layer in the FCM.
- Trigger Notification: FCM will intern trigger the push notification to mobile apps.
Start from the FCM integration.
We have to generate our own Firebase SDK admin key.It’s a JSON file with your Firebase project credentials.
Go to Firebase Console Project Settings to Service Account and Generate new private key and save file. We’ll use it in the next step.
Spring Boot Application
First of all, add a field in application.properties. I added a new key/value pair containing a file path.
#put the path of FireBase-adminsdk file
app.firebase-configuration-file=resources\push-notifications-example-firebase-adminsdk.json.
Now we’ll need to add maven dependencies of Firebase in the pom.xml file.
<dependency> <groupId>com.google.firebase</groupId> <artifactId>firebase-admin</artifactId> <version>6.15.0</version> </dependency>
Now we have to initialize our Firebase application. This is the time to use our app.firebase-configuration-file. I used @Value annotation to inject the path value to the String field.
public class FCMInitializer { @Value("${app.firebase-configuration-file}") private String firebaseConfigPath; @PostConstruct public void initialize() { try { FirebaseOptions options = new FirebaseOptions.Builder() .setCredentials(GoogleCredentials.fromStream(new ClassPathResource(firebaseConfigPath).getInputStream())).build(); if (FirebaseApp.getApps().isEmpty()) { FirebaseApp.initializeApp(options); } } catch (IOException e) { e.printStackTrace() } } }
Send Notification
I created a PushNotificationRequest class to add some mandatory fields.
public class PushNotificationRequest { private String title; private String message; private String token; public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public String getToken() { return token; } public void setToken(String token) { this.token = token; } }
Next step is to prepare for our FCMService class.
In this class we completed Android configuration and Apple Push Notification service (APNs) configuration.
Sending push notifications with payload data.
@Service public class FCMService { Logger logger = LoggerFactory.getLogger(FCMService.class); public void sendMessage(Map<String, String> data, PushNotificationRequest request) throws InterruptedException, ExecutionException { Message message = getPreconfiguredMessageWithData(data, request); String response = sendAndGetResponse(message); logger.info("Sent Notification. Title: " + request.getTitle() + ", " + response); } private String sendAndGetResponse(Message message) throws InterruptedException, ExecutionException { return FirebaseMessaging.getInstance().sendAsync(message).get(); } private AndroidConfig getAndroidConfig() { return AndroidConfig.builder() .setTtl(Duration.ofMinutes(60).toMillis()) .setPriority(AndroidConfig.Priority.HIGH) .setNotification(AndroidNotification.builder().setSound("default").setColor("#FFFF00").build()) .build(); } private ApnsConfig getApnsConfig() { return ApnsConfig.builder().setAps(Aps.builder().setSound("default").build()).build(); } private Message getPreconfiguredMessageWithData(Map<String, String> data, PushNotificationRequest request) { return getPreconfiguredMessageBuilder(request).putAllData(data).setToken(request.getToken()).build(); } private Message.Builder getPreconfiguredMessageBuilder(PushNotificationRequest request) { AndroidConfig androidConfig = getAndroidConfig(); ApnsConfig apnsConfig = getApnsConfig(); return Message.builder() .setApnsConfig(apnsConfig) .setAndroidConfig(androidConfig) .setNotification(new Notification(request.getTitle(), request.getMessage())); } }
We can test it right now by calling the proper method. We are using spring scheduler to send push notifications.
For scheduling, I used @Scheduled annotation with cron job(0 0/2 * 1/1 * ?) to send push notifications every 2 min. Remember to annotate your Application class with @EnableScheduling.
@Service public class PushNotificationService { @Autowired FCMService fcmService; private String token="eLs0WItVXAERsHw2:APA91bFxeQ0-BPVWb6IX905s8ZacvVR6x1DYlp3-ikfitZwGMONyYT7mBMDBLRB07kbdWIzXCm"; @Scheduled(cron="0 0/2 * 1/1 * ?") public void sendPushNotificationWithData() { PushNotificationRequest pushNotificationRequest=new PushNotificationRequest(); pushNotificationRequest.setMessage("Send push notifications from Spring Boot server"); pushNotificationRequest.setTitle("test Push Notification"); pushNotificationRequest.setToken(token); Map<String, String> appData= new HashMap<>(); appData.put("name", "PushNotification"); try { fcmService.sendMessage(appData, pushNotificationRequest); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } }
It is configured properly and working fine.
Look at this screenshot with received notifications interval of 2 min.