I need to enable push notifications in my project. I have already integrated twilio conversations.
I followed this documentation and seems to be ok, but there is a problem with the setPushRegistrationId method.
I have this code:
import { getMessaging, getToken, onMessage } from "firebase/messaging";
import initFirebase from "../firebase/initFirebase";
export const handleNotifications = async (conversationClientInstance) => {
const app = initFirebase();
const messaging = getMessaging(app);
getToken(messaging, {
vapidKey:
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
})
.then((currentToken) => {
if (currentToken) {
console.log("currentToken", currentToken);
//Here is the problem <----------
conversationClientInstance
.setPushRegistrationId("fcm", currentToken)
.then((el) => console.log("el", el));
onMessage((payload) => {
conversationClientInstance.handlePushNotification(payload);
});
} else {
// Show permission request UI
console.log(
"No registration token available. Request permission to generate one."
);
// ...
}
})
.catch((err) => {
console.log("An error occurred while retrieving token. ", err);
// ...
});
};
I am getting this error on the twilio dashboard:
I also replicated this situation in this github repo. It is deployed, so you can try it live.
In console I can see the FCM token, but setPushRegistrationId returns undefined (the console.log('el', el))
I think I forgot something, but I can't figure out what. What do you thik?
Related
I made alert service using FCM, it works fine in my local server. but after I deployed my server in ec2, trying alert function on ec2 app gives me this error :
[ient-SecureIO-1] o.a.t.websocket.pojo.PojoEndpointBase : No error handling configured for [springboot.utils.WebsocketClientEndpoint] and the following error occurred
java.lang.IllegalArgumentException: Exactly one of token, topic or condition must be specified
Reading the error message, i guess that there's no token in my server.
In notification.js, I'm trying to get token and request POST to '/register'
const firebaseModule = (function () {
async function init() {
// Your web app's Firebase configuration
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('/firebase-messaging-sw.js')
.then(registration => {
var firebaseConfig = {
configuration Information
};
// Initialize Firebase
console.log("firebase Initialization");
firebase.initializeApp(firebaseConfig);
// Show Notification Dialog
const messaging = firebase.messaging();
messaging.requestPermission()
.then(function() {
console.log("Permission granted to get token");
return messaging.getToken();
})
.then(async function(token) {
console.log("Token: ", token);
await fetch('/register', { method: 'post', body: token })
messaging.onMessage(payload => {
const title = payload.notification.title
const options = {
body : payload.notification.body
}
navigator.serviceWorker.ready.then(registration => {
registration.showNotification(title, options);
})
})
})
.catch(function(err) {
console.log("Error Occured : " +err );
})
})
})
}
}
And by debugging it by console.log(), I found out that code is stopped before "if ('serviceWorker' in navigator) {"
So I need to make it proceed. But to be honest, it's been a while since i made this function, and I don't know almost anything about Javascript. I don't even know what navigator means(I googled it, but couldn't find clear answer) I'm having trouble figuring out what is wrong and how can I fix it. Can someone help me??
I am trying to get FCM token in react js application.
First thing i tried is to use messaging.useServiceWorker(registration) then use messaging.getToken() and it's working fine on localhost for firefox and google chrome, but on an HTTPS live server it works fine on firefox but in chrome it throws an error: DOMException: Failed to execute 'subscribe' on 'PushManager': Subscription failed - no active Service Worker.
I saw firebase docs and found that messaging.useServiceWorker is deprecated now and I have to use messaging.getToken({ serviceWorkerRegistration }) instead but it throws an error: FirebaseError: Messaging: We are unable to register the default service worker. Failed to register a ServiceWorker for scope ('http://localhost:3000/firebase-cloud-messaging-push-scope') with script ('http://localhost:3000/firebase-messaging-sw.js'): The script has an unsupported MIME type ('text/html'). (messaging/failed-service-worker-registration).
Notes
firebase-messaging-sw.js File is under the public directory.
firebase-messaging-sw.js File is empty.
This how I register the service worker:
export const registerServiceWorker = () => {
if ("serviceWorker" in navigator) {
return new Promise((resolve, reject) => {
navigator.serviceWorker
.register(process.env.PUBLIC_URL + "/firebase-messaging-sw.js")
.then(function (registration) {
console.log("[registration]", registration)
// messaging.useServiceWorker(registration)
resolve(registration);
})
.catch(function (err) {
console.log("[ERROR registration]: ", err)
reject(null);
});
});
} else {
console.log("SERVICE WORKER NOT IN THE BROWSER")
}
};
What should I do to get FCM token in a write way?
I have found a solution for this issue here is my code:
class Firebase {
constructor() {
if (firebase.apps.length) return;
firebase.initializeApp(config);
this.auth = firebase.auth();
this.messaging = firebase.messaging();
navigator.serviceWorker.getRegistrations().then((registrations) => {
if (registrations.length) {
[this.registration] = registrations;
return;
}
navigator.serviceWorker
.register("/firebase-message-sw.js")
.then((registration) => {
this.registration = registration;
});
});
}
async askNotificationPermission() {
try {
const token = await this.messaging.getToken({
serviceWorkerRegistration: this.registration,
});
return token;
} catch (error) {
console.error("[FIREBASE ERROR]: ", error);
return null;
}
}
}
And I am firing askNotificationPermission function with a click action.
With VueJS and Firebase, I want to create a user and then if it succeed add more info to a users collection.
Problem is my variable usersCollection is undefined when I get in the .then. I know I can take that exact code out of the .then and it works. Also, the auth function works as it is supposed to. It would seem that the problem is that I'm trying to access the collection inside the .then. But then again, I need to do this only if I successfully create a new user for authentication to avoid having users info from unregistered users. I don't enter the .catch either and I don't get an error of any kind in the chrome console. Any idea how to get this logic to work?
I initialize everything about firebase with this :
import * as firebase from 'firebase/app'
import 'firebase/auth'
import 'firebase/firestore'
import 'firebase/analytics'
const firebaseConfig = {
//configs
};
firebase.initializeApp(firebaseConfig);
firebase.analytics();
const db = firebase.firestore();
const auth = firebase.auth();
const usersCollection = db.collection('users');
export {
db,
auth,
usersCollection
}
The code is located in the main store of the app :
import * as types from './types';
import {
auth,
usersCollection,
} from '../../../../config/firebase';
//...
[types.ADD]: ({commit}, user) => {
auth.createUserWithEmailAndPassword(user.email, user.password)
.then((e) => {
usersCollection.add(user)
.then((docRef) => {
commit(types.MUTATE_ADD, user);
console.log("Document written with ID: ", docRef.id);
})
.catch((error) => {
console.error("Error adding document: ", error);
});
})
.catch((e) => {
//...
alert('An error occured while creating employee.\n' + e.code + '\n' + e.message);
return false;
});
}
Above, the the user I use for authentication is created, but when I get to the .then usersCollection is undefined, yet I get no error in the Chrome console and the user is not created.
As explained earlier, if I take the block where I add the user to the collection out of the .then I get to add the user to the collection :
[types.ADD]: ({commit}, user) => {
auth.createUserWithEmailAndPassword(user.email, employeeHelper.makePassword(user))
.then((e) => {
})
.catch((e) => {
var errorCode = e.code;
var errorMessage = e.message;
alert('An error occured while creating employee.\n' + e.code + '\n' + e.message);
return false;
});
usersCollection.add(user)
.catch((error) => {
console.error("Error adding document: ", error);
});
}
Using another method made it work exactly as I intended :
[types.ADD]: ({commit}, user) => {
commit(types.MUTATE_ADD, user);
auth.createUserWithEmailAndPassword(user.email, employeeHelper.makePassword(user))
.then((e) => {
usersCollection.doc(user.email).get().then((querySnapshot) => {
querySnapshot.ref.set(user).then(() => {
//log success
})
}).catch((e) => {
console.log(e);
//log error
})
})
.catch((e) => {
//log error
return false;
});
}
The difference is that instead of using .add() method on my usersCollection, I used .doc(user.email).get().then(...) and I set data afterwards instead of using .add(...). For some reason, the Chrome console still shows usersCollection as if it is undefined if I put a breakpoint there :
usersCollection.doc(user.email).get().then((querySnapshot) => {
But the data is properly pushed to firestore nonetheless. So I'm not completely comfortable with the fact that I don't know why it works this way but not the other, but the result is exactly what I needed even though I suspect it creates some overhead.
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
Index.js
import FCM from "react-native-fcm";
class Register extends Component {
constructor(props) {
super(props);
componentDidMount () {
// this method generate fcm token.
FCM.requestPermissions();
FCM.getFCMToken().then(token => {
console.log("TOKEN (getFCMToken)", token);
});
// This method get all notification from server side.
FCM.getInitialNotification().then(notif => {
console.log("INITIAL NOTIFICATION", notif)
});
// This method give received notifications to mobile to display.
this.notificationUnsubscribe = FCM.on("notification", notif => {
console.log("a", notif);
if (notif && notif.local_notification) {
return;
}
this.sendRemote(notif);
});
// this method call when FCM token is update(FCM token update any time so will get updated token from this method)
FCM.on("refreshToken", token => {
console.log("TOKEN (refreshUnsubscribe)", token);
this.props.onChangeToken(token);
});
}
sendRemote(notif) {
console.log('send');
FCM.presentLocalNotification({
title: notif.title,
message: notif.message,
priority: "high",
click_action: notif.click_action,
show_in_foreground: true,
local: true
});
}
componentWillUnmount() {
this.refreshUnsubscribe();
this.notificationUnsubscribe();
}
This is a portion of my code for generating token and handling notification from server. What wrong i am doing? Can't figure out.Please help.
Thanks in advance. Below is the screenshot of warning error i got.
I understand that this is too late but having faced the same issue I fixed it by importing
import FCM, {FCMEvent} from "react-native-fcm";
and then using FCMEvent for subscribing the events:
this.notificationSubscribe = FCM.on(FCMEvent.Notification, notif => {
this.showNotification(notif);
});