I'm trying to set up firebase in my angularJS project to use background notification and in app notification.
What I did:
install firebase by npm install --save firebase
add manifest.json with sender id to root directory
put this scripts in <head>:
<script src="node_modules/firebase/firebase-app.js"></script>
<script src="node_modules/firebase/firebase-messaging.js"></script>
Add this script just after <body> is open:
<script>
var config = {
apiKey: "AIzaSyDAVuWKUL-aPoGasdEi-EMR7uFN1gtgk0s",
authDomain: "testproject-d71.firebaseapp.com",
databaseURL: "https://testproject-12d71.firebaseio.com",
projectId: "testproject-12d71",
storageBucket: "",
messagingSenderId: "123128116401"
};
firebase.initializeApp(config);
</script>
Add this script at the end of <body>
<script src="js/configFcm.js"></script>
which is:
const messaging = firebase.messaging();
messaging.setBackgroundMessageHandler(function(payload) {
console.log('[firebase-messaging-sw.js] Received background message ', payload);
// Customize notification here
const notificationTitle = 'Title';
const notificationOptions = {
body: 'body.',
icon: '/firebase-logo.png'
};
return self.registration.showNotification(notificationTitle,
notificationOptions);
});
That's all what I did I didn't configure in app notification yet only background ones. I got error in console:
Uncaught code:
"messaging/only-available-in-sw"
message:
"Messaging: This method is available in a service worker context (messaging/only-available-in-sw)."
stack:
"FirebaseError: Messaging: This method is available in a service worker context. (messaging/only-available-in-sw)
What is service-worker? Is it just client side? I'm executing this scripts from index.html so I'm confused.
You are currently using default firebase library. Instead, use it with the angularfire library which will take care of most of the things related to firebase.
Below is the basic tutorial to use firebase with angularfire:
Initialisation steps are fine.
Inject angularfire in your index.html.
<!-- AngularFire -->
<script src="https://cdn.firebase.com/libs/angularfire/2.3.0/angularfire.min.js"></script>.
Register firebase as a module in the application.
var app = angular.module("sampleApp", ["firebase"])
Now you are good to go.
Please follow the references below for more information on how to use angularfire with firebase.
https://github.com/firebase/angularfire/
https://code.tutsplus.com/tutorials/creating-a-web-app-from-scratch-using-angularjs-and-firebase--cms-22391
Related
I'm using React with create-react-app and I have integrated Firebase Messaging for push notifications, it requires that you create a file in the public folder firebase-messaging-sw.js that is responsible to setup the service worker with firebase messaging to enable it.
It all works properly, my problem is using the firebase configuration keys directly into code, I know they're public keys, it is still really bad practice to hardcode them plus I have more than one environment (different firebaseConfigs) so it's even more frustating to keep them hardcoded.
The firebase-messaging-sw.js looks like this:
importScripts('https://www.gstatic.com/firebasejs/8.2.0/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/8.2.0/firebase-messaging.js');
const firebaseConfig = {
apiKey: 'example',
authDomain: 'example',
databaseURL: 'example',
projectId: 'example',
storageBucket: 'example',
messagingSenderId: 'example',
appId: 'example',
};
firebase.initializeApp(firebaseConfig);
const messaging = firebase.messaging();
messaging.onBackgroundMessage(function (message) {
return self.registration.showNotification(
"Title",
"Message"
);
});
I've seen other questions like this How to use process.env in a React service worker
The solutions won't work, the cra-append-sw lib results in babel and webpack errors (those other libs are handled by CRA, so I don't mess with them)
My react-scripts version is 4.0.3
I don't have an actual answer, but I ran into the same problem and what I've been trying is to use the getToken() function. If you take a look to the docs, you can use the optional parameter ServiceWorkerRegistration to set a custom service worker.
const swRegistration = await navigator.serviceWorker.register('/src/firebase-messaging-sw.js');
const token = await fcm.getToken({
serviceWorkerRegistration: swRegistration,
});
Now the service worker can live inside the src directory, where it will be built and you can use env variables there. The thing is that if do it this way, I get a mimetype error when registering the service worker. You can see why this error ocurrs in the last answer of this forum.
Maybe you can build up from this and find a solution, good luck!
I am trying to set-up a Firebase-messaging-sw.js file (for web push notifications). I am wondering if there is a way to avoid exposing my Firebase config data to the public as much as possible - though it might be revealed anyways? (I'm not too sure about the nuances)
I've tried following: How can I customize my Service Worker based on environment variables? But the answer's swEnvbuild doesn't seem to be running, as the swenv.js file is not found. I suspect it might need to be set-up differently in React?
(first question, please feel free to provide constructive criticisms of my question)
I recently had to do this with a CRA app, it's not easy to find information on it so I figured I should share my solution. Assuming you've already changed serviceWorker.unregister() to serviceWorker.register() in ./src/index.js, and have a .env file with your variables set in the root of your project, then you can update ./src/serviceWorker.js to include your process.env variables as a query string.
In the register function in serviceWorker.js, update const swUrl as shown below, notice the const firebaseConfig w/process.env, declared before swUrl..
./src/serviceWorker.js:
// Convert environment variables to URL `search` parameters
const firebaseConfig = new URLSearchParams({
apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN,
databaseURL: process.env.REACT_APP_FIREBASE_DATABASE_URL,
projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGING_SENDER_ID,
appId: process.env.REACT_APP_FIREBASE_APP_ID,
measurementId: process.env.REACT_APP_FIREBASE_MEASUREMENT_ID
}).toString();
// Service worker URL w/config variables
const swUrl = `${process.env.PUBLIC_URL}/firebase-messaging-sw.js?${firebaseConfig}`;
then in ./public/firebase-messaging-sw.js (create it if it doesn't exist), you can do something like the following..
./public/firebase-messaging-sw.js
importScripts('https://www.gstatic.com/firebasejs/8.0.2/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/8.0.2/firebase-messaging.js');
// Set Firebase configuration, once available
self.addEventListener('fetch', () => {
const urlParams = new URLSearchParams(location.search);
self.firebaseConfig = Object.fromEntries(urlParams);
});
// "Default" Firebase configuration (prevents errors)
const defaultConfig = {
apiKey: true,
projectId: true,
messagingSenderId: true,
appId: true,
};
// Initialize Firebase app
firebase.initializeApp(self.firebaseConfig || defaultConfig);
const messaging = firebase.messaging();
// Configure message handler (assumes backend is set up)
messaging.onBackgroundMessage((payload) => {
const { icon, body, title } = payload.data;
self.registration.showNotification(title, { body, icon });
});
If there's a more ideal solution, would love to hear about it, but this configuration worked for me.
I found this article which uses cra-append-sw to append the env vars. Then I created two pre scripts in my package.json. When I run npm start the prestart script runs creating a [root folder]/public/firebase-messaging-sw.js file that contains the env vars (after being processed by webpack).
Implementation
I created a [root folder]/firebase-messaging-sw.js. This file will be processed by webpack replacing the values of the env vars.
// Give the service worker access to Firebase Messaging.
// Note that you can only use Firebase Messaging here. Other Firebase libraries
// are not available in the service worker.
importScripts('https://www.gstatic.com/firebasejs/8.1.1/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/8.1.1/firebase-messaging.js');
// Initialize the Firebase app in the service worker by passing in
// your app's Firebase config object.
// https://firebase.google.com/docs/web/setup#config-object
firebase.initializeApp({
apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN,
databaseURL: process.env.REACT_APP_FIREBASE_DATABASE_URL,
projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGING_SENDER_ID,
appId: process.env.REACT_APP_FIREBASE_APP_ID,
measurementId: process.env.REACT_APP_FIREBASE_MEASUREMENT_ID,
});
// Retrieve an instance of Firebase Messaging so that it can handle background
// messages.
const messaging = firebase.messaging();
messaging.onBackgroundMessage(function (payload) {
console.log('[firebase-messaging-sw.js] Received background message ', payload);
// Customize notification here
const notificationTitle = 'Background Message Title';
const notificationOptions = {
body: 'Background Message body.',
icon: '/logo.png'
};
self.registration.showNotification(notificationTitle, notificationOptions);
});
then I have [root folder]/.env.dev and [root folder]/.env.prod
REACT_APP_FIREBASE_API_KEY=A...
REACT_APP_FIREBASE_AUTH_DOMAIN=d...
REACT_APP_FIREBASE_DATABASE_URL=h...
REACT_APP_FIREBASE_PROJECT_ID=d...
REACT_APP_FIREBASE_STORAGE_BUCKET=d...
REACT_APP_FIREBASE_MESSAGING_SENDER_ID=7...
REACT_APP_FIREBASE_APP_ID=1...
REACT_APP_FIREBASE_MEASUREMENT_ID=G...
And finally, i added 2 pre scripts in my package.json
...
"scripts": {
"prestart": "cra-append-sw --mode dev --env ./.env.dev ./firebase-messaging-sw.js",
"prebuild": "cra-append-sw --mode build --env ./.env.prod ./firebase-messaging-sw.js",
...
I had real troubles with this one myself. The service worker gets involved in the stack way before your environment gets bootstrapped so it makes sense that it doesn't have access to your .Env variables.
My Solution
I built an npm module that on build, using webpack, extracts your "safe" versioning variables from your .env file and puts them into a stand-alone JS file. You can then go ahead and import this file and use it in your service worker.
https://www.npmjs.com/package/vue-enverywhere
Disclaimer:
I know this is for vue, but its webpack, and it's not vue specific. Also, You might be better to just copy the code, and not use the module. This was more of a fun exercise for myself :)
In index.js file (or wherever you want to register service worker) :
if ("serviceWorker" in navigator) {
console.log("Registration started");
const firebaseConfig = encodeURIComponent(
JSON.stringify({
apiKey: process.env.FCM_API_KEY,
projectId: process.env.FCM_PROJECT_ID,
messagingSenderId: process.env.FCM_SENDER_ID,
appId: process.env.FCM_APP_ID,
})
);
navigator.serviceWorker
.register(
`../../../firebase-messaging-sw.js?firebaseConfig=${firebaseConfig}`
)
.then(function (registration) {
console.log("Registration successful, scope is:", registration.scope);
})
.catch(function (err) {
console.log("Service worker registration failed, error:", err);
});
In Service Worker, firebase-messaging-sw.js :
importScripts("https://www.gstatic.com/firebasejs/8.10.0/firebase-app.js");
importScripts(
"https://www.gstatic.com/firebasejs/8.10.0/firebase-messaging.js"
);
firebase.initializeApp(
JSON.parse(new URL(location).searchParams.get("firebaseConfig"))
);
firebase.messaging();
This is enough for receiving Background Push Notifications on sending notification-type message.
this solution will work,
Just remember to edit the path to your Service-worer file (while registering in index.js or so), according to your project,
Or It will give "Mime Error".
I am setting a new firebase project. In the project I try to use firebase.auth() to create a new user with user email and password. However, when I use firebase serve and do a post request with the link in postman, i get an error which says firebase.auth is not a function.
I believe that there are questions regarding this issue, however I tried all the solutions that they have provided but none of the worked for me.
I tried:
- Adding require firebase/auth
- Deleting node modules and reinstalling firebase and firebase functions
- Import firebase and functions in different order
- Install firebase and functions in a different order
- Create a new project and install firebase and functions from scratch
const firebase = require('firebase');
const config = {
apiKey: "xxxxx,
authDomain: "xx",
databaseURL: "xxxx",
projectId: "xxxx",
storageBucket: "xxxx",
messagingSenderId: "xxx",
appId: "xxxxxx"
};
firebase.initializeApp(config);
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const app = require('express')();
admin.initializeApp();
//Signup route
app.post('/signup', (req, res) => {
const newUser = {
email: req.body.email,
password: req.body.password,
confirmPassword: req.body.confirmPassword,
handle: req.body.handle,
}
// TODO: validate data
firebase.auth().createUserWithEmailAndPassword(newUser.email, newUser.password)
.then(data => {
return res.status(201).json({ message: `user ${data.user.uid} signed up successfully`})
})
.catch(err => {
console.error(err);
return res.status(500).json({error: err.code});
});
});
Expected results: get status 201 on postman and created new user in firebase
Actual results: TypeError: firebase.auth is not a function. In the console and postman.
You should understand the difference of Firebase JavaScript SDK and Firebase Admin SDK for Node.
The Firebase JavaScript SDK is for the client side.
Firebase Admin SDK is for the server side(like the Cloud Functions).
So in your case, you should use admin.auth().createUser() .
See:
https://firebase.google.com/docs/web/setup
https://firebase.google.com/docs/admin/setup
It seems you want to instantiate the application using the client sdk instead of the server.
You need to use a private key instead, to get one go to your firebase console -> Project Overview -> Service accounts -> Generate new private key
then after you download and include the key in your project:
const admin = require('firebase-admin')
const serviceAccount = require('your_firebase_key/path/goes/here')
admin.initializeApp({
credential: admin.credential.cert(serviceAccount)
})
Good luck!
I was able to resolve this issue by installing firebase as well as firebase-tools. I had initially only installed firebase-tools. Try running npm i firebase, restart the server firebase serve and see if you're still having the issue.
I want to show push notification on angular web app when Server sends a message via FCM.
What would be the best way to approach this, is there an Angular plugin for this (which I must admit I cannot find myself).
You should check the Firebase Cloud Messaging Quickstart example. Be careful to include the file firebase-messaging-sw.js in your /dist folder during deployment.
Following Firebase Javascript Web Setup which requires you to do the following all you will have left to do is expose the obejcts and perform the initialization in your appropriate angular artifacts.
Updated 1/28/2019: Make sure you add script tags to get firebase-messaging bundle <script src="https://www.gstatic.com/firebasejs/4.9.0/firebase-messaging.js"></script>
but if you have browserify etc you can following their article and samples fully.
The raw JavaScript is as below:-
<script src="https://www.gstatic.com/firebasejs/4.9.0/firebase.js"></script>
<script>
// Initialize Firebase
// TODO: Replace with your project's customized code snippet
var config = {
apiKey: "<API_KEY>",
authDomain: "<PROJECT_ID>.firebaseapp.com",
databaseURL: "https://<DATABASE_NAME>.firebaseio.com",
storageBucket: "<BUCKET>.appspot.com",
messagingSenderId: "<SENDER_ID>",
};
firebase.initializeApp(config);
</script>
You could do this initialization in your config block - something like below. Remember firebase is a global object.
app.config(function() {
var config = {
apiKey: "<API_KEY>",
authDomain: "<PROJECT_ID>.firebaseapp.com",
databaseURL: "https://<DATABASE_NAME>.firebaseio.com",
storageBucket: "<BUCKET>.appspot.com",
messagingSenderId: "<SENDER_ID>",
};
firebase.initializeApp(config);
});
You can also create background message handler in some service or same config block according to firebase-messaging-sample Here is the gits of it:-
const messaging = firebase.messaging();
// [END initialize_firebase_in_sw]
**/
// If you would like to customize notifications that are received in the
// background (Web app is closed or not in browser focus) then you should
// implement this optional method.
// [START background_handler]
messaging.setBackgroundMessageHandler(function(payload) {
console.log('[firebase-messaging-sw.js] Received background message ', payload);
// Customize notification here
const notificationTitle = 'Background Message Title';
const notificationOptions = {
body: 'Background Message body.',
icon: '/firebase-logo.png'
};
return self.registration.showNotification(notificationTitle,
notificationOptions);
});
I start to learn how to use firebase in my app. I follow the instruction in angular website and set the snippet in the index.html like:
<!-- The codes to add firebase -->
<script src="https://www.gstatic.com/firebasejs/3.2.0/firebase.js"></script>
<!-- The core firebase client (required) -->
<script src="https://www.gstatic.com/firebasejs/3.1.0/firebase-app.js"></script>
<!-- firebase-auth - Firebase Authentication (optional) -->
<script src="https://www.gstatic.com/firebasejs/3.1.0/firebase-auth.js"></script>
<!-- firebase-database - The Firebase Realtime Database (optional) -->
<script src="https://www.gstatic.com/firebasejs/3.1.0/firebase-database.js"></script>
<script>
var config = {
apiKey: ...,
authDomain: ...,
databaseURL: "https://...",
storageBucket: "...",
};
firebase.initializeApp(config);
</script>
And then I try to use HTTP request to put data like:
submitForm(personalInfo: PersonalInfo, educationsInfo: Education[], experiencesInfo: Experience[]): Observable<string>{
let body = JSON.stringify({personalInfo, educationsInfo, experiencesInfo});
let headers = new Headers({'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers});
console.log(body);
let url = this.firebaseUrl + 'apply-form.json';
return this.http.put(url, body)
.map((response) => {
return response;
})
.catch(this.handleError);
}
However, I got the following error:
PUT https://XXX.firebaseio.com/apply-form.json 401 (Unauthorized)
I don't know what the problem is. I'm new in using firebase and really need someone to help me. Thank you!
Your Firebase Database is by default only writeable by authenticated users. See the warning in the first blue box on the page on saving data to the database.
To work around this you can of course configure the security rules of your database to allow public access. But while that is typically fine during development, it's a bad idea as you get your app ready for release to people other than yourself.
The proper way to post data securely is to require the user to sign in with Firebase Authentication and then use that information to ensure they can only access data that they're authorized to. By using HTTP to access the Firebase Database, you've made this more difficult for yourself than needed. I recommend using the Firebase JavaScript SDK for both authentication and accessing the database.