ãããã£ãŠãä»åŸ2ãæã§ãPWAã®ãããã¯ã«é¢ããèšäºãå ¬éããã ãã§ãªãã10æ11æ¥-Progressive Web Apps Dayã§ããŒãå¥ã®ãªã³ã©ã€ã³äŒè°ãéå¬ããäºå®ã§ãã ãããŸã§ã®éãAirBerlinã®PWAã䜿çšããå®éã®ã±ãŒã¹ã«æ³šç®ããŠãã ããã
Airberlinã¯ããã®ãããªWebãµã€ãããã°ã©ã ãéçºããäžçåã®äŒæ¥ã§ãããã¢ãã€ã«éçºããã³ã€ãããŒã·ã§ã³ã®è²¬ä»»è ã§ããHans Schwagerã¯ãäŒè°åå è ãšçµéšãå ±æããŸãããä¹å®¢ã«ãšã£ãŠãã©ãã«ããŠããæ å ±ããã°ããç°¡åã«ç¢ºèªããã¢ãã€ã«ããã€ã¹ããçŽæ¥æä¹åžãåãåãããšãéèŠã§ãã ãã®ãããææãªéçºéšéãéããŠãããã°ã¬ãã·ãWebã¢ããªãäœæããŸãããããã¯ãã¢ãã€ã«ã¢ããªã±ãŒã·ã§ã³ãšã€ã³ã¿ãŒããããµã€ãã®æè¯ã®åŽé¢ãçµã¿åããããã€ããªããã§ããã
ææ°ã®ãŠã§ãã¢ããªã±ãŒã·ã§ã³ã®ãã¯ãããžãŒã«ããããšã¢ãã«ãªã³ã®ä¹å®¢ã¯ãããã«ãèªå® ã®Wi-Fiãä»ããŠãµã€ããæåŸã«èšªãããšãã«ãæä¹åžãæ è¡ã«é¢ããæ å ±ã«ãã€ã§ãã¢ã¯ã»ã¹ã§ããããã«ãªããçªç¶ç©ºæž¯ã«é£çµ¡ãåããªããªããŸããã ããã«ãããã客æ§ã«éåžžã«ã·ã³ãã«ã§ç解ãããããµãŒãã¹ãæäŸããå©äŸ¿æ§ãé«ããã¢ãã€ã«éçºã®æªæ¥ãå°ãã ãè¿ã¥ããããšãã§ããŸãã
ãææ°ã®Webã¢ããªã±ãŒã·ã§ã³ããšã¯äœã§ããïŒ
ç°¡åã«èšãã°ãããã¯ã¢ãã€ã«ã¢ããªã±ãŒã·ã§ã³ã®ããã«èŠããWebãµã€ãã§ãã æåã®åŒã³åºãã®åŸããã£ãã·ã¥ã®ãããã§ïŒéšåçãŸãã¯å®å šã«ïŒãªãã©ã€ã³ã§äœ¿çšã§ããŸããããŒãžã§ã³40ã®Chromeããã³Firefoxãã©ãŠã¶ãŒãããã³çŸåšã®Operaãã«ãããµããŒãããŠããŸãã ãã®ãããªãã¢ããªã±ãŒã·ã§ã³ãã¯ããµã€ãã®éåžžã®ã¢ãã€ã«ããŒãžã§ã³ãšã¯ç°ãªããäœéã®ã€ã³ã¿ãŒãããæ¥ç¶ïŒããšãã°ã空枯ã§ã®éè² è·ã®ç¡æWi-FiïŒã§ããŸãæ©èœããæå°éã®ãã©ãã£ãã¯ãè²»ãããéåžžã®ã¢ã€ã³ã³ã®ããã«ãã¹ã¯ãããã«è¿œå ã§ããã¢ã¯ã»ã¹ã§ããŸãã¹ããŒããã©ã³ã®éç¥ã·ã¹ãã ã«æ¥ç¶ããã¹ããŒããã©ã³ã®ãªãœãŒã¹ãèŠæ±ããŸããã
PWA airberlinã®äœææ¹æ³
ããªã¢ã³ã»ãã·ã¥ãã³ãšã¢ã¯ã»ã«ã»ãã·ã§ã«ã«ãããã¬ãŒã·ã§ã³
ã³ã¢æè¡
åçŽãªãã®ã¯PWAã®å éšã«é ãããŠããŸããäž»ãªã¿ã¹ã¯ã¯ããã¹ãŠãæ£ããæ¹æ³ã§çµã¿ç«ãŠãããšã§ãã
Webã³ã³ããŒãã³ã
èãæ¹ã¯åçŽã§ããããã°ã¬ãã·ãWebã¢ããªã±ãŒã·ã§ã³ã€ã³ã¿ãŒãã§ã€ã¹ä»¥å€ã¯ãã¹ãŠã³ã³ããŒãã³ãã§ãã Polymer 1.0ã䜿çšããã¹ã©ã€ããŒçšã«åå¥ã®ã³ã³ããŒãã³ããäœæããŸãããããã«ã¯ãçµæãäœæãããã¹ãŠã®çš®é¡ã®ãã©ãŒã ã詳现ãèŠçŽ ãã€ãŸããŠãŒã¶ãŒã«è¡šç€ºããããä»®æ³ãã±ããããå«ãŸããŸãã
ã«ã¹ã¿ã ã€ãã³ã
ã³ã³ããŒãã³ãéã®çžäºäœçšã®ããã«ãéåæãªã¯ãšã¹ããå±¥æŽãã¢ããªã±ãŒã·ã§ã³ã§äœ¿çšãããããŒã¿ããããã®ãã£ãã·ã¥ããã³ããããžã§ãã³ã°ãäžå 管çããåºæ¬çãªã¹ã¯ãªãããäœæããŸããã
HistoryAPI
å®éãããã°ã¬ãã·ãã¢ããªã±ãŒã·ã§ã³ã¯1ããŒãžã§æ§æãããŠããŸãã ãµãŒãã¹ã¯ãŒã«ãŒãŸãã¯ãã£ãã·ã¥ã¯URLã®ããã·ã¥ã®æäœæ¹æ³ãç¥ããªããããGETãšã¢ããªã±ãŒã·ã§ã³ã®ããŸããŸãªãç»é¢ããåºå¥ããããã«GETã䜿çšããããšã«ããŸããã ååãšããŠããœãªã¥ãŒã·ã§ã³ã¯æ£åžžã§ããããªãã©ã€ã³äœæ¥ã«ããã€ãã®åé¡ããããŸãã å°æ¥çã«-å€ã®ã¿ã䜿çšãããããã«ãã©ã¡ãŒã¿ãŒãéä¿¡ããŸã-èŠæ±ãæ£åžžã«åŠçããå Žåã¯ãå€ã®ãã¢ãéä¿¡ããŸãã ãŸãã¯ãURLã§ãšã³ã³ãŒãããæ å ±ã«åºã¥ããŠãããã®èŠæ±ãåäœæããŸãïŒããã«ã€ããŠã¯ãåŸã»ã©ã³ãŒãäŸã§èª¬æããŸãïŒã
ãµãŒãã¹ã¯ãŒã«ãŒ
ãã§ã«è¿°ã¹ãããã«ãç§ãã¡ã®ã¢ããªã±ãŒã·ã§ã³ã¯ãå®éã«ã¯ã1ã€ã®ãŠãŒã¶ãŒã±ãŒã¹ãæã€1ããŒãžã®Webãµã€ãã§ãã ãã®ãããžã§ã¯ãã«ãªãã©ã€ã³äœæ¥çšã®ãµãŒãã¹ã¯ãŒã«ãŒãè¿œå ããŸã-梚ã®æ®»ãããã®ãšåããããç°¡åã§ãã ã€ã³ã¿ãŒãã§ãŒã¹èªäœã¯æåã®ãã€ã³ã¹ããŒã«ãäžã«ãã£ãã·ã¥ãããããŒã¿ãšè¿œå ãã¡ã€ã«ã¯æåã®ãªã¯ãšã¹ãã§ããŠã³ããŒããããŸãã åé¡ã¯ãé©åãªã¿ã€ãã³ã°ã§é©åãªããŒã¿ãåé€ããããšã§ããã ãŸãããµãŒãã¹ã¯ãŒã«ãŒãéããŠããã·ã¥éç¥ãçµ±åãã2ã€ã®ã¿ãã¹ã§ãã§ãã¯ã€ã³ãå®è£ ããŸããã
WebSQL
ãªãã©ã€ã³ãã³ãã©ãŒã«å ããŠãlocalForageã䜿çšããŠãããã¯ãŒã¯ã«æ¥ç¶ããã«äœæ¥ãããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãåäžãããããšèããŠããŸãããããã¯ãIndexDBãWebSQLãlocalStorageãããã«å«ããã¯ãããžãŒã§ãã ãµãŒããŒãšã¯ã©ã€ã¢ã³ãéã®ãã¹ãŠã®å¯Ÿè©±ã¯JSONã§èšè¿°ãããããããããªãéçºãå€§å¹ ã«ç°¡çŽ åãããŸãã
ããã©ãã¹
ä»ã®ãã¹ãŠã«äœ¿çšãããŸãã åºæ¬çãªDOMã»ã¬ã¯ã¿ãŒãäžéšã®éåæãªã¯ãšã¹ããäžè¬çã«ããµãŒãããŒãã£ã®ã©ã€ãã©ãªãä»ããŠå®è£ ããããªããã®ãã¹ãŠã æ¢è£œã®jsãæ¥ç¶ããå¯äžã®ã±ãŒã¹ã¯ãããŸããŸãªã¿ã€ã ãŸãŒã³ãšæ¥ä»ã®èšç®ãå®å šã«åŠçããç¬éã䜿çšããããšã§ããæçµçã«ãäžéšã®ãã©ã€ãã¯éå»/æªæ¥ã«ããªããéãããšãã§ããŸãã æ®ãã®ããã«ã ããã€ãã®åºæ¬
ãããã§ã¹ããšã¡ã¿ããŒã¿
ãããã®ããšã¯ããŠãŒã¶ãŒãã¢ããªã±ãŒã·ã§ã³ãããŒã ç»é¢/ãã¹ã¯ãããã«è¿œå ã§ããããã«ããããã«å¿ èŠã§ãã æ®å¿µãªãããã¢ããªã±ãŒã·ã§ã³ã®ãªãã©ã€ã³æ©èœããµããŒããããšãã芳ç¹ããiOSã¯Androidã®ãŸãŸã§ããïŒããã§ã¯ãããŸããïŒãAndroidãšiOSã®æ£ããã¢ã€ã³ã³ãã¿ã€ãã«ãé è²ããŠãŒã¶ãŒã«æäŸããããšã«ããŸããã
ã©ããã£ãŠãã£ã
ã¯ã€ãã¯ãã§ãã¯ã€ã³ãšãé»è©±ã«ç¹å¥ãªãã®ãäœãã€ã³ã¹ããŒã«ããã«é£è¡æ©ã«æä¹ããæ©èœã¯çŽ æŽãããã®ã§ãã¢ããªã±ãŒã·ã§ã³ãé«éã«ãããã£ãã®ã§ãã ãããã£ãŠãDOMããããã¯ãããããŠã³ããŒããåŸ æ©ãããããããšãªããåºæ¬çãªcssãšäžéšã®ãã¬ãŒã¹ãã«ããŒãé€ããã¹ãŠãåçã«ããŒãããŸãã
åºæ¬çãªHTMLæ§é ïŒ
<section class="page" id="dashboard"> <header> <slider-element name="dashboard" display="all"></slider-element> </header> <div class="contents"> <ul class="collection"> <li><a href="#flightdetails">Journey details</a></li> <li><a href="#explore">Explore destination</a></li> <li><checkin-element></checkin-element></li> </ul> </div> </section> <section class="page" id="flightdetails"> <header> <slider-element name="flightdetail" display="activeFlight"></slider-element> </header> <flightdetails-element></flightdetails-element> </section> <section class="page" id="explore"> <place-element></place-element> </section>
ã¹ã¿ãŒã¿ãŒJavaScriptïŒ
(function() { var raf = window.RequestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame; // defer loading of all app relevant javascript // and non criticial CSS function deferLoad() { // JS var element = document.createElement("script"), l = document.createElement('link'); element.src = "javascript/app.js"; document.body.appendChild(element); // CSS l.rel = 'stylesheet'; l.href = 'css/main.css'; document.getElementsByTagName('head')[0].appendChild(l); } if (raf) { raf(deferLoad); } else if (window.addEventListener) { window.addEventListener("load", deferLoad, false); } else if (window.attachEvent) { window.attachEvent("onload", deferLoad); } else { window.onload = deferLoad; } })();
ã©ã®ããã«æ©èœããŸããïŒ
æåã¯ããŠãŒã¶ãŒã®ããã€ã¹ã«éä¿¡ãããã®ã¯ã¢ããªã±ãŒã·ã§ã³ã®ã¹ã±ã«ãã³ã ãã§ãã åºæ¬ã¬ã€ã¢ãŠããã¡ãã¥ãŒããŒãåçãããå Žæã®ã«ã©ãŒãã£ããããŠãŒã¶ãŒãèŠãããŒãžã®ãã®éšåã®çãããã¹ãã
ã¡ã€ã³CSSãã¹ã¯ãªããã®å€§éšåãããã³ãµãŒãããŒãã£ã©ã€ãã©ãªïŒããªããŒãã¢ãŒã¡ã³ããããŒã«ã«ãã©ã¬ãŒãžïŒãããã¯ã°ã©ãŠã³ãã§èªã¿èŸŒãŸãããã®åŸã¡ã€ã³ãµã€ããããªããŒãä»ããŠããŸããŸãªèŠçŽ ãæ¥ç¶ããŸãã ããŒã«ã»ã«ã€ã¹ã¯ãã®ãããã¯ã«é¢ããåªããèšäºãæžããŠããŸãïŒ aerotwist.com/blog/polymer-for-the-performance-obsessed
éåžžã®ã¢ãã€ã«ããŒãžïŒm.airberlinïŒãšæ¯èŒãããšãåèšããŠã³ããŒãæéã¯ã»ãŒåãã§ãã3Gæ¥ç¶ã䜿çšããã¢ãããŒãã§ã¯1.5ç§ãåŸæ¥ã®ã¢ãããŒãã§ã¯2.5ç§ã§ãã ãã ããã³ã³ãã³ããšãµã€ãèªäœã®ã¬ã³ããªã³ã°ã¯ã¯ããã«æ©ãå§ãŸããŸããã¢ããªã±ãŒã·ã§ã³ãéããŠãã0.5ç§åŸã§ãã ã¢ãã€ã«ãµã€ãã«ã¯ãæåã®èŠçŽ ã®1.2ç§åã«ã²ã©ãæéããããŸãã ãã®æãŸã§ã«ãPWAã¯ãã§ã«éããŠãããæºåãã§ããŠããŸãã èªã¿èŸŒã¿ãããã«é«éåããããåªããŠããŸããã䜿çšãããŠãããã¯ãããžãŒã«ããèªã¿èŸŒã¿æéãæå°éã«æããããã¹ã¿ã€ã«ãåçã®èªã¿èŸŒã¿äžã«ããŒãžäžã§èŠçŽ ããžã£ã³ãããæ§åãèŠãå¿ èŠããªããªããŸããã
ã¡ãã£ãšããããªãã¯
åŸ ã¡æéãççž®ããFacebook'aã§èŠããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãæ¹åããã®ã«åœ¹ç«ã€å¥ã®ããªãã¯ã ææ°ã®ããã€ã¹ã¯ããã£ã¹ãã¬ã€ã®è§£å床ãšéåžžã«é žæ§åºŠã®äœãã€ã³ãžã±ãŒã¿ãŒã®ç¯å²ãç°ãªããŸã-720pã®6ã€ã³ãã·ã£ãã«ã2560x1440ãã£ã¹ãã¬ã€ã®5ã€ã³ãããã€ã¹ããŸãã¯ã¢ãã€ã«ããã€ã¹ã®4k2kã§ã€ãŸãããŸãã äžè¬çãªãœãªã¥ãŒã·ã§ã³ã«ã¯ããããç¬èªã®èæ¯ç»åãããããŠãŒã¶ãŒãã¢ãã¯ãã®èæ¯ãèŠãã®ãé²ãããã«ãéåžžã«å°ããªç»åïŒ60x40ãã¯ã»ã«ïŒãšã¬ãŠã¹ãŒããã䜿çšããŸããã ãã®çµæããŠãŒã¶ãŒã¯å¿ èŠãªè§£å床ã§ã»ãŒãã¹ãŠã衚瀺ããå¿ èŠãªè§£å床ã®ç»åãããã¯ã°ã©ãŠã³ãã§èªã¿èŸŒãŸãããšããã«ããŒãããäœè§£å床ããã£ãã·ã¥ã®çŸåšã®ç»åã«çœ®ãæããŸãã
æåã®ãã³ãã©ãŒã¯ãã»ãã®æ°è¡ã®ã³ãŒãã§æ§æãããŠããŸããã ã¢ã¯ãã£ãåããåŸããã¹ãŠã®éçã³ã³ãã³ããããŒãããéãæ¹æ³ã§ãã¹ãŠããã£ãã·ã¥ã«è©°ããŸããã ãã®ã¢ãããŒãã¯ããããã¿ã€ãã¢ããªã±ãŒã·ã§ã³ã§äœæ¥ããŠãããšãã«é©ããŠããŸããããããã¿ã€ãã¢ããªã±ãŒã·ã§ã³ã§ã¯ã1ã€ã® "ãã©ã€ã"ãããã1ã€ã®ç®çå°ããããå±¥æŽããªããé¢é£æ§ã倱ãããå¯èœæ§ããããŸããã ãã¡ãããå®éã«ã¯ãPWAã¯ããå°ãå¿ èŠã§ãããã©ã€ãæ å ±ã衚瀺ããæä¹åžãäœæããŸãã ãããŠåœŒã¯ããã©ã€ãåŸã«ç Žæ£ãŸãã¯æåŠãããªããã°ãªãããããŸããŸãªãã©ã€ãã«ã€ããŠã¯ãåçãããã¹ããªã©äœã§ãè¿œå æ å ±ã衚瀺ããå¿ èŠããããŸãã
ãã©ã€ãã®ãã§ãã¯ã€ã³ãããç°¡åãã€è¿ éã«ãªããŸããããã©ã€ããäºçŽçªå·ãè¿œå ãããã¿ã³ãã¯ãªãã¯ããŠæä¹åžãåãåããŸããã ç°¡åã«ã¯ãªããŸããã
ãã¹ãŠããã£ãã·ã¥ã«å ¥ãããããã¹ãŠã®æ¹åã«é¢ãããã¹ãŠã®æ å ±ãäžåºŠã«ä¿åããããšã¯ãã©ããããããããã»ã©é²æ©çã§ã¯ãªããããé£è¡æ©ãçéžããŠãã48æéåŸã«ãã¹ãŠãç Žæ£ããŸãã WebSQLãšããŒã«ã«ã¹ãã¬ãŒãžã䜿çšããŠãããããããŒã¿ã2ååé€ããå¿ èŠããããŸãã ä»ããã®ã³ãŒãã¯ããã«è²¬ä»»ããããŸãïŒ
ã³ãŒããã©ã°ã¡ã³ãapp.jsïŒ
function _isEmpty = function(obj) { if ('undefined' !== Object.keys) { return (0 === Object.keys(obj).length); } for(var prop in obj) { if(obj.hasOwnProperty(prop)) { return false; } } return true; }; // called whenever a checkin is requested to be displayed function checkCheckinStatus( checkinID ) { var tS = Math.floor(now.getTime() / 1000), removeCheckinFromApp = function(cid) { // remove from data delete app.data[cid]; // update local cache localforage.setItem('flightData',app.data); // trigger event for updating UI elements var event = new CustomEvent( 'updatedData', {detail: {modified: cid}} ); document.dispatchEvent(event); }; // no data or no checkin data? - return if(_isEmpty(app.data) || !app.data[checkinID]) { return false; } // remove only in case arrival time is min. 48 hours in past if((tS - app.data[checkinID].ticket.arrivalTimestamp) < (60 * 60 * 48) ) { return false;} if ('serviceWorker' in navigator) { // delete cache of flight in service worker... app.sendMessage( { command: 'deleteCheckin', keyID: checkinID } ).then(function(data) { // remove the checkin from app data... removeCheckinFromApp(checkinID); }).catch(e) { // could not remove checkin from service worker }; } else { removeCheckinFromApp(checkinID); } } // send data to the service worker app.sendMessage = function(message) { return new Promise(function(resolve, reject) { var messageChannel = new MessageChannel(); // the onmessage handler messageChannel.port1.onmessage = function(event) { if (event.data.error) { reject(event.data.error); } else { resolve(event.data); } }; if(!navigator.serviceWorker.controller){ return; } // This sends the message data and port to the service worker. // The service worker can use the port to reply via postMessage(), which // will he onmessage handler on messageChannel.port1. navigator.serviceWorker .controller.postMessage(message,[messageChannel.port2]); }); }
ã³ãŒããã©ã°ã¡ã³ãservice-worker.jsïŒ
var cacheName = 'v1', checkinDataRegex = /applicable\?pnr=([a-zA-Z0-9]+)&lastname=([a-zA-Z]+)/ ticketRegex = /image\/pnr\/([a-zA-Z0-9]+)\/lastname\/([a-zA-Z]+)\/ticket\/([0-9]+)/; self.addEventListener('fetch', function(event) { var request = event.request, matchCheckin = checkinDataRegex.exec(request.url); if (matchCheckin) { // Use regex capturing to grab only the bit of the URL // that we care about (in this case the checkinID) var cacheRequest = new Request(match[1]); event.respondWith( caches.match(cacheRequest).then(function(response) { return response || fetch(request).then(function(response) { caches.open(cacheName).then(function(cache) { cache.put(cacheRequest, response); }) return response; }); }) ); } if (ticketRegex) { // disable the image (by replacing it) [...] } [...] }); // communication between the service worker and the app.js self.addEventListener("message", function(event) { var data = event.data; switch(data.command) { case 'deleteCheckin': // open current cache caches.open(cacheName).then(function(cache) { // remove the flight data (JSON) cache.delete(data.checkinID).then(function(success) { event.ports[0].postMessage({ error: success ? null : 'Item was not found in the cache.' }); )}; }) break; [...] } });
ãã£ãã·ã¥ãæäœãã
äžéšã®ããªããŒèŠçŽ ã§ã¯app.jsãå®è¡ã§ããŸããapp.jsã®å éšã§ã¯ããã£ãã·ã¥ã«ä¿åãããŠããæ å ±ãé¢é£ããŠãããã©ãããç¹å¥ãªæ¹æ³ã§ãã§ãã¯ããŸãã ããŒã¿ãå€ãå Žåããã³ãã©ãŒã¯ãæžã蟌ã¿ãã³ãã³ããåãåããå éšãã£ãã·ã¥ãæ¶å»ããããŒã«ã«ã¹ãã¬ãŒãžããããŒã¿ãåé€ããŸãããã®åŸãé¢å¿ã®ãããã¹ãŠã®ããªããŒèŠçŽ ã«ããŒã¿ãå€æŽãããããšãéç¥ããŸãã
äžèšã®ã³ãŒãã«ã¯ãã§ãããã³ãã©ãå«ãŸããŠããŸãã ãã³ãã©ãŒã察話ããURLã¯å€æŽãããå¯èœæ§ãããããïŒããšãã°ãfirebaseåæçšã®è¿œå ã®GETãã©ã¡ãŒã¿ãŒã衚瀺ãããïŒãå¿ èŠãªãã©ã¡ãŒã¿ãŒã»ããããããã¢ãŠãããŠWebã¢ããªã±ãŒã·ã§ã³ãã£ãã·ã¥ã«å ¥ããæ£èŠè¡šçŸãäœæããŸããã ãããã£ãŠãURLã«çžãããããšã¯ãªãããã®URLããç°¡åã«ããŒã¿ãååŸããŠãåŠçãšä¿åã容æã«ãªããŸãã
ä»ã®äœã
ã¢ãã€ã«ããã€ã¹ã§ã®ããŠã³ããŒãæéãå€§å¹ ã«ççž®ããæãå¹æçãªæ¹æ³ã¯ãåã ã®ãã¡ã€ã«ãšã¢ã€ãã ã®æ°ãæžããããã³ãã©ãŒãä»ããŠãé 延ããŠã³ããŒããã䜿çšããããšã§ããã æåã®ã¹ãããã¯ããã¹ãŠã®Webã³ã³ããŒãã³ããããã¯ããŠã¢ãã€ã«ããã€ã¹ã«éä¿¡ããããšã§ãããã³ãã©ãŒã¯å¿ èŠãªãã®ããã¹ãŠããŒãããããŸã§åŸ æ©ããŸãã åæã«ãããã¯ã°ã©ãŠã³ãã®CSSãã¹ã¯ãªãããç»åãèªã¿èŸŒãã§ãã£ãã·ã¥ã«å ¥ããŸãã 次ã«ããåºæ¬ãèšèšããåéãããªãœãŒã¹ããŠãŒã¶ãŒããã€ã¹ã«ããŠã³ããŒãããããšãã«è©³çŽ°ãšç²Ÿå·§ãªèšèšã§ã©ããããŸãã
ããšãã°ãçŽ æµãªèæ¯ãå®å ã«é¢ããè¿œå æ å ±ãããã¯ã°ã©ãŠã³ãã§ããŒããããŸãã ãããŠãäž»ãªæ©èœã¯ããããããŠã©ã€ãã®ãšããžæ¥ç¶ã§æ¥ç¶ãããŠããå Žåã§ãããããã®å¯æããªãã§æ©èœããŸãã
æ®å¿µãªãããéæ³ã®ãã¿ã³ããããå·ã€ãããã¯ãŸã çºæãããŠããªãã®ã§ãä»»æã®APIãä»ããŠãããŒã ç»é¢ã«ãµã€ããè¿œå ããã¿ã³ãã¯ãªãã¯ããŠãŠã£ã³ããŠã衚瀺ããã ãã§ã¯æ©èœããŸããã æ©ç¥ãšæŸèæã®ã»ããã䜿çšããå¿ èŠããããŸããã€ãŸããã¡ãã»ãŒãžãšãPWAããã¹ã¯ãããã«è¿œå ããæ¹æ³ããŠãŒã¶ãŒã«äŒãããã€ã¢ãã°ããã¯ã¹ãèšè¿°ããŸãã ãã®å Žåãèªè»¢è»ã®çºæã«ãã§ãã¯ãè¿œå ããããã®æç¹ã§ãã€ã¢ãã°ã衚瀺ãããŸãã ãã¹ãŠã®æ å ±ã¯ããã©ã€ãã®ãã§ãã¯ã€ã³åŸã«ã®ã¿ãªãã©ã€ã³ã§å©çšã§ããããã«ãªããããã·ã§ãŒãã«ãããäœæãããããŠãŒã¶ãŒãæåŸ ããã®ã¯ãã®åŸã§ãã å®éããã¹ãŠãã·ã³ãã«ã§ãïŒ
var deferredPromptEvent; window.addEventListener('beforeinstallprompt', function(e) { e.preventDefault(); deferredPromptEvent = e; return false; }); // and in the moment your condition is fulfilled // check if the prompt had been triggered if(deferredPromptEvent !== undefined && deferredPromptEvent) { // show message deferredPromptEvent.prompt(); // do something on the user choice deferredPromptEvent.userChoice.then(function(choiceResult) { if(choiceResult.outcome != 'dismissed') { } // finally remove it deferredPromptEvent = null; }); }
ãã®å ŽåããŠãŒã¶ãŒããã±ãããä¿åããããšãéç¥ãããããã¢ãããéãããšãã¡ãã»ãŒãžã衚瀺ãããŸãã
ããªããŒã®èŠçŽ ã¯ååã§ãïŒååã¯ãŸã åå²ãããŠããããšã¯ããã£ãŠããŸãããä»ã§ã¯ååæ§ãšããŠã®äžå¯åæ§ãæå³ãç¶ããŠããŸãïŒã ãã®ãããååæ§ãããåããªããŒèŠçŽ ãã€ã³ã©ã€ã³CSSãšjavascriptãéã¶ããšã«ãªããŸãã ãã¡ãããå€éšã¹ã¿ã€ã«/ã¹ã¯ãªãããè¿œå ã§ããŸãããã€ã³ã©ã€ã³å®è£ ã¯ããéãããŒãããããã確å®ã«åäœããŸãã ãã¡ãããç¬èªã®ãã€ãã¹ããããŸãããã®ãããªã³ãŒããç¹ã«CSSãç¶æããã®ã¯ããå°é£ã§ãã ç§ãã¡ã®è§£æ±ºçã¯ãGruntã䜿çšããæ£ç¢ºã«ã€ã³ã©ã€ã³ã§åã蟌ãããšã§ãããŸããCSSã®ããªã³ã³ãã€ã©ãšããŠSCSSã䜿çšããŠãã ããã åèŠçŽ ã¯ãæ£èŠåãããCSSãšäžç·ã«ãåºæ¬çãªãã©ã¡ãŒã¿ãŒïŒé¢æ°ãšå€æ°ïŒãæã€ç¬èªã®SCSSãã¡ã€ã«ãåãåããŸãã Gruntã¯çæãããCSSãååŸããã€ã³ã©ã€ã³ã¹ã¿ã€ã«ãšããŠåã蟌ã¿ããã®åŸèŠçŽ ã«ãã€ã³ãããŸãã ãã¡ãããåãããšãgulpãŸãã¯LESSã§ãæ©èœããŸãã
PWAã®äœæããã»ã¹ã§åŠãã ããš
äœæ¥ã容æã«ããèªã¿èŸŒã¿ãé«éåããæ¹æ³ã¯ããã€ããããŸãããæãèå³æ·±ãå¹æçãªæ¹æ³ã®1ã€ã¯ãããªããŒãªããžã§ã¯ãã®ããŒã¿ããŒã¹ãšããŠãªããžã§ã¯ãã®é åã䜿çšããããšã§ãããç¹ã«ãã¹ããããèŠçŽ ãæäœããå Žåã1ã€ã®å°ããªè€éãããããŸãã ç§ãã¡ã®å Žåãã¢ããªã±ãŒã·ã§ã³ã«ã¯æä¹åžãå«ãã¹ã©ã€ããŒããããŸããã ã¯ãŒãã³ã®ã¬ã³ããªã³ã°å šäœããµãŒããŒããã¯ã©ã€ã¢ã³ãã«è»¢éãããããã¯ã©ã€ã¢ã³ãããµãŒããŒããåä¿¡ããã¬ã³ããªã³ã°ã®ããŒã¿ã®ééã¯éåžžã«å°ãªããªããŸããå°ãã®JSONãããã€ãã®ãã€ããª...ããã«ãããç¹ã«ãµãŒããŒã®äœæ¥ã容æã«ãªããèªã¿èŸŒã¿æéãççž®ãããŸãçŸä»£ã®ã¬ãžã§ããã å€ãããã€ã¹ã§ã¯ãç©äºã¯ããã»ã©ç°¡åã§ã¯ãããŸããã äºåã«ã¬ã³ããªã³ã°ãããã³ã³ãã³ããäœæããããããããŒã¿ãäœæããæ¹ãç°¡åãªå ŽåããããŸãããPWAã®æåã®èµ·åã«ã¯æéãããããŸãã ããã¯ãã¹ãŠãç¹å®ã®ã¢ããªã±ãŒã·ã§ã³ã®ç¹å®ã®ã±ãŒã¹ãç 究ããç®çã§ãããA / Bãã¹ãã®ç®çã¯ãã¿ã¹ã¯åŸã®åé¡ã解決ããããã®ç¹å®ã®ã¢ãããŒãã®å©äŸ¿æ§ãè©äŸ¡ããããšã§ãã
人çãå€§å¹ ã«ç°¡çŽ åããŸãããè¡æ¶²ãå°ç¡ãã«ããå¯èœæ§ã®ãã2çªç®ã¯ãã³ãã©ãŒã§ãã ã¯ããããŒããšã¬ã³ããªã³ã°ã®é床ãåäžãããªãã©ã€ã³äœæ¥ãç°¡çŽ åãããå€æ°ã®ãµãŒããŒãªã¯ãšã¹ããåé€ãããŸããããã¯ãäžå®å®ãªã¢ãã€ã«æ¥ç¶ã§ã®äœæ¥æã«ããã«åœ±é¿ããŸãã ãã ãããã®ã¢ãããŒãã§ã¯ãããã£ãã·ã¥ãã察象ããšããã£ãã·ã¥ããæ¹æ³ãã®åé¡ãçºçããŸãã Androidã§ãã¹ãŠãå€ããå°ãªããæ確ã§ããã°ãææ°ã®ããã€ã¹ã§ã¯åé¡ã¯ãããŸããããiOSã®å Žåã¯ãŸã åé¡ãæ®ã£ãŠããŸããããšãã°ãã¯ããŒãºãã¢ãŒããã¯ãã£ãšãã©ãããã©ãŒã ã®æ©èœã§ãã ãã¹ã¯ãããã«ã·ã§ãŒãã«ãããè¿œå ããããšãã§ããïŒç¹å®ã®ãã©ãŠã¶ãŒãã£ãã·ã¥ã¡ã«ããºã ã«ããïŒãªãã©ã€ã³ã§ãéåžžã«æªãæ¥ç¶ã§ãåäœããŸãããåæã«æç«ã衚瀺ããããšãã§ããŸãã
ä»æ¥ã¯ããã§ãã¹ãŠã§ãããè¿ãå°æ¥ãPWAã®ãããã¯ã«æ»ããŸãã