PWA技術及其用戶體驗設計
- 2020 年 4 月 10 日
- 筆記
實驗室最近多了一個實驗產品MAX:群控手機的項目。主要包括:後端服務、web前端客戶端、Androidapp客戶端。涉及到的程式語言:Java、Nodejs。技術上主要涉及Android的MediaProjection API、配合websocket來實現。
MediaProjection 提供了錄屏功能;websocket主要是傳輸方便,可以做到實時。

今天主要介紹下web前端客戶端的實現,主要使用了PWA技術。
– 什麼是PWA?

PWA全稱Progressive Web Apps,漸進增強 Web 應用程式,它可以離線運行,並且可以在運行的系統中選擇性安裝,它從外觀還是執行效果來看,與一般應用程式無異。
不知大家體驗過微軟的郵件服務沒?Outlook.com已經完成了PWA版本,可以在瀏覽器裡面像本地應用一樣直接打開即用。
比如我使用的mac,添加了一個PWA應用之後,底部菜單欄多了一個應用的icon,效果如下:

就是mixlab那個logo
PWA是一系列技術的集合,裡面最核心的是一個叫「app shell」的概念。
– 什麼是App shell?
我們先了解下,渲染網站主要有兩種方法:在伺服器上或在客戶端上。
-伺服器端渲染(SSR)
意味著網站每次都是在伺服器上渲染,因此它提供了更快的首次載入,但是在頁面之間跳轉需要每次都下載所有內容,因而它的載入速度往往會比較慢。
-客戶端渲染(CSR)
頁面是在客戶端(瀏覽器)渲染的,因而載入速度往往取決於瀏覽器的性能,訪問速度會比較快,但是在開始時需要更多的初始下載(首次訪問時網站速度較慢),以保證整個網站其他頁面實現客戶端渲染所需要的數據。
兩種方式各有利弊,而PWA使用的方法是「app shell」,它混合了SSR和CSR的方式。
App shell,可以理解為程式的外殼。App shell意圖儘快載入最小的用戶介面,然後快取它,以便在後續訪問時可以離線使用,然後載入應用程式的所有內容。這樣,下次有人從設備訪問應用程式時,UI立即從快取載入,並從伺服器請求新內容(如果它已在快取中不可用)。
一個App shell的程式碼結構如下:
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="utf-8"> <title>Max</title> <meta name="description" content="app的介紹"> <meta name="author" content="作者"> <meta name="theme-color" content="#B12A34"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta property="og:image" content="icons/icon-512.png"> <link rel="shortcut icon" href="favicon.ico"> <link rel="stylesheet" href="style.css"> <link rel="manifest" href="manifest.json"> <script src="app.js" defer></script> </head> <body> <header> <p>MAX-demo</p> </header> <main> <h1>HELLO WORLD</h1> <button id="notifications">Request notifications</button> <section id="content"> // Content inserted in here </section> </main> <footer> <p>© max 2012-2018, created and maintained by shadow.</p> </footer> </body> </html>
為了配合app shell,需要一個叫Service Worker API的支援。
– Service Worker
Service Worker API可以完成2種任務,一種是快取App shell所需的數據,另一種是如果你有比較耗時的計算,你可以把它們從主執行緒中抽離出來,在Service Worker中進行計算,最後在它們計算完畢的時候從Service Worker中取得計算結果。
Service Worker主要由3項技術構成:
- 快取機制是依賴 Cache API 實現的
- 依賴 HTML5 fetch API 發起網路請求
- 依賴 Promise 實現非同步
service worker是需要註冊的,我們在app.js中,輸入:
if ('serviceWorker' in navigator) { window.addEventListener('load', function() { navigator.serviceWorker.register('/serviceWorker.js', { scope: '/' }) .then(function(registration) { // 註冊成功 console.log('ServiceWorker registration successful with scope: ', registration.scope); }) .catch(function(err) { // 註冊失敗 console.log('ServiceWorker registration failed: ', err); }); }); };
即可,使用上我們編寫好的serviceWorker.js文件。
serviceWorker.js主要對有install跟fetch事件進行監聽,對cache進行操作,達到快取的目的。
let cacheName = 'max-v1'; let contentToCache = [ '/', '/index.html', '/style.css', '/app.js' ]; // 對app shell和主體內容(content)裡面的數據創建快取 self.addEventListener('install', function(e) { console.log('[Service Worker] Install'); e.waitUntil( // 安裝成功後操作 CacheStorage 快取,使用之前需要先通過 caches.open() 打開對應快取空間。 caches.open(cacheName).then(function(cache) { console.log('[Service Worker] Caching all: app shell and content'); // 通過 cache 快取對象的 addAll 方法添加 快取 return cache.addAll(contentToCache); }) ); }); //如果條件允許,service worker將從快取中請求content中所需的數據,從而提供離線應用功能 self.addEventListener('fetch', function(e) { e.respondWith( caches.match(e.request).then(function(r) { console.log('[Service Worker] Fetching resource: ' + e.request.url); return r || fetch(e.request).then(function(response) { return caches.open(cacheName).then(function(cache) { console.log('[Service Worker] Caching new resource: ' + e.request.url); cache.put(e.request, response.clone()); return response; }); }); }) ); });
兩種方式可以比較一下:
– install
優點是第二次訪問即可離線,缺點是需要將需要快取的 URL 在編譯時插入到腳本中,增加程式碼量和降低可維護性;
– fetch
優點是無需更改編譯過程,也不會產生額外的流量,缺點是需要訪問過一次才能離線使用。
因此,在設計技術架構的時候,需要考慮到2種方式的優缺點。
除了配置serviceWorker.js之外,我們還需要配置manifest.json文件。
– 添加至桌面功能
serviceWorker使得網頁在速度跟體驗上接近原生app,除此之外,還需要引導用戶添加pwa應用到桌面,以方便下次使用。
實現 PWA 應用添加至桌面的功能,除了要求站點支援 HTTPS 之外,需要準備 manifest.json 文件去配置應用的圖標、名稱等資訊。一個基本的 manifest.json 應包含如下資訊:
{ "name": "max-demo-v1", "short_name": "max", "description": "demo", "icons": [{ "src": "icons/mix-logo.png", "sizes": "72x72 96x96 128x128 256x256", "type": "image/png" }], "start_url": "/index.html", "display": "fullscreen", "theme_color": "#4a4a4a", "background_color": "#eeeeee" }
運行之後,在瀏覽器地址欄右側,可以看到一個+號,點擊安裝。

另外,調試可以在chrome的Application面板中進行查看。
由於PWA的api不是所有瀏覽器都支援,因而,你還需要注意使用caniuse.com 來查看主流瀏覽器的支援情況。
– 如何告知普通用戶什麼是離線模式?或者什麼是PWA?

這是體驗設計上需要注意的地方,我們應該認識到並不是每個用戶都是技術出身,都對PWA的概念了解得很清楚。因而,用戶體驗設計需要為用戶提供指導,以便他們可以了解什麼是PWA(或者離線模式)。
確實,離線模式比PWA(漸進式)更為容易理解,但是離線模式對每個人來說都是一個全新的心智模式。通俗來講,您需要告訴用戶當他們無法連接上網路時會發生什麼變化。比如:
哪些功能無法使用;
或者是頁面上的數據是什麼時間更新的;
目前的網路連接情況;
等等。
除此之外,設計上要考慮首次載入的問題,如首次載入時間過長,需要設計動畫提示,可以把載入的文件內容簡要告知用戶,讓用戶知道網頁正在載入,而不是「死機了」。
下一步,擬集成TensorFlowJS,探索下可能性。