I've been working on integrating FCM in my Vue PWA app. So far I've managed to get the background notification working, but handling notifications when the app's on the foreground doesn't work. Here's my code.
src/App.vue
import firebase from './plugins/firebase'
export default {
// Other stuff here...
methods: {
prepareFcm () {
var messaging = firebase.messaging()
messaging.usePublicVapidKey(this.$store.state.fcm.vapidKey)
messaging.getToken().then(async fcmToken => {
this.$store.commit('fcm/setToken', fcmToken)
messaging.onMessage(payload => {
window.alert(payload)
})
}).catch(e => {
this.$store.commit('toast/setError', 'An error occured to push notification.')
})
}
},
mounted () {
this.prepareFcm()
}
}
public/firebase-messaging-sw.js
importScripts('https://www.gstatic.com/firebasejs/5.5.6/firebase-app.js')
importScripts('https://www.gstatic.com/firebasejs/5.5.6/firebase-messaging.js')
firebase.initializeApp({
messagingSenderId: '123456789'
})
const messaging = firebase.messaging()
messaging.setBackgroundMessageHandler(function (payload) {
return self.registration.showNotification(payload)
})
src/plugins/firebase.js
import firebase from '#firebase/app'
import '#firebase/messaging'
// import other firebase stuff...
const firebaseConfig = {
apiKey: '...',
authDomain: '...',
databaseURL: '...',
projectId: '...',
storageBucket: '...',
messagingSenderId: '123456789',
appId: '...'
}
firebase.initializeApp(firebaseConfig)
export default firebase
What did I do wrong?
I've found a solution in another QA here in StackOverflow (which I can't find anymore for some reason).
Turns out you have to use Firebase API v7.8.0 instead of 5.5.6 like the docs said at the time. So those first two lines in public/firebase-messaging-sw.js should read like this instead:
importScripts('https://www.gstatic.com/firebasejs/7.8.0/firebase-app.js')
importScripts('https://www.gstatic.com/firebasejs/7.8.0/firebase-messaging.js')
Same issue i was faced. In my case firebase version in "package.json" and "firebase-messaging-sw.js" importScripts version was different. After set same version in "firebase-messaging-sw.js" importScripts which was in
"package.json", my issue is resolved.
Before change
**"package.json"**
"firebase": "^8.2.1",
**"firebase-messaging-sw.js"**
importScripts('https://www.gstatic.com/firebasejs/7.8.0/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/7.8.0/firebase-messaging.js');
After change
**"package.json"**
"firebase": "^8.2.1",
**"firebase-messaging-sw.js"**
importScripts('https://www.gstatic.com/firebasejs/8.2.1/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/8.2.1/firebase-messaging.js');
In my case the version on package.json (8.2.1) was different from the actual SDK_VERSION (8.0.1)
After changed service-workers with the same version worked..
I had a bunch of issues setting firebase push notifications for Vue 3 (with Vite), and I had PWA support enabled with vite-plugin-pwa, so it felt like I was flying blind half the time. I was finally able to set up support for PWA, but then I ran into the following issues:
I was getting notifications in the background (when my app was not in focus), but not in the foreground.
When I did get notifications in the background, it appeared twice.
Here's my complete setup. I have the latest firebase as of this post (9.12.1)
// firebase-messaging-sw.js file in the public folder
importScripts(
"https://www.gstatic.com/firebasejs/9.12.1/firebase-app-compat.js"
);
importScripts(
"https://www.gstatic.com/firebasejs/9.12.1/firebase-messaging-compat.js"
);
// Initialize Firebase
firebase.initializeApp({
apiKey: "",
authDomain: "",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: "",
measurementId: "",
});
const messaging = firebase.messaging();
messaging.onBackgroundMessage(function (payload) {
// Customize notification here
const notificationTitle = payload.notification.title;
const notificationOptions = {
body: payload.notification.body,
icon: "/icon.png",
};
self.registration.showNotification(notificationTitle, notificationOptions);
});
I've seen some posts online provide the onBackgroundMessage here in the service worker, but I experimented with commenting it out and it seemed to fix the issue of notifications appearing twice.
Next, is a firebase.js file with which I retrieve tokens and subsequently listen for foreground notifications.
// firebase.js in same location with main.js
import firebase from "firebase/compat/app";
import { getMessaging } from "firebase/messaging";
const firebaseConfig = {
apiKey: "",
authDomain: "",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: "",
measurementId: "",
};
const app = firebase.initializeApp(firebaseConfig);
export default getMessaging(app);
And then in main.js
import App from "./App.vue";
import firebaseMessaging from "./firebase";
const app = createApp(App)
app.config.globalProperties.$messaging = firebaseMessaging; //register as a global property
And finally, in App.vue (or wherever you wish to get tokens and send to your serverside)...
import {getToken, onMessage} from "firebase/messaging";
export default {
mounted() {
getToken(this.$messaging, {
vapidKey:
"XXX-XXX",
})
.then((currentToken) => {
if (currentToken) {
console.log("client token", currentToken);
onMessage(this.$messaging, (payload) => {
console.log("Message received. ", payload);
});
//send token to server-side
} else {
console.log(
"No registration token available. Request permission to generate one"
);
}
})
.catch((err) => {
console.log("An error occurred while retrieving token.", err);
});
}
}
Of course don't forget the vapidKey. Took a minute, but it worked perfectly.
For now, I am not offering any opinion as to what the foreground notification should look like, so I am merely logging the payload. But feel free to show it however you deem fit.
Related
I try to migrate my chrome-extension from manifest version 2 to v3, and was wondering if it is possible to use FCM in chrome extension Manifest version 3.
As I could not find helpful documentation/guides on this topic, I hope this thread will also be helpful to others.
In manifest version 2 I use the following code:
firebase-messaging-sw.js:
import { initializeApp } from "firebase/app";
import { getMessaging, onBackgroundMessage } from "firebase/messaging/sw";
const firebaseConfig = {
apiKey: "<api-key>",
authDomain: "<auth-domain>",
projectId: "<project-id>",
storageBucket: "<storage-bucket>",
messagingSenderId: "<messaging-sender-id>",
appId: "<app-id>",
};
// Initialize Firebase
initializeApp(firebaseConfig);
const messaging = getMessaging();
onBackgroundMessage(messaging, async (payload) => {
console.log('[firebase-messaging-sw.js] Received background message ', payload);
const allClients = await self.clients.matchAll({ includeUncontrolled: true, type: 'all' })
allClients.forEach((client: any) => {
client.postMessage({ type: 'msg_type', payload });
});
});
In the background.js (now my SW):
if ('serviceWorker' in navigator) {
const firebaseConfig = {
apiKey: "<api-key>",
authDomain: "<auth-domain>",
projectId: "<project-id>",
storageBucket: "<storage-bucket>",
messagingSenderId: "<messaging-sender-id>",
appId: "<app-id>",
};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
// Initialize Firebase Cloud Messaging and get a reference to the service
const messaging = getMessaging(app);
getToken(messaging, { vapidKey: "<vapid-key>" })
.then((registrationToken: string) => {
onMessage(messaging, async (payload) => {
//doSomething
});
});
navigator.serviceWorker.addEventListener('message', async (message: MessageEvent) => {
if (message.data.type === 'msg_type') {
//doSomething
}
});
}
I try to follow this guide, and other related threads/videos,
But there is no guide for firebase-messaging-sw.js or other alternatives that I have found.
Hope you can help with this.
I have the problem that as soon as I want to make a call to my firebase functions I get a Cors policy Error. I have already read multiple questions about that but I couldn't find one that solves the issue in the Firebase version 9. The call syntax is different in v9. And I can't figure out how to solve it.
Error:
Access to fetch at 'https://us-central1-mmonitor-19efd.cloudfunctions.net/sendRequest' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
Firebase Initialization:
import { initializeApp } from 'firebase/app';
import { getFunctions } from 'firebase/functions';
const firebaseConfig = {
apiKey: "XXXX",
authDomain: "XXXX",
projectId: "XXXX",
storageBucket: "XXXX",
messagingSenderId: "XXXX",
appId: "XXXX",
measurementId: "XXXX"
};
export const firebaseApp = initializeApp(firebaseConfig);
export const functions = getFunctions()
Function Call:
import { firebaseApp, functions } from "./firebase"
import { httpsCallable } from 'firebase/functions';
function sendRequest(e) {
const sendRequest = httpsCallable(functions, 'sendRequest');
sendRequest()
}
function App() {
return (
<button onClick={sendRequest}>send Request</button>
);
}
export default App;
Firebase Functions:
const functions = require("firebase-functions");
exports.sendRequest = functions.https.onCall(async(data, context) => {
console.log("ok")
});
Note: (I am using the emulator at the moment)
Note: (I tried to change the location of the server but I am not sure how to do that in the emulator and in the frontend in v9)
Thank you for your time!
Try this
import { connectFunctionsEmulator } from "firebase/functions";
connectFunctionsEmulator(functions, "localhost", 5001);
I couldn't find a better way than just downgrading to firebase#8.10.0 and using the following code:
Firebase init:
import firebase from "firebase/app";
import "firebase/functions"
const firebaseConfig = {
apiKey: "XXXX",
authDomain: "XXXX",
projectId: "XXXX",
storageBucket: "XXXX",
messagingSenderId: "XXXX",
appId: "XXXX",
measurementId: "XXXX"
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
firebase.functions().useEmulator("localhost", 5001);
export default firebase
Funcion Call:
import firebase from "./firebase.js";
function sendRequest(e) {
const sendRequest = firebase.functions().httpsCallable('sendRequest');
sendRequest()
}
Im trying to upload an image to Firebase storage. When i try to upload the image, i get the error as 404, but i have created the storage in firebase.
Firebase npm version : firebase": "^7.24.0
Error:
code: 404
message: "Not Found. Could not access bucket \"<project>.appspot.com\""
status: "ACCESS_BUCKET"
Storage Rules:
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if true;
}
}
}
Firebase Initialization:
const app = firebase.initializeApp({
apiKey: process.env.REACT_APP_FIREBASE_KEY,
authDomain: process.env.REACT_APP_FIREBASE_DOMAIN,
projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.REACT_APP_FIREBASE_SENDER_ID,
appId: process.env.REACT_APP_FIREBASE_APP_ID,
measurementId: process.env.REACT_APP_FIREBASE_MEASUREMENT_ID
});
export const analytics = app.analytics();
export const storage = firebase.storage();
export default app;
Service JS :
export async function uploadImageCloud(image){
const storageRef = storage.ref("image/" + image.name);
return storageRef.put(image);
}
Upload function:
function uploadImage(){
setDataImageUploading(true);
uploadImageCloud(getDataImage).then((data)=>{
console.log(data);
setDataImageUploading(false);
}).catch((e)=>{
console.log(e);
setDataImageUploading(false);
});
}
Any idea where did i messed up?
I had the same issue and finally I found out that the value of the storageBucket passed to initializeApp is very sensitive data. It should be exactly the bucket name on the top files(without gs://):
in this project for example it is steem-engine-dex.appspot.com.
const app = firebase.initializeApp({
//...
storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
//...
});
Important:
storageBucket is case sensitive. e.g. steem-engine-dex.appSpot.com is invalid
storageBucket shouldn't include any extra space in beginning or end. e.g. steem-engine-dex.appspot.com and steem-engine-dex.appspot.com are invalid
I am doing a small project with Google authentication. Now, this is my first time doing this, so I might be doing something wrong which I am not seeing. I did the following steps:
-I went on firebase and linked my account
-I enabled google to be able to use it for authentication
-I pasted the project data in my file, as I will show in a bit
-and I put the code for the autentication
<script src="https://www.gstatic.com/firebasejs/7.6.2/firebase-app.js"></script>
<script>
// Your web app's Firebase configuration
var firebaseConfig = {
apiKey: "AIzaSyArVSWB1OYZYQJEkmc6uIi9jyfmRIW1oSk",
authDomain: "assignment-da42d.firebaseapp.com",
databaseURL: "https://assignment-da42d.firebaseio.com",
projectId: "assignment-da42d",
storageBucket: "assignment-da42d.appspot.com",
messagingSenderId: "569189156463",
appId: "",
measurementId: "G-N6D1788RXF"
};
firebase.initializeApp(firebaseConfig);
function googleSignIn(){
var provider = new firebase.auth.GoogleAuthProvider();
firebase.auth().signInWithRedirect(provider)
}
</script>
<button onclick="googleSignIn()">Google Sign in</button>
However, even after following multiple tutorials, using the same methods, I kept getting the error:
Uncaught TypeError: Cannot read property 'GoogleAuthProvider' of undefined
What am I doing wrong please?
I had the same issues late week and I've since solved it.
Can you point out where you include the following or some other version of the auth library?
<script src="/__/firebase/[version number]/firebase-auth.js"></script>
If that's missing you can paste it in before your code.
I installed the whole package - $ npm install --save firebase
and my config file looks like
import firebase from "firebase/app";
import "firebase/storage";
import "firebase/firestore";
import "firebase/auth";
const firebaseConfig = {
apiKey: "......",
authDomain: ".....",
databaseURL: ".....",
projectId: ".....",
storageBucket: ".....",
messagingSenderId: "......",
appId: "......",
measurementId: "...."
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
export const projectStorage = firebase.storage();
export const projectFirestore = firebase.firestore();
export const timestamp = firebase.firestore.FieldValue.serverTimestamp;
export const auth = firebase.auth();
export const provider = new firebase.auth.GoogleAuthProvider();
export const signInWithGoogle = () =>{
auth.signInWithRedirect(provider).then(function(){
});
};
and I can call
const logIn = () => {
let ret = signInWithGoogle();
console.log(ret);
getCredentials();
}
in the navbar.
I'm trying to add authentication using Firebase in my Vue app, but I'm getting [Vue warn]: Error in v-on handler: "TypeError: _config_firebase__WEBPACK_IMPORTED_MODULE_8__.user.SignInWithEmailAndPassword is not a function" error.
Here is my irebase config file:
import firebase from "firebase/app";
import "firebase/firestore";
import "firebase/auth";
const firebaseConfig = {
apiKey: "MY_API_KEY",
authDomain: "MY_AUTH_DOMAIN",
databaseURL: "MY_DB_URL",
projectId: "MY_PROJECT_ID",
storageBucket: "MY_STORAGE_BUCKET",
messagingSenderId: "MY_MESSAGE_SENDER_ID",
appId: "MY_APP_ID"
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
// Get a Firestore instance
export const user = firebase.auth();
export const db = firebase.firestore();
Then the action in Vuex:
import { db, user } from "./config/firebase";
loginUser({ commit }, payload) {
user
.SignInWithEmailAndPassword(payload)
.then(user => {
console.log(user);
commit("SET_USER", user);
})
.catch(error => {
commit("setLoading", false);
commit("setError", error);
console.log(error);
});
router.push("/");
}
So far, I have been able to Create, Read, Update and Delete, although, the config file was slightly different than this, when I added auth was when I altered the code.
Change this:
user.SignInWithEmailAndPassword(payload)
into this:
user.signInWithEmailAndPassword(payload)
From the docs:
Asynchronously signs in using an email and password.