Firebase cloud message not sending to device - javascript

I am trying to allow users to receive push notifications if an action happened ( like, comment, etc). In the log I sometimes get sucesscount: 1 however device does not receive a notification. But most of the time it is faliurecount:1 the second time. Regardless I am not getting the push notification. When I deployed my functions there was no errors.
When I do send myself a test message from Firebase cloud messaging, that however does work correctly and sends a push notification to everyones devices successfully.
Here is observing likes for example
exports.observeLikes = functions.database.ref('/user-likes/{uid}/{postId}').onCreate((snapshot, event) => {
var uid = event.params.uid;
var postId = event.params.postId;
return admin.database().ref('/users/' + uid).once('value', snapshot => {
var userThatLikedPost = snapshot.val();
return admin.database().ref('/posts/' + postId).once('value', snapshot => {
var post = snapshot.val();
if(uid === post.ownerUid) {
return Promise.resolve();
}
return admin.database().ref('/users/' + post.ownerUid).once('value', snapshot => {
var postOwner = snapshot.val();
var payload = {
notification: {
body: userThatLikedPost.username + ' liked your post ',
sound: 'default'
}
};
admin.messaging().sendToDevice(postOwner.fcmToken, payload)
.then((response) => {
// Response is a message ID string.
console.log('Successfully sent message:', response);
return response;
})
.catch((error) => {
console.log('Error sending message:', error);
throw new Error('Error sending message:', error);
});
})
})
})
})
Log

So I found the issue. I deleted the app from my device and created a new account ( and it created a new FCM token for the account) and push notifications does work. I did another check and manually changed the FCM token on another device to a new one it registered with , and push notifications are successful. It appears I now need to find a way to update every current test users FCM token because their current devices aren't receiving notifications.

Related

why old Email returns after updating it in firebase and VUE.JS?

am trying to allow users to change their primary email in my VUE App which uses firebase as authentication,
the code am using works fine and it gives me that the email has been updated, however after the email is updated I can log with the new email for one time only and once I have logged out then like it has never been changed, and the old email is working again.
What is am doing wrong that keeps getting the old email assigned with the user
currently am using the following code :
firebase.auth()
.signInWithEmailAndPassword(oldEmailAddress, currentPass)
.then(
() => {
firebase.auth().currentUser.updateEmail(newEmailAddress).then(() => {
console.log('Email Updated');
}).catch((error) => {
console.log('Email Error updating user:', error);
});
},
(err) => {
console.log('log in user error:', err);
}
);
try using this function from firebase/auth as the docs say:
const auth = getAuth();
updateEmail(auth.currentUser, "user#example.com").then((result) = { console.log(result) })

Send notifications to android app using Firebase Functions

I am developing a chat app and so, I need to send notifications that new messages have been received.
For that, I am using Firebase Functions.
I'm using the sendToDevice function, that needs a token to send a notification. The problem is, I can't seem to retrieve token of the user that sent the message.
This is my .js code:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification = functions.database.ref("/chats/{id}/messages/{messageId}/content")
.onWrite((change,context) => {
var content = change.after.val();
var payload = {
data:{
title: "Stranger has sent you a message",
text: content
}
};
// Here I need to the ID of the person who sent the message
// And then compare this Id with the two Ids of the to users that are in the conversation
// If the two Ids are different, then save the other Id as the token
// So that I can send a notification to the other user.
const senderId = database.ref("/chats/{id}/messages/{id}/sender/{senderId}");
admin.messaging().sendToDevice(senderId, payload)
.then(function(response){
console.log("Successfully sent message: ", response);
return null;
})
.catch(function(error){
console.log("Error sending message: ", error);
})
});
As you can see, I am checking for any changes in the messages/content child.
That as the content of my notification.
Then, I am trying to retrieve the message sender ID so I can know who sent the message and retrieve the other user Id to notify him.
This might be a little confusing so here is my Firebase Realtime Database:
What am I doing wrong so this piece of code works as it should? This is the activity I have in android to receive the message:
class MyFirebaseInstanceId : FirebaseMessagingService() {
override fun onMessageReceived(p0: RemoteMessage) {
if(p0.data.size > 0){
val payload :Map<String, String> = p0.data
sendNotification(payload)
}
}
private fun sendNotification(payload: Map<String, String>) {
val builder = NotificationCompat.Builder(this)
builder.setSmallIcon(R.drawable.common_google_signin_btn_icon_disabled)
builder.setContentTitle(payload.get("username"))
builder.setContentText(payload.get("email"))
val intent = Intent(this, MainActivity::class.java)
val stackBuilder = TaskStackBuilder.create(this)
stackBuilder.addNextIntent(intent)
val resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
builder.setContentIntent(resultPendingIntent)
val notificationManager = (getSystemService(Context.NOTIFICATION_SERVICE)) as NotificationManager
notificationManager.notify(0, builder.build())
}
}
Following our comments above, here is how to use the once() and val() methods in your Cloud Function:
//.....
const refSenderId = database.ref("/chats/{id}/messages/{id}/sender/{senderId}");
return refSenderId.once('value')
.then(dataSnapshot => {
const senderId = dataSnapshot.val();
return admin.messaging().sendToDevice(senderId, payload)
})
.then(function(response){
console.log("Successfully sent message: ", response);
return null;
})
.catch(function(error){
console.log("Error sending message: ", error);
return null; // <- Note the return here.
})
//.....

Trying to subscribe to topic on Firebase Cloud Messaging gives Error

When i try to subscribe to a topic i get the following error:
.subscribeToTopic is not a function
const messaging = firebase.messaging();
messaging
.requestPermission()
.then(() => {
return messaging.getToken();
})
.then(token => {
messaging
.subscribeToTopic(token, 'allUsers')
.then(response=> {
console.log(JSON.stringify(response));
})
.catch(function(error) {
console.log('Error subscribing to topic:', error);
});
})
.catch(err => {
console.log('Unable to get permission to notify.', err);
});
If I remove that line of .subscribeToTopic and add a POST call via http it works using the following url:
https://iid.googleapis.com/iid/v1/TOKEN/rel/topics/TOPIC_NAME
I took a look to this question and the docs
Cloud Messaging in Cloud Functions: admin.messagin(...).send is not a function
https://firebase.google.com/docs/cloud-messaging/js/topic-messaging
ah i solved it by handling on backend side ( nodeJS ) where the documentation is easy to handle topic.
so in this case we have alr generate token on frontend side then in backend (nodeJS) we tried to subscribe to topic by the token.
so in frontend end when we stream or firebase.messaging().onMessage(payload => { would like to trigger and show the message by topic.
FYI : https://github.com/firebase/firebase-js-sdk/issues/5289#issuecomment-899542765
so from the link we know that
Notification.vue
// these from frontend side ( for example vueJS )
import firebase from 'firebase/app'
import 'firebase/messaging'
// firebase only for get token, onMessaging, request permission check, there is no function to subscribe topic by the token, so we handle on backend side my alternative
then in server.js
// these from backend side ( for examle nodeJS )
const { admin } = require('./firebase-config');
// admin.messaging().sendToTopic()
// admin.messaging().subscribeToTopic()
// admin.messaging().sendToDevice()
if you are looking for the firebase-config.js here is
/*
* Initialize firebase
*/
var admin = require("firebase-admin");
var serviceAccount = require("./firebase.json"); // you can get the .json file on firebase service account .
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://project-xxxxxxx.firebaseio.com"
});
module.exports.admin = admin
my implementation :
app.get('/firebase/notification', (req, res)=>{
const registrationToken = req.body.registrationToken;
admin.messaging().subscribeToTopic(registrationToken, 'myTopic')
.then(response => {
console.log('Successfully subscribed to topic:', response)
const options = notification_options;
const message_notification = {
notification: {
title: 'Yogi Arif Widodo',
body: '2 10 pm',
url: 'https://localhost:8080',
other: 'other data',
}
};
admin.messaging().sendToTopic('myTopic', message_notification, options).then( response => {
so when i tested on firebase console send by topic myTopic my Notification.vue trigger these code
firebase.messaging().onMessage(payload => {
.....console.log
}
You need to use the method send not sendToTopic:
// The topic name can be optionally prefixed with "/topics/".
var topic = 'highScores';
var message = {
data: {
score: '850',
time: '2:45'
},
topic: topic
};
// Send a message to devices subscribed to the provided topic.
admin.messaging().send(message)
.then((response) => {
// Response is a message ID string.
console.log('Successfully sent message:', response);
})
.catch((error) => {
console.log('Error sending message:', error);
});
send() was released and replaced sendtotopic/sendtodevice in version FCM v1
https://firebase.googleblog.com/2018/02/firebase-cloud-messaging-v1-now.html
https://firebase.google.com/docs/cloud-messaging/js/topic-messaging

Message returned as undefined

I tried to send notifications through firebase functions when data is stored in my firebase database. It sends the message alright but a log tag I added to see if it got the name of the file that was uploaded to my firebase database came back as "Lecture note uploaded is: undefined". That's line 12 I don't understand why.
Below is my code.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.sendNotification = functions.database.ref('/Lecture_Materials/{MIS}/{MISId}/name')
.onWrite(( change,context) =>{
// Grab the current value of what was written to the Realtime Database.
var eventSnapshot = change.after.val();
var str1 = "Lecture material uploaded is: " + eventSnapshot.name;
console.log(str1);
var topic = "Management.Information.System";
var payload = {
data: {
name: str1,
}
};
// Send a message to devices subscribed to the provided topic.
return admin.messaging().sendToTopic(topic, payload)
.then(function (response) {
// See the MessagingTopicResponse reference documentation for the
// contents of response.
console.log("Successfully sent message:", response);
return;
})
.catch(function (error) {
console.log("Error sending message:", error);
});
});

How to add results from a promise based API call with message.addReply using Recast.ai?

I'm making a bot that searches restaurants based on location. Can anyone help me why this doesnt show up in FB messenger?:
restaurants(result.getMemory('location').raw)
.then(res=>{
message.addReply(res);
message.reply();
});
}
The call to the restaurants function returns the results from a YELP API call (an array of restaurants) but when I add it as a reply to message, nothing happens in FB messenger.
Here is the full code for message.js:
const recastai = require('recastai');
const restaurants = require('./restaurants');
// This function is the core of the bot behaviour
const replyMessage = (message) => {
// Instantiate Recast.AI SDK, just for request service
const request = new recastai.request(process.env.REQUEST_TOKEN,
process.env.LANGUAGE);
// Get text from message received
const text = message.content;
console.log('I receive: ', text);
// Get senderId to catch unique conversation_token
const senderId = message.senderId;
// Call Recast.AI SDK, through /converse route
request.converseText(text, { conversationToken: senderId })
.then(result => {
//Recast takes text analyses that, returns a result object, generates replies adds messages to reply stack and then sends the replies
//Call Yelp API with when the intent is Location. When Yelp returns result we add it to the result.replies array.
//Then we add everything in result.replies to the messaging queue that sends the responses to FB
if (result.action) {
console.log('The conversation action is: ', result.action.slug);
}
// If there is not any message return by Recast.AI for this current conversation
if (!result.replies.length) {
message.addReply({ type: 'text', content: 'I don\'t have the reply to this yet :)' });
} else {
// Add each reply received from API to replies stack
result.replies.forEach(replyContent => message.addReply({ type: 'text', content: replyContent }));
}
// Send all replies
message.reply()
//send initial reply generated by Recast first
.then(() => {
//call restaurant function that returns a list of results from API
//if the action is location and done
if(result.action && result.action.slug === 'location' && result.action.done){
restaurants(result.getMemory('location').raw)
.then(res=>{
console.log(res);
message.addReply(res);
message.reply();
});
}
})
.catch(err => {
console.error('Error while sending message to channel', err);
});
})
.catch(err => {
console.error('Error while sending message to Recast.AI', err);
});
};
module.exports = replyMessage;
And here is my restaurants.js code that is imported into the message.js file for the bot behavior:
const rp = require('request-promise');
// Load configuration
require('./config');
const restaurants = (location) => {
return Promise.all([
yelpCall(location)
]).then(result => {
//result contains the return value from Yelp call
return result;
});
};
const yelpCall = (location) => {
const auth = {
method: 'POST',
url: 'https://api.yelp.com/oauth2/token?grant_type=client_credentials&client_id='+ process.env.YELP_APP_ID +'&client_secret='+process.env.APP_SECRET
};
return rp(auth)
.then(result => {
const tokens = JSON.parse(result);
return tokens;
})
.then(result=>{
const options = {
url: 'https://api.yelp.com/v3/businesses/search?location=' + location + "&term=thai",
headers: {Authorization: "Bearer " + result.access_token}
};
return rp(options).then(findings =>{
return findings;
});
});
};
module.exports = restaurants;
A few thoughts :
message.reply is thenable, therefore return message.reply() in two places.
request.converseText() is thenable, therefore return request.converseText(...).
restaurants is thenable, therefore return restaurants(...).
in message.js, message.addReply() is passed object of the form {type:..., content:...} in two places but finally just res. Is that correct?
in restaurants.js, Promise.all() appears to be unnecessary. It will cause its result to be wrapped in an array. module.exports = location => yelpCall(location); seems more appropriate.

Categories

Resources