如何使用推送通知將 WebApp 轉換為 PWA

已發表: 2022-03-20

在本文中,我們將了解如何使用 Firebase 雲消息傳遞將 Web 應用程序或網站轉換為帶有推送通知的 PWA。

在現代世界中,大多數 Web 應用程序正在轉換為 PWA(漸進式 Web 應用程序),因為它提供了離線支持、推送通知、後台同步等功能。 PWA 功能使我們的 Web 應用程序更像原生應用程序,並提供豐富的用戶體驗。

例如,像 Twitter 和亞馬遜這樣的大公司已經將他們的 Web 應用程序轉換為 PWA 以提高用戶參與度。

什麼是 PWA?

PWA = (Web App) + (一些原生應用功能)

PWA 是您的同一個 Web 應用程序(HTML+CSS+JS)。 它在所有瀏覽器上的工作方式與您的 Web 應用程序相同,就像以前一樣。 但是當您的網站在現代瀏覽器上加載時,它可以具有本機功能。 它使您的 Web 應用程序比以前更強大,也使其更具可擴展性,因為我們可以在前端預取和緩存資產,它減少了對後端服務器的請求。

PWA 與 Web App 有何不同

  • 安裝:您的 Web 應用可以像原生應用一樣安裝
  • 漸進式:與您的網絡應用程序相同,但具有一些本機功能
  • 原生應用體驗:一旦安裝,用戶就可以像原生應用一樣使用和導航 Web 應用。
  • 易於訪問:與我們的網絡應用程序不同,我們的用戶無需在每次訪問時都輸入網址。 安裝後,只需輕輕一按即可打開。
  • 應用程序緩存:在 PWA 之前,我們的 Web 應用程序實現的唯一緩存機制是使用僅對瀏覽器可用的 HTTP 緩存。 但是使用 PWA,我們可以使用 Web 應用程序中不可用的客戶端代碼本身來緩存內容。
  • (App/Play) 商店發布PWA 可以在 Google Play Store 和 IOS App Store 發布。

將您的應用程序轉換為 PWA 只會使其更強大。

為什麼企業應該考慮 PWA

雖然我們的大多數客戶聯繫我們並要求首先開發 Web App 解決方案,然後他們要求 Android 和 iOS 應用程序。 我們要做的就是由一個單獨的團隊在 web 應用程序中構建與 Android/IOS 應用程序相同的功能,這需要更多的開發成本和更多的上市時間。

但是有些客戶的預算有限,或者有些客戶可能認為上市時間對他們的產品更重要。

PWA 功能本身可以滿足大多數客戶端需求。 對於他們,我們只建議 PWA,如果他們想在 Playstore 中部署,我們建議他們使用 TWA 將他們的 PWA 轉換為 Android 應用程序。

如果您的需求確實需要 PWA 無法滿足的原生應用程序功能。 客戶可以按照自己的意願去開發這兩個應用程序。 但即使在那種情況下。 他們可以在 Play 商店中部署 PWA,直到 Android 開發完成。

示例:泰坦 Eyeplus

最初,他們開發了一個 PWA 應用程序,並使用 TWA(Trusted Web Activity)將其部署在 Play 商店中。 一旦他們完成了他們的 Android 應用程序開發。 他們在 Play 商店中部署了他們真正的 Android 應用程序。 他們使用 PWA 實現了上市時間和開發成本。

PWA 功能

PWA 為我們的 Web 應用程序提供了類似原生應用程序的功能。

主要特點是:

  • 可安裝:像本機應用程序一樣安裝的 Web 應用程序。
  • 緩存:應用程序緩存是可能的,這為我們的應用程序提供了離線支持。
  • 推送通知:可以從我們的服務器發送推送通知,以吸引我們的用戶訪問我們的網站。
  • 地理圍欄:只要設備位置發生變化,就可以通過事件通知應用程序。
  • 支付請求:在您的應用程序中啟用支付功能,並像原生應用程序一樣提供出色的用戶體驗。

未來還有更多功能。

其他特點是:

  • 快捷方式:清單文件中添加的可快速訪問的 URL。
  • Web Share API:讓您的應用程序接收來自其他應用程序的共享數據。
  • 徽章 API:在已安裝的 PWA 中顯示通知計數。
  • 定期後台同步 API:保存用戶的數據,直到它連接到網絡。
  • 聯繫人選擇器:用於從用戶的手機中選擇聯繫人。
  • 文件選擇器:用於訪問本地系統/移動設備上的文件

PWA 相對於原生應用程序的優勢

本機應用程序比 PWA 性能更好,並且比 PWA 具有更多功能。 但是,它仍然比本機應用程序具有一些優勢。

  • PWA 在 Android、IOS、桌面等跨平台上運行。
  • 它降低了您的開發成本。
  • 與本機應用程序相比,易於功能部署。
  • 易於發現,因為 PWA(網站)對 SEO 友好
  • 安全,因為它僅適用於 HTTPS

PWA 相對於原生應用程序的缺點

  • 與本機應用程序相比,可用的功能有限。
  • PWA 功能不保證支持所有設備。
  • PWA 的品牌知名度很低,因為它在應用商店或 Play 商店中不可用。

您可以使用 android Trusted Web Activity (TWA) 在 Play 商店中將 PWA 部署為 Android 應用程序。 這將有助於您的品牌推廣。

將 Web App 轉換為 PWA 所需的東西

用於將任何 Web 應用程序或網站轉換為 PWA。

  • Service-Worker:任何用於緩存、推送通知的 PWA 應用程序的核心,是我們請求的代理。
  • 清單文件:它包含有關您的 Web 應用程序的詳細信息。 它曾經像在主屏幕上下載我們的應用程序一樣下載我們的應用程序。
  • 應用程序徽標:應用程序圖標的高質量圖像 512 x 512 像素。 PWA 在主屏幕、啟動屏幕等上需要應用徽標。因此我們必須使用任何工具為我們的 APP 創建一組 1:1 比例的圖像。
  • 響應式設計:Web 應用程序應該能夠響應不同屏幕尺寸的工作。

什麼是服務工作者:

服務工作者(客戶端腳本)是您的 Web 應用程序和外部之間的代理,為我們的 Web 應用程序提供推送通知並支持緩存。

Service Worker 獨立於主 javascript 運行。 所以它無法訪問 DOM API。 它只能訪問 IndexedDB API、Fetch API、Cache Storage API。 但它可以通過消息與主線程通信。

service worker 提供的服務:

  • 攔截來自您的源域的 HTTP 請求。
  • 從您的服務器接收推送通知。
  • 我們的應用程序的離線可用性

Service Worker 控制您的應用程序並可以操縱您的請求,但它獨立運行。 因此,出於這個原因,必須使用 HTTPS 啟用源域以避免中間人攻擊。

什麼是清單文件

清單文件 (manifest.json) 包含有關我們的 PWA 應用程序的詳細信息,以告知瀏覽器。

  • 名稱:應用程序的名稱
  • short_name:我們的應用程序的簡稱。 如果提供
  • 同時具有屬性名稱和短名稱,瀏覽器將採用短名稱。
  • 描述:描述我們的應用程序的描述。
  • start_url:指定我們的 PWA 啟動時應用程序的主頁。
  • 圖標:用於主屏幕等的 PWA 圖像集。
  • background_color:在我們的 PWA 應用程序中設置啟動畫面的背景顏色。
  • display:自定義我們的瀏覽器 UI 以顯示在我們的 PWA 應用程序中。
  • theme_color:PWA 應用的主題顏色。
  • 範圍:我們為 PWA 考慮的應用程序的 URL 範圍。 默認為清單文件所在的位置。
  • 快捷方式:我們的 PWA 應用程序的快速鏈接。

將 Web 應用程序轉換為 PWA

出於演示目的,我創建了一個帶有靜態文件的 Geekflare 網站文件夾結構。

  • index.html – 主頁
  • 文章/
    • index.html – 文章頁面
  • 作者/
    • index.html – 作者頁面
  • 工具/
    • index.html – 工具頁面
  • 交易/
    • index.html – 交易頁面

如果您已經有任何網站或 Web 應用程序,請嘗試按照以下步驟將其轉換為 PWA。

為 PWA 創建所需的圖像

首先,獲取您的應用程序徽標,並以 1:1 的比例將其裁剪為 5 種不同的尺寸。 我已經使用 https://tools.crawlink.com/tools/pwa-icon-generator/ 快速獲得不同的圖像尺寸。 所以你也可以使用它。

創建清單文件

其次,使用您的應用程序詳細信息為您的 Web 應用程序創建一個 manifest.json 文件。 對於演示,我為 Geekflare 網站創建了一個清單文件。

 {
	“名稱”:“Geekflare”,
	"short_name": "Geekflare",
	"description": "Geekflare 製作高質量的技術和金融文章,製作工具和 API 來幫助企業和人們成長。",
	"start_url": "/",
	“圖標”:[{
		"src": "assets/icon/icon-128x128.png",
		“尺寸”:“128x128”,
		“類型”:“圖像/png”
	}, {
		"src": "assets/icon/icon-152x152.png",
		“尺寸”:“152x152”,
		“類型”:“圖像/png”
	}, {
		"src": "assets/icon/icon-192x192.png",
		“尺寸”:“192x192”,
		“類型”:“圖像/png”
	}, {
		"src": "assets/icon/icon-384x384.png",
		“尺寸”:“384x384”,
		“類型”:“圖像/png”
	}, {
		"src": "assets/icon/icon-512x512.png",
		“尺寸”:“512x512”,
		“類型”:“圖像/png”
	}],
	"background_color": "#EDF2F4",
	“顯示”:“獨立”,
	"theme_color": "#B20422",
	“範圍”: ”/”,
	“捷徑”:[{
			“名稱”:“文章”,
			"short_name": "文章",
			"description": "1595 篇關於安全、系統管理員、數字營銷、雲計算、開發和許多其他主題的文章。",
			“網址”:“/文章”,
			“圖標”:[{
				"src": "/assets/icon/icon-152x152.png",
				“尺寸”:“152x152”
			}]
		},
		{
			“名稱”:“作者”,
			"short_name": "作者",
			"description": "Geekflare - 作者",
			“網址”:“/作者”,
			“圖標”:[{
				"src": "/assets/icon/icon-152x152.png",
				“尺寸”:“152x152”
			}]
		},
		{
			“名稱”:“工具”,
			"short_name": "工具",
			"description": "Geekflare - 工具",
			“網址”:“/工具”,
			“圖標”:[{
				"src": "/assets/icon/icon-152x152.png",
				“尺寸”:“152x152”
			}]
		},
		{
			“名稱”:“交易”,
			"short_name": "交易",
			"description": "Geekflare - 優惠",
			“網址”:“/交易”,
			“圖標”:[{
				"src": "/assets/icon/icon-152x152.png",
				“尺寸”:“152x152”
			}]
		}
	]
}

註冊服務工作者

在根文件夾中創建腳本文件 register-service-worker.js 和 service-worker.js。

第一個,register-service-worker.js 是 javascript 文件,將在可以訪問 DOM API 的主線程上運行。 但是 service-worker.js 是一個獨立於主線程運行的 service worker 腳本,它的生命週期也很短。 每當事件調用服務工作者時它就會運行並運行直到它完成該過程。

通過檢查主線程 javascript 文件,您可以檢查服務工作者是否在其中註冊。 如果沒有,您可以註冊服務工作者腳本(service-worker.js)。

將以下代碼段粘貼到 register-service-worker.js 中:

 if ('serviceWorker' in navigator) {
    window.addEventListener('load', function() {
        navigator.serviceWorker.register('/service-worker.js');
    });
}

將以下代碼段粘貼到 service-worker.js

 self.addEventListener('install', (event) => { // service worker 安裝時的事件
    console.log('安裝',事件);
    self.skipWaiting();
});

self.addEventListener('activate', (event) => { // service worker 激活時的事件
    console.log('激活',事件);
    返回 self.clients.claim();
});

self.addEventListener('fetch', function(event) { // HTTP 請求攔截器
    event.respondWith(fetch(event.request)); // 發送所有 http 請求,沒有任何緩存邏輯
    /*event.respondWith(
        caches.match(event.request).then(function(response) {
            返迴響應 || 獲取(事件。請求);
        })
    );*/ // 緩存新請求。 如果已經在緩存中,則與緩存一起使用。
});

我們沒有專注於如何啟用緩存以支持離線支持。 我們只討論如何將 Web 應用程序轉換為 PWA。

在 HTML 頁面的 all head 標籤中添加清單文件和腳本。

 <link rel="manifest" href="/manifest.json">
<script src="/register-service-worker.js"></script>

添加後刷新頁面。 現在您可以在移動 chrome 上安裝您的應用程序,如下所示。

在 android chrome 中安裝 PWA

在主屏幕上,應用程序被添加。

chrome中的pWA快捷方式

如果您使用的是 WordPress。 嘗試使用現有的 PWA 轉換器插件。 對於 vueJS 或 reactJS,您可以按照上述方法或使用現有的 PWA npm 模塊來加快您的開發速度。 因為 PWA npm 模塊已經啟用了離線支持緩存等。

啟用推送通知

Web 推送通知被發送到瀏覽器,以使我們的用戶更頻繁地與我們的應用程序互動/互動。 我們可以通過使用啟用它

  • Notification API:用於配置我們的推送通知應該如何顯示給用戶。
  • Push API:用於接收從我們的服務器發送到瀏覽器的通知消息。

在我們的應用程序中啟用推送通知的第一步是檢查通知 API 並從用戶那裡獲得顯示通知的權限。 對於該複製並將下面的代碼段粘貼到您的 register-service-worker.js 中。

 if ('Notification' in window && Notification.permission != 'granted') {
    console.log('詢問用戶權限')
    Notification.requestPermission(狀態 => {  
        console.log('狀態:'+狀態)
        displayNotification('通知已啟用');
    });
}


常量 displayNotification = notificationTitle => {
    console.log('顯示通知')
    if (Notification.permission == 'granted') {
        navigator.serviceWorker.getRegistration().then(reg => {
            控制台日誌(註冊)
            常量選項 = {
                    body: '感謝允許推送通知!',
                    圖標:'/assets/icons/icon-512x512.png',
                    振動:[100, 50, 100],
                    數據: {
                      dateOfArrival: Date.now(),
                      主鍵:0
                    }
                  };
    
            reg.showNotification(通知標題,選項);
        });
    }
};

如果一切順利。 您將收到來自應用程序的通知。

pwa 通知 api 權限
pwa-通知-api-顯示-通知

窗口中的“通知”將告訴我們該瀏覽器支持通知 API。 Notification.permission將告訴用戶已被允許顯示通知。 如果用戶允許我們的應用程序,則該值將被“授予”。 如果用戶拒絕了該值,則該值將被“阻止”。

啟用 Firebase 雲消息傳遞並創建訂閱

現在真正的部分開始了。 為了從您的服務器向用戶推送通知,我們需要為每個用戶提供一個唯一的端點/訂閱。 為此,我們將使用 firebase 雲消息傳遞。

第一步,通過訪問此鏈接 https://firebase.google.com/ 創建一個 Firebase 帳戶,然後按開始。

  1. 使用名稱創建一個新項目,然後按繼續。 我將使用名稱 Geekflare 創建它。
  2. 在下一步中,默認情況下啟用 Google Analytics。 您可以切換我們現在不需要它,然後按繼續。 如果需要,您可以稍後在 Firebase 控制台中啟用它。
  3. 創建項目後,它將如下所示。
Firebase 控制台

然後轉到項目設置並單擊雲消息傳遞並生成密鑰。

firebase 雲消息密鑰生成

通過上述步驟,您獲得了 3 個密鑰。

  • 項目服務器密鑰
  • Web 推送證書私鑰
  • 網絡推送證書公鑰

現在將以下代碼段粘貼到 register-service-worker.js 中:

 常量 updateSubscriptionOnYourServer = 訂閱 => {
    console.log('在此處編寫您的 ajax 代碼以將用戶訂閱保存在您的數據庫中', subscription);
    // 使用 fetch、jquery、axios 編寫自己的 ajax 請求方法,將訂閱保存在服務器中以備後用。
};

const subscribeUser = async () => {
    const swRegistration = 等待 navigator.serviceWorker.getRegistration();
    常量 applicationServerPublicKey = 'BOcTIipY07N4Y63Y-9r7NMoJHofmCzn3Pu9g-LMsgIMGH4HVr42_LW9ia0lMr68TsTLKS3UcdkE3IcC52hJDYsY'; // 粘貼你的 webpush 證書公鑰
    常量 applicationServerKey = urlB64ToUint8Array(applicationServerPublicKey);
    swRegistration.pushManager.subscribe({
      userVisibleOnly:真,
      應用服務器密鑰
    })
    .then((訂閱) => {
        console.log('用戶新訂閱:', subscription);
        updateSubscriptionOnServer(訂閱);
    })
    .catch((錯誤) => {
        if (Notification.permission === '拒絕') {
          console.warn('通知權限被拒絕')
        } 別的 {
          console.error('訂閱用戶失敗:', err)
        }
    });
};
常量 urlB64ToUint8Array = (base64String) => {
    const padding = '='.repeat((4 - base64String.length % 4) % 4)
    const base64 = (base64String + padding)
        .replace(/\-/g, '+')
        .replace(/_/g, '/')

    常量 rawData = window.atob(base64);
    常量 outputArray = new Uint8Array(rawData.length);

    for (讓 i = 0; i < rawData.length; ++i) {
        outputArray[i] = rawData.charCodeAt(i);
    }
    返回輸出數組;
};

const checkSubscription = async () => {
    const swRegistration = 等待 navigator.serviceWorker.getRegistration();
    swRegistration.pushManager.getSubscription()
    .then(訂閱 => {
        如果(!!訂閱){
            console.log('用戶已訂閱');
            updateSubscriptionOnYourServer(訂閱);
        } 別的 {
            console.log('用戶未訂閱。新訂閱用戶');
            訂閱用戶();
        }
    });
};

檢查訂閱();

將以下代碼段粘貼到 service-worker.js 中。

 self.addEventListener('push', (event) => {
  常量 json = JSON.parse(event.data.text())
  console.log('推送數據', event.data.text())
  self.registration.showNotification(json.header, json.options)
});

現在全部設置在前端。 通過使用訂閱,您可以隨時向您的用戶發送推送通知,直到他們沒有被拒絕推送服務。

從 node.js 後端推送

您可以使用 web-push npm 模塊使其更容易。

從 nodeJS 服務器發送推送通知的示例片段。

 常量 webPush = 要求('web-push');
    // pushSubscription 只不過是您從前端發送的訂閱以將其保存在數據庫中
    const pushSubscription = {"endpoint":"https://updates.push.services.mozilla.com/wpush/v2/gAAAAABh2…E0mTFsHtUqaye8UCoLBq8sHCgo2IC7UaafhjGmVCG_SCdhZ9Z88uGj-uwMcg","keys":{"auth":"qX6AMD5JWbu41cFWE3Lk8w","p2 :"BLxHw0IMtBMzOHnXgPxxMgSYXxwzJPxpgR8KmAbMMe1-eOudcIcUTVw0QvrC5gWOhZs-yzDa4yKooqSnM3rnx7Y"}};
    //你的網絡證書公鑰
    常量 vapidPublicKey = 'BOcTIipY07N4Y63Y-9r7NMoJHofmCzn3Pu9g-LMsgIMGH4HVr42_LW9ia0lMr68TsTLKS3UcdkE3IcC52hJDYsY';
    //你的網絡證書私鑰
    const vapidPrivateKey = '網絡證書私鑰';

    var 有效負載 = JSON.stringify({
      “選項”: {
        "body": "後端 PWA 推送通知測試",
        "徽章": "/assets/icon/icon-152x152.png",
        "icon": "/assets/icon/icon-152x152.png",
        “振動”:[100, 50, 100],
        “數據”: {
          “id”:“458”,
        },
        “行動”:[{
          “動作”:“視圖”,
          “標題”:“視圖”
        }, {
          “動作”:“關閉”,
          “標題”:“關閉”
        }]
      },
      "header": "來自 Geekflare-PWA 演示的通知"
    });

    變量選項 = {
      虛無細節:{
        主題:'mailto:[電子郵件保護]',
        公鑰:vapidPublicKey,
        私鑰:vapidPrivateKey
      },
      生存時間:60
    };

    webPush.sendNotification(
      推送訂閱,
      有效載荷,
      選項
    ).then(數據 => {
      return res.json({status : true, message : '通知發送'});
    }).catch(錯誤 => {
      返回 res.json({status : false, message : err });
    });

上面的代碼將向訂閱發送推送通知。 service-worker 中的推送事件將被觸發。

從 PHP 後端推送

對於 PHP 後端,您可以使用 web-push-php 作曲家包。 檢查示例代碼以發送下面的推送通知。

 <?php if ( !defined('BASEPATH')) exit('不允許直接腳本訪問');

需要 __DIR__.'/../vendor/autoload.php';
使用 Minishlink\WebPush\WebPush;
使用 Minishlink\WebPush\Subscription;

// 訂閱存儲在數據庫中
$subsrciptionJson = '{"endpoint":"https://updates.push.services.mozilla.com/wpush/v2/gAAAAABh2…E0mTFsHtUqaye8UCoLBq8sHCgo2IC7UaafhjGmVCG_SCdhZ9Z88uGj-uwMcg","keys":{"auth":"qX6AMD5JWbu41cFWE3L8"p526dh8 ":"BLxHw0IMtBMzOHnXgPxxMgSYXxwzJPxpgR8KmAbMMe1-eOudcIcUTVw0QvrC5gWOhZs-yzDa4yKooqSnM3rnx7Y"}}';
$payloadData = 數組 (
'選項' => 數組 (
                'body' => '後端的 PWA 推送通知測試',
                '徽章' => '/assets/icon/icon-152x152.png',
                '圖標' => '/assets/icon/icon-152x152.png',
                '振動' => 
                大批 (
                  0 => 100,
                  1 => 50,
                  2 => 100,
                ),
                '數據' => 
                大批 (
                  'id' => '458',
                ),
                '行動' => 
                大批 (
                  0 => 
                  大批 (
                    '動作' => '視圖',
                    '標題' => '視圖',
                  ),
                  1 => 
                  大批 (
                    '動作' => '關閉',
                    '標題' => '關閉',
                  ),
                ),
),
'header' => '來自 Geekflare-PWA Demo 的通知',
);

// 認證
$身份驗證 = [
    'GCM' => 'your project private-key', // 已棄用且可選,此處僅出於兼容性原因
    'VAPID' => [
        'subject' => 'mailto:[email protected]', // 可以是 mailto: 或您的網站地址
        'publicKey' => 'BOcTIipY07N4Y63Y-9r7NMoJHofmCzn3Pu9g-LMsgIMGH4HVr42_LW9ia0lMr68TsTLKS3UcdkE3IcC52hJDYsY', //(推薦)以 Base64-URL 編碼的未壓縮公鑰 P-256
        'privateKey' => 'your web-certificate private-key', //(推薦)實際上是 Base64-URL 中編碼的私鑰的秘密乘數
    ],
];

$webPush = 新的 WebPush($auth);

$subsrciptionData = json_decode($subsrciptionJson,true);


// 網絡推送 6.0
$webPush->sendOneNotification(
  訂閱::create($subsrciptionData),
  json_encode($payloadData) // 可選(默認為空)
);

結論

我希望這能讓您對將 Web 應用程序轉換為 PWA 有所了解。 您可以在此處查看本文的源代碼並在此處進行演示。 我也在示例代碼的幫助下通過從後端發送推送通知來測試推送通知。