Mobishit, klient do edziennika Mobireg

Trochę tła, czyli czemu?

W 2017 roku zacząłem uczęszczać do Technikum łączności w Krakowie. Szkoła ta korzystała z dziennika elektronicznego Mobireg. Pomimo że jest to dużo wygodniejsze rozwiązanie niż klasyczny dziennik papierowy to akurat Mobireg to bardzo staro wyglądający system informatyczny.

Zrzut ekranu strony głównej, nie wygląda źle, choć trochę przestarzale
Zrzut ekranu strony głównej, nie wygląda źle, choć trochę przestarzale

Strona internetowa może i była nowoczesna we wczesnych latach 2000, ale czasy się zmieniły. Większość osób korzysta z urządzeń mobilnych, a mobilnej wersji ta witryna nie ma.

No to może jest aplikacja mobilna? No niby jest, to trzeba przyznać, ale to jedyna dobra cecha o niej.

Zrzut ekranu strony głównej, nie wygląda źle, choć trochę przestarzale
Na pierwszy rzut oka nie wygląda jakoś bardzo źle

Korzystając szybko natrafimy na brak wielu funkcji, których moglibyśmy się spodziewać po takowej aplikacji. Takich funkcji jak:

  • Powiadomienia
  • Pokazywanie średnich z ocen
  • Wysyłanie wiadomości do nauczycieli
  • Widżet planu lekcji
  • Podgląd sprawdzianów
  • Ciemny motyw

Mając trochę doświadczenia w rozwijaniu Androidowych aplikacji postanowiłem spróbować swoich sił w stworzeniu takiej, która byłaby super przydatna i miała wszystko co użytkownicy mogliby zapragnąć.

Otrzymanie dostępu do danych

Najwygodniej byłoby mieć dostęp do danych poprzez oficjalne API z dokumentacją. Niestety o takich rzeczach możemy zapomnieć przy obecnej sytuacji rynkowej. Firmy oferujące usługi dzienników elektronicznych prześcigają się w tym która będzie najbardziej zamkniętą i najmniej wygodną platformą dla programistów z zewnątrz.

Pozostają dwie opcje: scraping oraz inżynieria wsteczna istniejącej już aplikacji.

Na początku próbowałem tej pierwszej - utworzyłem Androidowe WebView, symulowałem kliknięcia w poszczególne elementy i odczytywałem HTMLa po zmianie. Dobrze że poznałem regexy, bo byłoby bardzo ciężko bez nich. Generalnie udało mi się odczytać oceny oraz ich pewny opis, ale działało to bardzo wolno, niepewnie i miało sporo limitacji - nie wszystkie informacje o ocenie były w HTML domyślnie, po niektóre trzeba było wysyłać dodatkowe zapytania a wysyłanie zapytania dla każdej oceny było jeszcze wolniejsze. Potrzebowałem lepszego rozwiązania...

Lepszym rozwiązaniem będzie poznanie jak oficjalna aplikacja bierze te dane. W tym celu użyłem aplikacji Packet Capture i bardzo szybko byłem w stanie określić endpoint API oraz jak się z nim komunikować.

Zrzut ekranu aplikacji Packet Capture pokazujący, że oficjalna aplikacja zbiera niepotrzebnie do działania dane o urządzeniu bez zgody użytkownika
Zrzut ekranu aplikacji Packet Capture pokazujący, że oficjalna aplikacja zbiera niepotrzebnie do działania dane o urządzeniu bez zgody użytkownika

Wygląda na to, że jest tylko jeden endpoint dający plik JSON będący pewnym zrzutem bazy danych. Wysyła się do niego login oraz hasło zahaszowane MD5 oraz pewne dodatkowe parametry takie jak lmt, dzięki któremu możemy określić kiedy ostatni raz synchronizowaliśmy się a serwer poda nam różnice w danych od tego czasu. Obiekty zwracane przez API są pogrupowane oraz mają pole „action”, które może mieć wartość „D” jeżeli ten element został usunięty np. ocena została usunięta.

Muszę przyznać, że sposób w jaki zostało to zaprojektowane jest całkiem sprytny i wygodny do korzystania, gdyż umożliwia wysoką użyteczność aplikacji offline.

Pierwsza publiczna wersja i wrażenia

Moją aplikację oprócz mnie testowało kilka osób - moich kolegów. Dzięki temu byłem wstanie szybko stworzyć minimalną, lecz funkcjonalną wersję i udostępnić szerszej społeczności z pewnością, że zadziała… Oczywiście że u innych nie działała 😂

Dogadałem się z moim przyjacielem - p0358 - aby użył swojego bota, który był już używany przez wielu uczniów mojej szkoły. To dało mi natychmiastowych użytkowników… i natychmiastowe raporty błędów do poprawy.

Dogadałem się z moim przyjacielem - <a href="https://github.com/p0358" rel=noreferrer target=_blank>p0358</a> - aby użył swojego bota, który był już używany przez wielu uczniów mojej szkoły. To dało mi natychmiastowych użytkowników… i natychmiastowe raporty błędów do poprawy.
Reklama jaką dostali użytkownicy bota, pokazuje zrzuty ekranu z pierwszej wersji

Pierwszym problem jaki aplikacja napotkała a nie wyszło to na testach to inny format loginów do systemu. W zależności od rocznika i szkoły loginy miały różny format i aplikacja nie zawsze potrafiła się odpowiednio zachować. To pokazuje konieczność testowania w bardzo różnych środowiskach, szczególnie jeżeli nie znamy dokumentacji API.

Aplikacja nie miała też obsługi kont rodziców, którzy w jednej szkole mieli więcej niż jedno dziecko. Dzięki społeczności wiele z takich problemów zostało zauważonych i mogłem je naprawić.

Ogółem wrażenia były bardzo pozytywne pomimo początkowych problemów z logowaniem. Aplikacja zyskała setki użytkowników i zaczęło spływać do mnie również wiele podziękowań i sugestii nowych funkcji.

Dalszy rozwój

Minimalna aplikacja, którą udostępniłem była lepsza od oficjalnej ale nie zaprzestałem na tym. Szybko wziąłem się do pracy, aby dodać jeszcze więcej funkcji, które chcieli użytkownicy.

Na początku ważniejsza była funkcjonalność od wyglądu, jak aplikacja działała to mogłem polepszać aspekt wizualny. Jednym z takich aspektów było wprowadzenie Easter Egga - aplikacja losowo obrażała dziennik Mobireg porównując go do twoich „beznadziejnych” ocen. To pokazywało się na ekranie logowania oraz na liście sekcji aplikacji.

Na początku ważniejsza była funkcjonalność od wyglądu, jak aplikacja działała to mogłem polepszać aspekt wizualny. Jednym z takich aspektów było wprowadzenie Easter Egga - aplikacja losowo obrażała dziennik Mobireg porównując go do twoich „beznadziejnych” ocen. To pokazywało się na ekranie logowania oraz na liście sekcji aplikacji.
Ekran logowania z Easter Eggiem. Przymiotnik co chwilę się zmienia na inny synonim słowa beznadziejny.

Przez wiele iteracji przeszły też ekrany takie jak szczegóły oceny. Zależało mi na najlepszym dla użytkownika interfejsie i użycie BottomSheet, na które wpadłem zupełnie przypadkowo było strzałem w dziesiątkę. Nie pamiętam już skąd wziąłem inspirację, może z Google Photos?

Na początku ważniejsza była funkcjonalność od wyglądu, jak aplikacja działała to mogłem polepszać aspekt wizualny. Jednym z takich aspektów było wprowadzenie Easter Egga - aplikacja losowo obrażała dziennik Mobireg porównując go do twoich „beznadziejnych” ocen. To pokazywało się na ekranie logowania oraz na liście sekcji aplikacji.
Kolejne iteracje szczegółowego podglądu oceny.

Wraz z rozwojem aplikacji zacząłem dodawać więcej funkcji jak kalkulator średnich z możliwością przewidywania średniej po dostaniu oceny - jeden z najbardziej sugerowanych i uwielbianych przez uczniów dodatków do apki.

Na początku ważniejsza była funkcjonalność od wyglądu, jak aplikacja działała to mogłem polepszać aspekt wizualny. Jednym z takich aspektów było wprowadzenie Easter Egga - aplikacja losowo obrażała dziennik Mobireg porównując go do twoich „beznadziejnych” ocen. To pokazywało się na ekranie logowania oraz na liście sekcji aplikacji.
Ilość zakładek na liście głównej aplikacji dobrze obrazuje rozwój.

Wsparcie z powietrza, czyli VPS

Jednym z problemów których nie byłem w stanie łatwo rozwiązać to brak natychmiastowych powiadomień. Mobireg nie daje możliwości otrzymywania informacji o zmianach na bieżąco gdy się pojawiają. Trzeba się o nie najpierw zapytać - takie podejście nazywamy „powiadomieniami pull”.

Alternatywnym podejściem są „powiadomienia push” czyli takie, które wysyła serwer do urządzeń bez pytania się o nie co chwilę. Jest to dużo lepsze rozwiązanie z powodu efektywności rozwiązania – zamiast zużywać zasoby bez przerwy na bezowocne zapytania podczas gdy nic się nie dzieje (a większość czasu nie będzie żadnych powiadomień) to serwer powie aplikacji, że coś się stało natychmiast gdy będzie coś interesującego dla użytkownika.

Serwer Mobirega Aplikacja Mobishit Okresowe odpytywanie API

Tak wyglądała architektura aplikacji na początku. Urządzenie łączy się tylko z serwerem dziennika elektronicznego. Aby uzyskać powiadomienia push, musiałem zbudować własny system, który wysyła powiadomienia do użytkowników. Wygląda tak:

Serwer Mobirega Aplikacja Mobishit Okresowe odpytywanie API Firebase Mój serwer Wysyłanie powiadomień Wybudzanie urządzenia Okresowe sprawdzanie Dodatkowe funkcje scrapując HTML

Należy zaznaczyć, że korzystanie z dolnej części schematu jest opcjonalne i użytkownik może z niej zrezygnować. Aplikacja potrafi działać samodzielnie – według pierwotnego schematu, jednak pozbawi to użytkownika wielu funkcji. Takie podejście jest też dla mnie wygodne, gdyż mogę w dowolnym momencie zrezygnować z zapewniania usług, które przecież wykorzystują mój serwer za darmo.

W taki sposób zaimplementowałem, też sprawdziany, porównania oraz wysyłanie wiadomości. Pomimo, że nie ma takich funkcjonalności w API to stworzyłem własne API w Pythonie, które symulując przeglądarkę (scrapując HTML) umożliwiło takie rzeczy.

Rola społeczności i czego się nauczyłem

Nie byłoby Mobishita gdyby nie społeczność. A przynajmniej nie byłoby w takiej postaci. Co urodziło się jako mały dodatek do osobistej aplikacji z rozkładami busów przeszło ogromną transformację w stało się świetną apką pokochaną przez uczniów.

Osiągnięcie tego wymagało kontaktu ze społecznością, dlatego uważam, że cokolwiek bym nie programował muszę rozmawiać i słuchać co mi mówią użytkownicy. Myślę, że to najważniejsza rzecz.

Pamiętam, że dostałem wiadomość od jednego z użytkowników z pytaniem czy mógłbym dodać możliwość zmiany nazwy przedmiotu lub nauczyciela. Z początku pomyślałem, że to przecież bez sensu, po co ktoś chciałby zmieniać nazwę przedmiotu? Ale stwierdziłem OK, spoko, ogarnę, bo był to mały dodatek. Gdy dodałem tą funkcjonalność to sam zacząłem dodawać pseudonimy dla nauczycieli, moi znajomi jak zobaczyli to też zaczęli ustawiać własne nicki. Naprawdę świetna zabawa 🤣 i to dzięki sugestii społeczności.

W tym projekcie doceniłem też system kontroli wersji GIT. Nie dość, że pozwala mi bezpiecznie eksperymentować na osobnej gałęzi to jeszcze zapisuje całą historię kodu. To potencjalnie uratowało mi wiele godzin szukania błędów. Raz miałem dziwny błąd, który miał miejsce tylko w opublikowanej wersji (release), nie był widoczny na pierwszy rzut oka, ale sprawiał, że aplikacja się nie synchronizowała, czyli można powiedzieć że całkowicie psuł funkcjonalność. Ale przecież w poprzedniej wersji działało, a nic nie zmieniałem z synchronizacją… Dzięki GITowi byłem w stanie namierzyć problem — zaktualizowałem jedną z bibliotek do nowszej wersji i okazało się, że to w niej jest problem. Może nie powinienem jej używać, bo była w wersji przedpremierowej, ale z drugiej strony super przydatna.

Inną nieoczywistą umiejętnością, którą nabyłem to SQL. W tym projekcie używałem baz SQLite oraz MySql. Pisałem zapytania „z palca” i nadal jestem fanem takiego pisania zamiast używania ORMów, które sprawiają, że troszkę bardziej skomplikowane zapytania, które można od tak napisać w czystym SQL to godziny „hakowania” ORMa.

Osiągnięcie tego wymagało <b>kontaktu ze społecznością</b>, dlatego uważam, że cokolwiek bym nie programował muszę rozmawiać i słuchać co mi mówią użytkownicy. Myślę, że to najważniejsza rzecz.
Przykładowe zapytanie do bazy pobierające oceny z przedmiotu do kalkulatora średnich, biblioteka Room w Kotlinie

Co dalej?

Po dwóch latach mojej nauki w szkole pojawiły się plotki, że Mobireg odchodzi do lamusa i zastąpi go Librus. To by oznaczało, że Mobishit będzie zupełnie nieprzydatny.

I tak się stało. Mobireg został podobno wykupiony przez Librusa i wszystkie szkoły, które korzystały z ich rozwiązań Mobirega zostały przejęte przez Librusa.

Wszystkie? Nie! Z jakiegoś powodu Mobireg pozostał w szkołach muzycznych i aktualnie reklamuje się jako Dziennik dla szkół muzycznych. Nawet zmienili logo, żeby to pokazać 😂

Taki obrót spraw, zmniejszył popularność mojej aplikacji. Jednak są jej jacyś użytkownicy. Muszę przyznać, że bardzo zaskoczył mnie Issue na GitHubie od jednego z użytkowników po kilku latach niewspierania apki. Szybko udało mi się rozwiązać problem, niemniej pokazuje to, że apka wziąć jest w użyciu, co oczywiście jest miłe 😊

Dzięki za przeczytanie
Jakieś pytania, sugestie, opinie? Śmiało, napisz do mnie