渐进式Web 应用开发初探

利用一系列现代Web技术的组合,

以在移动设备上提供更好的交互体验。

移动设备Web Apps的一些需求

  • work offline (网络条件不可预测、离线可用)
  • push notifications (系统通知)
  • installed (更快捷的入口,而不是难记的url)

What is a Progressive Web App?

  • Progressive
  • Responsive
  • Connectivity independent
  • App-like
  • Fresh
  • Safe
  • Discoverable
  • Re-engageable
  • Installable
  • Linkable

Web App可以渐进式地模拟Native App

比如被添加到主屏幕、全屏方式运行、离线工作及推送通知消息等。

  • discoverable & installable

  • work offline & store data for offline
  • push notifications & background sync
  • Application Shell architecture

  • Service Workers

Web App Manifest:

manifest.json


  <link rel="manifest" href="/manifest.json">
{
  "lang": "en",
  "dir": "ltr",
  "name": "Super Racer 3000",
  "description": "The ultimate futuristic racing game from the future!",
  "short_name": "Racer3K",
  "icons": [{
    "src": "icon/lowres.webp",
    "sizes": "64x64",
    "type": "image/webp"
  },{
    "src": "icon/lowres.png",
    "sizes": "64x64"
  }, {
    "src": "icon/hd_hi",
    "sizes": "128x128"
  }],
  "scope": "/racer/",
  "start_url": "/racer/start.html",
  "display": "fullscreen",
  "orientation": "landscape",
  "theme_color": "aliceblue",
  "background_color": "red",
  "screenshots": [{
    "src": "screenshots/in-game-1x.jpg",
    "sizes": "640x480",
    "type": "image/jpeg"
  },{
    "src": "screenshots/in-game-2x.jpg",
    "sizes": "1280x920",
    "type": "image/jpeg"
  }]
}

typical manifest

iOS


    <!-- Sets whether a web application runs in full-screen mode. -->
    <meta name="apple-mobile-web-app-capable" content="yes">

    <!-- Enables or disables automatic detection of possible phone numbers. -->
    <meta name="format-detection" content="telephone=no">

    <!-- Changing the Status Bar Appearance -->
    <meta name="apple-mobile-web-app-status-bar-style" content="black">

    <!-- Hiding Safari User Interface Components -->
    <meta name="apple-mobile-web-app-capable" content="yes">


    <!-- Specifying a Webpage Icon for Web Clip -->
    <link rel="apple-touch-icon" href="touch-icon-iphone.png">
    <link rel="apple-touch-icon" sizes="76x76" href="touch-icon-ipad.png">
    <link rel="apple-touch-icon" sizes="120x120" href="touch-icon-iphone-retina.png">
    <link rel="apple-touch-icon" sizes="152x152" href="touch-icon-ipad-retina.png">

    <!-- Specifying a Startup Image -->
    <link rel="apple-touch-startup-image" href="/startup.png">

相关参考

Application Shell

Server-side rendering ( not isomorphism)

An application shell is the minimal HTML, CSS, and JavaScript powering a user interface.

  • load fast
  • be cached
  • dynamically display content

Service Worker

A script that your browser runs in the background, separate from a web page, opening the door to features that don't need a web page or user interaction.

Web Workers

  • https://www.html5rocks.com/zh/tutorials/workers/basics/
  • https://developer.mozilla.org/zh-CN/docs/Web/API/Worker

HTML5 标准的一部分,一套API,容许一段JavaScript程序运行在主线程之外的另一个线程中。

支持的事件

Register

<script>

if ('serviceWorker' in navigator) {
  navigator.serviceWorker
    .register('/sw.js')
    .then(function(registration) {
      // Registration was successful
      console.log(
        'ServiceWorker registration successful with scope: ',
        registration.scope
      )
    })
    .catch(function(err) {
      // registration failed :(
      console.log(
        'ServiceWorker registration failed: ',
        err
      )
    })
}

</script>
registerServiceWorker() {
    if (!('serviceWorker' in navigator)) {
      // Service worker is not supported on this platform
      return;
    }

    navigator.serviceWorker.register('/sw.js', {
      scope: '/'
    }).then((registration) => {
      console.log('Service worker is registered.');

      var isUpdate = false;

      // If this fires we should check if there's a new Service Worker
      // waiting to be activated. If so, ask the user to force refresh.
      if (registration.active) {
        isUpdate = true;
      }

      registration.onupdatefound = function(updateEvent) {
        console.log('A new Service Worker version has been found...');

        // If an update is found the spec says that there is a new Service
        // Worker installing, so we should wait for that to complete then
        // show a notification to the user.
        registration.installing.onstatechange = function(event) {
          if (this.state === 'installed') {
            if (isUpdate) {
              ToasterSingleton.getToaster().toast(
                  'App updated. Restart for the new version.');
            } else {
              ToasterSingleton.getToaster().toast(
                  'App ready for offline use.');
            }
          }
        };
      };
    })
    .catch((err) => {
      console.log('Unable to register service worker.', err);
    });
  }

注意事项

Install and activate


self.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open('v1').then(function(cache) {
      return cache.addAll([
        '/sw-test/',
        '/sw-test/index.html',
        '/sw-test/style.css',
        '/sw-test/app.js',
        '/sw-test/image-list.js',
        '/sw-test/star-wars-logo.jpg',
        '/sw-test/gallery/',
        '/sw-test/gallery/bountyHunters.jpg',
        '/sw-test/gallery/myLittleVader.jpg',
        '/sw-test/gallery/snowTroopers.jpg'
      ])
    })
  )
})

Custom responses to request



self.addEventListener('fetch', function(event) {
  console.log('The service worker is serving the asset.')
  event.respondWith(fromNetwork(event.request, 400)
    .catch(function() {
      return fromCache(event.request)
  }))
})

更多示例参考:Service Worker Cookbook

资源参考

Made with Slides.com