I am using Firebase messaging for sending notifications. I have created an API to send notifications using node and I have hosted the API of Cyclic free server.
Notification works fine on the local server and while sending directly from the Firebase console. However, when sent from API hosted on Cyclic server notification on foreground does not work. It works in the background though and after it receives notifications in the background it starts getting notifications in the foreground too.
my node code
async function sendPushNotification(qrId, requestData) {
try {
const users = await findUsersByQrId(qrId);
if (users.length === 0) {
return { message: 'No user found with the provided qrId' };
}
const user = users[0];
const invalidTokens = [];
const notificationData = {
"qrId": requestData.qrId,
"name": requestData.name,
"email": requestData.email,
"phoneNumber": requestData.phoneNumber,
"location": requestData.location,
"customMsg": requestData.customMsg,
"userId": user._id
}
console.log("notification data", notificationData);
const message = createNotificationMessage(notificationData);
sendNotificationToTokens(message, user.fcmTokens, invalidTokens, user);
await saveNotificationToDatabase(requestData, user);
return {
message: 'Notifications Sent',
invalidTokens,
};
} catch (error) {
throw new Error('An error occurred');
}
}
// Function to find users by qrId
async function findUsersByQrId(qrId) {
const users = await User.find({ qrId });
return users;
}
// Function to create a notification message
function createNotificationMessage(data) {
return {
notification: {
title: `Notification from ${data.name}`,
body: data.customMsg || data.location || data.name,
},
data: { //you can send only notification or only data(or include both)
userId: `${data.userId}`,
},
android:{
priority: 'high'
}
};
}
// Function to send a notification to multiple FCM tokens
function sendNotificationToTokens(message, tokens, invalidTokens, user) {
FCM.sendToMultipleToken(message, tokens, (err, response) => {
if (err) {
console.log("Error code", err.code);
console.log("Error", err);
if (err.code === 'messaging/registration-token-not-registered') {
console.log("Invalid tokens", fcmToken);
invalidTokens.push(fcmToken);
} else {
throw err;
}
} else {
response.forEach(async element => {
if (element["response"] === "Error sending message:") {
invalidTokens.push(element["token"]);
}
});
removeInvalidTokens(user, invalidTokens);
}
});
}
My flutter side code
class FirebaseNotification {
FirebaseNotification();
final _firebaseMessaging = FirebaseMessaging.instance;
final _androidChannel = const AndroidNotificationChannel(
'high_importance_channel', // id
'High Importance Notifications', // title
description:
'This channel is used for important notifications.', // description
importance: Importance.max,
);
final _localNotifications = FlutterLocalNotificationsPlugin();
Future<void> initNotifications() async {
await _firebaseMessaging.requestPermission();
initPushNotification();
initLocalNotifications();
}
Future initPushNotification() async {
await FirebaseMessaging.instance
.setForegroundNotificationPresentationOptions(
alert: true, badge: true, sound: true);
FirebaseMessaging.instance.getInitialMessage().then(handleMessage);
FirebaseMessaging.onMessageOpenedApp.listen(handleMessage);
FirebaseMessaging.onBackgroundMessage(handleBackgroundMessage);
FirebaseMessaging.onMessage.listen((message) {
final notification = message.notification;
if (notification == null) return;
_localNotifications.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
_androidChannel.id,
_androidChannel.name,
channelDescription: _androidChannel.description,
icon: '@drawable/logo',
)),
payload: jsonEncode(message.toMap()));
});
}
Future initLocalNotifications() async {
const iOS = DarwinInitializationSettings();
const android = AndroidInitializationSettings('@drawable/logo');
const settings = InitializationSettings(
android: android,
iOS: iOS,
);
await _localNotifications.initialize(settings,
onDidReceiveNotificationResponse: onDidReceiveNotificationResponse);
}
void onDidReceiveNotificationResponse(
NotificationResponse notificationResponse) async {
final String? payload = notificationResponse.payload;
if (notificationResponse.payload != null) {
final message = RemoteMessage.fromMap(jsonDecode(payload!));
handleMessage(message);
final platform =
_localNotifications.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>();
await platform?.createNotificationChannel(_androidChannel);
}
}
}