I have written this code with nodejs to send a push notification from a nodejs server to a specific user of a mobile application:
const { admin } = require("../config/Firebase");
const sendNotification = async (req, res) => {
const requestBody = req?.body;
const registrationToken = requestBody?.registrationToken; // get it from mobile app
const data = {
message: {
token: registrationToken,
notification: {
title: "Notification Title",
body: "Notification Body ",
description: "Notification description",
},
android: {
notification: {
imageUrl: "https://foo.bar.pizza-monster.png",
},
},
apns: {
payload: {
aps: {
"mutable-content": 1,
},
},
fcm_options: {
image: "https://foo.bar.pizza-monster.png",
},
},
webpush: {
headers: {
image: "https://foo.bar.pizza-monster.png",
},
},
data: {
Nick: "Mario",
Room: "PortugalVSDenmark",
},
},
};
try {
admin.messaging().send(data.message);
res.status(200).json({ notificationStatus: "success" });
} catch (error) {
console.log("Error while sending notification: ", error);
res.status(500).json({ notificationStatus: "failed" });
}
};
But it works only for android devices. So i would like to know if there a config or something like that which makes the server sends it to both iOS and android devices ?
I'm currently working on a chat application and I want to implement Parse Server Push notifications. I follow the documentation and put all the code that is required. My problem is that I can't see the notification, even though the console tells me that it was sent.
This is my MainActivity.java where is the Parse Installation.
#Override
protected void onCreate(Bundle savedInstanceState) {
notificationsPush();
createGraphicElements();
super.onCreate(savedInstanceState);
}
private void notificationsPush(){
ParseInstallation.getCurrentInstallation().saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
if (e == null){
System.out.println("---------------------");
System.out.println("SUCCESS ON INSTALLATION");
System.out.println("----------------------");
ParsePush.subscribeInBackground("Chat", new SaveCallback() {
#Override
public void done(ParseException e) {
if (e == null) {
System.out.println("----------------------");
System.out.println("SUCCESS ON CHANNEL");
System.out.println("----------------------");
} else {
System.out.println("----------------------");
System.out.println("ERROR ON CHANNEL: " + e.getMessage());
System.out.println("CODE: " + e.getCode());
System.out.println("----------------------");
}
}
});
}else{
System.out.println("---------------------");
System.out.println("ERROR ON INSTALLATION");
System.out.println("ERROR: " + e.getMessage());
System.out.println("CODE: " + e.getCode());
System.out.println("----------------------");
}
}
});
}
These are my implementations on graddle module. (There is also the one that is required to connect to Firebase).
implementation platform('com.google.firebase:firebase-bom:28.4.1')
implementation 'com.google.firebase:firebase-analytics'
implementation 'com.google.firebase:firebase-messaging'
//Parse Server
implementation "com.github.parse-community.Parse-SDK-Android:parse:1.26.0"
//PUSH Parse Server
implementation "com.github.parse-community.Parse-SDK-Android:fcm:1.26.0"
These are the functions that I use on my ParseCloud (they are on main.js).
Parse.Cloud.define("SendPush", function(request) {
var query = new Parse.Query(Parse.Installation);
query.exists("deviceToken");
// here you can add other conditions e.g. to send a push to sepcific users or channel etc.
var payload = {
alert: request.params.Message
// you can add other stuff here...
};
Parse.Push.send({
data: payload,
where: query
}, {
useMasterKey: true
})
.then(function() {
response.success("Push Sent!");
}, function(error) {
response.error("Error while trying to send push " + error.message);
});
});
Parse.Cloud.define("SendPush2", function(request) {
var msg = request.params.Message;
var query = new Parse.Query(Parse.User);
var user = request.params.user;
query.equalTo("objectId", user);
Parse.Push.send({
where: query,
data:{
alert: {
"title" : msg,
"body" : msg
},
sound: 'default'
}
}, {
useMasterKey: true,
success: function(){
response.success("Push Sent!");
},
error: function(error){
response.error("Error while trying to send push " + error.message);
}
});
});
Parse.Cloud.define("SendPush3", function(request, response) {
var userId = request.params.user;
var message = "sening a test message"; //request.params.message;
var queryUser = new Parse.Query(Parse.User);
queryUser.equalTo('objectId', userId);
var query = new Parse.Query(Parse.Installation);
query.matchesQuery('user', queryUser);
Parse.Push.send({
where: query,
data: {
alert: message,
badge: 0,
sound: 'default'
}
}, {
success: function() {
console.log('##### PUSH OK');
response.success();
},
error: function(error) {
console.log('##### PUSH ERROR');
response.error('ERROR');
},
useMasterKey: true
});
});
Finally, the piece of code of my app where I test those ParseCloud functions to send the notification.
private void sendMessage(){
if(messageEditText.getText().toString().length() > 0) {
String messageToSend = messageEditText.getText().toString();
messageEditText.setText("");
MessageBO messageBO = new MessageBO();
messageBO.setText(messageToSend);
messageBO.setUserIdSender(idUser);
messageBO.setUserIdReceiver(idContact);
insertMessage(messageBO.getUserIdSender().toString(),
messageBO.getUserIdReceiver().toString(),
messageBO.getText().toString());
enviarNotificacionPush(messageBO);
}
actualizarMensajes();
}
private void sendNotificationPush(MessageBO m){
HashMap<String,String> map = new HashMap<String, String>();
map.put("Message", m.getText().toString());
ParseCloud.callFunctionInBackground("SendPush",map, new FunctionCallback<Object>() {
#Override
public void done(Object object, ParseException e) {
if (e == null){
System.out.println("----------------------------");
System.out.println("NOTIFICATION SUCCES: " + object);
System.out.println("----------------------------");
}else{
System.out.println("----------------------------");
System.out.println("ERROR ON NOTIFICATION PUSH: " + e.getMessage());
System.out.println("CODE: " + e.getCode());
System.out.println("----------------------------");
}
}
});
HashMap<String,String> map2 = new HashMap<String, String>();
map2.put("Message", m.getText().toString());
map2.put("user", idUser);
ParseCloud.callFunctionInBackground("SendPush2",map2, new FunctionCallback<Object>() {
#Override
public void done(Object object, ParseException e) {
if (e == null){
System.out.println("----------------------------");
System.out.println("NOTIFICATION 2.0 SUCCESS: " + object);
System.out.println("----------------------------");
}else{
System.out.println("----------------------------");
System.out.println("ERROR ON NOTIFICATION PUSH 2.0: " + e.getMessage());
System.out.println("CODE: " + e.getCode());
System.out.println("----------------------------");
}
}
});
ParseCloud.callFunctionInBackground("SendPush3",map2, new FunctionCallback<Object>() {
#Override
public void done(Object object, ParseException e) {
if (e == null){
System.out.println("----------------------------");
System.out.println("NOTIFICACION 3.0 SUCCESS: " + object);
System.out.println("----------------------------");
}else{
System.out.println("----------------------------");
System.out.println("ERROR ON NOTIFICACION PUSH 3.0: " + e.getMessage());
System.out.println("CODE: " + e.getCode());
System.out.println("----------------------------");
}
}
});
}
As you can see, I use 3 functions that send notifications, all of them said that it was a success, but in my android emulator never arrive a notification. I check my parse Dashboard and even though that it says that the notifications were sent, it also says 0 deliveries. I need your help please because I don't know exactly what I'm doing wrong.
If you need, the info of my Android emulator is the following:
My android emulator info
[EDIT 1]
(I don't know how to refer the comment that ask me to do it but anyways) Because I see that maybe you'll need the installation class.
installation class
All installations are from the emulator due to I uninstall and install again the application. There is algo my smartphone, that is a Huawei (that also I can't see notifications but I know thats due to Huawei problems with google services).
[EDIT 2]Hello again, here is my Parse Server configuration(aka the index.js of my parse). I'm using the parse_server_example repository by the way.
// Example express application adding the parse-server module to expose Parse
// compatible API routes.
const express = require('express');
const ParseServer = require('parse-server').ParseServer;
const path = require('path');
var ParseDashboard = require('parse-dashboard');
const args = process.argv || [];
const test = args.some(arg => arg.includes('jasmine'));
const databaseUri = process.env.DATABASE_URI || process.env.MONGODB_URI;
if (!databaseUri) {
console.log('DATABASE_URI not specified, falling back to localhost.');
}
const config = {
databaseURI: databaseUri || 'mongodb://admin:123#localhost:27017/ParseServer?authSource=admin',
cloud: process.env.CLOUD_CODE_MAIN || __dirname + '/cloud/main.js',
appId: process.env.APP_ID || 'MY_APP_ID',
masterKey: process.env.MASTER_KEY || 'MY_MASTER_KEY', //Add your master key here. Keep it secret!
serverURL: process.env.SERVER_URL || 'http://192.168.10.100:1337/parse/', // Don't forget to change to https if needed
liveQuery: {
classNames: ['Posts', 'Comments'], // List of classes to support for query subscriptions
},
push: {
android: {
apiKey: 'AAAASP09btg:APA91bGxn3e0vJX0ri2DeFEWUjAODTCaP3mfCQ0la3oiIgNqNYUlj2THFlEwRjqnXGuI-8H_l5-0xZtyscn3yY4mRrAL5tNHYXrM8NBltgCwCx1gH8LFVvgAWubmV2Zsa5NkmD53vCeO'
}
}
};
// Client-keys like the javascript key or the .NET key are not necessary with parse-server
// If you wish you require them, you can set them as options in the initialization above:
// javascriptKey, restAPIKey, dotNetKey, clientKey
var configdashboard = {
"allowInsecureHTTP": true,
"apps": [
{
"serverURL": "http://192.168.10.100:1337/parse/",
"appId": "MY_APP_ID",
"masterKey": "MY_MASTER_KEY",
"appName": "ParseServer01"
}
],"users": [
{
"user": "root",
"pass": "123456"
}
]
};
var dashboard = new ParseDashboard(configdashboard,{allowInsecureHTTP:configdashboard.allowInsecureHTTP});
const app = express();
app.use('/dashboard', dashboard);
// Serve static assets from the /public folder
app.use('/public', express.static(path.join(__dirname, '/public')));
// Serve the Parse API on the /parse URL prefix
const mountPath = process.env.PARSE_MOUNT || '/parse';
if (!test) {
const api = new ParseServer(config);
app.use(mountPath, api);
}
// Parse Server plays nicely with the rest of your web routes
app.get('/', function (req, res) {
res.status(200).send('I dream of being a website. Please star the parse-server repo on GitHub!');
});
// There will be a test page available on the /test path of your server url
// Remove this before launching your app
app.get('/test', function (req, res) {
res.sendFile(path.join(__dirname, '/public/test.html'));
});
const port = process.env.PORT || 1337;
if (!test) {
const httpServer = require('http').createServer(app);
httpServer.listen(port, function () {
console.log('parse-server-example running on port ' + port + '.');
});
// This will enable the Live Query real-time server
ParseServer.createLiveQueryServer(httpServer);
}
module.exports = {
app,
config,
};
[EDIT 3] Hello again, I was trying to send notifications with curl and this is what happens:
curl -X POST \
-H "X-Parse-Application-Id: wPacsFQMmP" \
-H "X-Parse-Master-Key: DwonoEbeNf" \
-H "Content-Type: application/json" \
-d '{
"where": {
"deviceType": {
"$in": [
"android"
]
}
},
"data": {
"title": "The Shining",
"alert": "All work and no play makes Jack a dull boy."
}
}'\ http://192.168.10.100:1337/parse/push
{"result":true}[
Also as additional info, when I try making a push using FCM only (that means, follow this Firebase FCM documentation) and the result is basically the same, it says it was sent succesfully but I don't see it on the android emulator, not even in my old smartphone (Nokia 6).
[EDIT 4] I turn on verbose, and this is what I found in my parse logs about SendPush cloud function.
REQUEST for [POST] /parse/push: {\\n \\\"channels\\\": [\\n \\\"SignChat\\\"\\n ],\\n \\\"data\\\": {\\n \\\"alert\\\": \\\"The Giants won against the Mets 2-3.\\\"\\n }\\n}\",\n \"method\": \"POST\",\n \"timestamp\": \"2021-10-28T20:25:27.623Z\",\n \"url\": \"/parse/push\"\n },\n {\n \"level\": \"verbose\",\n \"message\": \"RESPONSE from [POST] /parse/functions/SendPush: {\\n \\\"response\\\": {}\\n}\",\n \"result\": {\n \"response\": {}\n },\n \"timestamp\": \"2021-10-28T20:25:27.619Z\"\n }
To send push notifications for Android devices, the required fields are deviceToken and GCMSenderID.
However, according to the screenshot you sent, the GCMSenderId of your installations is empty, and it's required for sending push notifications.
In your MainActivity, you're not explicitly set it, which is needed to save it properly.
Here's a sample code showing how you can do that:
ParseInstallation installation = ParseInstallation.getCurrentInstallation();
installation.put("GCMSenderId", INSERT_YOUR_SENDER_ID);
installation.saveInBackground();
Once both fields are filled, the push notification might work properly.
I have this code that works correctly but I want to add the 'mensaje' in the body of the notification, the problem is that I do not know how to get it to be able to send it.
This is the structure of my data in firebase:
enter image description here
And this is the function:
const functions = require('firebase-functions');
let admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendPush = functions.database.ref('/chats/{chat}/{mensaje}/').onWrite((snapshot, context) => {
nombreChat = context.params.chat;
return cargarUsuarios(nombreChat).then(usuarios => {
let tokens = [];
for (let user of usuarios){
if(user.token !== undefined){
console.log('User', "Usuario: " + user.nombre);
console.log('User token', "Token: " + user.token);
tokens.push(user.token);
}
}
let payload = {
notification:{
title:'Trado GO',
body: 'Has recibido un nuevo mensaje',
sound: 'default',
badge: '1'
}
};
return admin.messaging().sendToDevice(tokens, payload);
});
});
function cargarUsuarios(chat){
var arrayParticipantesChat = chat.split(',');
let dbRef = admin.database().ref('/usuarios');
let defer = new Promise((resolve, reject) => {
dbRef.once('value', (snap) => {
let data = snap.val();
let usuarios = [];
for (var property in data){
usu=data[property];
if(arrayParticipantesChat.includes(usu['nombre'])){
usuarios.push(data[property]);
}
}
resolve(usuarios);
}, (err) => {
reject(err);
});
});
return defer;
}
I'm developing an Android Application using Ionic 3 and I want to use push notification with tool OneSignal. Here is the code that I use at my main component:
let iosSettings = {
kOSSettingsKeyAutoPrompt: true,
kOSSettingsKeyInAppLaunchURL: false
}
this.oneSignal
.startInit(APP_ID, GOOGLE_PROJECT_NUMBER)
.iosSettings(iosSettings);
this.oneSignal.inFocusDisplaying(this.oneSignal.OSInFocusDisplayOption.Notification);
this.oneSignal
.handleNotificationReceived()
.subscribe((notification: OSNotification) => {
console.log(notification)
});
this.oneSignal.endInit();
And here is the code that I use at my node webservice:
function sendNotification(scheduling) {
const schedulingID = scheduling.email + scheduling.date;
const message = {
app_id: APP_ID,
headings: {"en": MY_APP_NAME},
contents: {"en": "Scheduling confirmed!"},
data: {"agendamento-id": schedulingID},
included_segments: ["All"]
};
const headers = {
"Content-Type": "application/json; charset=utf-8",
"Authorization": "Basic " + REST_API_KEY
};
const options = {
host: "onesignal.com",
port: 443,
path: "/api/v1/notifications",
method: "POST",
headers: headers
};
console.log("Sending notification...");
const req = https.request(options, function (res) {
res.on('data', function (data) {
console.log("Response:");
console.log(JSON.parse(data));
});
});
req.on('error', function (e) {
console.log("ERROR:");
console.log(e);
});
req.write(JSON.stringify(message));
req.end();
}
But, when I execute the Android App on my devices, I get the message error:
{id: '', recipients: 0, errors: ['All included players are not subscribed']}
This will solve your problem:
'included_segments' => array(
'Subscribed Users'
),
I need help, I've been searching for solutions all day but I can't fix my issue, the code below won't read the device tokens.
Below contains my db structure. I manage to receive the log: 'We have a new News for you.' When I added a new post but I received the log "There are no notification tokens to send to." Which means it cannot detect the device tokens even though there is already ones. What am I doing wrong?
{
"Newsv2" : {
"All" : {
"-Ktr7ZkuChCjsUIMb_4f" : {
"title" : "",
"type" : "",
}
},
"Usersv2" : {
"h0RzzpdO7nZVLpAR4fi7xRWUqsT2" : {
"device_token" : "",
"name" : "",
"user_no" : ""
}
},
}
/--News
--All
--name
--desc
/--Usersv2
--{userID}
--device_token
exports.sendNotif = functions.database.ref('/Newsv2/All/{newsID}').onWrite(event => {
const newsID = event.params.newsID;
const userID = event.params.userID;
if (!event.data.val()) {
return console.log('News! ', newsID);
}
console.log('We have a new News for you!',newsID);
// Get the list of device notification tokens.
const getDeviceTokensPromise = admin.database().ref(`/Usersv2/${userid}/device_token`).once('value');
return Promise.all([getDeviceTokensPromise]).then(results => {
const tokensSnapshot = results[0];
//const follower = results[1];
// Check if there are any device tokens.
if (!tokensSnapshot.hasChildren()) {
return console.log('There are no notification tokens to send to.');
}
console.log('There are', tokensSnapshot.numChildren(), 'tokens to send notifications to.');
//console.log('Fetched follower profile', follower);
// Notification details.
const payload = {
notification: {
title: 'Test Message',
body: '',
icon: ''
}
};
// Listing all tokens.
const tokens = Object.keys(tokensSnapshot.val());
// Send notifications to all tokens.
return admin.messaging().sendToDevice(tokens, payload).then(response => {
// For each message check if there was an error.
const tokensToRemove = [];
response.results.forEach((result, index) => {
const error = result.error;
if (error) {
console.error('Failure sending notification to', tokens[index], error);
// Cleanup the tokens who are not registered anymore.
if (error.code === 'messaging/invalid-registration-token' ||
error.code === 'messaging/registration-token-not-registered') {
tokensToRemove.push(tokensSnapshot.ref.child(tokens[index]).remove());
}
}
});
return Promise.all(tokensToRemove);
});
});
});
To get the device token I store it in my firebase DB when a user registers or logs in.
private DatabaseReference mUserDatabase;
mUserDatabase = FirebaseDatabase.getInstance().getReference().child("Users/");
//and if the login/register is successful
mUserDatabase.child("device_token").setValue(deviceToken).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Intent intent = new Intent(application.getApplicationContext(), MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP |Intent.FLAG_ACTIVITY_NEW_TASK);
application.startActivity(intent);
}
});
as for my firebase funciton:
const deviceToken = admin.database().ref(`/Users/${unique_id}/device_token`).once('value');