24-05-2021 | Programowanie
PWA – historia prawdziwa
Tagi: 

Alfred jest front-end developerem i jak każdy developer w celach szkoleniowo – naukowych rozwija swoje dodatkowe projekty. Od jakiegoś czasu pracuje nad jedną aplikacją. Koncept jest taki, że jest to aplikacja mająca pomóc w dbanie o zdrowie użytkownika, taki medyczny asystent. Jako, że na codzień Alfred pisze w React to postanowił wpasować się w standard PWA, tj strony która na urządzeniach mobilnych wygląd i zachowuje się jak natywna aplikacja. Jest to koncept znany i w miarę polecany. Jeden kod obsługuje Androida, iOS oraz web. W necie dostępne jest wiele informacji i tutoriali na ten temat. Ogólnie PWA jest chwalone, jako alternatywa do natywnych rozwiązań. Częstym wątkiem jest to, że z poziomu PWA można mieć dostęp do kamery urządzenia oraz lokalizacji. Dostępność informacji oraz niski próg wejścia spowodował że Alfred uznał ten wybór za słuszny i od razu zabrał się do pracy.

ServiceWorker

To pierwszy z ważnych plików które Alfred musiał dodać do projektu. ServiceWorker stanowi kwintesencje PWA, jest to plik który odpala się na osobnym procesie niż sama aplikacja i może działać nawet kiedy aplikacja już jest ubita. ServiceWorker stanowi pewnego rodzaju proxy dla naszej aplikacji, pozwala na przechwytywanie zapytań fetch oraz obsługuje cachowanie. Komunikuje się z aplikacją i stanowi istotne ogniwo w aplikacja PWA. Podstawowy, ServiceWorker jest prosty do napisania, więc Alfred uporał się z nim raz dwa. Oczywiście SW może zawierać bardziej rozbudowane funkcje i mechanizmy … ale na razie ten temat zaparkuje tutaj, Alfred sam potem o tym opowie.

manifest.json

Ten plik determinuje sposób wyświetlania się aplikacji. Nie ma tu jakiejś większej logiki tylko dodanie ikon, tytułu, skróconej nazwy. To co zasługuje tutaj na uwagę to tryb wyświetlania. Należy pamiętać, że aplikacja PWA to defacto jest w dalszym ciągu stroną www. Więc uruchamiana jest przez silnik przeglądarki internetowej, co za tym idzie domyślnie otrzymujemy pasek adresu i inne dobrodziejstwa znane z przeglądarek. Dopiero ustawienie trybu na ‘standalone‘ wymusza wyświetlanie aplikacji w trybie pełnoekranowym. Wtedy nasza strona wygląda jak natywna aplikacja.

Początkowe przemyślenia

Dzięki dodaniu dwóch wyżej wymienionych plików strona Alfreda zaczęła zachowywać się jak aplikacja natywna. Możliwość użycia React i rozwiązań znanych z aplikacji webowych spowodowało że, pisanie samej aplikacji szło mu dobrze, większość logiki biznesowej oraz interface był już gotowe. Alfred musiał teraz dostosować parę rzeczy pod standardy smartphonów. I tu zaczęły się chece. 

Po jakimś czasie Alfred zadzwonił do mnie aby podzielić się pewnymi refleksjami.

Add to homescreen

– To jakiś dziwne jest – zaczął – mam parę przemyśleń na temat tego całego PWA. Kiedy miałem już działającą, pierwszą, podstawową wersję aplikacji chciałem ją przetestować na urządzaniu. Mam starego Samsunga z Androidem oraz Iphona, czyli wszystkie systemy na których chciałem aby to działało. 
– A która masz wersje Androida? – zapytałem.
– Hehe, dobrze, że o tym wspominasz – zaczął się śmiać do telefonu – Na moim Samsungu mam Androida 7 ale wrócę do tego tematu później … .
– Ok, czyli czuje że były z tym jakieś komplikacje.
– Fakt, ale tak jak powiedziałem, rozwinę temat później – zakończył myśl – Reasumując nasz główny wątek, na webie, czyli normalnie w przeglądarce aplikacja śmiga normalnie jako stronka, no ale chciałem ją “zainstalować”. Na Androidzie jest nawet przepis jak pojawić boxa z info czy chcesz zainstalować aplikacje, aczkolwiek coś mi z tym nie zaskoczyło. Pomyślałem że, później się tym zajmę, zawsze mogę zainstalować ją ręcznie. Klikam opcje przeglądarki i tam jest “Dodaj do ekranu głównego”.
– Czyli nie jest to opcja jakoś super widoczna dla użytkownika? – zapytałem.
– Tak, generalnie albo użytkownik o tym wie, albo trzeba jakiś pop up z instrukcją wyświetlić. Ale słuchaj, na iOS jest weselej, wchodzę przez chroma …. i nigdzie nie ma opcji “Install” ani nic z tych rzeczy. Dopiero jak się wejdzie przez Safari to opcja ta jest widoczna, ale dopiero jak klikniesz w udostępnienia strony i tak jest “Add to homescreen”.
– No bo na iOS PWA chodzi pod kontrolą Safari, więc w Chromie tego nie znajdziesz – zauważyłem.
– Czyli widzisz, jest kilka przypadków, Chrom na Androidzie,btw innych przeglądarek na Adroidzie na razie nie sprawdzałem, iOS. Pasowało by wykryć na jakiej przeglądarce jesteś aby dopasować komunikaty. Np jak ktoś wejdzie na Chromie na iOS to treść powinna być taka “hej koleś, jak chcesz sobie zainstalować tą stronę jako apke, to wejdź na ten adres z Safari i tam kliknij share i add to screen”.
– Hehe… no trochę słabo.

Offline mode

Następnie opowiadał mi o wprowadzeniu funkcjonalność trybu offline i tutaj PWA wraz z ServiceWorkerem dają fajne możliwości.

Flow jest następujące: aplikacja wykonuje strzał po dane do serwera, serwer odpowiada danymi i teraz do głosu dochodzi ServiceWorker. Niejako przechwytuje tą odpowiedź, rozszyfrowuje jaki to był typ danych, dodaje je do IndexedDB, czyli do takiej wewnątrz przeglądarkowej bazy danych, następnie zwraca dane do aplikacji

– No dobra – zapytałem – to jak zachowuje się pobieranie danych?
– Jest tak, w momencie kiedy aplikacja strzela po dane i jest offline, tj z serwera nie przychodzi odpowiedź, to serviceWorker dostarcza danych właśnie z indexdDB. W indexedDB jest zrzut danych z ostatniej synchronizacji.
– Ok, brzmi spoko, a w momencie dodania danych do aplikacji? Jak to obsłużyłeś?
– Więc tak. Stworzyłem dwa rodzaje tablic w indexedDB. Jedne służą do odczytywania z nich danych, a drugie przechowują dane do wysłania do serwera. Kiedy dodaje jakiś „item” do aplikacji to tak naprawdę, pod maską dodaje moje nowe dane do indexedDB do koszyka “do wysyłania” i informuje ServiceWorkera o zarejestrowaniu nowej operacji “sync”…
– sync ? – zapytałem zaciekawiony.
– Tak, to jest mega fajne w ServiceWorkerze. Są zdarzenie sync, czyli operacje które mają się wydarzyć tylko kiedy będzie połączenie z internetem. W głównym wątku aplikacji rejestrujesz taki event na ServiceWorkerze, a on już ogarnia resztę.
– Ok, czyli twoje dane czekaj na wysyłkę na server?
– Tak, jednocześnie są wczytywane do aplikacji.
– Czyli użytkownik może normalnie korzystać z aplikacji? – chciałem się upewnić, bo naprawdę zaimponował mi ten koncept.
– Co do zasady, tak. Obsłużyłem praktycznie 90% najbardziej potrzebnych funkcji aby było dostępne offline. Kiedy użytkownik dodaje „item” do listy, kiedy usuwa, kiedy edytuje. Działa to naprawdę spoko i wydajnie. 
– Ale jak o tym mówisz to brzmi fajnie, ale ton twojego głosu nie jest jakiś specjalnie szczęśliwy – zauważyłem.
– Fakt. Po pierwsze rozwiązanie to wymaga dołożenia kodu i logiki, ServiceWorket trochę spuchł. Po drugie ServiceWorker nie za bardzo komunikuje się z aplikacją na poziomie buildów w webpacku i miałem trochę zabawy ze zmiennymi środowiskowymi itp.

IMO Alfred miał całkiem dobry pomysł na obsługę trybu offline. Szczególnie podoba mi się zaciągnięcie ServiceWorkera do pracy, aby zarządzał danymi.

Notyfikacje

– I wszystko było ok, aż doszedłem do momentu “notyfikacji” – opowiadał dalej Alfred – Chciałem aby aplikacja w odpowiednim czasie wysyłała powiadomienie. Zbiegły mi się tutaj dwa tematy, Pierwszy to sama istota notyfikacji. Aplikacja jest de facto stroną webową, więc w przeglądarce wystarczy wyświetlić monit o zgodzie na powiadomienia i to śmiga.
– Takie standardowe powiadomienia w przeglądarce?
– Tak, trochę można jest “odpicować”, wiesz swoją ikonę dodaj, akcje pod przyciskiem. Całkiem spoko.
– Android wspiera to rozwiązanie?
– Android wspiera to rozwiązanie …. ale dopiero od wersji .
– A ty mówiłeś, że testowałeś ti na Adroidzie 7 – zauważyłem.
– Tak, i to jest właśnie lipa, że defacto na miom testowym urządzeniu nie mogłem tego sprawdzić, muszę inny telefon wziąść do testów. Ale to i tak dobrze bo iOS …. ma to w nosie. Aplikacja PWA na iOS jest defacto odpalonym procesem safari, a tam nie ma notyfikacji dy design. I kiszka – ton jego głosu jasno wskazywał, że Alfred stracił na tym sporo nerwów.
– To jak to zrobić? – spytałem.
– Jedyna droga prowadzi przez Appla, trzeba być zarejestrowanym developerem itd itd. Na poziomie developmentu nie zagłębiałem się w to.
– Uuuuu, to słabo.
– Nooo lipa trochę. Ale to jeszcze nie koniec tego temat. Stwierdziłem że na razie ten temat zostawię. Zwłaszcza, że doszedł tu drugi temat. Otóż powiadomienie ma przyjść w konkretnym momencie, więc chciałem aby było to ustawiane z poziomu apki a nie serwera, aby być niezależnym od tego czy aplikacja jest online czy offline. Więc chciałem aby ustawiona w czasie notyfikacja była pamiętana w aplikacji i w odpowiednim momencie robiła “ping” …
– No ok, ma to sens. Chciałeś uzyskać scheduled notification – wtrąciłem.
– Taaaak. I znowu lipa …
– Jak to?? – teraz to już byłem zaintrygowany.
– Z poziomu PWA tak do końca nie da się tego zrobić. W Chromie jest eksperymentalny feature do schedulowania, “Notification Triggers API” , ale nie jest on pewny, oficjalny. No a o Safari to można zapomnieć.
– Wow, ale pod górkę. Jak rozwiązałeś ten problem?
– W ServiceWorkerze dodałem funkcję coś a’la cron – Alfred zaczął tłumaczyć z przejęciem – Kiedy dodaje item do aplikacji tworzone są wpisy czasowe kiedy mają iść powiadomienia, te wpisy lecą do bazy. ServiceWorker co jakiś czas pobiera listę najbliższych powiadomień i wrzuca je do indexedDB, a druga funkcja sprawdza czy w indexedDB sa powiadomienia do wyświetlenia, jeżeli tak to leci notyfikacja.
– I to zadziałało?
– Tak, w zakresie ograniczeń o których wcześniej ci mówiłem. Na webie luz, android dopiero od wersji 8, iOS nie działa.
– To dość poważny problem z tym iOS.
– Tak, no ale taką mają politykę, wszystko musi iść przez nich. I w sumie ta jedna kwestia dużo mi napsuła w moim koncepcie jak to powinno wyglądać i działać.
– No nie dziwie się.

Deploy

Zacząłem się zastanawiać jak wygląda sprawa  z deployem na produkcję takiej apki i zapytałem o to Alfreda.

– Aplikacja jest defacto stroną web, więc jeżeli wejdziesz na urla z dowolnego urządzenia to wyświetli ci się strona w przeglądarce. Tutaj działa wszystko fajnie. użytkownik może “zainstalować” apkę, czyli dodać ją do homescreen.
– Jeżeli wie jak …
– Taaaak, jeżeli użytkownik wie jak. Ale jeżeli to już zrobi to aplikacja jest na telefonie, ma swoją ikonę. Odpala się w trybie pełnoekranowym, bez widocznego paska url.
– Czy tak pod maską, jest to process chrome/safari który renderuje stronę WWW w fullscreen mode?
– No tak należy na to patrzeć.
– A jakbyś chciał dodać tą aplikację do AppStore i Google Store?
– Google store wspiera apki PWA, trzeba dodatkowo zapakować apke w Trusted Manifest i jest to do zrobienia, jednak znów jest Apple – ciężkie westchnienie – No to rozwiązanie po prostu u nich nie zadziała. Trochę straciłem chęć grzebania za tymi informacjami. Wydaje mi się to to nie warte jest zachodu.

Końcowe przemyślenia

– No dobra – zapytałem na koniec – jakbyś miał to tak podsumować.
– Hmm, PWA jako standard jest świetny. Strony które działają jak aplikacje natywne … brzmi super. Ale, jak zawsze jest “ale”. Można znaleźć dużo pochlebnych opinii na ten temat i dużo tutoriali. Ja mam takie przemyślenia na ten temat. Otóż jeżeli planujemy apke, należało by wypisać wszystkie technologie i koncepty z których chcemy skorzystać i sprawdzić co gdzie działa. Bo na przykład w moim przypadku, na największy problem napotkałem pod koniec developmentu.
– Te notyfikacje? – upewniłem się
– Tak, te notyfikacje były dla mnie bardzo istotne i w momencie kiedy do nich doszedłem i okazało się, że nie mogę ich użyć w sposób jaki planowałem spowodował u mnie wybuch złości…
– No nie dziwie się. Czyli masz bardzo mieszane odczucia?
– Z jednej strony jako front pracujący w React-cie to PWA było naturalne dla mnie, z drugie strony są mega ograniczenia i przeszkody po drodze. Wydaje mi się że w przypadku bardziej złożonych aplikacji to PWA nie jest wystarczające.
– Ok, tylko w takim razie co z projektem?- miałem nadzieję, że Albert nie porzuci projektu, bo zapowidała się naprawdę ciekawie – Masz napisany server, aplikacje w PWA która działa, ale nie do końca tak jak być chciał.
– Odpowiem krótko: React-Native.

O tym jak poszedł proces developmentu na React-Native i jak wyglądają dalsze losy aplikacji Alfreda napisze innym razem.

A tymczasem
Miłego dnia