在傳統的 Web 應用中,一般只能經過在瀏覽器的地址欄裏輸入相應的網址才能進行訪問,或者把網頁地址建立到桌面上經過點擊,而後在瀏覽器裏打開。css
傳統模式下,圖標、啓動畫面、主題色、視圖模式、屏幕方向等等都沒法去自定義和控制。html
而目前能夠經過 PWA 標準中的特性來完成上面這些功能,使得訪問 Web 應用的路徑更短、曝光性更大,下面說一下這一塊。web
安裝 Web 應用須要一些前期準備。chrome
首先須要在網站下創建 manifest.json
文件,並在頁面中引入:json
<link rel="manifest" href="./manifest.json" />
複製代碼
且 manifest.json
文件中必須配置以下字段:canvas
{
"short_name": "短應用名",
"name": "長應用名",
"icons": [
{
"src": "icons/192.png",
"sizes": "144x144",
"type": "image/png"
}
],
"start_url": ".",
"display": "standalone",
}
複製代碼
要求:瀏覽器
icons
,且至少爲 144x144
的 PNG
圖像。display
設置爲 standalone
或者 fullscreen
。name
或者 short_name
。start_url
。prefer_related_applications
未設置或設置爲 false
。manifest 的詳細設置信息,能夠參考前面寫的 manifest 專題文章。bash
按要求配置好後,在瀏覽器端打開網站。服務器
從 Chrome 68 之後,當知足安裝應用的條件時,會當即在瀏覽器底部彈出 「Mini信息條」,用戶單擊信息條時,彈出「添加到主屏幕」的對話框,點擊「添加」後,完成安裝,此時頁面上就出如今應用圖標。 app
注意:Chrome 68 - 75 的Mini 信息條是沒法經過代碼來控制是否展現的,Chrome 76 以後版本支持經過代碼控制顯示。 當用戶點擊 Mini 信息條上的 「X」 時,至少三個月瀏覽器不會再出現 Mini 條的提示,但事件層不受影響,能夠經過代碼實現。
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 上,當啓動 Web 應用時,Chrome 會根據實時 manifest 來檢查當前安裝的 manifest。若是須要更新,則在 wifi 環境下自動進入更新隊列。
觸發更新規則:
/manifest.json
更改成 /manifest2.json
,則 Web 應用將再也不更新。(很是不建議這樣作)PC 端暫時不支持更新,後續可能會支持。
目前此特性在各平臺的兼容性以下:
像 IOS 下的 Safari 是支持安裝到桌面的特性,但並無走 manifest 的規範。IOS 針對桌面圖標、啓動畫面、應用文本及主題色須要單獨的特性 Meta 進行設置。
須要在網頁中增長:
<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">
複製代碼
須要在網頁中增長:
<link rel="apple-touch-startup-image" href="/launch.png">
複製代碼
默認狀況下使用 <title></title>
中的值,須要修改的話須要指定 meta。
<meta name="apple-mobile-web-app-title" content="應用標題">
複製代碼
例如設置爲黑色:
<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