2015. augusztus 17.

Webappok és offline működés

10 perc olvasási idő

Webappok és offline működés

Az offline elérhetőséghez szükséges appcache technológia már évek óta elérhető és használják is, ám az utóbbi időben került előtérbe és kezdett népszerűvé válni. A webappok elterjedésével egyre gyakrabban felmerül az igény is, hogy a webes szolgáltatás ne csak online legyen elérhető, hanem akár internet hiányában is használható legyen.

Miért lehet rá szükséged?

A webalkalmazások offline elérésével függetlenítheted alkalmazásod az internetkapcsolattól. Kevésbé gyakran változó adatok esetén kifejezetten előnyös (pl. menetrend, egyéb információs appok), hiszen ha van internet, akkor ellenőrzöd van-e változás, ha pedig nincs, akkor a felhasználók gond nélkül elérhetik a már meglévőket. Az appcache használatával ugyanakkor jelentősen gyorsíthatod a működést is, növelve ezzel a felhasználói élményt, ráadásul a kevesebb hálózati lekérés által még a telefon üzemidejének is kedvezel.

Mikor érdemes alkalmaznod?

Alapvetően webalkalmazások esetén lehet ideális a módszer, viszont érdemes egy oldalt használó statikus oldalaknál is alkalmazni sebesség optimalizálás céljából. HTML5 játékok esetén kifejezetten ideális, hiszen ha minden függőséget lecache-elsz, és a főoldalra kiteszed az elérést, bármikor elérhetővé válik az alkalmazás. Minél több a dinamikus adat, annál kevésbé ajánlott a használata, hiszen van egy szint, amikor el kell fogadnod, hogy csak online módon használható a termék.

A mobilos böngészők nagy része már a kezdetektől támogatja az egyes oldalak főoldali elérését, sajnos a Chrome for Android csak 2015. áprilisától (42.0.2311 verzió) tette lehetővé. Ez azért lehet érdekes és fontos, mert sokakban fel sem merült, hogy valami offline módban is működhet, amíg a szokásos „megnyitom a böngészőt és beírom az url-t” módon érte el azt.

Mobilon főoldalra app ikon

Hogyan kezdj hozzá?

A folyamatot három részre lehet bontani:

Statikus elemek lekezelése: A futáshoz szükséges HTML, CSS, JavaScript fájlokat egyenként megadod a böngészőnek és kényszeríted rá, hogy mentse le őket az appcache tárolóba. Ide tartozhatnak még a webfontok, sprite-ok és egyéb képek is.

Dinamikus tartalmak kezelése: A webappod jellemzően távoli, API-tól kapott adatokkal dolgozik, melyek XML, JSON, esetleg CSV formátumban jutnak el az apphoz. Értelemszerűen internet kapcsolat nélkül ezek nem állnak rendelkezésre, így gondoskodnod kell a tárolásukról.

Offline működés biztosítása: Az alkalmazásnak le kell kezelni azt a helyzetet, ha nincsen internet kapcsolat és ilyenkor mindent abból kell megoldanod, amit letárolt.

Statikus elemek

Ugyan a böngészőnknek van saját gyorsítótára, melyet minden oldal megtekintéskor igénybe vesz, viszont ez elég labilis és sok tényezőtől függhet a hatékonysága. A HTML5 bevezetésével elérhetővé vált az application cache interfész, ami kifejezetten hosszútávú tárolásra ad lehetőséget, jó pár extra tulajdonsággal.

A működés lényege, hogy létrehozol egy manifest fájlt (lehetőleg .appcache kiterjesztéssel), ami a következőket tartalmazhatja:

CACHE MANIFEST  
#v1.0 

CACHE:
index.html
script.js
style.css

NETWORK:
login.php

FALLBACK:
/user/*.jpg img/user.jpg

Minden esetben az első sorban szerepelnie kell a CACHE MANIFEST leírásnak, ami jelzi a böngészőnek hogyan kell feldolgoznia a tartalmakat.

Fontos, hogy ha módosítod a letárolandó fájlok tartalmát, a böngésző nem fogja automatikusan lehúzni a frissebb verziót. Ellenben, ha bármilyen változást észlel az appcache fájlban, akkor minden abban felsorolt fájlt újrahúz. Erre a legpraktikusabb megoldás a második sorban elhelyezett megjegyzés, ami egyfajta verziózásnak felel meg.
Érdemes még megemlíteni ezzel kapcsolatban, hogy emiatt az apró macera miatt ajánlott az appcache bevezetését a projekt legvégére hagyni, hogy ne kelljen minden egyes módosítást külön lekezelni.

Ezután minden appcache fájlban három szekciót lehet elkülöníteni és használni.

A CACHE szekcióban felsorolt fájlokat a böngésző automatikusan letölti, tárolja, és minden esetben elsőként a tárolt verzióhoz nyúl az online elérés helyett.

A NETWORK szekció tartalmazza mindazon url-eket, amiket mindenképp online kell meghívnia az appnak. Amennyiben a CACHE szekcióban konkrétan felsoroltad az összes letárolandó fájlt, a „*” szabály lekezel minden, előzőleg nem említett hívást.

A FALLBACK szekció olyan (akár wildcard jellegű) url párokat tartalmaz, melyek offline módban kerülnek feldolgozásra. Az első tag megadja, hogy mit figyeljen, a második (space után) pedig, hogy mire hivatkozzon abban az esetben. A példa kódban minden felhasználó profilkép lekérésekor ugyanazt az user.jpg fájlt fogod visszakapni. Nem elhanyagolható tényező, hogy kizárólag ugyanarról az url-ről tudsz fallback szabályokat definiálni, ahol a manifest fájl is található!

Az appcache alkalmazása előtt érdemes átrágni magad a konkrét működésén, mert egy rosszul megírt manifest file lelassíthatja és megnehezítheti a későbbi munkát. Ajánlom ezt az oldalt kiindulásnak.

network

Dinamikus tartalom

Amennyiben dinamikus tartalmakat akarsz megjeleníteni, melyek egy API-tól jönnek (elmenteni egy játék eredményeit, vagy bármilyen beállítást), nem tudod elkerülni a HTML5 webstorage használatát. Több alternatíva is adott, viszont a támogatottságok itt már eléggé meghatározzák, hogy mit érdemes konkrétan igénybe venni. Ezeket most nem részletezem, inkább az általam preferált megoldást emelem ki.

A Mozilla létrehozott egy zseniális libet, ami megoldást nyújt minden storage technológiákkal kapcsolatos bizonytalanságra. A localForage böngészőtől függően kiválasztja a megfelelő drivert és azt használja, ráadásul aszinkron módon, ami szintén fontos az adatok megfelelő kezelése szempontjából. A használata majdnem megegyezik a localStorage szintaktikájával, azzal a lényeges különbséggel, hogy konkrétan visszakapod az adatot, amivel dolgoznod kell.

// localStorage használatával
localStorage.setItem('key', JSON.stringify('value'));
doSomethingElse();

// localForage esetén használhatunk callback függvényt:
localforage.setItem('key', 'value', doSomethingElse);

// vagy "promises" megoldást:
localforage.setItem('key', 'value').then(doSomethingElse);

Működési logika

A fenti technológiák alkalmazásával elérheted, hogy minden szükséges adat le legyen tárolva kliens oldalon, viszont fontos része a működésnek a szinkronizálás és a kettéválasztott működés. Tapasztalataim szerint, a legjárhatóbb út, ha az API hívásokat lehetőleg egy helyen, elkülönítve minden más funkcionalitástól kezeled, így a lehető legkevesebb alkalommal kell vizsgálni az internetkapcsolat állapotát és elkerülheted a felesleges 404-es requesteket és timeoutokat.

Érdemes megemlíteni, hogy a navigator.onLine metódus nem minden esetben ad vissza pontos értéket (itt kifejtve). Ezt többen is felismerték és létrejött az online.js library, ami mindig biztos értéket ad vissza. Kisebb hátulütője a dolognak, hogy 5 másodpercenként meghív egy távoli fájlt (amit megszakít), amivel a telefon akkumulátorát terheled, így szerintem csak indokolt esetben érdemes használni.

Tapasztalatok

Fontos! Ha szeretnéd, hogy a webalkalmazásod offline is elérhető legyen, már a tervezéskor figyelembe kell venni és az egyes funkciókat úgy kell kialakítani, hogy azok internetkapcsolat nélkül is elérhetők legyenek, viszont online állapotban szinkronizáljon az APIval. Egy már meglévő, kicsit is bonyolultabb appot elég körülményes és túlbonyolított folyamat lehet átalakítani. Érdemes mérlegelni, hogy egyáltalán belekezdj. Továbbá számolnod kell azzal is, hogy a kliens oldali tároló (localStorage) mérete mindig véges. A képeket csak módjával, API-tól kapott adatokat csak megfelelő szűrés után ajánlott elmenteni, ezzel is spórolva a helyen. Általában 5MB a korlát, de ha nem bánsz vele megfelelően, a storage tele lesz szeméttel, ami hamar káoszhoz vezet.

Amennyiben felkeltette érdeklődésed a technológia, mindenképp ajánlom ezt a linkgyűjteményt és az offlinefirst.org oldalt, ahol rengeteg hasznos információt szerezhetsz a témával kapcsolatban!

Tóth Zoltán

Vezető fejlesztő. Közel tíz éve foglalkozik webfejlesztéssel, igyekszik egyaránt backend és frontend területen is képben lenni. WordPresspárti, böngészőkiegészítő- és bookmarkletgyűjtő.

Tóth Zoltán

Hozzászólások