使用浏览器服务工作者通知新的应用程序版本

Notify new application version with browser service workers

我使用 Polymer 和 polymer-cli 构建了一个 html/js 应用程序(一个渐进式网络应用程序),以及用于缓存和离线的良好生成的服务工作者。

我想知道当有新版本的应用程序可用时如何通知用户并邀请他重新启动浏览器。

有什么想法吗?

编辑

在 IO2016 上的一次演讲,Eric Bidel 谈到了 service worker 并通知用户应用程序的新版本: https://youtu.be/__KvYxcIIm8?list=PLOU2XLYxmsILe6_eGvDN3GyiodoV3qNSC&t=1510

需要检查 google IO Web 源代码

感谢 IO 团队 .. 我们需要检查当前的 service-worker 是否变得多余

// Check to see if the service worker controlling the page at initial load
// has become redundant, since this implies there's a new service worker with fresh content.
if (navigator.serviceWorker && navigator.serviceWorker.controller) {
   navigator.serviceWorker.controller.onstatechange = function(event) {
     if (event.target.state === 'redundant') {
       // Define a handler that will be used for the next io-toast tap, at which point it
       // be automatically removed.
       const tapHandler = function() {
         window.location.reload();
       };

       if (IOWA.Elements && IOWA.Elements.Toast &&
          IOWA.Elements.Toast.showMessage) {
            IOWA.Elements.Toast.showMessage(
            'A new version of this app is available.', tapHandler, 'Refresh',
            null, 0); // duration 0 indications shows the toast indefinitely.
       } else {
         tapHandler(); // Force reload if user never was shown the toast.
       }
     }
  };
}

参考文献:

  • https://developers.google.com/web/fundamentals/instant-and-offline/service-worker/lifecycle
  • https://classroom.udacity.com/courses/ud899

    // page script
    document.addEventListener('DOMContentLoaded', function(){
        if ('serviceWorker' in navigator) {
            navigator.serviceWorker
            .register('/sw.js')
            .then(function(registration) {
                console.info('ServiceWorker registration successful with scope:', registration.scope);
    
               // if there's no controller, this page wasn't loaded
               // via a service worker, so they're looking at the latest version.
               // In that case, exit early
               if (!navigator.serviceWorker.controller) return;
    
               // if there's an updated worker already waiting, update
               if (registration.waiting) {
                   console.info('show toast and upon click update...');
                   registration.waiting.postMessage({ updateSw: true });
                   return;
               }
    
               // if there's an updated worker installing, track its
               // progress. If it becomes "installed", update
               if (registration.installing) {
                   registration.addEventListener('statechange', function(){
                       if (registration.installing.state == 'installed'){
                           console.info('show toast and upon click update...');
                           registration.installing.postMessage({ updateSw: true });
                           return;          
                       }
                   });
               }
    
               // otherwise, listen for new installing workers arriving.
               // If one arrives, track its progress.
               // If it becomes "installed", update
               registration.addEventListener('updatefound', function(){
                   let newServiceWorker = registration.installing;
    
                   newServiceWorker.addEventListener('statechange', function() {
                       if (newServiceWorker.state == 'installed') {
                           console.info('show toast and upon click update...');
                           newServiceWorker.postMessage({ updateSw: true });           
                       }
                   });
               });
            })
            .catch(function(error) {
                console.info('ServiceWorker registration failed:', error);
            });
    
    
          navigator.serviceWorker.addEventListener('controllerchange', function() {
              window.location.reload();
          });
        }
    
    });
    
    // sw script
    self.addEventListener('message', function(e) {
        if (e.data.updateSw){
            self.skipWaiting();
        }
    });