如何实现服务工作者?

时间:2015-10-12 13:57:11

标签: google-chrome service-worker chrome-gcm web-push push-api

我已经通过不同的博客解释了服务工作者,其中一个是open Web Push notification。我按照Open Web Push通知中的说明操作并实现了一个创建curl注册ID的代码。一旦创建了注册ID,我就把它放在数据库中。但我没有得到通知。我通常在谷歌控制台中启用gcm。 我是否还应该编写gcm服务器和客户端代码,因为我已经阅读了很多博客,但没有人说这样做。 我该怎么做才能收到通知。

如果遗漏了任何内容,请参阅下面的代码。

index.html

<!doctype html>

<html lang="en">
<head>

    <title>Push Messaging &amp; Notifications</title>

    <!-- Add to homescreen for Chrome on Android -->
    <meta name="mobile-web-app-capable" content="yes">
    <link rel="icon" sizes="192x192" href="../images/touch/chrome-touch-icon-192x192.png">

    <!-- Add to homescreen for Safari on iOS -->
    <meta name="apple-mobile-web-app-title" content="Push Messaging and Notifications Sample">

    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <link rel="apple-touch-icon-precomposed" href="../images/apple-touch-icon-precomposed.png">

    <!-- Tile icon for Win8 (144x144 + tile color) -->
    <meta name="msapplication-TileImage" content="images/touch/ms-touch-icon-144x144-precomposed.png">
    <meta name="msapplication-TileColor" content="#3372DF">

    <link rel="icon" href="../images/favicon.ico">

    <!-- Include manifest file in the page -->
    <link rel="manifest" href="manifest.json">


<body>
    <h1>Push Messaging &amp; Notifications</h1>

    <p>
        <button class="js-push-button" disabled>
            Enable Push Messages
        </button>
    </p>

    <br />
    <br />

    <h2>cURL Command to Send Push</h2>
    <div class="js-curl-command"></div>

    <script src="config.js"></script>
    <script src="demo.js"></script>
    <script src="main.js"></script>

</body>
</html>

main.js

    'use strict';

var API_KEY = window.GoogleSamples.Config.gcmAPIKey;
var GCM_ENDPOINT = 'https://android.googleapis.com/gcm/send';

var curlCommandDiv = document.querySelector('.js-curl-command');
var isPushEnabled = false;

// This method handles the removal of subscriptionId
// in Chrome 44 by concatenating the subscription Id
// to the subscription endpoint
function endpointWorkaround(pushSubscription) {
    // Make sure we only mess with GCM
    if (pushSubscription.endpoint.indexOf('https://android.googleapis.com/gcm/send') !== 0) {
        return pushSubscription.endpoint;
    }

    var mergedEndpoint = pushSubscription.endpoint;
    // Chrome 42 + 43 will not have the subscriptionId attached
    // to the endpoint.
    if (pushSubscription.subscriptionId &&
      pushSubscription.endpoint.indexOf(pushSubscription.subscriptionId) === -1) {
        // Handle version 42 where you have separate subId and Endpoint
        mergedEndpoint = pushSubscription.endpoint + '/' +
          pushSubscription.subscriptionId;

    }
    return mergedEndpoint;
}

function sendSubscriptionToServer(subscription) {
    // TODO: Send the subscription.endpoint
    // to your server and save it to send a
    // push message at a later date
    //
    // For compatibly of Chrome 43, get the endpoint via
    // endpointWorkaround(subscription)
    var sub = subscription.endpoint;
    var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (xhttp.readyState == 4 && xhttp.status == 200) {
      //document.getElementById("demo").innerHTML = xhttp.responseText;
    }
  }
  xhttp.open("POST", "myusers.php?id="+sub, true);
  xhttp.send();

    console.log(subscription.endpoint);

    var mergedEndpoint = endpointWorkaround(subscription);

    // This is just for demo purposes / an easy to test by
    // generating the appropriate cURL command
    showCurlCommand(mergedEndpoint);
}

// NOTE: This code is only suitable for GCM endpoints,
// When another browser has a working version, alter
// this to send a PUSH request directly to the endpoint
function showCurlCommand(mergedEndpoint) {
    // The curl command to trigger a push message straight from GCM
    if (mergedEndpoint.indexOf(GCM_ENDPOINT) !== 0) {
        window.Demo.debug.log('This browser isn\'t currently ' +
          'supported for this demo');
        return;
    }

    var endpointSections = mergedEndpoint.split('/');
    var subscriptionId = endpointSections[endpointSections.length - 1];

    var curlCommand = 'curl --header "Authorization: key=' + API_KEY +
      '" --header Content-Type:"application/json" ' + GCM_ENDPOINT +
      ' -d "{\\"registration_ids\\":[\\"' + subscriptionId + '\\"]}"';

    curlCommandDiv.textContent = curlCommand;
}

function unsubscribe() {
    var pushButton = document.querySelector('.js-push-button');
    pushButton.disabled = true;
    curlCommandDiv.textContent = '';

    navigator.serviceWorker.ready.then(function (serviceWorkerRegistration) {
        // To unsubscribe from push messaging, you need get the
        // subcription object, which you can call unsubscribe() on.
        serviceWorkerRegistration.pushManager.getSubscription().then(
          function (pushSubscription) {
              // Check we have a subscription to unsubscribe
              if (!pushSubscription) {
                  // No subscription object, so set the state
                  // to allow the user to subscribe to push
                  isPushEnabled = false;
                  pushButton.disabled = false;
                  pushButton.textContent = 'Enable Push Messages';
                  return;
              }

              // TODO: Make a request to your server to remove
              // the users data from your data store so you
              // don't attempt to send them push messages anymore

              // We have a subcription, so call unsubscribe on it
              pushSubscription.unsubscribe().then(function (successful) {
                  pushButton.disabled = false;
                  pushButton.textContent = 'Enable Push Messages';
                  isPushEnabled = false;
              }).catch(function (e) {
                  // We failed to unsubscribe, this can lead to
                  // an unusual state, so may be best to remove
                  // the subscription id from your data store and
                  // inform the user that you disabled push

                  window.Demo.debug.log('Unsubscription error: ', e);
                  pushButton.disabled = false;
              });
          }).catch(function (e) {
              window.Demo.debug.log('Error thrown while unsubscribing from ' +
                'push messaging.', e);
          });
    });
}

function subscribe() {
    // Disable the button so it can't be changed while
    // we process the permission request
    var pushButton = document.querySelector('.js-push-button');
    pushButton.disabled = true;

    navigator.serviceWorker.ready.then(function (serviceWorkerRegistration) {
        serviceWorkerRegistration.pushManager.subscribe({ userVisibleOnly: true })
          .then(function (subscription) {
              // The subscription was successful
              isPushEnabled = true;
              pushButton.textContent = 'Disable Push Messages';
              pushButton.disabled = false;

              // TODO: Send the subscription subscription.endpoint
              // to your server and save it to send a push message
              // at a later date
              return sendSubscriptionToServer(subscription);
          })
          .catch(function (e) {
              if (Notification.permission === 'denied') {
                  // The user denied the notification permission which
                  // means we failed to subscribe and the user will need
                  // to manually change the notification permission to
                  // subscribe to push messages
                  window.Demo.debug.log('Permission for Notifications was denied');
                  pushButton.disabled = true;
              } else {
                  // A problem occurred with the subscription, this can
                  // often be down to an issue or lack of the gcm_sender_id
                  // and / or gcm_user_visible_only
                  window.Demo.debug.log('Unable to subscribe to push.', e);
                  pushButton.disabled = false;
                  pushButton.textContent = 'Enable Push Messages';
              }
          });
    });
}

// Once the service worker is registered set the initial state
function initialiseState() {
    // Are Notifications supported in the service worker?
    if (!('showNotification' in ServiceWorkerRegistration.prototype)) {
        window.Demo.debug.log('Notifications aren\'t supported.');
        return;
    }

    // Check the current Notification permission.
    // If its denied, it's a permanent block until the
    // user changes the permission
    if (Notification.permission === 'denied') {
        window.Demo.debug.log('The user has blocked notifications.');
        return;
    }

    // Check if push messaging is supported
    if (!('PushManager' in window)) {
        window.Demo.debug.log('Push messaging isn\'t supported.');
        return;
    }

    // We need the service worker registration to check for a subscription
    navigator.serviceWorker.ready.then(function (serviceWorkerRegistration) {
        // Do we already have a push message subscription?
        serviceWorkerRegistration.pushManager.getSubscription()
          .then(function (subscription) {
              // Enable any UI which subscribes / unsubscribes from
              // push messages.
              var pushButton = document.querySelector('.js-push-button');
              pushButton.disabled = false;

              if (!subscription) {
                  // We aren’t subscribed to push, so set UI
                  // to allow the user to enable push
                  return;
              }

              // Keep your server in sync with the latest subscription
              sendSubscriptionToServer(subscription);

              // Set your UI to show they have subscribed for
              // push messages
              pushButton.textContent = 'Disable Push Messages';
              isPushEnabled = true;
          })
          .catch(function (err) {
              window.Demo.debug.log('Error during getSubscription()', err);
          });
    });
}

window.addEventListener('load', function () {
    var pushButton = document.querySelector('.js-push-button');
    pushButton.addEventListener('click', function () {
        if (isPushEnabled) {
            unsubscribe();
        } else {
            subscribe();
        }
    });

    // Check that service workers are supported, if so, progressively
    // enhance and add push messaging support, otherwise continue without it.
    if ('serviceWorker' in navigator) {
        navigator.serviceWorker.register('service-worker.js')
        .then(initialiseState);
    } else {
        window.Demo.debug.log('Service workers aren\'t supported in this browser.');
    }
});

config.js

window.GoogleSamples = window.GoogleSamples || {};
window.GoogleSamples.Config = window.GoogleSamples.Config || {
    gcmAPIKey: '&lt;Your Public API Key ...&gt;'
};

服务worker.js

'use strict';

self.addEventListener('push', function (event) {
    console.log('Received a push message', event);

    var title = 'Yay a message.';
    var body = 'We have received a push message.';
    var icon = '/images/icon-192x192.png';
    var tag = 'simple-push-demo-notification-tag';

    event.waitUntil(

      self.registration.showNotification(title, {
          body: body,
          icon: icon,
          tag: tag
      })
    );
});


self.addEventListener('notificationclick', function (event) {
    console.log('On notification click: ', event.notification.tag);
    // Android doesn’t close the notification when you click on it
    // See: http://crbug.com/463146
    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) {
        for (var i = 0; i < clientList.length; i++) {
            var client = clientList[i];
            if (client.url == '/' && 'focus' in client)
                return client.focus();
        }
        if (clients.openWindow)
            return clients.openWindow('/');
    }));

});

demo.js

 'use strict';

    function Debug() {

    }

    Debug.prototype.log = function () {
        var paragraphElement = document.createElement('p');
        paragraphElement.textContent = Array.prototype.join.call(arguments, '');
        document.querySelector('.js-log').appendChild(paragraphElement);
    }

    window.addEventListener('load', function () {
        var logDiv = document.createElement('div');
        logDiv.classList.add('js-log');

        var heading = document.createElement('h2');
        heading.textContent = 'Log';
        logDiv.appendChild(heading);

        document.body.appendChild(logDiv);

        window.Demo = window.Demo || {};
        window.Demo.debug = window.Demo.debug || new Debug();
    });
写完所有这些代码之后还能做些什么? 我没有和gcm一起工作,所以很难找到帮助,需要帮助。

2 个答案:

答案 0 :(得分:1)

是的,“实际”用例需要编写服务器端代码。 curl命令只是对功能的一次性测试。

假设有一个Python App Engine后端,

https://github.com/gauntface/simple-push-demo是一个很好的服务器端起点。

答案 1 :(得分:1)

一些例子

https://github.com/beverloo/peter.sh/tree/master/tests有非常基本的php版服务器端代码。您可以忽略所有与加密相关的内容,因为只有在您需要发送有效负载时才需要。

https://github.com/johnmellor/push-api-appengine-demo包含一个python服务器端实现,您可以在https://johnme-gcm.appspot.com/chat/

中尝试

实际的发送代码非常简单。只需发送一个看起来像这样的JSON请求

{
        'registration_ids': registration_ids,
        'collapse_key': "constantString",
}

通过POST消息发送到https://android.googleapis.com/gcm/send 完整的API和更多示例(不是特定于网络推送但仍然有用)https://developers.google.com/cloud-messaging/