I'm developing an application for Android and iOS and I'm using PushSharp (on server-side) to send push notifications to both platform. In particular I'm using (for Android) the Firebase platform (FCM).
Following this guide I was able to send push notification to an Android device setting icon and sound too but I think there is a problem.
When the notification arrives it doesn't being shown as Heads-up notification but only as status bar notification.
To be clear, I would:
but i see only the application icon that appears on the status bar.
How can I tell to FCM to show my notification as Head-Up notification similary to what I obtain with the following code?
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_media_play)
.setContentTitle("My notification")
.setContentText("Hello World!")
.setDefaults(Notification.DEFAULT_ALL)
.setPriority(Notification.PRIORITY_HIGH);
I have fixed it by installing following version of react-native-push-notification
npm install zo0r/react-native-push-notification.git
in your index.android.js
function init(){
PushNotification.configure({
onNotification:async (notification)=>{
if(!notification.userInteraction && !notification.foreground){
PushNotification.localNotification({
message: "you message"
});
}
,
requestPermissions:true,
senderID:"31************",
popInitialNotification:false
})
}
you must create a channel in your MainActivity.java.
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.os.Build;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ NotificationChannel notificationChannel = new
+ NotificationChannel("500", "MainChannel",
+ NotificationManager.IMPORTANCE_HIGH);
+ notificationChannel.setShowBadge(true);
+ notificationChannel.setDescription("Test Notifications");
+ notificationChannel.enableVibration(true);
+ notificationChannel.enableLights(true);
+ notificationChannel.setVibrationPattern(new long[]{400, 200, 400});
+ NotificationManager manager = getSystemService(NotificationManager.class);
+ manager.createNotificationChannel(notificationChannel);
+ }
Add the channelId to your server: an example with node.js
await admin
.messaging()
.send({
android: {
priority: 'high',
notification: {
sound: 'default',
title: 'your title',
body: 'your message',
imageUrl: 'img-uri',
priority: 'high', // this is importnat
channelId: '500', // the channelId we created in MainActivity.java
},
},
apns: {
payload: {
aps: {
contentAvailable: true,
},
},
headers: {
'apns-push-type': 'background',
'apns-priority': '5',
'apns-topic': '', // your app bundle identifier
},
},
topic: //topic or token,
data: {//send a custom data here to your client},
notification: {
title: 'your title',
body:'your message',
imageUrl: 'img-url',
},
Related
I am trying to get custom notification sounds working for my flutter based Android app that uses Android version 26 with notification channels.
I have configured both the node.js server code, and the android app to use a notification channel with a custom sound.
My android code that initialises the channel looks as follows...
class MainActivity: FlutterActivity() {
override fun configureFlutterEngine(#NonNull flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val sound: Uri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + context.packageName + "/" + R.raw.app_alert)
val mChannel = NotificationChannel("app_alerts", "app_alerts_2", NotificationManager.IMPORTANCE_HIGH)
val audioAttributes: AudioAttributes = AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_ALARM)
.build()
mChannel.setSound(sound , audioAttributes)
mChannel.description = "Important app Notifications"
val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(mChannel)
}
}
}
And my node.js code is as follows...
const { messaging } = require('firebase-admin');
var admin = require('firebase-admin');
console.log(process.cwd());
var serviceAccount = require("path to my credentials");
const topic = 'all';
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
});
const payload = {
notification: {
title: "Test Notification",
body: "This is just a test",
},
android: {
notification: {
channelId: "app_alerts",
sound: 'app_alert'
},
},
apns: {
payload: {
aps: {
sound: 'app_alert.wav'
},
},
},
topic: 'all'
};
admin.messaging().send(payload).then(response => {
console.log("Successfully sent message:", response);
})
I have gone into my Android settings and confirmed that the notification channel has been created as expected...yet the custom sound does not play.
I am sending following payload for notification:
var message = {
data: {
user: sendData.from,
body: sendData.message,
sentto: sendData.to,
gcm_username: sendData.from
},
android: {
priority: 'high',
notification: {
title: 'Yeni mesaj aldınız',
body: sendData.from + ' size bir mesaj gönderdi',
tag: sendData.from,
sound: 'default',
channelId: 'messages'
}
},
token: deviceToken
};
But sometimes i have to cancel certain notification when user opens the app from the app icon.
I tried following code:
#RequiresApi(api = Build.VERSION_CODES.M)
public Notification deleteNotificationByTag(String senderCode) {
NotificationManager notificationManager = (NotificationManager) mApplication.getSystemService(Context.NOTIFICATION_SERVICE);
StatusBarNotification[] barNotifications = notificationManager.getActiveNotifications();
for(StatusBarNotification notification: barNotifications) {
Log.d(TAG, "getActiveNotification: " + notification.getTag());
if (notification.getTag() != null && notification.getTag().equals(senderCode)) {
notificationManager.cancel(notification.getId());
}
}
return null;
}
But notification.getId() method is always returning 0 value. So cancel is not working. How can i fix it?
You can use the tag to cancel the notification as follows:
public void cancel (String tag, int id);
So even if the id is 0, it should work if the tag is unique.
One option is to send data messages and create notifications with id manually and You can cancel messages as per your requirements.
My notification channel:
CharSequence name = mApplication.getString(R.string.notification_messages_channel);
String description = mApplication.getString(R.string.notification_messages_channel_description);
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel channel = new NotificationChannel(CHANNEL_MESSAGES, name, importance);
channel.setDescription(description);
channel.enableVibration(true);
channel.enableLights(true);
channel.setVibrationPattern(new long[]{500,100,500});
NotificationManager notificationManager = mApplication.getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
And this is my payload:
var message = {
data: {
user: "asdasd",
body: "adsadasd",
sentto: "asdasd",
gcm_username: "asdda"
},
android: {
priority: 'high',
notification: {
title: 'Yeni mesaj aldınız',
body: 'size bir mesaj gönderdi',
tag: "asd223",
sound: 'default'
}
},
token: deviceToken
};
When a notification arrives to the phone, it plays the notification sound but not vibrating. Where is the problem?
Channel looks set up correctly.
Try adding this directly to NotificationCompat.Builder()
val mBuilder = NotificationCompat.Builder(ctx, "ID")
.setVibrate(arrayOf(100L, 200L).toLongArray())
And make sure, you have your phone set to:
Ok, I found the answer. I added channel information to payload and problem resolved.
New payload:
var message = {
data: {
user: "asdasd",
body: "adsadasd",
sentto: "asdasd",
gcm_username: "asdda"
},
android: {
priority: 'high',
notification: {
title: 'Yeni mesaj aldınız',
body: 'size bir mesaj gönderdi',
tag: "asd223",
sound: 'default',
channel: 'messages'
}
},
token: deviceToken
}
I have push notifications working using FCM from a cloud function. This works for both iOS and Android and displays the appropriate icon and plays a custom sound on iOS.
All is working except the custom sound for Android, it simply plays the default sound.
I have created a folder and added my sound file to it as follows: android\app\src\main\res\raw\mp3_example.mp3
This mp3 is 27s long. I have also tried a .wav and .aiff.
I read that I may have to create a push notification channel for later versions of Android so it could be related to this. I tried creating a channel and using the channelID from the cloud function and it works but there is no sound just a vibration.
The test device is a Moto G6 running Android 8.
I am using:
FCM
Firebase Cloud Functions
Ionic 4
Capacitor
https://github.com/stewwan/capacitor-fcm
Cloud Function:
const notification: admin.messaging.Notification = {
title: title,
body: body
}
const message: admin.messaging.Message = {
notification,
topic: 'QMTBC',
android:{
notification:{
sound: 'mp3_example.mp3',
icon: 'push_logo',
color: '#000000'
}
},
apns:{
payload:{
aps: {
sound: 'gears-short.wav'
}
}
}
}
return admin.messaging().send(message)
app.component.ts
import { FCM } from 'capacitor-fcm';
const fcm = new FCM();
const { PushNotifications } = Plugins;
initializeApp() {
this.platform.ready().then(() => {
PushNotifications.register();
PushNotifications.addListener('registration', (token: PushNotificationToken) => {
console.log('token ' + token.value);
fcm
.subscribeTo({ topic: 'QMTBC' })
.then(r => console.log(`subscribed to topic`))
.catch(err => console.log(err));
});
PushNotifications.addListener('registrationError', (error: any) => {
console.log('error on register ' + JSON.stringify(error));
});
PushNotifications.addListener('pushNotificationReceived', (notification: PushNotification) => {
console.log('notification ' + JSON.stringify(notification));
this.pushNotificationService.notifications.push(notification);
});
PushNotifications.addListener('pushNotificationActionPerformed', (notification: PushNotificationActionPerformed) => {
console.log('notification ' + JSON.stringify(notification));
this.pushNotificationService.notifications.push(notification);
});
fcm.getToken()
.then(r => console.log(`Token ${r.token}`))
.catch(err => console.log(err));
});
}
UPDATE:
I tried creating a channel as follows.
If I use the channel I just get the default sound. If I specific no channel or one that does not exist I also get the default sound (default channel).
cloud function:
const message: admin.messaging.Message = {
notification,
topic: 'QMTBC',
android:{
notification:{
sound: 'punch.mp3',
icon: 'push_logo',
color: '#000000',
channelId: 'QMTBC'
}
}
app.component.ts
const channel: PushNotificationChannel = {
description: 'QMTBC',
id : 'QMTBC',
importance: 5,
name : 'QMTBC'
};
PushNotifications.createChannel(channel).then(channelResult => {
console.log(channelResult);
console.log('Channel created');
// PushNotifications.listChannels().then(channels => {
// console.log('Channels');
// console.log(channels);
// });
}, err => {
console.log('Error Creating channel');
console.log(err);
});
});
UPDATE 2:
I can see the channel I have created for the app on my device and it says the sound is default. I can manually change it to another inbuilt android sound and this works. But I still can't use my custom sound.
UPDATE 3:
The custom sound works on if the Android version is < 8. Only tested this on an emulator.
#MadMac I was facing the same problem these days, after read FCM documentations and the Capacitor Java code, I got it.
It's necessary to set the visibility to 1, place your file in res/raw folder.
PushNotifications.createChannel({
description: 'General Notifications',
id: 'fcm_default_channel',
importance: 5,
lights: true,
name: 'My notification channel',
sound: 'notifications.wav',
vibration: true,
visibility: 1
}).then(()=>{
console.log('push channel created: ');
}).catch(error =>{
console.error('push channel error: ', error);
});
I'm using this payload in my firestore function to send notifications
{
android: {
notification: {
defaultSound: true,
notificationCount: 1,
sound: 'notifications.wav',
channelId: 'fcm_default_channel'
},
ttl: 20000,
collapseKey
},
apns: {
payload: {
aps: {
badge: 1,
sound: 'default'
}
}
},
notification: {
title,
body: message,
},
token: token
};
This was such a good question that helped me find the answer. So I post my answer here. Try setting the sound of the notifications to notification channels themselves at the time when you create the channels. I suppose, based on your info, the old Android versions will play sound according to the sound field in the notification payload, but in the new versions you would have to set it directly to the notification channels themselves since that is where the control is now currently intended to be by Google. I had to uninstall and reinstall the app for this code change to work, because my channels were previously initialized and the channels won't update after the first initialization.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !notificationChannelsInitialized) {
val newMessagesChannel = NotificationChannel(NEW_MESSAGES_NOTIFICATION_CHANNEL_ID, "New Messages", NotificationManager.IMPORTANCE_HIGH)
val notificationSoundUri =
Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE.toString() + "://" + context.packageName + "/" + R.raw.ns) // ns.wav is my notification sound file in the res/raw folder in Android Studio
val notificationSoundUriAttributes = AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_NOTIFICATION)
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.build()
newMessagesChannel.setSound(notificationSoundUri, notificationSoundUriAttributes)
val notificationManager: NotificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannels(listOf( newMessagesChannel)) // and other channels
}
I was able to get it working for React Native using the react-native-push-notification library (here). The key to resolving is that you must create a channel within your app. (I had thought channels were created on the backend, but that's not right). After placing the mp3 file in the res/raw directory in the android folder of my app, I added the following code in React Native (copied from documentation in the above library), and it worked:
import PushNotification, {Importance} from 'react-native-push-notification';
...
PushNotification.createChannel(
{
channelId: "channel-id", // (required)
channelName: "My channel", // (required)
channelDescription: "A channel to categorise your notifications", // (optional) default: undefined.
playSound: true, // (optional) default: true
soundName: "mp3_example", // (optional) See `soundName` parameter of `localNotification` function
importance: Importance.HIGH, // (optional) default: Importance.HIGH. Int value of the Android notification importance
vibrate: true, // (optional) default: true. Creates the default vibration pattern if true.
},
(created) => console.log(`createChannel returned '${created}'`) // (optional) callback returns whether the channel was created, false means it already existed.
);
I am working on an Android app and by using Node.js based function, I'm sending notification to Android and in Android onMessageReceived() function is used to receive data to show notifications. Now the problem, I'm facing is that I want to send some String type data in parallel to Title and Body. What changes should I make?
Here is my Node.js code
'use-strict'
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification = functions.firestore.document("Users/{user_id}/Notifications/{notification_id}").onWrite((change,context)=> {
const user_id = context.params.user_id;
const notification_id = context.params.notification_id;
console.log("User ID:"+user_id+" | Notification ID:"+notification_id);
return admin.firestore().collection("Users").doc(user_id).collection("Notifications").doc(notification_id).get().then(queryResult =>{
const from_user_id = queryResult.data().from;
const from_message = queryResult.data().Message;
const from_data = admin.firestore().collection("Users").doc(from_user_id).get();
const to_data = admin.firestore().collection("Users").doc(user_id).get();
return Promise.all([from_data,to_data]).then(result =>{
const from_name = result[0].data().Name;
const to_name = result[1].data().Name;
const token_id = result[1].data().Token_ID;
const payload = {
notification: {
title: "Hey! "+from_name+" here",
body: "Dear "+to_name+", "+from_message+", Will you help me?",
icon: "default"
}
};
return admin.messaging().sendToDevice(token_id,payload).then(result =>{
return console.log("Notification Sent.");
});
});
});
});
And Here is my android code:
public class FirebaseMsgService extends FirebaseMessagingService {
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
String messageTitle = remoteMessage.getNotification().getTitle();
String messageBody = remoteMessage.getNotification().getBody();
Uri sound = Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.enough);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this, getString(R.string.default_notification_channel_id))
.setSmallIcon(R.drawable.logo)
.setContentTitle(messageTitle)
.setSound(sound)
.setContentText(messageBody)
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(messageBody))
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
int mNotificationID = (int) System.currentTimeMillis();
NotificationManager mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
mNotificationManager.notify(mNotificationID,mBuilder.build());
}
}
While I know squad about nodejs (or js in general) I got this working yesterday by passing a data object in the payload.
So, the json request that google makes (I'm using GCM still, but I'm sure FCM would be the same, or very similar payload) looks like this:
{
"to": "<GCM/FCM token>",
"priority": "normal",
"android_channel_id": -99,
"data": {
"title": "Some title",
"body": "Some body",
"more_data_one": "Some more data",
"more_data_two": "Some more data, again!"
}
}
Somehow, however, if I send both data and notification in the payload, the GCMServiceListener never gets called, and the app just displays whatever is in the notification portion of the payload.
By adding the data section (and therefore making the notification a "silent" notification), you are then on charge of intercepting the message, and displaying it with the Notification builder.