内容简介:在传统的 Web 应用中,通常只能通过在浏览器的地址栏里输入相应的网址才能进行访问,或者把网页地址创建到桌面上通过点击,然后在浏览器里打开。传统模式下,图标、启动画面、主题色、视图模式、屏幕方向等等都无法去自定义和控制。而目前可以通过 PWA 标准中的特性来完成上面这些功能,使得访问 Web 应用的路径更短、曝光性更大,下面说一下这一块。
在传统的 Web 应用中,通常只能通过在浏览器的地址栏里输入相应的网址才能进行访问,或者把网页地址创建到桌面上通过点击,然后在浏览器里打开。
传统模式下,图标、启动画面、主题色、视图模式、屏幕方向等等都无法去自定义和控制。
而目前可以通过 PWA 标准中的特性来完成上面这些功能,使得访问 Web 应用的路径更短、曝光性更大,下面说一下这一块。
安装
安装 Web 应用需要一些前期准备。
安装条件
首先需要在网站下建立 manifest.json
文件,并在页面中引入:
<link rel="manifest" href="./manifest.json" /> 复制代码
且 manifest.json
文件中必须配置如下字段:
{ "short_name": "短应用名", "name": "长应用名", "icons": [ { "src": "icons/192.png", "sizes": "144x144", "type": "image/png" } ], "start_url": ".", "display": "standalone", } 复制代码
要求:
- 运行在 https 环境。
- 必须注册并运行 serviceworker。
- manifest 中必须有
icons
,且至少为144x144
的PNG
图像。 - manifest 中
display
设置为standalone
或者fullscreen
。 - manifest 中必须有
name
或者short_name
。 - manifest 中必须有
start_url
。 - manifest 中
prefer_related_applications
未设置或设置为false
。
manifest 的详细设置信息,可以参考前面写的 manifest 专题文章。
显示安装提示
按要求配置好后,在浏览器端打开网站。
Android Chrome 端
从 Chrome 68 以后,当满足安装应用的条件时,会立即在浏览器底部弹出 “ Mini信息条 ”,用户单击信息条时,弹出“ 添加到主屏幕 ”的对话框,点击“ 添加 ”后,完成安装,此时页面上就出现在应用图标。
注意:Chrome 68 - 75 的Mini 信息条是无法通过代码来控制是否展示的,Chrome 76 之后版本支持通过代码控制显示。 当用户点击 Mini 信息条上的 “X” 时,至少三个月浏览器不会再出现 Mini 条的提示,但事件层不受影响,可以通过代码实现。
PC Chrome 端
Chrome 73 开始支持 PC 端安装 Web 到桌面
自定义安装时机
当 Web 应用符合安装时,会触发 beforeinstallprompt
事件,并弹出安装到屏幕的提示,我们可以基于这个事件来控制是否展示安装提示及何时安装。
beforeinstallprompt
事件在此应用未安装的情况下会每次进入页面都触发,如果已安装则不会触发。当用户卸载应用后,则会继续触发此事件。
安装提示事件捕获逻辑:
var installPromptEvent = null; window.addEventListener('beforeinstallprompt', (event) => { event.preventDefault(); // Chrome <= 67 可以阻止显示 installPromptEvent = event; // 拿到事件的引用 document.querySelector('#btn-install').disabled = false; // 更新安装 UI,通知用户可以安装 }); 复制代码
显示 prompt 对话框
手动显示安装对话框,可以通过调用捕获的 beforeinstallprompt
事件引用中的 prompt()
方法来触发。
通过事件 userChoice
属性的 Promise 结果中的 outcome
来获取。
用户点击安装逻辑:
document.querySelector('#btn-install').addEventListener('click', () => { if( !installPromptEvent ) { return; } installPromptEvent.prompt(); installPromptEvent.userChoice.then( choiceResult => { if (choiceResult.outcome === 'accepted') { console.log('用户已同意添加到桌面') } else { console.log('用户已取消添加到桌面') } }) }) 复制代码
已安装事件处理
可以通过 appinstalled
来监听应用是否安装:
window.addEventListener('appinstalled', (evt) => { console.log('已安装到桌面屏幕'); }); 复制代码
环境判断
当前应用是通过在浏览器里输入网址打开的,还是通过桌面图标打开的,可以通过 display-mode
属性来判断,然后根据需求设置不同的交互样式。
假设 manifest 中设置的 display
为 standalone
js 层判断:
if (window.matchMedia('(display-mode: standalone)').matches) { console.log('display-mode 是 standalone'); } 复制代码
css 层判断:
@media all and (display-mode: standalone) { /** 自定义样式 **/ } 复制代码
Safari 判断:
if (window.navigator.standalone === true) { console.log('display-mode 是 standalone'); } 复制代码
应用的更新
Web 应用安装到桌面后,对于后面修改 manifest 后的更新问题,目前每个平台的表现不一样。
Android 端
在 Android 上,当启动 Web 应用时,Chrome 会根据实时 manifest 来检查当前安装的 manifest。如果需要更新,则在 wifi 环境下自动进入更新队列。
触发更新规则:
- 更新检查仅在启动 Web 应用时发生。直接启动 Chrome 不会触发给定 Web 应用的更新检查。
- Chrome 会每隔 1 天或每 30 天检查一次更新。每天检查更新大多数时间都会发生。在更新服务器无法提供更新的情况下,它会切换到30天的时间间隔。
- 清除 Chrome 的数据(通过Android设置中的“清除所有数据”)会重置更新计时器。
- 如果 Web Manifest URL 未更改,Chrome 将仅更新 Web 应用。如果你将网页的 manifest 路径修改,如从
/manifest.json
更改为/manifest2.json
,则 Web 应用将不再更新。(非常不建议这样做) - 只有正式版 Chrome(Stable / Beta / Dev / Canary)创建的 Web 应用才会更新。它不适用于 Chromium(org.chromium.chrome)。
- 更新检查可能会延迟,知道连接可用 wifi。
PC 端
PC 端暂时不支持更新,后续可能会支持。
兼容
目前此特性在各平台的兼容性如下:
像 IOS 下的 Safari 是支持安装到桌面的特性,但并没有走 manifest 的规范。
IOS 上的适配
IOS 针对桌面图标、启动画面、应用文本及主题色需要单独的特性 Meta 进行设置。
apple-touch-icon:应用图标
需要在网页中增加:
<link rel="apple-touch-icon" href="/custom_icon.png"> 复制代码
不同分辨率的适配:
<link rel="apple-touch-icon" href="touch-icon-iphone.png"> <link rel="apple-touch-icon" sizes="152x152" href="touch-icon-ipad.png"> <link rel="apple-touch-icon" sizes="180x180" href="touch-icon-iphone-retina.png"> <link rel="apple-touch-icon" sizes="167x167" href="touch-icon-ipad-retina.png"> 复制代码
apple-touch-startup-image:启动画面
需要在网页中增加:
<link rel="apple-touch-startup-image" href="/launch.png"> 复制代码
apple-mobile-web-app-title:应用 icon 的标题
默认情况下使用 <title></title>
中的值,需要修改的话需要指定 meta。
<meta name="apple-mobile-web-app-title" content="应用标题"> 复制代码
apple-mobile-web-app-status-bar-style:应用状态栏的外观样式
例如设置为黑色:
<meta name="apple-mobile-web-app-status-bar-style" content="black"> 复制代码
兼容适配库
正常来说,所有的特性都要按照规范中的约束来使用,但向上面的 Safari 并没有按照规范来,这样会增加开发者的开发成本。
所以这里做一下适配脚本,只写规范中 manifest 的那些定义部分,剩下的交由脚本来完成。
(function(){function h(){var a=document.head.querySelector('link[rel="manifest"]'),b=a?a.href:"",d=A([b,window.location]);Promise.resolve().then(function(){if(!b)throw'can\'t find <link rel="manifest" href=".." />\'';var a={};"use-credentials"===b.crossOrigin&&(a.credentials="include");return window.fetch(b,a)}).then(function(a){return a.json()}).then(function(a){return B(a,d)}).catch(function(a){return console.warn("pwacompat.js error",a)})}function A(a){for(var b={},d=0;d<a.length;b={c:b.c},++d){b.c= a[d];try{return new URL("",b.c),function(a){return function(b){return(new URL(b,a.c)).toString()}}(b)}catch(n){}}return function(a){return a}}function t(a,b){a=document.createElement(a);for(var d in b)a.setAttribute(d,b[d]);document.head.appendChild(a);return a}function c(a,b){b&&(!0===b&&(b="yes"),t("meta",{name:a,content:b}))}function B(a,b){function d(b,d,f){var k=b.width,c=b.height,e=window.devicePixelRatio;b=u({width:k*e,height:c*e});b.scale(e,e);b.fillStyle=a.background_color||"#f8f9fa";b.fillRect(0, 0,k,c);b.translate(k/2,(c-32)/2);b.font="24px HelveticaNeue-CondensedBold";b.fillStyle=r?"white":"black";k=b.measureText(v).width;f&&(c=f.width/e,e=f.height/e,128<e&&(c/=e/128,e=128),48<=c&&48<=e&&(b.drawImage(f,c/-2,e/-2,c,e),b.translate(0,e/2+32)));b.fillText(v,k/-2,0);f=document.createElement("link");f.setAttribute("rel","apple-touch-startup-image");f.setAttribute("media","(orientation: "+d+")");f.setAttribute("href",b.canvas.toDataURL());return f}function n(a){var b=d(window.screen,"portrait", a);a=d({width:window.screen.height,height:window.screen.width},"landscape",a);w.forEach(function(a){return a.remove()});document.head.appendChild(b);document.head.appendChild(a);w.add(b);w.add(a)}var g=a.icons||[];g.sort(function(a,b){return parseInt(b.sizes,10)-parseInt(a.sizes,10)});var x=g.map(function(a){a={rel:"icon",href:b(a.src),sizes:a.sizes};t("link",a);if(p)return a.rel="apple-touch-icon",t("link",a)}),q=a.display;g=-1!==C.indexOf(q);c("mobile-web-app-capable",g);D(a.theme_color||"black"); E&&(c("msapplication-starturl",a.start_url||"/"),c("msapplication-TileColor",a.theme_color));document.head.querySelector('[name="theme-color"]')||c("theme-color",a.theme_color);var h=F(a.orientation);c("x5-orientation",h);c("screen-orientation",h);"fullscreen"===q?(c("x5-fullscreen","true"),c("full-screen","yes")):g&&(c("x5-page-mode","app"),c("browsermode","application"));if(p){var r=y(a.background_color||"#f8f9fa"),v=a.name||a.short_name||document.title;(q=G(a.related_applications))&&c("apple-itunes-app", "app-id="+q);c("apple-mobile-web-app-capable",g);c("apple-mobile-web-app-title",v);var w=new Set;n(null);if(x.length){var m=x[0],l=new Image;l.crossOrigin="anonymous";l.onload=function(){n(l);if(a.background_color){var b=z(l,a.background_color);null!==b&&(m.href=b,x.slice(1).forEach(function(b){var d=new Image;d.crossOrigin="anonymous";d.onload=function(){var c=z(d,a.background_color,!0);b.href=c};d.src=b.href}))}};l.src=m.href}}}function G(a){var b;(a||[]).filter(function(a){return"itunes"===a.platform}).forEach(function(a){a.id? b=a.id:(a=a.url.match(/id(\d+)/))&&(b=a[1])});return b}function F(a){a=String(a||"");a=a.substr(0,3);return"por"===a?"portrait":"lan"===a?"landscape":""}function D(a){if(p||H){var b=y(a);if(p)c("apple-mobile-web-app-status-bar-style",b?"black":"default");else{try{var d=Windows.UI.ViewManagement.ApplicationView.getForCurrentView().titleBar}catch(n){d=null}null===d?console.debug("UWP no titleBar"):(d.foregroundColor=r(b?"black":"white"),d.backgroundColor=r(a))}}}function r(a){a=m(a);return{r:a[0],g:a[1], b:a[2],a:a[3]}}function m(a){var b=u();b.fillStyle=a;b.fillRect(0,0,1,1);return b.getImageData(0,0,1,1).data}function y(a){a=m(a).map(function(a){a/=255;return.03928>a?a/12.92:Math.pow((a+.055)/1.055,2.4)});return 3<Math.abs(1.05/(.2126*a[0]+.7152*a[1]+.0722*a[2]+.05))}function z(a,b,d){d=void 0===d?!1:d;var c=u(a);c.drawImage(a,0,0);if(!d&&255==c.getImageData(0,0,1,1).data[3])return null;c.globalCompositeOperation="destination-over";c.fillStyle=b;c.fillRect(0,0,a.width,a.height);return c.canvas.toDataURL()} function u(a){a=void 0===a?{width:1,height:1}:a;var b=a.height,c=document.createElement("canvas");c.width=a.width;c.height=b;return c.getContext("2d")}if("fetch"in window){var C=["standalone","fullscreen","minimal-ui"],p=navigator.vendor&&-1!==navigator.vendor.indexOf("Apple"),E=navigator.userAgent&&-1!==navigator.userAgent.indexOf("Edge"),H="undefined"!==typeof Windows;"complete"===document.readyState?h():window.addEventListener("load",h)}})(); 复制代码
调用地址: http://unpkg.alipay.com/pwacompat@2.0.9/pwacompat.min.js
。
使用:
<link rel="manifest" href="./manifest.json" /> <script src="http://unpkg.alipay.com/pwacompat@2.0.9/pwacompat.min.js" crossorigin="anonymous"></script> 复制代码
博客名称:王乐平博客
CSDN博客地址: blog.csdn.net/lecepin
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Golang入门:从安装、部署以及GoLand的安装开始
- Clojure安装与入门
- webpack入门(2) - 安装,配置,环境搭建
- [ Laravel 5.7 文档 ] 快速入门 —— 安装配置
- 从安装到入门:ElasticSearch 快速学习手册
- ES 入门(一):安装部署与基本概念
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Text Processing in Python
David Mertz / Addison-Wesley Professional / 2003-6-12 / USD 54.99
Text Processing in Python describes techniques for manipulation of text using the Python programming language. At the broadest level, text processing is simply taking textual information and doing som......一起来看看 《Text Processing in Python》 这本书的介绍吧!