江苏专业网站建设,wordpress 图标上传,世界500强企业的核心价值观,河北港网站建设一、什么是PWA应用#xff1f;
1、PWA简介
渐进式Web应用#xff08;Progressive Web App#xff09;#xff0c;简称PWA#xff0c;是 Google 在 2015 年提出的一种使用web平台技术构建的应用程序#xff0c;官方认为其核心在于Reliable#xff08;可靠的#xf…一、什么是PWA应用
1、PWA简介
渐进式Web应用Progressive Web App简称PWA是 Google 在 2015 年提出的一种使用web平台技术构建的应用程序官方认为其核心在于Reliable可靠的、Fast快速的、Engaging可参与的结合了web网站程序和原生应用程序两者的优点可以带给用户更佳的使用体验。
PWA既能像网站一样通过一套代码在多个平台运行而且可以通过浏览器进行访问并通过Url链接进行分享。又能像原生应用一样通过应用商店或网页安装在设备上安装之后可以通过图标访问作为一个独立的应用程序被启动而且即使脱离网络也可以通过应用缓存访问到部分页面和数据。
但需要注意的是当PWA应用通过安装在设备上的图标打开时虽然从外观上看来像是一个原生的应用程序但从技术角度来看其仍属于网站范畴所以仍需要一个浏览器引擎来解析和运行为其提供正常运行的环境。因此其原理类似于打开了一个单独的、自定义窗口内容的浏览器窗口。
PWA不仅是一种技术更代表了一种Web网站的开发理念如果一个网站程序实现了可安装、可离线等多种特定功能我们就可以将其视为一个PWA应用。目前国内支持PWA的网站有微博、语雀等等。 2、PWA特点
原生应用程序代表了最佳的功能因为其与操作系统深入结合拥有易于访问、可离线、操作系统集成等优点。 Web 网站程序则代表了最广的范围因为其以浏览器为基础拥有跨平台、无需下载、易于更新部署等优点。而PWA 则处于原生应用程序功能和 Web 网站程序范围的交叉点是两者的结合体主要拥有以下几种特点
① 跨平台 PWA应用只需开发者书写一套代码就可以在不同操作平台上运行而且PWA应用采取渐进式增强的理念其核心功能可以在任何浏览器上正常运行其余强大的功能则需要依赖于浏览器对PWA特性的支持根据浏览器的支持性逐步升级体验。
② 可安装 PWA应用可以添加到主屏幕或应用程序菜单中实现类似原生应用的图标入口点击图标作为一个独立应用被启动用户可以更方便地访问应用。也可以将程序打包并上传各个应用商店让用户通过应用商店安装网站应用。
③ 离线访问 PWA应用具备离线访问的能力它们可以缓存应用的核心资源使得用户可以在没有网络连接的情况下继续访问应用查看到部分页面和数据提供基本的功能并在网络恢复时更新缓存。
④ 推送通知 PWA应用可以主动发送推送通知给用户使得应用可以及时通知用户有关重要更新、新消息或其他关键信息类似于原生应用的通知功能。
⑤ 快速加载 PWA应用使用Service Workers来缓存资源并提供离线体验这也使得应用可以更快地加载和响应用户操作。
⑥ 可搜索 PWA应用可以通过搜索引擎被发现而且可以通过url链接进行分享。
⑦ 热更新 PWA应用中的部分内容发生更新时可在联网后自动进行局部热更新确保用户能用到最新的应用程序而无需像原生应用一样重新下载安装客户端。
结合官方提出的Reliable可靠的、Fast快速的、Engaging可参与的三个核心我认为跨平台、离线访问体现了Reliable可靠的无论是在低版本浏览器还是无网络的情况下PWA都可以展示基本功能快速加载、热更新则体现了Fast快速的利用缓存和自动更新减少重复数据加载提升响应速度可安装和推送通知则体现了Engaging可参与的可安装在设备上并向用户推送通知。
3、适用场景
地图导航、资料文档、博客笔记等等。
二、PWA的核心技术是什么
PWA的实现依赖于多种技术实现其中最核心的技术为Service Worker、Web App Manifest和Push Notification。
1、Service Worker
Service Worker是一个独立于网页线程的脚本无权访问页面的DOM结构充当了网站和浏览器之间的代理服务器每个PWA应用都只能注册一个Service Worker其在PWA中主要用来实现离线访问、缓存资源、推送通知等功能当然除此之外它还具有很多其他功能在这我们就不展开讲述了。
在网络正常时当PWA应用请求Service Worker范围内的资源时Service Worker会拦截该请求并充当网络代理然后它可以决定是从缓存中获取数据还是从服务器中获取数据。如果是从服务器中获取数据Service Worker会缓存请求的数据等到离线访问时返回缓存的数据使得PWA应用可以在离线状态下运行并且可以利用缓存提升应用的加载速度。
由于Service Worker权利太大能够直接截取并返回用户的请求处于安全性考虑目前仅支持在HTTPS或本地环境的安全环境下使用。
Service Worker的浏览器兼容性如下图
如何为PWA注册Service Worker
在Service Worker控制页面之前必须在PWA应用中注册Service Worker服务。这意味着在用户第一次访问PWA应用时页面还并未受到Service Worker的控制也就无法实现离线访问等功能。
注册Service Worker时我们只需先判断浏览器是是否支持相关的API如果支持则直接通过navigator.serviceWorker.register(url)进行注册即可参数url表示具体Service Worker逻辑代码文件的路径。
// 这是页面中唯一与Service Worker有关的代码
if (serviceWorker in navigator) {navigator.serviceWorker.register(/service-worker.js).then(registration {console.log(Service Worker 注册成功, registration);}).catch(error {console.log(Service Worker 注册失败, error);});
} 如果想要查看Service Worker是否已经注册并正常运行以Chrome浏览器为例我们可以通过F12开发者工具中的Application然后选中左侧的Service Workers 如果右侧展示的信息中的Status中显示activity则表示已经注册并正常运行。 如果想要在移动端页面检查是否已经注册并正常运行也只能通过连接电脑调试的方法来查看具体可查看该文档tools-and-debug。
Service Worker的作用范围怎么确定
Service Worker在注册时引入的具体逻辑文件所在文件夹决定了其作用范围例如
navigator.serviceWorker.register(example.com/my-pwa/serviceworker.js); 则该Service Worker的作用范围在my-pwa文件夹下的任何文件如 example.com/my-pwa/index.html等等。
为了实现Service Worker在PWA应用中的作用最大化推荐将具体逻辑文件设置在PWA应用程序的根目录下因为这样可以拦截到PWA应用中的所有请求。
Service Worker的生命周期分为哪些阶段
Service Worker 的生命周期从注册 Service Worker 开始也就是前文所说的register()方法调用该方法时就会发生注册行为。该生命周期阶段并没有对应的事件然后我们可以通过register()方法的.then()来判断是否注册成功。
① Registration注册
if (serviceWorker in navigator) {navigator.serviceWorker.register(/service-worker.js).then(registration {console.log(Service Worker 注册成功, registration);}).catch(error {console.log(Service Worker 注册失败, error);});
} 然后浏览器开始下载并安装 Service Worker 文件安装成功后则会触发install事件在整个生命周期中install事件仅会触发这一次。开发者通常会在此事件中进行初始化缓存一些静态资源以备离线时访问。
② Installation安装
// 安装阶段
self.addEventListener(install, function(event) {event.waitUntil(// 向缓存中存储基本数据caches.open(cache-name).then(function(cache) {return cache.addAll([/path/to/resource1,/path/to/resource2,// ...]);}));
}); 在Service Worker中我们需要通过全局对象self才能监听各个生命周期事件。在waitUntil()方法执行结束之前Service Worker不会结束安装状态必须等待其内部代码执行结束之后才会进入到下一个生命周期。caches对象是限制在Service Worker 生命周期内使用的特殊对象用于实现数据的缓存。
③ Activation激活
当Service Worker安装完成后并不会立即进入激活状态为了不影响当前正在访问的页面此时Service Worker 并没有控制当前页面。所以要等到当前页面关闭且再次加载该页面时Service Worker才会进入激活状态触发activate事件开始控制网页的请求和缓存。在此阶段开发者通常会进行清理旧的缓存、处理更新逻辑等操作因为浏览器的缓存空间是有限的。
// Service Worker激活成功后
self.addEventListener(activate, function(event) {event.waitUntil(// 对缓存中的数据进行处理caches.keys().then(function(cacheNames) {return Promise.all(// 只保留符合要求的数据 删除不需要的旧数据cacheNames.filter(function(cacheName) {return cacheName ! cache-name;}).map(function(cacheName) {return caches.delete(cacheName);}));}));
}); 在waitUntil()方法执行结束之前Service Worker不会进入下个状态然后可以通过caches对象对缓存的数据进行操作。
还有要注意的一点是Service Worker 进入激活状态后它会一直保持激活状态除非被手动注销或者被新的 Service Worker 脚本取代。
④ Update更新
浏览器会周期性的检测当前应用的Service Worker是否有更新当检测到Server Worker 脚本文件发生更新时会在后台下载新的脚本并触发更新流程。更新流程与安装流程类似需要经历下载、安装、激活三个阶段。下载完成之后会立即进行安装但是安装完成之后默认并不会立即激活而且进入等待状态。因为同一时间只能有一个版本的 Service Worker处于Activation状态。只有当旧版本的Service Worker控制的所有页面都被关闭然后用户再重新访问这些页面时新的Service Worker才会被激活并接管旧版本所有页面的控制权。
我们也可以通过skipWaiting()方法来强制激活等待中 Service Worker使其取代旧版 Service Worker获得页面的控制权。该方法只有在存在等待状态的 Service Worker时调用才会有意义所以通常都在install事件中执行调用。
// 新版Service Worker的install事件
self.addEventListener(install, (event) {// 安装好后 调用skipWaiting() 使其立即激活// skipWaiting() 返回一个 promise但完全可以忽略它self.skipWaiting();// 然后执行 service worker 安装所需的缓存数据等其他操作e.waitUntil((async () {const cache await caches.open(cacheName);await cache.addAll(contentToCache);})(),);
});⑤ Termination终止
当Service Worker被手动注销或被新版本Service Worker取代后就会进入终止阶段它将不再控制页面的请求并释放相应的资源。即使不被注销或者取代Service Worker也不会无限期的存活各大浏览器的处理逻辑不同但在激活一段时间后Service Worker就会被终止。终止之后需要重新注册才能继续运行。
if (serviceWorker in navigator) {navigator.serviceWorker.register(/service-worker.js).then(registration {console.log(Service Worker 注册成功, registration);// 手动注销Service Workerregistration.unregister().then(function (boolean) {if(boolean) {console.log(Service Worker 注销成功)}});}).catch(error {console.log(Service Worker 注册失败, error);});
}⑥ Fetch请求
Service Worker 还提供了一个fetch事件每当Service Worker控制的页面中发出fetch请求或者html、css、js等资源请求时都会触发该事件我们可以在此阶段拦截请求并结合缓存使用自定义响应来响应请求。注意ajax请求不会触发该事件。
通常当请求的资源存在缓存时我们都会从缓存中获取资源而不是从服务器获取。如果缓存中没有那我们会使用另一个请求从服务器获取资源并将资源存储在缓存中以便下次请求或离线请求时使用。
self.addEventListener(fetch, (e) {e.respondWith((async () {// 从缓存中获取资源const r await caches.match(e.request);console.log(Service Worker正在请求资源: ${e.request.url});if (r) {// 如果缓存中存在资源 则直接返回缓存中的资源return r;}// 如果缓存中没有 则去服务器请求资源const response await fetch(e.request);const cache await caches.open(cacheName);console.log(Service Worker 缓存新资源: ${e.request.url});// 将请求的资源存储到缓存中 cache.put(e.request, response.clone());// 将请求结果缓存return response;})(),);
}); 该fetch事件的事件对象event中包含了一个respondWith()方法该方法可以阻止浏览器默认的fetch请求操作并允许自定义请求的response更多信息请查看FetchEvent.respondWith()。
2、Web App Manifest
Web App ManifestWeb应用清单是一个遵守W3C规范的JSON文件用来定义PWA安装的客户端在设备上应该如何显示和运行例如应用的名称、图标、启动方式等等该文件是实现PWA所必需的。通过该文件用户可将PWA应用安装到用户的主屏幕上使其更像一个原生应用的客户端。
该文件中可定义的应用信息很多其中比较常用的有以下几条
① name
该字段定义PWA应用的全名是Web App Manifes中必须的一个基本字段。该名称一般会显示为应用商店的应用名称也会在应用启动时显示在标题栏中。
name: 学科网PWA示例② short_name
该字段定义PWA应用的简称尽量控制在12个字符以内当应用程序被安装在桌面上时由于空间有限通常就会显示该简称但具体展示name还是short_name可能因设备、浏览器或操作系统而有所不同例如在macos系统中统一展示name字段。
short_name: PWA示例③ icons
该字段定义了应用程序安装在桌面上的图标属性值为一个数组数组元素为一个对象对象中包含src、sizes、type三个属性分别代表图标地址、图标的尺寸和图标的MIME类型。
src指定了图标文件的位置字段值可以是相对于manifest文件的相对URL或者是一个绝对的网络URL。sizes指明了图标的尺寸以宽×高的形式指定了图标的宽高单位默认为px目前设备适配性最好的图标尺寸为512×512。type指明了图标的MIME媒体类型帮助浏览器在选择合适的图标文件例如image/png、image/jpeg等等。
该字段属性值数组至少需要定义一个图标元素也可以定义多个不同格式的图标元素从而为用户提供最佳的图标效果。每个浏览器都会根据其需要和所安装的操作系统选择其中最接近其所需的规范的某个图标。图标选择规则很多主要有尺寸匹配、类型匹配、设备类型匹配等规则。
icons: [{src: icons/512.png,type: image/png,sizes: 512x512},{src: icons/1024.png,type: image/png,sizes: 1024x1024}
]④ start_url
该字段定义PWA应用的起始URL用户点击图标打开程序时将会加载这个URL所对应的页面可以是相对于manifest文件的相对路径也可以是一个绝对路径。推荐使用绝对路径如果PWA应用的主页是网站的根目录那么将该字段设置为/即可。如果没有设置该字段则默认将安装PWA应用时的URL作为该字段的值。
start_url: ./index.html⑤ display
该字段定义了PWA应用的打开方式字段值有以下四种
standalone推荐应用将以独立窗口打开类似于原生应用程序没有导航栏等浏览器功能。 fullscreen应用将以全屏模式打开隐藏浏览器的地址栏和工具栏。由于电脑操作系统的限制该字段值表现效果与standalone一致。 minimal-ui应用将独立窗口打开但保留了一部分浏览器的导航功能如后退、刷新功能等。 browser应用将以常规浏览器网页的形式打开类似于设置了一个网页的快捷方式。但是由于电脑操作系统的限制该字段值表现效果与standalone一致。 display: standalone⑥ id
该字段用于作为PWA应用的唯一标识如果未设置则默认以start_url的值为字段值。
id: xkw-pwa⑦ background_color
该字段定义了PWA应用窗口打开后且样式表加载完成之前的窗口背景色字段值支持关键字red、green等、十六进制色值#FFFFFF、#CCCCC等和RGB色值rgb(255,255,255)等但不建议使用rgba()等带有透明度的颜色因为各个浏览器的展示效果可能大相径庭。但是目前iOS 和 iPadOS 上的 Safari 以及部分桌面浏览器目前会忽略此字段。
background_color: #000000,⑧ theme_color
该字段定义了PWA应用的窗口主题色将会影响窗口工具栏、头部标题栏等区域的颜色段值支持关键字red、green等、十六进制色值#FFFFFF、#CCCCC等和RGB色值255,255,255等。但是该属性会被meta nametheme-color content#ccc标签设置的主题色所覆盖。
theme_color: #3880FF⑨ 其他属性
。。。
3、Push Notification
Push 和 Notification是两个独立的APIPush用来接收服务器推送的信息Notification 用来向用户推送信息。两者都需要在 Service Worker 内调用运行。
具体可查看Push Notification
三、如何开发一个PWA应用Demo
1、创建一个demo文件夹用来存储相关文件 2、创建manifest.json文件设置PWA应用信息
{name: 猪猪侠的PWA示例, short_name: PWA示例,start_url: /index.html,display: standalone,background_color: red,theme_color: #ccc,icons: [{src: /icons/android-chrome-192x192.png,sizes: 192x192,type: image/png},{src: /icons/android-chrome-512x512.png,sizes: 512x512,type: image/png}]
}
3、创建icons文件夹存储PWA应用图标文件
存储以下两个图标文件 4、创建main.css文件设置页面样式
h3 {color: red;
}5、创建sw.js文件设置Service Worker相关逻辑
这里我们只需要直接书写Service Worker的处理逻辑即可
// 缓存的key值用于区别新旧版本缓存
var cacheStorageKey minimal-pwa-2
// 设置初始需要缓存的文件
var cacheList [/,index.html,main.css,/icons/android-chrome-512x512.png
]
// 监听安装事件 并在此阶段 缓存基本资源
self.addEventListener(install, e {e.waitUntil(caches.open(cacheStorageKey).then(// 缓存基本资源cache cache.addAll(cacheList)).then(() // 当脚本更新时 使新版Service Worker强制进入activate状态self.skipWaiting()))
})
// 监听fetch请求事件
self.addEventListener(fetch, function (e) {// 拦截相关请求e.respondWith(// 如果缓存中已经有请求的数据就终止请求 直接返回缓存数据caches.match(e.request).then(async function (response) {if (response ! null) {return response}// 否则就重新向服务端请求const res await fetch(e.request)// 这块需要结合具体业务具体分析 我这里的示例逻辑是无脑全部缓存// 请求成功后将请求的资源缓存起来 后续请求直接走缓存const cache await caches.open(cacheStorageKey)cache.put(e.request, res.clone())// 将请求的资源返回给页面。return res;}))
})
// 监听激活事件
self.addEventListener(activate, function (e) {e.waitUntil(//获取所有cache名称caches.keys().then(cacheNames {return Promise.all(// 获取缓存中所有不属于当前版本cachekey下的内容cacheNames.filter(cacheNames {return cacheNames ! cacheStorageKey}).map(cacheNames {// 删除不属于当前版本的cache缓存数据return caches.delete(cacheNames)}))}).then(() {// 无须刷新页面 即可使新版server worker接管当前页面return self.clients.claim()}))
})6、创建主文件index.html设置页面DOM并引用各类资源
!DOCTYPE html
html langenheadmeta charsetUTF-8titleHello PWA/titlemeta nameviewportcontentwidthdevice-width, user-scalableno, initial-scale1.0, maximum-scale1.0, minimum-scale1.0link relstylesheet hrefmain.csslink relmanifest hrefmanifest.json
/headbodyh3Hello 猪猪侠的PWA/h3
/body
script// 检测浏览器是否支持SWif (serviceWorker in navigator) {// 为当前页面注册Service Workernavigator.serviceWorker.register(./sw.js).then(function (registartion) {console.log(当前浏览器支持sw:, registartion.scope);console.log(Service Worker注册成功, registartion);})}
/script
/html7、部署到服务器上(https) 或在本地环境使用
以本地环境为例使用VSCode作为辅助工具
① 在VSCode中右键选中index.html文件选中Open with live Server选项运行页面 ② F12控制台查看Service Worker是否注册成功
③ 然后点击Application选中左侧Service Workers查看sw脚本是否正常运行
④ 点击左侧Cache Storage选中我们定义的cacheStorageKey-当前域名地址查看初始资源(sw.js文件中定义的cacheList数组中的资源)是否被缓存
⑤ 点击Network选中All刷新页面查看请求资源情况
⑥ 经过上次刷新所有相关资源已被缓存再次刷新页面所有资源都将经过Service Worker之后从缓存中获取
⑦ 通过选中NetWork中的Offline选项切断网络查看在无网络时页面是否能利用缓存正常显示
⑧ 其他操作。。。
四、相关资料
PWA谷歌文档
PWA的MDN文档
Service Worker
Service Worker 生命周期
Web App Manifes