How do you use a custom channel with a local notification in Expo SDK 39 with Android?
On the topic of notifications, the Expo documentation seems to include a mishmash of instructions for both depreciated and the current version of Expo.
The documentation for LegacyNotifications mentions that a “LocalNotification” object can include configuration for “channelId”.
And, in fact, the legacy methods are what the current notification guide says to use:
Notifications.presentLocalNotificationAsync({
title: 'New Message',
body: 'Message!!!!',
android: {
channelId: 'chat-messages',
},
});
But, in multiple places, the documentation says to NOT use the legacy methods:
“This API is deprecated and will be removed in the SDK 40. Please, check the new notification module.”
“Instead of presentNotificationAsync developers are encouraged to use setNotificationHandler and scheduleNotificationAsync.”
Using the current API, I’m able to create a custom channel, ‘messages’, using “setNotificationChannelAsync”:
if (Platform.OS === 'android') {
Notifications.setNotificationChannelAsync('messages', {
name: 'Messages',
importance: Notifications.AndroidImportance.MAX,
vibrationPattern: [0, 250, 250, 250],
lightColor: '#FF231F7C',
});
}
The documentation gives the following simple example for using “scheduleNotificationAsync”:
async function schedulePushNotification() {
await Notifications.scheduleNotificationAsync({
content: {
title: "You've got mail! 📬",
body: 'Here is the notification body',
data: { data: 'goes here' },
},
trigger: { seconds: 2 },
});
}
According to the documentation, the only argument that “scheduleNotificationAsync” takes is “NotificationRequestInput,” which in turn can include “NotificationContentInput”. However, I did not see any mention of channelId.
Is there a way to use a custom channelId in scheduleNotificationAsync?
Folks on the Expo forums pointed out that NotificationRequestInput includes both NotificationContentInput and NotificationTriggerInput. The documentation for the NotificationTriggerInput types includes channelId.
Expanding upon the example for scheduleNotificationAsync, the simplest use of channelId would be
async function schedulePushNotification() {
await Notifications.scheduleNotificationAsync({
content: {
title: "You've got mail! 📬",
body: "Here is the notification body",
data: { data: "goes here" },
},
trigger: {
seconds: 2,
channelId: "messages",
},
});
}
Related
When developing an application, an external service was implemented for sending push notifications, all pushes sent must have a title, text and image, however, images appear randomly in push notifications or not. Images of different dimensions were tested and sometimes they appear on push and sometimes they don't. Any idea what can be done to help identify and fix the notifications issue?
Tests done on: android 12
Image: 520x470 => 393.8kB
Service that sends the push:
Ruby 2.7.1
Rails 6.0.3.3
command-line-args: 5.2.1
firebase-admin: 10.0.2
fork do
exec(
"node #{path} --tokens #{token} --title #{title} --message #{msg} --link '#{url}' --id #{id} --image #{img}"
)
end
The image path is sent as a string
App:
React Native v0.66.3
const admin = require("firebase-admin");
const serviceAccount = require("./app-name-c0529a8230hq.json");
const cli = require("./cli")();
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://app-name.firebaseio.com"
});
const payload = {
tokens: cli.tokens.split(','),
notification: {
body: cli.message,
title: cli.title,
},
data: {
openURL: cli.link,
},
apns: {
payload: {
aps: {
'mutable-content': 1,
},
},
fcm_options: {
image: cli.image,
},
},
android: {
notification: {
image: cli.image,
},
},
};
admin
.messaging()
.sendMulticast(payload)
.then((s) => {
console.log('Success: ', s);
}
})
.catch((e) => console.log("Error", e))
Thanks for any idea to help resolve this issue.
If image have to be downloaded locally maybe the problem is the image size, perhaps is too big for network connection. It also could be the image file extention (PNG or JPEG are allowed), or the image resolution.
In other hand, if you're working with android, it could have different behaviours depending on how you build the notification json and if the android app is background or not.
What if you try the payload adding
image: cli.image,
to notification, this way:
notification: {
body: cli.message,
title: cli.title,
image: cli.image,
},
I have a problem with Android repeating notifications (used Notifee library version "#notifee/react-native": "^4.1.0"). The notification is fired many times on some devices and must be killed from app settings. Looks like a never-ending loop of the same notification.
The problem found so far in these 2 situations: 1) the user doesn't use the app for a few days and then opens it (despite we are not scheduling notification in any hook, it's on the button), 2) the user had fly mode at the time of notification.
Notification set with this code:
notifee.createTriggerNotification(notification, trigger);
trigger:
{
alarmManager: {
allowWhileIdle: true,
},
type: TriggerType.TIMESTAMP,
timestamp: fireDate,
repeatFrequency: RepeatFrequency.WEEKLY,
};
notification:
{
title: alertTitle,
body: alertBody,
data: userInfo,
android: {
channelId,
importance: AndroidImportance.HIGH,
pressAction: {
id: 'default',
launchActivity: 'default',
launchActivityFlags: [AndroidLaunchActivityFlag.SINGLE_TOP],
},
smallIcon: 'ic_small_icon',
largeIcon: 'ic_launcher',
style: alertBody
? {
type: AndroidStyle.BIGTEXT,
text: alertBody,
}
: undefined,
showTimestamp: true,
visibility: AndroidVisibility.PUBLIC,
sound: 'default',
},
ios: {
sound: 'default',
foregroundPresentationOptions: {
sound: true,
alert: true,
badge: true,
},
},
};
Have you ever noticed similar behavior? Any ideas on what can cause it?
I am currently using Notifee with Firebase for local push notifications on react-native android, and on debug mode it works perfectly, with my custom sound playing normally. But after assembling a release apk, on some android devices the notification sound simply does not play after a while. I've checked the notification settings on the devices and it's normal, not set to silence and the devices aren't in "do not disturb".
Here's the code :
Channel Creation at index.js
notifee.createChannel({
id: 'service',
name: 'New Notifications',
vibration: true,
sound: 'siren',
badge:false,
vibrationPattern: [300, 500],
});
Creating the notification
const onMessageReceived = async (notification) => {
const { department_name, category_name, activity_name, description, destination} = notification.data;
const messageToBePresented = `Department: ${department_name}\nCategory: ${category_name}\nActivity: ${activity_name}\nDescription: ${description}\nBed: ${destination}`;
try {
notifee.displayNotification({
title:'New Service',
body:messageToBePresented,
data: notification.data,
android:{
channelId:'service',
style: { type: AndroidStyle.BIGTEXT, text:messageToBePresented },
pressAction: {
id: 'default',
},
sound:'siren',
}
});
}
catch (err) {
console.log(err);
}
}
firebase.messaging().onMessage(onMessageReceived);
firebase.messaging().setBackgroundMessageHandler(onMessageReceived);
Is there some Android setting that i might i've overlooked that causes notification sounds to stop playing ?
I have a cloud function which executes this code to send the notification to the user, I am getting notification correctly but I want to navigate to a particular screen for that I have to add click action something like this.
clickAction: FLUTTER_NOTIFICATION_CLICK
I have tried to put this property in different lines of code but nothing seem to work, can someone please tell where should I put it exactly?
This is my index.js file!
const message = {
token: data['guestFcmToken'],
notification: {
title: `New message from ${data['hostName']}.`,
body: data['type'] === 'image' ? 'Photo' : data['lastMessage'],
},
data: {
showForegroundNotification: 'false',
screen: 'chat'
},
}
console.log('Sending message');
const response = await admin.messaging().send(message);
console.log(response);
You can add clickAction: 'FLUTTER_NOTIFICATION_CLICK' in the following way
message = {
token: data['guestFcmToken'],
notification: {
title: `New message from ${data['hostName']}.`,
body: data['type'] === 'image' ? 'Photo' : data['lastMessage'],
},
data: {
showForegroundNotification: 'false',
screen: 'chat'
},
android: {
notification: {
clickAction: 'FLUTTER_NOTIFICATION_CLICK',
},
}
};
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.
);