Giter Club home page Giter Club logo

push-fcm-plugin's Introduction

Push.js FCM Plugin

What is FCM?

FCM, otherwise known as Firebase Cloud Messaging, is a free feature of the Google Firebase Platform, a collection of services for building scalable, effective web services. FCM allows web servers to send direct messages to a group of subscribers using ServiceWorkers. This means that by using this plugin, Push.js can now send targeted push notifications to a user's desktop without your website being open! Finally! ๐ŸŽ‰๐ŸŽ‰๐ŸŽ‰

Though, keep in mind this is the first plugin for Push.js, ever. Expect a few bumps and potholes.

Installing

Just like Push itself, this module is easily installable via NPM or Bower:

$ npm install push-fcm-plugin --save
$ bower install push-fcm-plugin --save 

How to Use

Configuring

With Push.js, managing FCM on your site becomes incredibly easy. To begin, you need to configure FCM Push's SafeConfig: Head on over to your Firebase console and add a new project. Once the project is created, click on it and then click "Add Firebase to your web app". Select the configuration map from the generated code in the popup window and add it to your JavaScript file. Then, add the map to Push's FCM configuration using the config() method. Your finally code should look something like this:

var config = {
    apiKey: "<YOUR_API_KEY>",
    authDomain: "<YOUR_AUTH_DOMAIN>",
    databaseURL: "<YOUR_DATABASE_URL>",
    projectId: "<YOUR_PROJECT_ID>",
    storageBucket: "<YOUR_STORAGE_BUCKET>",
    messagingSenderId: "<YOUR_MESSAGE_SENDER_ID>"
};

Push.config({
    FCM: config
});

Lastly, add a manifest.json file to the root of your web server with the following contents:

{
    "//": "Some browsers will use this to enable push notifications.",
    "//": "It is the same for all projects, this is not your project's sender ID",
    "gcm_sender_id": "103953800507"
}

then import it into your HTML:

<link rel="manifest" href="/manifest.json">

This sender ID is required in order to tell Firebase your website allows messages to be pushed to it. Do not change the above ID. It is the same for all Firebase projects, regardless of who you are or what you've built.

Using with AMD or CommonJS

If you use AMD or CommonJS to load Push, you'll have to manually install the plugin.

For AMD:

define(['push', 'pushjs-fcm'], function (Push, PushFCM) {
    Push.extend(PushFCM);
});

For CommonJS:

const Push = require('pushjs');
const PushFCM = require('pushjs-fcm');

Push.extend(PushFCM);

Initializing

To initialize FCM, just call:

Push.FCM();

And that's it! You can then use the returned promise to run additional functions:

Push.FCM().then(function(FCM) {
    FCM.getToken().then(function(token) {
        console.log("Initialized with token " + token);
    }).catch(function(tokenError) {
       throw tokenError; 
    });
}).catch(function(initError) {
   throw initError; 
});

The available functions are as follows:

Function Description Returns
getToken() generates a new Instance ID token or retrieves the current one if it already exists Promise(token, error)
deleteToken() deletes the current token Promise(deletedToken, error)
isTokenSentToServer() denotes whether the current token has been sent to the server via sendTokenToServer() (see "Additional Options") Boolean

Additional Options

The FCM SafeConfig has a few additional options you can pass to it:

  • serviceWorkerLocation: Specifies directory containing the firebase-messaging-sw ServiceWorker script. May need to change if Push has been installed via NPM or Bower. The default is ./.
  • onTokenFetched(token): Called when a new Instance ID token is retrieved
  • onTokenFetchedError(error): Called if an error occurs while retrieving a new Instance ID token
  • onPermissionRequired() Called when permission is required to retrieve an Instance ID
  • onPermissionGranted(): Called when said permission is granted
  • onPermissionDenied(): Called when said permission is denied
  • onMessage(payload): Called when a new message is received
  • sendTokenToServer(token): Function that sends the given token to your server for future use
  • onTokenDeleted(deletedToken): Called when the current token is deleted
  • onTokenDeletedError(error): Called if an error occurs while deleting the current token

Sending Server-side Notifications

To send a notification to a given Instance ID from your server, simply make a POST request to https://fcm.googleapis.com/fcm/send with the following data:

Header

Authorization: key=<YOUR_SERVER_KEY>
Content-Type: application/json

Body

{ 
  "notification": {
    "title": "Notification Title",
    "body": "Notification Body",
    "click_action" : "http://example.com"
  },
  "to" : "<INSTANCE_ID_TOKEN>"
}

You can find your server key by going to your project console on Firebase, clicking the gear icon on the right sidebar, selecting "Project Settings" and going to the "Cloud Messaging" tab. For more information on messaging types, read Google's documentation on the topic.

Writing Your Own Plugin

Documentation on writing plugins will be coming the official Push.js docs soon!

push-fcm-plugin's People

Contributors

nickersoft avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

push-fcm-plugin's Issues

Sample

Could you provide a full functional sample (with index.html, etc.) ?

Push.FCM() returns a pending Promise

First Thanks for all of your effort on this. We have push.js working and are working to get this working with the browser closed through push messaging. Currently when we call

Push.FCM() the promise never returns. It shows the PromiseStatus as "pending". Would be interested if you have any thoughts.

Thanks

Bad example

{ "notification": { "title": "Notification Title", "body": "Notification Body", "click_action" : "http://example.com" }, "to" : "<INSTANCE_ID_TOKEN>" }
This will never trigger on "push" event in the service worker if your app is in background.
See this:
firebase/quickstart-js#71

import not working

First thank you for the brilliant push library. It works really well but I am having an issue with this plugin.

I have tried
const Push = require('pushjs');
const PushFCM = require('pushjs-fcm');

as per the docs but it doesn't work.

I have changed the push import to
const Push = require('push.js');
and this works fine but I can't get the plugin to work

For the plugin I have tried
const PushFCM = require('pushjs-fcm');
which cannot find it
const PushFCM = require('push-fcm-plugin');
which gives me e(...) is not a function error
const PushFCM = require('push-fcm-plugin/bin/push.fcm');
factory(...) is not a function

I have installed both modules through npm.

Please let me know if this is a bug or if I am doing something wrong.

Thanks

on token refreshed

Token was renewed.. it called sendTokenToServer() with old token.... and then it called onTokenFetched() with the new token...
No idea why...

Closing notifications on mobile

Editing the .sw file to listen for clicks to close them does not work. Is there a way to make the notification redirect/close on click with this plugin?
This is what my sw looks like now;

importScripts('https://www.gstatic.com/firebasejs/4.1.2/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/4.1.2/firebase-messaging.js');

if (firebase.apps.length > 0)
    firebase.messaging();

self.addEventListener('message', function (event) {
    if (firebase.apps.length === 0) {
        firebase.initializeApp(event.data);
        firebase.messaging();
    }
    event.ports[0].postMessage(event.data);
});
self.addEventListener('notificationclick', function (event) {
    console.log('Clicked');
    const clickedNotification = event.notification;
    clickedNotification.close();
});

Safari Browser

How to use push.js and push-fm-plugin to work on Safari browser?

Event handler must be added on the initial evaluation of worker script

Hi, I installed the plugin with the help of npm, and I try to use it, however I get the following errors:

Event handler of 'push' event must be added on the initial evaluation of worker script
Event handler of 'pushsubscriptionchange' event must be added on the initial evaluation of worker script.
Event handler of 'notificationclick' event must be added on the initial evaluation of worker script.

package.json

{
  "name": "push-for-new-tickets",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "dependencies": {
    "push-fcm-plugin": "0.0.2",
    "push.js": "^1.0.5",
    "store": "^2.0.12"
  },
  "devDependencies": {
    "babel-core": "^6.26.3",
    "babel-loader": "^7.1.5",
    "babel-preset-env": "^1.7.0",
    "babel-preset-stage-0": "^6.24.1",
    "copy-webpack-plugin": "^4.5.2",
    "path": "^0.12.7",
    "webpack": "^4.15.1",
    "webpack-cli": "^3.0.8"
  },
  "scripts": {
    "build": "webpack --mode=production",
    "dev-watch": "webpack --mode=development  --watch  --progress --display-modules",
    "dev": "webpack --mode=development"
  },
  "author": "",
  "license": "ISC"
}

webpack.config.js:

const CopyWebpackPlugin = require('copy-webpack-plugin');
const webpack = require('webpack');
const path = require('path');

module.exports = {
    output: {
        filename: 'main.js',
        path: path.resolve(__dirname, 'js')
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /(node_modules|bower_components)/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['env']
                    }
                }
            }
        ]
    },
    plugins: [
        new CopyWebpackPlugin([
            {
                from: 'node_modules/push.js/bin/serviceWorker.min.js', to: 'serviceWorker.min.js',
            },
            {
                from: 'node_modules/push-fcm-plugin/bin/firebase-messaging-sw.min.js', to: 'firebase-messaging-sw.min.js',
            }
        ])
    ]

};

code:

let Push = require('push.js');
let PushFCM = require('push-fcm-plugin');
Push.extend(PushFCM);

Push.config({
    FCM: {
        apiKey: "hide",
        authDomain: "hide",
        databaseURL: "hide",
        projectId: "hide",
        storageBucket: "hide",
        messagingSenderId: "hide",
        serviceWorkerLocation: "/",
    },
    serviceWorker: '/serviceWorker.js',
    fallback: function (payload) {
        console.log(payload);
        alert('error');
    }
});

Push.FCM().then(function (FCM) {
    FCM.getToken().then(function (token) {
        console.log("Initialized with token " + token);
    }).catch(function (tokenError) {
        throw tokenError;
    });
}).catch(function (initError) {
    throw initError;
});

serviceWorker:

/* eslint eqeqeq: "off", curly: "error" */
'use strict';

function isFunction(obj) {
  return obj && {}.toString.call(obj) === '[object Function]';
}

function runFunctionString(funcStr) {
  if (funcStr.trim().length > 0) {
    var func = new Function(funcStr);
    if (isFunction(func)) {
      func();
    }
  }
}

self.addEventListener('message', function (event) {
  self.client = event.source;
});

self.onnotificationclose = function (event) {
  runFunctionString(event.notification.data.onClose);

  /* Tell Push to execute close callback */
  self.client.postMessage(JSON.stringify({
    id: event.notification.data.id,
    action: 'close'
  }));
}

self.onnotificationclick = function (event) {
  var link, origin, href;

  if (typeof event.notification.data.link !== 'undefined' && event.notification.data.link !== null) {
    origin = event.notification.data.origin;
    link = event.notification.data.link;
    href = origin.substring(0, origin.indexOf('/', 8)) + '/';

    /* Removes prepending slash, as we don't need it */
    if (link[0] === '/') {
        link = (link.length > 1) ? link.substring(1, link.length) : '';
    }

    event.notification.close();

    /* This looks to see if the current is already open and focuses if it is */
    event.waitUntil(clients.matchAll({
      type: "window"
    }).then(function (clientList) {
      var client, full_url;

      for (var i = 0; i < clientList.length; i++) {
        client = clientList[i];
        full_url = href + link;

        /* Covers case where full_url might be http://example.com/john and the client URL is http://example.com/john/ */
        if (full_url[full_url.length - 1] !== '/' && client.url[client.url.length - 1] === '/') {
          full_url += '/';
        }

        if (client.url === full_url && 'focus' in client){
          return client.focus();
        }
      }

      if (clients.openWindow) {
        return clients.openWindow('/' + link);
      }
    }).catch(function (error) {
      throw new Error("A ServiceWorker error occurred: " + error.message);
    }));
  }

  runFunctionString(event.notification.data.onClick);
}

Any ideas what to do?

Register a second SW on the same scope

I already have a service worker on my application, registered on the default scope "./"
It doesn't work with firebase-messaging-sw.js certainly because it is registered on the same scope.
Do you have a solution to register both service workers ?

How to tell if user has received a notification?

Hello. Thanks for this package.

I wonder if it is possible to know if user(s) have received notifications. I know that this can be achieved in an onMessage event by sending request to server. However, this does not work if user's tab/window is closed. Is there a way around?

Thanks.

onMessage is not called many times

Here is my service worker:

importScripts('https://www.gstatic.com/firebasejs/4.5.0/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/4.5.0/firebase-messaging.js');

if (firebase.apps.length > 0)
    firebase.messaging();

self.addEventListener('message', function (event) {
    if (firebase.apps.length === 0) {
        firebase.initializeApp(event.data);
        firebase.messaging();
    }
    //this is when the sw is first installed
    console.dir(event);
    event.ports[0].postMessage(event.data);
});
self.addEventListener('notificationclick', function(event) {
    console.dir(event);
    event.notification.close();
    // Do something as the result of the notification click
});
self.addEventListener('push', function(event) {
    console.dir(event);
});

And here is the code for Push:

Push.config({
                    FCM: {
                        apiKey: "NOT SHOWN HERE",
                        authDomain: ".firebaseapp.com",
                        databaseURL: "NOT SHOWN HERE",
                        projectId: "NOT SHOWN HERE",
                        storageBucket: "",
                        messagingSenderId: "NOT SHOWN HERE",
                        serviceWorkerLocation:"NOT SHOWN HERE",
                        onMessage: function(payload){
                            console.dir(payload);
                            pushNoti.onMessage(payload);
                        }
                    },
                    fallback: function(payload) {
                        Dialog.alert(payload.notification.title,payload.notification.body);
                    }
                });
pushNoti.onMessage = function(){
var options = {
                    body: message,
                    icon: ONLY_DOMAIN + 'assets/images/logo.png',
                    timeout: 0,//don't auto close
                    tag:Math.random(),//this is needed to create a unique notification
                    onClick: function () {
                        window.focus();
                        this.close();
                    }
                };
                if(typeof close !=='undefined' && (close)){
                    options['requireInteraction'] = true;
                }
                if(typeof link !=='undefined'){
                    options['link'] = link;
                }
                    Push.create(title, options);
                }

Token is saved and I am able to successfully send server side push but many times the onMessage is not triggered but the service worker code is triggered successfully.

Can somebody help me as to why push.js is not creating the push notification? I am on Chrome for Mac.

initial evaluation of worker script console messages

Hello,

When using this and registering FCM via VueJS I get the following warning messages in Chrome's console on initial loading of the service worker:

Event handler of 'push' event must be added on the initial evaluation of worker script.
t @ firebase-messaging.js:1766
e.INTERNAL.registerService.Messaging @ firebase-messaging.js:1766
value @ firebase-app.js:1825
h.(anonymous function) @ firebase-app.js:1825
s @ firebase-app.js:1825
(anonymous) @ firebase-messaging-sw.min.js:1
firebase-messaging.js:1766 Event handler of 'pushsubscriptionchange' event must be added on the initial evaluation of worker script.
t @ firebase-messaging.js:1766
e.INTERNAL.registerService.Messaging @ firebase-messaging.js:1766
value @ firebase-app.js:1825
h.(anonymous function) @ firebase-app.js:1825
s @ firebase-app.js:1825
(anonymous) @ firebase-messaging-sw.min.js:1
firebase-messaging.js:1766 Event handler of 'notificationclick' event must be added on the initial evaluation of worker script.

This appears to be a warning spit out by the following line in the Service Worker:

importScripts("https://www.gstatic.com/firebasejs/4.1.2/firebase-messaging.js")

Any idea why these are being thrown?

appId localConfig

Latest firebase requires appId to be passed in the config.

var config = {
appId: "<YOUR_APP_ID>",
apiKey: "<YOUR_API_KEY>",
authDomain: "<YOUR_AUTH_DOMAIN>",
databaseURL: "<YOUR_DATABASE_URL>",
projectId: "<YOUR_PROJECT_ID>",
storageBucket: "<YOUR_STORAGE_BUCKET>",
messagingSenderId: "<YOUR_MESSAGE_SENDER_ID>"
};

location of mainifest file

Is it possible to change the location, similar to the serviceWorkerLocation? Or just simply loading it in the HTML with whatever path it has work?

(I'm building this into a WordPress site and can't access the root directly)

How to display big picture?

Hello. I need to display big picture with both service-worker (when user is not on website/tab), and without it (when user is on website). Could anyone please help integrate this with push and push-fcp-plugin? Thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.