如何将WebApp转换为具有推送通知功能的PWA
在这篇文章中,我们将看到如何使用Firebase Cloud Messaging将Web应用程序或网站转换为PWA,并使用推送通知。
在现代世界中,大多数Web应用程序都在转换为PWA(渐进式Web应用程序),因为它提供了离线支持、push notification和后台同步等功能。PWA的特性使得我们的Web应用程序更像一个原生应用程序,并提供了丰富的用户体验。
例如,像Twitter和Amazon这样的大公司已经将他们的Web应用程序转换为PWA以获得更多的用户参与度。
PWA是什么?
PWA = (Web应用程序) + (一些原生应用程序功能)
PWA是您的Web应用程序(HTML+CSS+JS)。它在所有浏览器上的工作方式与以前相同。但是当您的网站在现代浏览器上加载时,它可以具有原生功能。它使您的Web应用程序比以前更强大,也使它更可扩展,因为我们可以在前端预取和缓存资产,从而减少对后端服务器的请求。
PWA与Web应用程序的不同之处
- 可安装:您的Web应用程序可以像原生应用程序一样安装
- 渐进式:与您的Web应用程序相同,但具有一些原生功能
- 原生应用体验:用户可以像使用原生应用一样使用和导航Web应用程序
- 易于访问:与我们的Web应用程序不同,用户无需每次访问时键入网址。一旦安装,只需轻轻一按即可打开。
- 应用程序缓存:在PWA之前,我们的Web应用程序仅通过使用仅对浏览器可用的HTTP缓存机制来实现缓存。但是通过PWA,我们可以使用客户端代码自身来缓存东西,这在Web应用程序中是不可用的。
- (应用/商店)发布:PWA可以在Google Play商店和iOS应用商店发布。
将您的应用程序转换为PWA只会使其更强大。
为什么企业应该考虑PWA
尽管大多数客户都联系我们并要求首先开发Web应用程序解决方案,然后他们要求我们提供Android and iOS apps。我们要做的就是通过一个单独的团队在Web应用程序中构建与Android / IOS应用程序相同的功能,这需要更多的开发成本和更长的上市时间。
但是一些客户预算有限,或者一些客户可能认为时间上市对于他们的产品更重要。
大多数客户的要求可以通过PWA功能本身来满足。对于他们,我们建议仅使用PWA,并向他们提供将他们的PWA转换为使用TWA部署在Playstore中的Android应用程序的想法。
如果您的需求确实需要PWA无法满足的原生应用程序功能。客户可以按照他们的意愿并行开发两个应用程序。但是即使在这种情况下,他们也可以在Android开发完成之前将PWA部署在Play商店中。
例如:Titan Eyeplus
起初,他们开发了一个PWA应用并使用TWA(可信Web活动)将其部署在Play商店中。一旦他们完成了Android应用程序的开发,他们就在Play商店中部署了他们的真正的Android应用程序。他们通过使用PWA实现了时间上市和开发成本的双重目标。
PWA功能
PWA提供了与原生应用程序类似的功能。
主要功能包括:
- 可安装:Web应用程序可以像原生应用程序一样安装。
- 缓存:可以进行应用程序缓存,从而提供离线支持。
- 推送通知:可以从服务器向用户发送推送通知,以吸引他们访问我们的网站。
- 地理围栏:每当设备位置发生变化时,应用程序可以通过事件进行通知。
- 付款请求:在您的应用程序中启用付款,提供与原生应用程序类似的出色用户体验。
还有更多功能即将推出。
其他功能包括:
- 快捷方式:在清单文件中添加的可以快速访问的URL。
- Web Share API:让您的应用程序从其他应用程序接收共享数据。
- Badge API:在安装的PWA中显示通知计数。
- 定期后台同步API:将用户的数据保存到连接到网络的时候。
- 联系人选择器:用于从用户的移动设备中选择联系人。
- 文件选择器:用于访问本地系统/移动设备上的文件。
PWA相对于原生应用的优势
原生应用的性能比PWA好,功能也比PWA多。但是,PWA仍然具有一些优势。
- PWA可以在Android、IOS和桌面等跨平台上运行。
- 它可以降低您的开发成本。
- 与原生应用相比,功能部署更加简单。
- 易于发现,因为PWA(网站)对搜索引擎友好。
- 安全,因为它只能在链接_2上运行。
PWA相对于原生应用的劣势
- 与原生应用相比,功能有限。
- PWA的功能不能保证支持所有设备。
- PWA的品牌力较低,因为它不能在应用商店或Play商店中获得。
您可以使用Android的链接_3将PWA部署为Play商店的Android应用程序。这将有助于您的品牌推广。
将Web应用程序转换为PWA所需的内容
将任何Web应用程序或网站转换为PWA所需的内容。
- Service-Worker:任何PWA应用程序的核心,用于缓存、推送通知和代理请求。
- 清单文件:包含有关您的Web应用程序的详细信息。它用于像本机应用程序一样在主屏幕上下载我们的应用程序。
- 应用程序图标:高质量的图像512 x 512像素用于您的应用程序图标。PWA需要应用程序图标用于主屏幕、启动画面等。因此,我们必须使用任何工具为我们的应用程序创建一组1:1比例的图像。
- 响应式设计:Web应用程序应具有响应式设计,以适应不同的屏幕尺寸。
什么是Service Worker:
Service Worker(客户端脚本)是您的Web应用程序和外部环境之间的代理,用于向我们的Web应用程序提供推送通知和支持缓存。
Service Worker独立于主JavaScript运行。因此,它无法访问DOM API,只能访问link_4、link_5、link_6。但是它可以通过消息与主线程通信。
Service Worker提供的服务:
- 拦截您的源域的HTTP请求。
- 从服务器接收推送通知。
- 应用程序的离线可用性
Service Worker控制您的应用程序并可以操纵您的请求,但它是独立运行的。因此,为了避免中间人攻击,源域必须启用HTTPS。
什么是清单文件
清单文件(manifest.json)包含有关我们的PWA应用程序的详细信息,以告诉浏览器。
- name:应用程序的名称
- short_name:应用程序的简称(如果提供了name和short_name属性,则浏览器将使用short_name)
- description:描述我们的应用程序的描述
- start_url:指定我们的PWA启动时的主页
- icons:用于PWA的一组图像,用于主屏幕等
- background_color:设置PWA应用程序启动画面的背景颜色
- display:自定义我们的浏览器UI,以在我们的PWA应用程序中显示
- theme_color:PWA应用程序的主题颜色
- scope:我们的应用程序的URL范围,用于PWA的考虑。默认为清单文件所在位置。
- shortcuts:我们的PWA应用程序的快捷链接
将Web应用程序转换为PWA
为了演示目的,我创建了一个Geekflare网站的文件夹结构,其中包含静态文件。
- index.html – 主页
- articles/
- 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网站创建了一个清单文件。
{ "name": "Geekflare", "short_name": "Geekflare", "description": "Geekflare提供高质量的技术和金融文章,制作工具和API,帮助企业和个人成长。", "start_url": "/", "icons": [{ "src": "assets/icon/icon-128x128.png", "sizes": "128x128", "type": "image/png" }, { "src": "assets/icon/icon-152x152.png", "sizes": "152x152", "type": "image/png" }, { "src": "assets/icon/icon-192x192.png", "sizes": "192x192", "type": "image/png" }, { "src": "assets/icon/icon-384x384.png", "sizes": "384x384", "type": "image/png" }, { "src": "assets/icon/icon-512x512.png", "sizes": "512x512", "type": "image/png" }], "background_color": "#EDF2F4", "display": "standalone", "theme_color": "#B20422", "scope": "/", "shortcuts": [{ "name": "文章", "short_name": "文章", "description": "安全、系统管理员、数字营销、云计算、开发等1595篇文章。", "url": "/articles", "icons": [{ "src": "/assets/icon/icon-152x152.png", "sizes": "152x152" }] }, { "name": "作者", "short_name": "作者", "description": "Geekflare - 作者", "url": "/authors", "icons": [{ "src": "/assets/icon/icon-152x152.png", "sizes": "152x152" }] }, { "name": "工具", "short_name": "工具", "description": "Geekflare - 工具", "url": "/tools", "icons": [{ "src": "/assets/icon/icon-152x152.png", "sizes": "152x152" }] }, { "name": "优惠", "short_name": "优惠", "description": "Geekflare - 优惠", "url": "/deals", "icons": [{ "src": "/assets/icon/icon-152x152.png", "sizes": "152x152" }] } ] }
注册Service Worker
在根目录下创建一个名为register-service-worker.js的脚本文件和service-worker.js的服务工作器脚本。
第一个文件register-service-worker.js是在主线程上运行的JavaScript文件,可以访问DOM API。而service-worker.js是一个独立于主线程运行的服务工作器脚本,其生命周期也很短。它会在事件调用服务工作器时运行,直到完成处理。
通过检查主线程的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(‘install', event);
self.skipWaiting();
});self.addEventListener(‘activate', (event) => { // 当service worker激活时的事件
console.log(‘activate', event);
return self.clients.claim();
});self.addEventListener(‘fetch', function(event) { // HTTP请求拦截器
event.respondWith(fetch(event.request)); // 发送所有HTTP请求,不进行任何缓存逻辑
/*event.respondWith(
caches.match(event.request).then(function(response) {
return response || fetch(event. request);
})
);*/ // 缓存新请求。如果已存在于缓存中,则从缓存中提供。
});我们没有关注如何启用离线支持的缓存。我们只讨论了如何将Web应用转换为PWA。
在HTML页面的所有head标签中添加清单文件和脚本。
添加后刷新页面。现在您可以在移动Chrome上像下面这样安装您的应用程序。
在主屏幕上,应用程序会被添加。
如果您使用WordPress,请尝试使用现有的PWA转换器插件。对于vueJS或reactJS,您可以按照上述方法进行操作,或者使用现有的PWA npm模块来加快开发速度。因为PWA npm模块已经启用了离线支持缓存等功能。
启用推送通知
Web推送通知发送到浏览器,使我们的用户更频繁地与我们的应用程序进行互动。我们可以通过使用以下内容来启用它:
Notification API:用于配置如何向用户显示推送通知。
Push API:用于接收从服务器发送到浏览器的通知消息。在我们的应用程序中启用推送通知的第一步是检查Notification API,并从用户那里获取显示通知的权限。为此,请将下面的代码段复制并粘贴到您的register-service-worker.js文件中。
if (‘Notification' in window && Notification.permission != ‘granted') {
console.log(‘Ask user permission')
Notification.requestPermission(status => {
console.log(‘Status:' + status)
displayNotification(‘Notification Enabled');
});
}const displayNotification = notificationTitle => {
console.log(‘display notification')
if (Notification.permission == ‘granted') {
navigator.serviceWorker.getRegistration().then(reg => {
console.log(reg)
const options = {
body: ‘Thanks for allowing push notification !',
icon: ‘/assets/icons/icon-512×512.png',
vibrate: [100, 50, 100],
data: {
dateOfArrival: Date.now(),
primaryKey: 0
}
};reg.showNotification(notificationTitle, options);
});
}
};如果一切正常,您将收到应用程序发送的通知。
‘Notification' in window将告诉我们该浏览器是否支持Notification API。Notification.permission将告知用户是否已被允许显示通知。如果用户允许我们的应用程序,则值将为“granted”。如果用户拒绝,则值将为“blocked”。
启用Firebase云消息传递并创建订阅
现在真正的部分开始了。为了从服务器向用户推送通知,我们需要为每个用户创建一个唯一的端点/订阅。为此,我们将使用Firebase云消息传递。
作为第一步,通过访问此链接https://firebase.google.com/创建一个Firebase帐户,然后按“开始”。
- 创建一个带有名称的新项目,然后按“继续”。我将用名称Geekflare创建它。
- 在下一步中,默认情况下启用了Google Analytics。您可以切换到不需要该功能,然后按“继续”。如果需要,您以后可以在Firebase控制台中启用它。
- 项目创建完成后,它将如下所示。
然后转到项目设置,单击云消息传递并生成密钥。
通过上述步骤,您已获得3个密钥。
- 项目服务器密钥
- Web推送证书私钥
- Web推送证书公钥
现在在register-service-worker.js中粘贴以下代码段:
const updateSubscriptionOnYourServer = subscription => { console.log('在此处编写您的ajax代码,将用户订阅保存到您的数据库中', subscription); // 使用fetch、jquery、axios等编写自己的ajax请求方法,将订阅保存到服务器以供以后使用。 }; const subscribeUser = async () => { const swRegistration = await navigator.serviceWorker.getRegistration(); const applicationServerPublicKey = 'BOcTIipY07N4Y63Y-9r7NMoJHofmCzn3Pu9g-LMsgIMGH4HVr42_LW9ia0lMr68TsTLKS3UcdkE3IcC52hJDYsY'; // 粘贴你的Web推送证书公钥 const applicationServerKey = urlB64ToUint8Array(applicationServerPublicKey); swRegistration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey }) .then((subscription) => { console.log('用户新订阅成功:', subscription); updateSubscriptionOnServer(subscription); }) .catch((err) => { if (Notification.permission === 'denied') { console.warn('通知权限已被拒绝') } else { console.error('订阅用户失败:', err) } }); }; const urlB64ToUint8Array = (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 { const swRegistration = await navigator.serviceWorker.getRegistration(); swRegistration.pushManager.getSubscription() .then(subscription => { if (!!subscription) { console.log('用户已经订阅。'); updateSubscriptionOnYourServer(subscription); } else { console.log('用户尚未订阅。重新订阅用户'); subscribeUser(); } }); }; checkSubscription();
在service-worker.js中粘贴以下代码段。
self.addEventListener('push', (event) => { const json = JSON.parse(event.data.text()) console.log('推送数据', event.data.text()) self.registration.showNotification(json.header, json.options) });
现在前端部分已经设置完成。通过使用订阅,您可以在需要时随时向用户发送推送通知,直到他们拒绝推送服务为止。
从node.js后端推送
您可以使用npm模块web-push使其更加简便。
从nodeJS服务器发送推送通知的示例代码。
const webPush = require('web-push'); // pushSubscription是从前端发送到服务器保存在数据库中的订阅对象 const pushSubscription = {"endpoint":"https://updates.push.services.mozilla.com/wpush/v2/gAAAAABh2…E0mTFsHtUqaye8UCoLBq8sHCgo2IC7UaafhjGmVCG_SCdhZ9Z88uGj-uwMcg","keys":{"auth":"qX6AMD5JWbu41cFWE3Lk8w","p256dh":"BLxHw0IMtBMzOHnXgPxxMgSYXxwzJPxpgR8KmAbMMe1-eOudcIcUTVw0QvrC5gWOhZs-yzDa4yKooqSnM3rnx7Y"}}; //你的网络证书公钥 const vapidPublicKey = 'BOcTIipY07N4Y63Y-9r7NMoJHofmCzn3Pu9g-LMsgIMGH4HVr42_LW9ia0lMr68TsTLKS3UcdkE3IcC52hJDYsY'; //你的网络证书私钥 const vapidPrivateKey = 'web-certificate private key'; var payload = JSON.stringify({ "options": { "body": "PWA后端推送测试", "badge": "/assets/icon/icon-152x152.png", "icon": "/assets/icon/icon-152x152.png", "vibrate": [100, 50, 100], "data": { "id": "458", }, "actions": [{ "action": "view", "title": "查看" }, { "action": "close", "title": "关闭" }] }, "header": "来自Geekflare-PWA演示的通知" }); var options = { vapidDetails: { subject: 'mailto:[email protected]', publicKey: vapidPublicKey, privateKey: vapidPrivateKey }, TTL: 60 }; webPush.sendNotification( pushSubscription, payload, options ).then(data => { return res.json({status : true, message : '通知已发送'}); }).catch(err => { return res.json({status : false, message : err }); });
以上代码将向订阅对象发送推送通知。service-worker中的推送事件将被触发。
从PHP后端推送
对于PHP后端,您可以使用web-push-php composer包。请查看以下示例代码以发送推送通知。
array ( 'body' => 'PWA后端推送通知测试', 'badge' => '/assets/icon/icon-152x152.png', 'icon' => '/assets/icon/icon-152x152.png', 'vibrate' => array ( 0 => 100, 1 => 50, 2 => 100, ), 'data' => array ( 'id' => '458', ), 'actions' => array ( 0 => array ( 'action' => 'view', 'title' => '查看', ), 1 => array ( 'action' => 'close', 'title' => '关闭', ), ), ), 'header' => '来自Geekflare-PWA演示的通知', ); // 认证 $auth = [ 'GCM' => '你的项目私钥', // 废弃且可选,仅为兼容性原因而在此 'VAPID' => [ 'subject' => 'mailto:[email protected]', // 可以是mailto: 或你的网站地址 'publicKey' => 'BOcTIipY07N4Y63Y-9r7NMoJHofmCzn3Pu9g-LMsgIMGH4HVr42_LW9ia0lMr68TsTLKS3UcdkE3IcC52hJDYsY', // (推荐) Base64-URL编码的P-256未压缩公钥 'privateKey' => '你的网站证书私钥', // (推荐) 实际上是Base64-URL编码的私钥的秘密乘法器 ], ]; $webPush = new WebPush($auth); $subsrciptionData = json_decode($subsrciptionJson,true); // webpush 6.0 $webPush->sendOneNotification( Subscription::create($subsrciptionData), json_encode($payloadData) // 可选(默认为null) );
结论
希望这能让你了解如何将Web应用程序转换为PWA。你可以检查本文的源代码 here 并进行演示 here。我还使用示例代码从后端发送了推送通知进行了测试。