O progresivních webových aplikacích jsme poprvé slyšeli v rámci vývojářské konference DEVEL.CZ v přednášce Ivana Kutila, který jejich použití demonstroval na reálné případové studii. Nicméně jsme tak trochu tápali, jak taková progresivní aplikace funguje, jak se liší od responzivní verze webu a naopak, co jí chybí do nativní mobilní aplikace.
"Progressive Web Apps (https://developers.google.com/web/progressive-web-apps) are experiences that combine the best of the web and the best of apps. They are useful to users from the very first visit in a browser tab, no install required. As the user progressively builds a relationship with the App over time, it becomes more and more powerful. It loads quickly, even on flaky networks, sends relevant push notifications, has an icon on the home screen and loads as a top-level, full screen experience."
A existuje i vytyčující manifest:
Pokud vám ani toto nepomohlo, tak v kostce se jedná o aplikaci, kterou spustíte ve webovém prohlížeči, tato aplikace se vás zeptá, jestli si ji chcete nainstalovat, a pokud ano, umístí vám do zařízení svou ikonku. Při dalším spuštění aplikace již máte spoustu zdrojů a dat aplikace v cache, takže se aplikace spustí rychle a při spouštění se dokonce prezentuje vlastním splash screenem. Aplikace navíc umí využívat hardware zařízení, jako např. fotoaparát, GPS, bluetooth nebo NFC a také dokáže běžet kompletně offline a až při dostupnosti připojení se synchronizovat se serverem. Tudíž, jak předesílala definice od autorů z Google, jedná se o to lepší z obou světů - webových a nativních aplikací.
V rámci našeho interního vývojářského dne kreativity jsme si chtěli takovou aplikaci vyzkoušet a zasadit ji nějak do toho, co právě děláme, tak, abychom z toho nejen my vývojáři měli vědomosti a zážitky, ale nějaké ty znalosti nabyla i naše firma a mohla je v budoucnu uplatnit a zúročit.
V tu dobu jsme pro jednoho našeho klienta připravovali soutěž, jejímž cílem bylo sbírat od soutěžících fotografie produktů, dodávaných tímto klientem. Soutěžící pořídí fotografii nějakého produktu, tuto fotografii zašle do soutěže a těší se na svou výhru. Ta mu připadne, pokud bude patřit mezi nejlepší. Soutěž interně slouží jako marketingový nástroj k tomu, aby klient získal grafický materiál a podklady pro další kampaně a propagaci.
Napadlo nás tedy vytvořit progresivní webovou aplikaci, která by umožnila soutěžícím pořídit onu fotografii přímo pomocí jejich zařízení s kamerou nebo fotoaparátem, nahrát ji do soutěže a o této skutečnosti informovat ostatní soutěžící pomocí notifikace.
Co je to App Shell? Jedná se o jakési jádro a (zejména vizuální) obálku aplikace, do které se donačítá aktuální obsah aplikace, pokud je aplikace online. Nebo se zobrazí data z cache, pokud zrovna není dostupné připojení k internetu a aplikace je offline.
Opět přikládáme oficiální definici:
"An application shell is the minimal HTML, CSS, and JavaScript powering a user interface. The application shell should load fast, be cached and dynamically display content."
V našem případě se tedy bavíme o splash screen, liště s názvem aplikace, ovládacích prvcích, assety a výkonném kódu aplikace, který ji celou oživuje a propojuje se serverem. Obsah jako takový již přiteče přes API z backendu a my jej na klientu jen zobrazujeme a cachujeme tak, aby při dalším spuštění aplikace již byl dostupný a uživatel neviděl pouze prázdnou stránku.
Doporučuji vývoj aplikace nastartovat buď pomocí tohoto workshopu (https://codelabs.developers.google.com/codelabs/your-first-pwapp), nebo (pokud jste zkušenější JavaScript vývojář) můžete zkusit tento sandbox (https://github.com/google/web-starter-kit), který mi ale osobně přišel na naučení příliš komplexní.
Service Worker je možné si představit jako vlastní server aplikace, který běží na pozadí a ve své podstatě propojuje samotnou aplikaci se skutečnou serverovou logikou. My jsme Service Worker v aplikaci využili následovně:
Service Workery toho umí více. Jedná se však o velmi mladou technologii, dokonce označovanou za experimentální, a její podpora v prohlížečích je velmi slabá. Nicméně, do budoucna by měly umět i např. geofencing nebo synchronizaci na pozadí. Více o Service Workerech se můžete dočíst tady: http://www.html5rocks.com/en/tutorials/service-worker/introduction, tady https://github.com/slightlyoff/ServiceWorker/blob/master/explainer.md nebo tady https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API.
Díky Web App Manifestu prohlížeč a koncové zařízení pozná, že je naše aplikace progresivní. Zde se definuje vstupní bod aplikace, její název, ikony pro různá rozlišení, barevné téma atd. Jedná se tedy o jakýsi zavaděč webové aplikace zapsaný v podobě JSON. Struktura dat je definována pomoci W3C specifikace (https://www.w3.org/TR/appmanifest - v současné době stále ve stádiu draftu). Samotný manifest je pak nalinkovaný do hlavičky webové stránky, resp. aplikace.
Tato funkce aplikace se opírá o ne úplně nové, leč velmi výkonné a užitečné technologie - HTML 5 Video a Canvas, aka <video> a <canvas> HTML tagy a protokol WebRTC. Tato kombinace umožňuje přesně to, co potřebujeme, a sice otevřit stream videa z kamery či fotoaparátu, zobrazit jej v prohlížeči jako zdroj medií pro <video> tag a udělat snapshot do <canvas>, který lze pohodlně serializovat do data-uri nebo binární podoby. Pak už jen stačí snapshot zapersistovat a máme požadovaný materiál pro soutěž.
V průběhu implementace jsme narazili na pár úskalí, mezi něž patří zejména různá nebo nulová podpora těchto technologií v jednotlivých prohlížečích. Nicméně, pro naši aplikaci jsme se spokojili s funkčností v Chrome a Firefoxu, a to jak na desktopu, tak v jejich mobilních verzích. Překvapil nás i prohlížeč Edge z dílny Microsoftu, který také fungoval velmi dobře. S Internet Explorerem včetně verze 11, Operou a ani Safari jsme spokojení nebyli. Drobná podpora zde byla a možná by se s větším úsilím a několika polyfilly konal úspěch i zde. Zatím na to ale prostor nebyl.
Dalším úskalím bylo, že na internetu není dostatek dostupných, relevantních a hlavně aktuálních materiálů. V časovém presu a přístupem quick'n'dirty jsme nakonec sáhli po tomto tutoriálu: https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Taking_still_photos, který zafungoval na první dobrou. Výborná dema a příklady lze nalézt také zde: https://webrtc.github.io/samples.
Drobnou překážkou při testování na mobilním zařízení byla také nutnost přistupovat k aplikaci přes HTTPS. Přes obyčejné HTTP prohlížeč Chrome odmítal zpřístupnit hardware zařížení. Na desktopové verzi s tímto problém nebyl, protože aplikace byla dostupná lokálně přes localhost, který je v Chrome whitelistován. Nakonec jsme naši aplikaci zprovoznili na serveru přístupném zvenčí pod HTTPS. Při vývoji, a zejména testování progresivních webových aplikací, je s tímto drobným omezením nutné počítat.
Push notifikace využívají Push API (http://w3c.github.io/push-api) a Notification API (https://notifications.spec.whatwg.org) implementované do prohlížeče Chrome od verze 42 (nicméně s jistými omezeními a specifikami by měly fungovat např. i v novějším Firefoxu). Push API se stará o přenos zpráv ze serveru na klienta (do webového prohlížeče), kdežto Notification API obstarává samotné zobrazení notifikace v prohlížeči.
Naším cílem bylo využít tato API v kombinaci se Service Workery, aby šlo např. z fiktivního redakčního systému poslat notifikaci návštěvníkům webu bez nutnosti přítomnosti na stránce.
V prohlížeči tedy poběží Service Worker poslouchající na *push* událost a v reakci na ni zobrazí notifikaci se zaslanými daty. O přenos zprávy ze serveru na klienta se postará Google Cloud Messaging API (https://developers.google.com/cloud-messaging) - dále jen GCM, přes které doručíme zprávu z redakčního systému na klienty. GCM omezuje rozeslání notifikací na max. 100 klientů v jedné dávce, což nám vadit zatím nebude, protože pro demonstraci budeme zasílat notifikaci pouze na jednoho vybraného klienta.
Implementace má tedy dvě části:
Na straně klienta je potřeba nejprve vyžádat práva pro zobrazení notifikací a následně získaný token odeslat na backend (v ideálním případě i s nějakým identifikátorem zařízení, aby bylo možné, v případě revokace práv, aktualizovat token zařízení). Přes token je pak možné na straně backendu identifikovat klienta a cíleně mu přes GCM zaslat notifikace.
Při implementaci jsme narazili na zásadní problém v tom, že webové prohlížeče nepodporují v Push notifikaci zasílat vlastní data. Tato funkce je v současné době plně dostupná pouze pro mobilní zařízení. Prohlížeč Chrome tuto funkci podporuje až od verze 50, nicméně data je nutné zašifrovat pomocí algoritmu (https://developers.google.com/web/updates/2016/03/web-push-encryption), pro který v té době nebyla implementace v podobě knihovny pro PHP a na vlastní implementaci nebyl prostor. Pro jednoduchost jsme tedy pouze zobrazili napevno danou notifikaci.
Technologie se nám líbí, je to zajímavý směr, ale je v plenkách. Podpora v prohlížečích je slabá a různá. API není stabilní a často se mění. Určitě jsou případy, kdy využití tohoto přístupu dává smysl, ale zatím bych raději sáhl po hybridní nebo rovnou nativní mobilní aplikaci. Samotné povolení a zprovoznění zmiňovaných Google API také nebylo zrovna jednoduché, jelikož prostředí Google API Console prošlo v poslední době nemalými změnami, a dokonce ani oficiální návody použitých technologií tyto změny často nereflektují.