亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

Understanding PWA

EsgynChina / 2382人閱讀

摘要:安裝事件綁定在文件中,當(dāng)安裝成功后,事件就會被觸發(fā)。激活當(dāng)安裝完成后并進(jìn)入激活狀態(tài),會觸發(fā)事件。這會導(dǎo)致更新得不到響應(yīng)。由兩個(gè)構(gòu)成用來顯示系統(tǒng)的通知用來處理下發(fā)的消息這兩個(gè)都是建立在在基礎(chǔ)上的,在后臺響應(yīng)推送消息時(shí)間,并把他們傳遞給應(yīng)用。

原文地址: https://blog.webkong.cn/2018/...

What is pwa?

Progressive Web App, 簡稱 PWA,是提升 Web App 的體驗(yàn)的一種新方法,能給用戶原生應(yīng)用的體驗(yàn)。

PWA 能做到原生應(yīng)用的體驗(yàn)不是靠特指某一項(xiàng)技術(shù),而是經(jīng)過應(yīng)用一些新技術(shù)進(jìn)行改進(jìn),在安全、性能和體驗(yàn)三個(gè)方面都有很大提升,PWA 本質(zhì)上是 Web App,借助一些新技術(shù)也具備了 Native App 的一些特性,兼具 Web App 和 Native App 的優(yōu)點(diǎn)。

技術(shù)依賴:

Service Worker

Web storage(IndexedDB, Caches)

Fetch

Promises

PWA advantages

PWA應(yīng)用應(yīng)該是:

discoverable 可發(fā)現(xiàn), 可以被識別為應(yīng)用程序,通過搜索引擎容易找到

installable 可安裝,可用于移動設(shè)備,添加到用戶主屏幕

linkable 可連接 通過URL共享,無需復(fù)雜安裝

network independent 網(wǎng)絡(luò)獨(dú)立 可工作在離線或者低速的網(wǎng)絡(luò)環(huán)境

progressive 漸進(jìn)增強(qiáng) 適用于所有用戶,支持的瀏覽器可以體驗(yàn)更好,不支持的瀏覽器訪問不會郵到影響

re-engageable 再參與 通過提醒,讓用戶容易進(jìn)行參與

responsive 響應(yīng)式 適合任何形式的設(shè)備

safe 安全 內(nèi)容傳遞機(jī)制可以防止監(jiān)聽,并保證內(nèi)容不被篡改

Progressive web app advantages. To find out how to implement PWAs, consult the guides listed in the below section.

Progressive(漸進(jìn)性)

強(qiáng)調(diào)是漸進(jìn)式的,改造過程中可以逐步進(jìn)行,降低站點(diǎn)的改造成本,新技術(shù)支持程度不完整,跟著新技術(shù)逐步進(jìn)化。
PWA 涉及到從安全、性能和體驗(yàn)等方面的優(yōu)化,可以考慮以下步驟:

第一步,應(yīng)該是安全,將全站 HTTPS 化,因?yàn)檫@是 PWA 的基礎(chǔ),沒有 HTTPS,就沒有 Service Worker

第二步,應(yīng)該是 Service Worker 來提升基礎(chǔ)性能,離線提供靜態(tài)文件,把用戶首屏體驗(yàn)提升上來

第三步,App Manifest,這一步可以和第二步同時(shí)進(jìn)行

后續(xù),再考慮其他的特性,離線消息推送等

支持程度/覆蓋率





Service Worker

Service Worker,是一個(gè)瀏覽器和network之間的代理,解決的是如何緩存頁面的資產(chǎn)和如果在脫機(jī)狀態(tài)下仍然正常工作的問題。獨(dú)立于當(dāng)前網(wǎng)頁進(jìn)程,有自己獨(dú)立的 worker context,沒有對于DOM的訪問權(quán)限,與傳統(tǒng)的API不同,它是非阻塞的,并基于promise方法在就緒時(shí)返回結(jié)果。它不但只是離線能力,還有消息通知、添加桌面圖標(biāo)等功能。

前提條件

HTTPS, 由于 Service Worker 要求 HTTPS 的環(huán)境,我們可以借助 github page 進(jìn)行學(xué)習(xí)調(diào)試。一般瀏覽器允許調(diào)試 Service Worker 的時(shí)候 host 為 localhost。

Service Worker 的緩存機(jī)制是依賴 Cache API實(shí)現(xiàn)的

依賴 HTML5 fetch API

依賴 Promise 實(shí)現(xiàn)

Lifecycle

A more detailed introduction to The Service Worker Lifecycle

A service worker goes through three steps in its lifecycle:

Registration 注冊

Installation 安裝

Activation 激活

1. 注冊

在install Server Worker之前,要在主進(jìn)程JavaScript代碼里面注冊它,注冊是為了告訴瀏覽器我們的Servic e Worker文件是哪個(gè),然后在后臺,Service Worker就開始安裝激活。

注冊代碼可以放到html文件的標(biāo)簽中,也可以多帶帶放到main.js文件在引入html文件中。
if ("serviceWorker" in navigator) {
  navigator.serviceWorker.register("/service-worker.js")
  .then(function(registration) {
    console.log("Registration successful, scope is:", registration.scope);
  })
  .catch(function(error) {
    console.log("Service worker registration failed, error:", error);
  });
}

代碼中,先檢測是瀏覽器是不是支持Service Worker,如果支持,就用navigator.serviceWorker.register注冊,如果成功,就會在promise的 .then 里面得到registration.

service-worker.js文件就是我們要編寫Service Worker功能的文件。

注冊時(shí),還可以指定可選參數(shù)scope,scope是Service Worker 可以以訪問到的作用域,或者說是目錄。

navigator.serviceWorker.register("/service-worker.js", {
  scope: "/app/"
});

代碼中指定作用域是/app/,意思就是說,Service Workder 可以控制的path是類似于app /app/home/ /app/abbout/等內(nèi)部目錄,而不能訪問 / "/images"等 /app更上一次層的path。

如果Service Worker 已經(jīng)安裝了,再次注冊會返回當(dāng)前活動的registration對象。

chrome瀏覽器已經(jīng)很好的支持了Service Worker的debug功能,可在瀏覽器輸入chrome://inspect/#service-workers查看是否注冊成功了。
或者在控制臺的application選項(xiàng)查看。

2.安裝

install事件綁定在Service Worker文件中,當(dāng)安裝成功后,install事件就會被觸發(fā)。
一般我們會在install事件里面進(jìn)行緩存的處理,用到之前提到的Cahce API,它是一個(gè)Service Worker上的全局對象[5],可以緩存網(wǎng)絡(luò)相應(yīng)的資源,并根據(jù)他們的請求生成key,這個(gè)API和瀏覽器標(biāo)準(zhǔn)的緩存工作原理相似,但是只是針對自己的scope域的,緩存會一直存在,知道手動清楚或者刷新。

var cacheName = "cachev1"
self.addEventListener("install", function(event) {
  event.waitUntil(
    caches.open(cacheName).then(function(cache) {
      return cache.addAll(
        [
          "/css/bootstrap.css",
          "/css/main.css",
          "/js/bootstrap.min.js",
          "/js/jquery.min.js",
          "/offline.html"
        ]
      );
    })
  );
});

新增install的監(jiān)聽器,并用event.waitUntil()來確保,Service Worker不會在waitUntil()執(zhí)行完成之前安裝完成。

使用caches.open()創(chuàng)建一個(gè)cachev1的新緩存,返回一個(gè)緩存的promise對象,當(dāng)它resolved時(shí)候,我們在then方法里面用caches.addAll來添加想要緩存的列表,列表是一個(gè)數(shù)組,里面的URL是相對于origin的。

如果promise被rejected,安裝失敗,我們并沒有catch,所以并不會做任何事情,也可以修改代碼,加上重新注冊的代碼。

當(dāng)安裝完成時(shí),Service Worker就會激活成功。

3. 激活

當(dāng) Service Worker 安裝完成后并進(jìn)入激活狀態(tài),會觸發(fā) activate 事件。通過監(jiān)聽 activate 事件你可以做一些預(yù)處理,如對舊版本的更新、對無用緩存的清理等。

Service Worker 如何更新呢?

service-worker.js控制著頁面資源和請求的緩存,如果 js 內(nèi)容有更新,當(dāng)訪問網(wǎng)站頁面時(shí)瀏覽器獲取了新的文件,逐字節(jié)比對js 文件發(fā)現(xiàn)不同時(shí)它會認(rèn)為有更新啟動 更新算法,于是會安裝新的文件并觸發(fā) install 事件。但是此時(shí)已經(jīng)處于激活狀態(tài)的舊的 Service Worker 還在運(yùn)行,新的 Service Worker 完成安裝后會進(jìn)入 waiting 狀態(tài)。直到所有已打開的頁面都關(guān)閉,舊的 Service Worker 自動停止,新的 Service Worker 才會在接下來重新打開的頁面里生效。

如果希望在有了新版本時(shí),所有的頁面都得到及時(shí)自動更新怎么辦呢?可以在 install 事件中執(zhí)行 self.skipWaiting() 方法跳過 waiting 狀態(tài),然后會直接進(jìn)入 activate 階段。接著在 activate 事件發(fā)生時(shí),通過執(zhí)行 self.clients.claim() 方法,更新所有客戶端上的 Service Worker。

// 安裝階段跳過等待,直接進(jìn)入 active
self.addEventListener("install", function (event) {
    event.waitUntil(self.skipWaiting());
});

self.addEventListener("activate", function (event) {
    event.waitUntil(
        Promise.all([
            // 更新客戶端
            self.clients.claim(),

            // 清理舊版本
            caches.keys().then(function (cacheList) {
                return Promise.all(
                    cacheList.map(function (cacheName) {
                        if (cacheName !== "cachev1") {
                            return caches.delete(cacheName);
                        }
                    })
                );
            })
        ])
    );
});

當(dāng)js 文件可能會因?yàn)闉g覽器緩存問題,當(dāng)文件有了變化時(shí),瀏覽器里還是舊的文件。這會導(dǎo)致更新得不到響應(yīng)。如遇到該問題,可嘗試這么做:在 Web Server 上添加對該文件的過濾規(guī)則,不緩存或設(shè)置較短的有效期。

或者手動調(diào)用update()來更新

navigator.serviceWorker.register("/service-worker.js").then(reg => {
  // sometime later…
  reg.update();
});

可以結(jié)合localStorage來使用,不必每次加載更新

var version = "v1";

navigator.serviceWorker.register("/service-worker.js").then(function (reg) {
    if (localStorage.getItem("sw_version") !== version) {
        reg.update().then(function () {
            localStorage.setItem("sw_version", version)
        });
    }
});

示意圖

每個(gè)狀態(tài)都會有ing,進(jìn)行態(tài)。

Web Storage

選擇正確的存儲機(jī)制對于本地設(shè)備存儲和基于云的服務(wù)器存儲都非常重要。 良好的存儲引擎可確保以可靠的方式保存信息,并減少帶寬和提升響應(yīng)能力。正確的存儲緩存策略是實(shí)現(xiàn)離線移動網(wǎng)頁體驗(yàn)的核心構(gòu)建基塊。

存儲的類別,存儲的持久化,瀏覽器支持情況等原因,如何更高效的存儲是我們討論的重點(diǎn)。

資料

Web Storage Overview

Using Cache API

Offine Storage for PWA

Best Practices for Using IndexedDB

Inspect and Manage Storage, Databases, and Caches

cache API和 IndexedDB

針對于離線存儲數(shù)據(jù),建議可以有:

對于網(wǎng)址可尋址的資源,使用[Cache API]() (Service Worker 的一部分)

對于所有其他數(shù)據(jù),使用[IndexedDB}(https://developer.mozilla.org... (就有一個(gè)promise包裝器)

基本原理

上面的兩個(gè)API都是異步的(IndexedDB是基于事件的,而Cache API是基于Promise的)。他們可以與web Workers windows service workers一起使用。IndexedDB基本可以在所有瀏覽器環(huán)境使用(參看上面的CanIUse),Service Wokers和Cahce API的支持情況,可以通過上面的圖看到,已經(jīng)支持Chrome,F(xiàn)irefox,Opera。IndexedDB的Promise包裝器隱藏了IndexedDB庫自帶的一些強(qiáng)大但同時(shí)非常復(fù)雜的machinery(例如:事務(wù)處理 transactions,架構(gòu)版本schema versioning)。IndexedDB將支持observers,這個(gè)特性可以輕松實(shí)現(xiàn)標(biāo)簽之間的同步。

對于PWA,我們可以緩存靜態(tài)資源,從而使用 Cache API 編寫的應(yīng)用 Application Shell(JS/CSS/HTML 文件),并從 IndexedDB 填充離線頁面數(shù)據(jù)。

對于Web Storage(LocalStorage/SessionStorage)是同步的,不支持 Web worker線程,并且有大小和類型(僅限字符串)的限制。

添加到桌面

允許將站點(diǎn)添加至主屏幕,是 PWA 提供的一項(xiàng)重要功能。雖然目前部分瀏覽器已經(jīng)支持向主屏幕添加網(wǎng)頁快捷方式以方便用戶快速打開站點(diǎn),但是 PWA 添加到主屏幕的不僅僅是一個(gè)網(wǎng)頁快捷方式,它將提供更多的功能,讓 PWA 具有更加原生的體驗(yàn)。

PWA 添加至桌面的功能實(shí)現(xiàn)依賴于 manifest.json。

為了實(shí)現(xiàn) PWA 應(yīng)用添加至桌面的功能,除了要求站點(diǎn)支持 HTTPS 之外,還需要準(zhǔn)備 manifest.json 文件去配置應(yīng)用的圖標(biāo)、名稱等信息。舉個(gè)例子,一個(gè)基本的 manifest.json 應(yīng)包含如下信息:

{
    "name": "Easyify Docs",
    "short_name": "Easyify Docs",
    "start_url": "/",
    "theme_color": "#FFDF00",
    "background_color": "#FFDF00",
    "display":"standalone",
    "description": "A compilation tools for FE, built with webpack4.x, compile faster and smart, make work easier.",
    "icons": [
      {
        "src": "./_assets/icons/32.png",
        "sizes": "32x32",
        "type": "image/png"
      }
    ],
    ...
  }

使用 link 標(biāo)簽將 manifest.json 部署到 PWA 站點(diǎn) HTML 頁面的頭部,如下所示:

參數(shù)解釋:

name: {string} 應(yīng)用名稱,用于安裝橫幅、啟動畫面顯示
short_name: {string} 應(yīng)用短名稱,用于主屏幕顯示
icons: {Array.} 應(yīng)用圖標(biāo)列表
    src: {string} 圖標(biāo) url
    type {string=} 圖標(biāo)的 mime 類型,非必填項(xiàng),該字段可讓瀏覽器快速忽略掉不支持的圖標(biāo)類型
    sizes {string} 圖標(biāo)尺寸,格式為widthxheight,寬高數(shù)值以 css 的 px 為單位。如果需要填寫多個(gè)尺寸,則使用空格進(jìn)行間隔,如"48x48 96x96 128x128"
start_url: {string=} 應(yīng)用啟動地址
scope: {string} 作用域
    // scope 應(yīng)遵循如下規(guī)則:

    //如果沒有在 manifest 中設(shè)置 scope,則默認(rèn)的作用域?yàn)?manifest.json 所在文件夾;
    //scope 可以設(shè)置為 ../ 或者更高層級的路徑來擴(kuò)大PWA的作用域;
    //start_url 必須在作用域范圍內(nèi);
    //如果 start_url 為相對地址,其根路徑受 scope 所影響;
    //如果 start_url 為絕對地址(以 / 開頭),則該地址將永遠(yuǎn)以 / 作為根地址;
background_color: {Color} css色值 可以指定啟動畫面的背景顏色。
display: {string} 顯示類型
    //fullscreen    應(yīng)用的顯示界面將占滿整個(gè)屏幕    
    //standalone    瀏覽器相關(guān)UI(如導(dǎo)航欄、工具欄等)將會被隱藏
    //minimal-ui    顯示形式與standalone類似,瀏覽器相關(guān)UI會最小化為一個(gè)按鈕,不同瀏覽器在實(shí)現(xiàn)上略有不同
    //browser    瀏覽器模式,與普通網(wǎng)頁在瀏覽器中打開的顯示一致
orientation: string 應(yīng)用顯示方向
    //orientation屬性的值有以下幾種:
    //landscape-primary
    //landscape-secondary
    //landscape
    //portrait-primary
    //portrait-secondary
    //portrait
    //natural
    //any
theme_color: {Color} // css色值theme_color 屬性可以指定 PWA 的主題顏色??梢酝ㄟ^該屬性來控制瀏覽器 UI 的顏色。比如 PWA 啟動畫面上狀態(tài)欄、內(nèi)容頁中狀態(tài)欄、地址欄的顏色,會被 theme_color 所影響。
related_applications: Array. 關(guān)聯(lián)應(yīng)用列表 可以引導(dǎo)用戶下載原生應(yīng)用
    platform: {string} 應(yīng)用平臺
    id: {string} 應(yīng)用id
Push Notifications

我們都是通知就是在我們設(shè)備上彈出的消息。通知可以是本地觸發(fā)的,也可以是服務(wù)器推送的,而且我們的應(yīng)用當(dāng)時(shí)并沒有運(yùn)行。消息推送可以使App的更新提醒,也可能是我們感興趣的內(nèi)容。

當(dāng)我們的web可以實(shí)現(xiàn)push的時(shí)候,web的體驗(yàn)就里Native APP更近一步了。

Push Notifications 由兩個(gè)API構(gòu)成:

Notifications API 用來顯示系統(tǒng)的通知

Push API 用來處理Server下發(fā)的push消息

這兩個(gè)API都是建立在在Service Worker API基礎(chǔ)上的,Service Worker 在后臺響應(yīng)推送消息時(shí)間,并把他們傳遞給應(yīng)用。

Notification
獲取許可

在創(chuàng)建通知之前,應(yīng)該先獲取用戶的許可:

// main.js
Notification.requestPermission(function(status) {
    console.log("Notification permission status:", status);
    //status 會有三個(gè)取值default granted denied 分別代表: 默認(rèn)值(每次訪問頁面都詢問)、 允許、拒絕
});
添加通知

獲取到用戶的許可之后,就可以通過 showNotification()方法來限制主應(yīng)用程序的通知。

// main.js
function displayNotification() {
  if (Notification.permission == "granted") {
    navigator.serviceWorker.getRegistration().then(function(reg) {
      reg.showNotification("Hello world!");
    });
  }
}

要注意showNotification,在Service Woker注冊對象上調(diào)用該方法。將在活動Service Worker上創(chuàng)建通知,以便監(jiān)聽與通知交互觸發(fā)的事件。

showNotification方法有可選項(xiàng)參數(shù)options,用于配置通知。

// main.js
function displayNotification() {
  if (Notification.permission == "granted") {
    navigator.serviceWorker.getRegistration().then(function(reg) {
      var options = {
        body: "Here is a notification body!", // 對通知添加描述
        icon: "images/example.png", // 添加一個(gè)icon圖像
        vibrate: [100, 50, 100], // 指定通知的電話振動模式,手機(jī)將振動100ms,暫停50ms,再次振動100ms
        data: {
          dateOfArrival: Date.now(),
          primaryKey: 1
        }, // 給通知添加自定義數(shù)據(jù),當(dāng)監(jiān)聽到通知的時(shí)候,可以捕獲到這些數(shù)據(jù),方便使用。
        actions: [
          {action: "explore", title: "Explore this new world",
            icon: "images/checkmark.png"},
          {action: "close", title: "Close notification",
            icon: "images/xmark.png"},
        ] // 自定義的操作
     };
      reg.showNotification("Hello world!", options);
    });
  }
}
監(jiān)聽事件

用戶收到通知之后,通過對通知的操作,就會觸發(fā)監(jiān)聽的Notifications的相關(guān)事件,比如在關(guān)閉通知的時(shí)候就會有notificationclose事件。

// service-worker.js
self.addEventListener("notificationclick", function(e) {
  var notification = e.notification;
  var primaryKey = notification.data.primaryKey;
  var action = e.action;

  if (action === "close") {
    notification.close();
  } else {
    clients.openWindow("http://www.example.com");
    notification.close();
  }
});
Push

通知操作要結(jié)合push,才能實(shí)現(xiàn)與用戶的交互,主動通知、提醒用戶

Push service

每個(gè)瀏覽器都有一個(gè)push service(推送服務(wù)),當(dāng)用戶授權(quán)當(dāng)前網(wǎng)站的push權(quán)限的時(shí)候,就可以將當(dāng)前網(wǎng)站訂閱到瀏覽器的push service。這就會創(chuàng)建一個(gè)訂約對象,其中包含推送服務(wù)的endpoint和公鑰(keys)。當(dāng)下發(fā)push消息的時(shí)候,就會發(fā)送到endpoint這個(gè)URL,并用公鑰進(jìn)行加密,push service就會發(fā)送到正確的客戶端。

推送服務(wù)如何知道將消息發(fā)送到哪個(gè)客戶端?端點(diǎn)URL包含唯一標(biāo)識符。此標(biāo)識符用于路由您發(fā)送到正確設(shè)備的消息,并在瀏覽器處理時(shí)標(biāo)識應(yīng)處理請求的Service Worker。

推送通知和Service Worker是匹配工作的,所以要求推送通知也必須是HTTPS,這就確保了服務(wù)器和push service之間通信是安全的,并且從push service到用戶也是安全的。

但是,HTTPS不能確保push service本身是安全的。我們必須確保從服務(wù)器發(fā)送到客戶端的數(shù)據(jù)不會被任何第三方篡改或直接檢查。所以必須加密服務(wù)器上的消息。

整個(gè)發(fā)送接收展示的過程

在客戶端:

1.訂閱推送服務(wù)

2.將訂閱對象發(fā)送到服務(wù)器

在服務(wù)器:

1.生成給用戶下發(fā)的數(shù)據(jù)

2.使用用戶的公鑰加密數(shù)據(jù)

3.使用加密數(shù)據(jù)的有效負(fù)載將數(shù)據(jù)發(fā)送的endpoint URL

消息將路由到用戶的設(shè)備。喚醒瀏覽器,找到正確的Service Worker并調(diào)用推送事件。

1.在推送事件中接收消息數(shù)據(jù)(如果有)

2.在推送事件中執(zhí)行自定義邏輯

3.顯示通知

處理推送事件

當(dāng)支持推送消息的瀏覽器收到消息時(shí),它會向Service Worker發(fā)送一個(gè)push事件。我們可以在Service Worker中創(chuàng)建一個(gè) push事件監(jiān)聽器來處理消息:

// service-worker.js

self.addEventListener("push", function(e) {
  var options = {
    body: "This notification was generated from a push!",
    icon: "images/example.png",
    vibrate: [100, 50, 100],
    data: {
      dateOfArrival: Date.now(),
      primaryKey: "2"
    },
    actions: [
      {action: "explore", title: "Explore this new world",
        icon: "images/checkmark.png"},
      {action: "close", title: "Close",
        icon: "images/xmark.png"},
    ]
  };
  e.waitUntil(
    self.registration.showNotification("Hello world!", options)
  );
});

與之前不同的地方就是,這里監(jiān)聽的是push事件,之前是notification事件,并且,這里用了event.waitUntil方法來延長push事件的生命周期,到showNotification異步操作執(zhí)行完成。

訂閱推送通知

在發(fā)送推送消息之前,我們必須首先訂閱推送服務(wù)。訂閱返回訂閱對象或者是一個(gè)subscription。它是整個(gè)過程中很關(guān)鍵一個(gè)部分,我們才能知道push發(fā)送到哪里。

// main.js
//檢查是否訂閱了
    if ("serviceWorker" in navigator) {
        navigator.serviceWorker.register("sw.js").then(function (reg) {
                console.log("Service Worker Registered!", reg);

                reg.pushManager.getSubscription().then(function (sub) {
                    if (sub === null) {
                        // Update UI to ask user to register for Push
                        console.log("Not subscribed to push service!");
                    } else {
                        // We have a subscription, update the database
                        console.log("Subscription object: ", sub);
                    }
                });
            })
            .catch(function (err) {
                console.log("Service Worker registration failed: ", err);
            });
    }

    function subscribeUser() {
        if ("serviceWorker" in navigator) {
            navigator.serviceWorker.ready.then(function (reg) {

                reg.pushManager.subscribe({
                    userVisibleOnly: true
                }).then(function (sub) {
                    console.log("Endpoint URL: ", sub.endpoint);
                }).catch(function (e) {
                    if (Notification.permission === "denied") {
                        console.warn("Permission for notifications was denied");
                    } else {
                        console.error("Unable to subscribe to push", e);
                    }
                });
            })
        }
    }
Web推送協(xié)議

Web Push協(xié)議是發(fā)送發(fā)往瀏覽器的推送消息的正式標(biāo)準(zhǔn)。它描述了如何創(chuàng)建推送消息,加密推送消息并將其發(fā)送到推送消息傳遞平臺的結(jié)構(gòu)和流程。該協(xié)議抽象出用戶具有哪個(gè)消息傳遞平臺和瀏覽器的細(xì)節(jié)。

Web Push協(xié)議很復(fù)雜,但我們不需要了解所有細(xì)節(jié)。瀏覽器自動負(fù)責(zé)使用推送服務(wù)訂閱用戶。作為開發(fā)人員,我們的工作是獲取訂閱令牌,提取URL并向那里發(fā)送消息。

{"endpoint":"https://fcm.googleapis.com/fcm/send/dpH5lCsTSSM:APA91bHqjZxM0VImWWqDRN7U0a3AycjUf4O-byuxb_wJsKRaKvV_iKw56s16ekq6FUqoCF7k2nICUpd8fHPxVTgqLunFeVeB9lLCQZyohyAztTH8ZQL9WCxKpA6dvTG_TUIhQUFq_n",
"keys": {
    "p256dh":"BLQELIDm-6b9Bl07YrEuXJ4BL_YBVQ0dvt9NQGGJxIQidJWHPNa9YrouvcQ9d7_MqzvGS9Alz60SZNCG3qfpk=",
    "auth":"4vQK-SvRAN5eo-8ASlrwA=="
    }
}

通常用VSPID身份驗(yàn)證來識別身份。
直接上一個(gè)例子,客戶端生成

//main.js
    var endpoint;
    var key;
    var authSecret;

    // We need to convert the VAPID key to a base64 string when we subscribe
    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;
    }

    function determineAppServerKey() {
      var vapidPublicKey = "BAyb_WgaR0L0pODaR7wWkxJi__tWbM1MPBymyRDFEGjtDCWeRYS9EF7yGoCHLdHJi6hikYdg4MuYaK0XoD0qnoY";
      return urlBase64ToUint8Array(vapidPublicKey);
    }

    if ("serviceWorker" in navigator) {
      navigator.serviceWorker.register("sw.js").then(function (registration) {

        return registration.pushManager.getSubscription()
          .then(function (subscription) {

            if (subscription) {
              // We already have a subscription, let"s not add them again
              return;
            }

            return registration.pushManager.subscribe({
                userVisibleOnly: true,
                applicationServerKey: determineAppServerKey()
              })
              .then(function (subscription) {

                var rawKey = subscription.getKey ? subscription.getKey("p256dh") : "";
                key = rawKey ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawKey))) : "";
                var rawAuthSecret = subscription.getKey ? subscription.getKey("auth") : "";
                authSecret = rawAuthSecret ?
                  btoa(String.fromCharCode.apply(null, new Uint8Array(rawAuthSecret))) : "";

                endpoint = subscription.endpoint;

                return fetch("http://localhost:3111/register", {
                  method: "post",
                  headers: new Headers({
                    "content-type": "application/json"
                  }),
                  body: JSON.stringify({
                    endpoint: subscription.endpoint,
                    key: key,
                    authSecret: authSecret,
                  }),
                })

              });
          });
      }).catch(function (err) {
        // registration failed :(
        console.log("ServiceWorker registration failed: ", err);
      });
    }
  
// server.js

const webpush = require("web-push");
const express = require("express");
var bodyParser = require("body-parser");
var path = require("path");
const app = express();

// Express setup
app.use(express.static("public"));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({     // to support URL-encoded bodies
  extended: true
}));

function saveRegistrationDetails(endpoint, key, authSecret) {
  // Save the users details in a DB
}

webpush.setVapidDetails(
  "mailto:contact@deanhume.com",
  "BAyb_WgaR0L0pODaR7wWkxJi__tWbM1MPBymyRDFEGjtDCWeRYS9EF7yGoCHLdHJi6hikYdg4MuYaK0XoD0qnoY",
  "p6YVD7t8HkABoez1CvVJ5bl7BnEdKUu5bSyVjyxMBh0"
);

// Send a message
app.post("/sendMessage", function (req, res) {

  var endpoint = req.body.endpoint;
  var authSecret = req.body.authSecret;
  var key = req.body.key;

  const pushSubscription = {
    endpoint: req.body.endpoint,
    keys: {
      auth: authSecret,
      p256dh: key
    }
  };

  var body = "Breaking News: Nose picking ban for Manila police";
  var iconUrl = "https://raw.githubusercontent.com/deanhume/progressive-web-apps-book/master/chapter-6/push-notifications/public/images/homescreen.png";

  webpush.sendNotification(pushSubscription,
    JSON.stringify({
      msg: body,
      url: "http://localhost:3111/article?id=1",
      icon: iconUrl,
      type: "actionMessage"
    }))
    .then(result => {
      console.log(result);
      res.sendStatus(201);
    })
    .catch(err => {
      console.log(err);
    });
});

// Register the user
app.post("/register", function (req, res) {

  var endpoint = req.body.endpoint;
  var authSecret = req.body.authSecret;
  var key = req.body.key;

  // Store the users registration details
  saveRegistrationDetails(endpoint, key, authSecret);

  const pushSubscription = {
    endpoint: req.body.endpoint,
    keys: {
      auth: authSecret,
      p256dh: key
    }
  };

  var body = "Thank you for registering";
  var iconUrl = "/images/homescreen.png";

  webpush.sendNotification(pushSubscription,
    JSON.stringify({
      msg: body,
      url: "https://localhost:3111",
      icon: iconUrl,
      type: "register"
    }))
    .then(result => {
      console.log(result);
      res.sendStatus(201);
    })
    .catch(err => {
      console.log(err);
    });

});

// The server
app.listen(3111, function () {
  console.log("Example app listening on port 3111!")
});

后面再多帶帶寫一篇文章詳細(xì)說整個(gè)push過程。

也可以看先Google給出的教程描述https://developers.google.com/web/ilt/pwa/introduction-to-push-notifications#push_api

參考

Progressive Web Apps Training

App Shell

Service Workers: an Introduction

MDN Progressive web apps

MDN WorkerGlobalScope [1]

The Service Worker Lifecycle

W3C IndexedDB API 3.0

Introduction to Push Notifications

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/97882.html

相關(guān)文章

  • PWA學(xué)習(xí)與實(shí)踐】(1) 2018,開始你的PWA學(xué)習(xí)之旅

    摘要:學(xué)習(xí)與實(shí)踐系列文章已整理至學(xué)習(xí)手冊,文字內(nèi)容已同步至。本系列文章學(xué)習(xí)與實(shí)踐會逐步拆解背后的各項(xiàng)技術(shù),通過實(shí)例代碼來講解這些技術(shù)的應(yīng)用方式。而隨著在中也開始支持其中的某些技術(shù),的舞臺更大了。這個(gè)最開始是不具備任何的能力。 《PWA學(xué)習(xí)與實(shí)踐》系列文章已整理至gitbook - PWA學(xué)習(xí)手冊,文字內(nèi)容已同步至learning-pwa-ebook。轉(zhuǎn)載請注明作者與出處。 PWA作為今年最火...

    blastz 評論0 收藏0
  • 前端每周清單半年盤點(diǎn)之 PWA

    摘要:前端每周清單專注前端領(lǐng)域內(nèi)容,以對外文資料的搜集為主,幫助開發(fā)者了解一周前端熱點(diǎn)分為新聞熱點(diǎn)開發(fā)教程工程實(shí)踐深度閱讀開源項(xiàng)目巔峰人生等欄目。 前端每周清單專注前端領(lǐng)域內(nèi)容,以對外文資料的搜集為主,幫助開發(fā)者了解一周前端熱點(diǎn);分為新聞熱點(diǎn)、開發(fā)教程、工程實(shí)踐、深度閱讀、開源項(xiàng)目、巔峰人生等欄目。歡迎關(guān)注【前端之巔】微信公眾號(ID:frontshow),及時(shí)獲取前端每周清單;本文則是對于...

    崔曉明 評論0 收藏0
  • Service Worker學(xué)習(xí)與實(shí)踐(二)——PWA簡介

    摘要:簡稱,是提升的體驗(yàn)的一種新方法,能給用戶原生應(yīng)用的體驗(yàn)。當(dāng)網(wǎng)站以這種方式啟動時(shí)它具有唯一的圖標(biāo)和名稱,以便用戶將其與其他網(wǎng)站區(qū)分開來。表示啟動時(shí)的方向,橫屏豎屏等,具體參數(shù)值可參考文檔。下一篇文章中,主要講述在實(shí)踐中的重要能力。 這周,Chrome 70正式版本發(fā)布,Progressive Web Apps(PWA)已經(jīng)正式支持到Windows 10平臺,然而,早在前幾個(gè)版本之前,Ch...

    KavenFan 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<