I'm trying to implement web push notifications with FireBase. It works good in desktop chrome/firefox, but when it comes to android I can't get the notification token - the promise, returned from messaging.getToken is never resolved, neither throws an error (always pending). I have a service worker, and it is active and running. Here is my code - what do I do wrong?
<script src="https://www.gstatic.com/firebasejs/5.4.2/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/5.4.2/firebase-messaging.js"></script>
<script>
var config = {
apiKey: "AIzaSyBuFGsjFDCILwYVzLHWLvoRIHSoDZIQBl8",
authDomain: "mobilepush-fd2d5.firebaseapp.com",
databaseURL: "https://mobilepush-fd2d5.firebaseio.com",
projectId: "mobilepush-fd2d5",
storageBucket: "mobilepush-fd2d5.appspot.com",
messagingSenderId: "106871298920"
};
firebase.initializeApp(config);
const messaging = firebase.messaging();
messaging.usePublicVapidKey("BBYGyuGH2KqQSHyc55Di5IQnHc52fY6gqmExfWtg85-wabmQimja6X6ViR2jmNgPBZBuLeX0BXf9A0yLqUV5m90");
var curStatus = messaging.getNotificationPermission_();
if (curStatus == 'granted') {
messaging.getToken().then(function(currentToken) {
if (currentToken) {
processToken(currentToken, 1);
} else {
reqPerm();
}
}).catch(function(err) {
//error
});
} else if (curStatus == 'denied') {
//denied
} else {
reqPerm();
}
function reqPerm() {
messaging.requestPermission().then(function() {
messaging.getToken().then(processToken);
}).catch(function(err) {
//error
});
}
function processToken(token, hasAlready) {
alert(token);
}
</script>
Found it - the phone memory was absolutely full, so Firebase script couldn't add token data to the local indexeddb of the browser. Deleted some files on device and now it works.
Related
I'm trying a basic proof of concept with firebase cloud messaging and I'm having pain receiving messages, nothing happens when I send messages even if the app is in foreground, the onMessage event doesn't return anything despite I don't have any error on sending all seem to be ok from postman or fcm console.
I noticed also that chrome://gcm-internals/ displays state "CONNECTING"
here is my app.js but for me it seems more to be related to the gcm state who should display "CONNECTED"
var firebase = require("firebase/app");
require('firebase/messaging');
// Your web app's Firebase configuration
var firebaseConfig = {
apiKey: "AIzaSyCbrs6uvQQ5s6kAp6YfvDzsds_CfMt3-hA",
authDomain: "test-flarum-fcm.firebaseapp.com",
databaseURL: "https://test-flarum-fcm.firebaseio.com",
projectId: "test-flarum-fcm",
storageBucket: "",
messagingSenderId: "977636469573",
appId: "1:977636469573:web:76e2e191f02f8923df6c2c"
};
// Initialize Firebase
var app = firebase.initializeApp(firebaseConfig);
// Retrieve Firebase Messaging object.
var messaging = firebase.messaging();
//console.log(messaging);
console.log('myToken : '+getToken());
Notification.requestPermission().then((permission) => {
if (permission === 'granted') {
console.log('Notification permission granted.');
//getMyToken();
if(isTokenSentToServer()){
console.log("token already saved")
}else{
// TODO(developer): Retrieve an Instance ID token for use with FCM.
getMyToken();
}
} else {
console.log('Unable to get permission to notify.');
setTokenSentToServer(false);
}
});
// Get Instance ID token. Initially this makes a network call, once retrieved
// subsequent calls to getToken will return from cache.
function getMyToken() {
messaging.getToken().then((currentToken) => {
if (currentToken) {
console.log(currentToken);
//sendTokenToServer(currentToken);//#todo
//updateUIForPushEnabled(currentToken);
saveToken(currentToken);
setTokenSentToServer(true);
} else {
// Show permission request.
console.log('No Instance ID token available. Request permission to generate one.');
// Show permission UI.
//updateUIForPushPermissionRequired();//#todo
//setTokenSentToServer(false); //#todo
setTokenSentToServer(false);
}
}).catch((err) => {
console.log('An error occurred while retrieving token. ', err);
//showToken('Error retrieving Instance ID token. ', err);
setTokenSentToServer(false);
});
}
// Callback fired if Instance ID token is updated.
messaging.onTokenRefresh(() => {
messaging.getToken().then((refreshedToken) => {
console.log('Token refreshed.');
// Indicate that the new Instance ID token has not yet been sent to the
// app server.
setTokenSentToServer(false);
// Send Instance ID token to app server.
//sendTokenToServer(refreshedToken);
// ...
}).catch((err) => {
console.log('Unable to retrieve refreshed token ', err);
//showToken('Unable to retrieve refreshed token ', err);
});
});
function setTokenSentToServer(sent) {
window.localStorage.setItem('sentTokenToServer', sent ? 1 : 0);
}
function isTokenSentToServer(){
return window.localStorage.getItem('sentTokenToServer') == 1;
}
function saveToken(token){
myToken = token;
window.localStorage.setItem('myToken', token);
}
function getToken(){
return window.localStorage.getItem('myToken');
}
messaging.onMessage((payload) => {
console.log('Message received. ', payload);
// ...
});
Thanks for your help
[update] I solved the problem of gcm state but that's not wworking better despite the send result seems to be ok in postman
{
"multicast_id": 7270949329343339591,
"success": 1,
"failure": 0,
"canonical_ids": 0,
"results": [
{
"message_id": "0:1569712574121124%e609af1cf9fd7ecd"
}
]
}
I'm trying to ensure that I'll be able to get an fcm device token from firebase whenever I request one via messaging.getToken(). Though I'm having an issue retrieving the token constantly on Google Chrome, it works intermittently.
When I test getting an FCM device token on page refresh on Firefox, it works every single time without fail and I receive a token in my callback function.
On the other hand with Google Chrome, its a completely different story, I only manage to receive a token intermittently. My code stops running at the point where I print in the console "Notification permission granted". No error messages from the catch block.
Upon further investigation, I found that the function messaging.getToken() does not return a token i.e. it was undefined, again, this only happens when I use Google Chrome.
I also tried doing this in a Brave browser, the behavior is similar to that of Google Chrome, except with Google Chrome, when I paste the following code into the console:
if(token){
console.log("value of token is:", token)
}
else
{
console.log("value of token is:", token);
}
});
it actually prints the token, whereas Brave doesn't.
Then of course IE and Safari don't support Firebase messaging
Code
firebase-init.js:
var firebaseConfig = {
apiKey: "api-key-here",
authDomain: "domain-here",
databaseURL: "data-base-url-here",
projectId: "project-id",
storageBucket: "storage-bucket",
messagingSenderId: "sender-id-here",
appId: "app-id-here"
};
console.log(firebase);
firebase.initializeApp(firebaseConfig);
const messaging = firebase.messaging();
// Request for permission
Notification.requestPermission()
.then((permission) => {
console.log('Notification permission granted.');
console.log(permission);
//code stops running here on google chrome
messaging.getToken()
.then((currentToken) => {
if (currentToken) {
console.log('Token: ' + currentToken);
sendTokenToServer(currentToken);
var data = { newToken: currentToken };
var url = "/Account/UpdateFirebaseToken";
$.ajax({
url: url,
type: "POST",
data: JSON.stringify(data),
dataType: "text",
processData: false,
contentType: "application/json; charset=utf-8",
success: function (data, status, jqXHR) {
console.log("successfully retrieved token:", data, status, jqXHR);
},
error: function (jqXHR, status, err) {
console.log(err);
},
complete: function (jqXHR, status) {
console.log("request complete");
}
});
} else {
//doesn't reach here
console.log('No Instance ID token available. Request permission to generate one.');
setTokenSentToServer(false);
}
})
.catch(function (err) {
//doesn't reach here either
console.log('An error occurred while retrieving token. ', err);
setTokenSentToServer(false);
});
})
.catch(function (err) {
console.log('Unable to get permission to notify.', err);
});
//});
firebase-messaging-sw.js:
importScripts('https://www.gstatic.com/firebasejs/6.2.3/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/6.2.3/firebase-messaging.js');
var config = {
apiKey: "api-key-here",
authDomain: "auth-domain-here",
messagingSenderId: "sender-id",
};
firebase.initializeApp(config);
var messaging = firebase.messaging();
messaging.setBackgroundMessageHandler(function (payload) {
var dataFromServer = JSON.parse(payload.data.notification);
var notificationTitle = dataFromServer.title;
var notificationOptions = {
body: dataFromServer.body,
icon: dataFromServer.icon,
data: {
url: dataFromServer.url
}
};
return self.registration.showNotification(notificationTitle, notificationOptions);
});
self.addEventListener("notificationclick", function (event) {
var urlToRedirect = event.notification.data.url;
event.notification.close();
event.waitUntil(self.clients.openWindow(urlToRedirect));
});
Removing the following script tag:
<script src="https://cdn.jsdelivr.net/npm/promise-polyfill"></script>
from my _Layout.cshtml resolved the issue.
I'm not sure how that script is interfering with the promises, but I'd really appreciate it if someone could explain it to me.
It seems to be related with IndexedDB (that's where it hangs when debugging
the firebase code).
I had the exact same issue you did although I was injecting promise-polyfill through a webpack build. Your post allowed me to fix something that was making me mad for several weeks.
I resolved my particular issue by only applying the polyfill if window.Promise was not present so that my code (and the firebase SDK) would use the native Promise.
So I'm using VueJS with the PWA option enabled. When using Firebase Cloud Messaging (for web app), I'm getting a notification saying: This site has been updated in the background but Only when the tab is not focused or open. If the tab is active, I don't receive anything in the console.
I'm using Postman to send notifications for now, and it returns success
{
"multicast_id": 5364665067527599460,
"success": 1,
"failure": 0,
"canonical_ids": 0,
"results": [
{
"message_id": "0:1550148053476716%2fd9afcdf9fd7ecd"
}
]
}
Here is my main.js
const config = {
apiKey: "API_KEY",
authDomain: "AUTH_DOMAIN",
databaseURL: "DATABASE_URL",
projectId: "PROJECT_ID",
storageBucket: "STORAGE_BUCKET",
messagingSenderId: "SENDER_ID"
};
firebase.initializeApp(config);
const messaging = firebase.messaging();
messaging.usePublicVapidKey("PUBLIC_VAPID_KEY");
navigator.serviceWorker.register('./firebase-messaging-sw.js')
.then((registration) => {
console.log("Now using registration: " + registration);
messaging.useServiceWorker(registration);
}).catch(err => {
console.log("Error in registration");
console.log(err)
});
My firebase-messaging-sw.js (I never saw the console log thats inside setBackgroundMessageHandler)
importScripts('https://www.gstatic.com/firebasejs/5.8.2/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/5.8.2/firebase-messaging.js');
var config = {
messagingSenderId: 'SENDER_ID'
};
firebase.initializeApp(config);
let messaging = firebase.messaging();
messaging.setBackgroundMessageHandler(function(payload) {
console.log('[firebase-messaging-sw.js] Received background message ', payload);
return self.registration.showNotification('title', {body: 'message'});
});
And in my App.vue (neither have I ever seen the console log in onMessage)
created() {
this.$messaging.onMessage(function(payload) {
console.log('Message received: ', payload);
// ...
});
},
methods: {
sendNotif() {
this.$messaging.requestPermission().then(() => this.$messaging.getToken())
.then((token) => {
console.log(token) // Receiver Token to use in the notification
})
.catch(function(err) {
console.log("Unable to get permission to notify.", err);
});
},
},
I can access the token, none of my configuration is wrong or else the postman request wouldn't give success. I've checked out several other questions related to this but no success so far...
I'm using firestore with react native like below, but while running my app data is not added to the cloud. am not sure why, please help me to understand the actual problem here.
componentWillMount() {
console.log('Test1');
firebase.initializeApp({
apiKey: 'xxxxxxx',
authDomain: 'testing-8ex763xxxxxxxxxxxxxx',
databaseURL: 'https://testing-8e76xxxo.com',
projectId: 'testing-xxxxx',
storageBucket: 'testing-8xxxxx.com',
messagingSenderId: '73664xxx042'
});
firebase.firestore().enablePersistence()
.then(function() {
// Initialize Cloud Firestore through firebase
var db = firebase.firestore();
console.log('Test3', db);
db.collection('us').add({
first: 'hai',
last: '111',
born: 1815
})
.then(function(docRef) {
console.log("Document written with ID: ", docRef.id);
})
.catch(function(error) {
console.error("Error adding document: ", error);
});
})
.catch(function(err) {
if (err.code == 'failed-precondition') {
// Multiple tabs open, persistence can only be enabled
// in one tab at a a time.
// ...
} else if (err.code == 'unimplemented') {
// The current browser does not support all of the
// features required to enable persistence
// ...
}
});
}
You have not given the reference of doc.
And also use 'set' instead of add method.
db.collection('us').doc('some_name').set({
first: 'hai',
last: '111',
born: 1815
})
I have setup Firebase to my Cordova App to authenticate with Facebook which works fine in Android due a workaround I have found. However, in my browser I can't make it work.
Problem: Once I call signInWithRedirect(provider) method its redirect to firebase and logs in correctly (checked on firebase's dashboard), then It redirects to my localhost:8000 but it never stops in getRedirectResult() method.
No console log errors displayed.
My app set up:
index.html
<script src="https://www.gstatic.com/firebasejs/4.3.0/firebase.js"></script>
<script src="https://www.gstatic.com/firebasejs/4.1.1/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/4.1.1/firebase-auth.js"></script>
app.js
var config = {
apiKey: "*********",
authDomain: "*********",
databaseURL: "*********",
projectId: "*********",
storageBucket: "*********",
messagingSenderId: "*********"
};
firebase.initializeApp(config);
login_controller.js
var provider = new firebase.auth.FacebookAuthProvider();
firebase.auth().signInWithRedirect(provider).then(function() {
firebase.auth().getRedirectResult().then(function(result) {
// This gives you a Google Access Token.
// You can use it to access the Google API.
var token = result.credential.accessToken;
// The signed-in user info.
var user = result.user;
console.log('result '+ result);
debugger;
}).catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
debugger;
});
}).catch(function(error){
debugger;
});
Firebase configuration
localhost domain added
web env setup
Facebook auth setup
What did I miss?
I set it up like this (it is intertwined with a plugin I wrote):
This method gets called when it is identified that a user is not logged in:
toggleWebViewWithAuth: function () {
var win = function(d) {
console.log("web view toggled, going to auth");
auth.presentLogin().then(function() {
auth.getResult();
});
};
var fail = function(e) {
console.log(e)
}
cordova.exec(win, fail, "NavigationPlugin", "toggleWebView", []);
}
auth.presentLogin is an async function I made that looks like this:
presentLogin: async function () {
var provider = new firebase.auth.FacebookAuthProvider();
//provider.addScope('default');
provider.addScope('email');
//provider.addScope('pages_show_list');
return firebase.auth().signInWithRedirect(provider);
},
Also in the auth variable is:
getResult: function () {
firebase.auth().getRedirectResult().then(function(result) {
if (result.credential) {
// This gives you a Facebook Access Token. You can use it to access the Facebook API.
var token = result.credential.accessToken;
// ...
}
// The signed-in user info.
app.user = result.user;
console.log("result.user in presentLogin:", app.user);
}).then(function() {
//iosNav.getCurrentTabControllerName();
iosNav.toggleWebView();
}).catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
alert("Error:", error);
// The email of the user's account used.
var email = error.email;
// The firebase.auth.AuthCredential type that was used.
var credential = error.credential;
// ...
});
}
So now go back and read the toggleWebViewWithAuth method that I posted, and you will see how I used it. This makes it so that getRedirectWithResult waits for signInWithRedirect. All of this can be configured outside of a plugin (without using cordova.exec, all that method does on the iOS side is open or close the UIWebView) - The most important part is that you just need to make sure to use my presentLogin method how I did to present it, calling getResult in the then block.
Also, for your js imports, firebase-app, and all of the firebase module js files, replaced using the global firebase.js import. You only need:
<script>.../firebase-app.js</script>
<script>.../firebase-auth.js</script>