Управление подпиской push-уведомлений на стороне клиента и сервера - PullRequest
0 голосов
/ 04 сентября 2018


Я стираю все мои предыдущие вопросы о том, как использовать код, приведенный в документации push-уведомления рабочего ящика , чтобы показать вам решение, которое я нашел более четко.

прежде чем показывать вам код, я объясню, что мне потребовалось много времени, чтобы понять. Вы обычно используете три файла, которые работают с сервисным работником. В моем случае server.js, index.js и sw.js. Когда браузер получает все файлы, необходимые для отображения вашего сайта, я также получаю файл index.js. Этот файл запускает работника сервиса с navigator.serviceWorker.register('sw.js'). Затем он проверяет, согласился ли пользователь уже получать уведомление. В конце он проверяет, существует ли подписка или нет, и управляет ее.
Подписная часть очень важна и сложна в управлении. С swRegistration.pushManager.subscribe() мы получим sub объект. Этот объект содержит конечную точку , auth и p256th . Эта информация очень важна, и нам нужно отправить ее на наш сервер, чтобы сохранить ее в нашей базе данных. элемент fetch() делает это. Таким образом, мы сможем отправить уведомление для нашего пользователя в будущем.

Последнее, что вам нужно знать, и как создавать закрытые и открытые ключи Vapid. Чтобы сгенерировать его, отобразите в своем терминале console.log , который находится ниже моей переменной privateVapidKey внутри server.js . Затем скопируйте и вставьте оба результата в переменную, как я делал server.js, и скопируйте и вставьте publicsVapidKey в файл index.js .
server.js:

var express = require('express');
var app = express();
var https = require('https');
var fs = require('fs');
var webPush = require('web-push');
var bodyParser = require('body-parser');    

https.createServer({
  key: fs.readFileSync('key_localhost2.pem'),
  cert: fs.readFileSync('cert_localhost2.pem'),
  passphrase: 'localhost',
}, app).listen(8080);

//*****************************************************************
//-------------------------- TEMPLATES --------------------------
//*****************************************************************
//moteur de modèles ou de templates
app.set('view engine', 'ejs');

//*****************************************************************
//-------------------------- MIDDLEWARE --------------------------
//*****************************************************************    
app
  .use('/static', express.static(__dirname + '/public'))
  .use(express.static(__dirname + '/public/js'))
  .use(bodyParser.json());

//*****************************************************************
//--------------------------- ROUTES ------------------------------
//*****************************************************************   
app.get('/', function (request, response) {
  response.render('./pages/index.ejs');
});

var publicVapidKey = "BKwLqQWMQpLfSNGb-VXCsAPE1H5o7Oh3VxDiEIqWWOm2OdAoFPqr9K9WI7dKKtjYYHLTKm7tjJO04091pDXZiJs"
var privateVapidKey = "483sZs2cZUxSQegGKKOZXLl_b7_ywBF_qJO77gXFsHE"
//console.log('Publics keys : ' + vapidKeys.publicKey)
//console.log('Private key : ' + vapidKeys.privateKey)

webPush.setVapidDetails(
  'mailto:localhost:8080',
  publicVapidKey,
  privateVapidKey
);

var pushSubscription; 

app.post('/subscription_push_notification', function (req, resp) {
  pushSubscription = req.body;
  console.log(pushSubscription)

  //I'm able to save this information into my database
  endpointVal = req.body.endpoint;
  authVal = req.body.keys.auth;
  p256dhVal = req.body.keys.p256dh;

  setTimeout(function () {

    if (endpointVal) {

      var payload = 'Here is a payload!';

      webPush.sendNotification(
        pushSubscription,
        payload
      ).catch(function (err) {
        console.log(err);
      });
    }
  }, 2000)

  resp.json({});
});

index.js:

window.addEventListener('load', function () {

    //*********************************************************
    // Start SW, permission notification, register subscribe
    //*********************************************************
    if ('serviceWorker' in navigator) {

        //+++++++++++++++++++++++++++++
        //Register Service worker
        navigator.serviceWorker.register('sw.js')
            .then(function (swRegistration) {

                //Ask to notification permission
                displayNotification();

                var publicVapidKey = "BKwLqQWMQpLfSNGb-VXCsAPE1H5o7Oh3VxDiEIqWWOm2OdAoFPqr9K9WI7dKKtjYYHLTKm7tjJO04091pDXZiJs";
                var applicationServerKey = urlBase64ToUint8Array(publicVapidKey);

                //Manage push notifiaction
                swRegistration.pushManager.getSubscription().then(function (sub) {
                    if (sub === null) {
                        // Update UI to ask user to register for Push
                        console.log('Not subscribed to push service!');

                        swRegistration.pushManager.subscribe({
                            userVisibleOnly: true,
                            applicationServerKey: applicationServerKey
                        }).then(function (sub) {
                            // We have a subscription, update the database
                            console.log('Endpoint URL: ', sub.endpoint);
                            fetch('/subscription_push_notification', {
                                method: 'POST',
                                body : JSON.stringify(sub),
                                headers: {
                                    'content-type':'application/json'
                                }
                            });
                        }).catch(function (e) {

                            if (Notification.permission === 'denied') {
                                console.warn('Permission for notifications was denied');
                            } else {
                                console.error('Unable to subscribe to push', e);
                            }
                        });

                    } else {
                        // We have a subscription, update the database
                        console.log('Subscription object: ', sub);
                        fetch('/subscription_push_notification', {
                            method: 'POST',
                            body : JSON.stringify(sub),
                            headers: {
                                'content-type':'application/json'
                            }
                        });

                    }
                });
            })
            .catch(function (err) {
                console.log('Service Worker registration failed: ', err);

            })

    }


    //*********************************************************
    // Function ask to notification permission
    //*********************************************************
    function displayNotification() {

        if (Notification.permission === 'granted') {
            //Mean, the notification is accepted.
            console.log('Notification accepted...');

        } else if (Notification.permission === "blocked" || Notification.permission === "denied") {
            // the user has previously denied notification. Can't reprompt.
            console.log('Notification blocked...');

        } else {
            // show a prompt to the user
            console.log('Prompt to accept notification');

            Notification.requestPermission();
        }
    }


    //*********************************************************
    // Transform public Vapid key
    //*********************************************************
    function urlBase64ToUint8Array(base64String) {
        const padding = '='.repeat((4 - base64String.length % 4) % 4);
        const base64 = (base64String + padding)
            .replace(/\-/g, '+')
            .replace(/_/g, '/');

        const rawData = window.atob(base64);
        const outputArray = new Uint8Array(rawData.length);

        for (let i = 0; i < rawData.length; ++i) {
            outputArray[i] = rawData.charCodeAt(i);
        }
        return outputArray;
    }

});

sw.js:

importScripts('https://storage.googleapis.com/workbox-cdn/releases/3.4.1/workbox-sw.js');

if (workbox) {
  console.log(`Yay! Workbox is loaded ?`);
} else {
  console.log(`Boo! Workbox didn't load ?`);
}


//*********************************************************
// Save file from site to work in offline mode
//*********************************************************
workbox.precaching.precacheAndRoute([
  { url: '/', revision: '383676' },
  { url: '/static/css/style.css', revision: '383677' },
  { url: '/static/js/index.js', revision: '383678' },
]);

//*********************************************************
// The notification click event
//*********************************************************
//Inform when the notification close/hide from the window 
self.addEventListener('notificationclick', function (e) {
  console.log('notification was clicked')
  var notification = e.notification;
  var action = e.action;

  if (action === 'close') {
    notification.close();
  } else {
    clients.openWindow('https://www.google.fr');
  };
});


//*********************************************************
// Handling the push event in the service worker
//*********************************************************
self.addEventListener('push', function (e) {
  console.log('Hi man !!!')

  var options = {
    body: e.data.text(),
    icon: '/static/img/logo_menu.png',
    vibrate: [100, 50, 100],
    data: {
      dateOfArrival: Date.now(),
      primaryKey: '2'
    },
  };
  e.waitUntil(
    self.registration.showNotification('Hello world!', options)
  );
});
...