Upozornenia v aplikáciách
prístup k blesku fotoaparátu, overenie existencie blesku, komunikácia s používateľom pomocou Toast
-u a Alert
dialógu, ukončenie aplikácie, ikona aplikácie, rozličné rozlíšenia cieľových zariadení a ich značenie, Android Asset Studio
Záznam z prednášky
Intro
(slide) Stále pracujeme na aplikácii baterka, ktorá sa už po “grafickej” stránke správa podľa prototypu webovej aplikácie z prezentácie.
Stále však nesvieti a tento problém sa pokúsime vyriešiť na dnešnej prednáške.
Okrem toho však budeme potrebovať ošetriť prípady, kedy bude aplikácia spustená na zariadení, ktoré nie je vybavené bleskom a teda svietiť nebude (napr. emulátor). A taktiež musíme vyriešiť situáciu, keď aplikácia bude spustená na Android-e, ale nebude mať práva na prístup ku blesku.
A popri tom všetkom by bolo dobré používateľa vždy informovať o tom, k čomu došlo. A to buď pomocou toast-ov alebo alert-ov.
Buď svetlo!
(slide) Rámec React Native nevie priamo pristupovať ku fotoaparátu a ovládať jeho blesk. Ak ho chceme používať, musíme nainštalovať vhodný modul. Pre naše potreby použijeme modul react-native-torch.
Modul nainštalujeme príkazom:
$ yarn add react-native-torch
Po nainštalovaní necháme aplikáciu znova zostaviť. Predtým však vyčistíme aktuálne zostavenie priamo v priečinku
android/
. Spustíme teda nasledovnú postupnosť príkazov:$ cd android $ ./gradlew clean $ cd .. $ yarn run android
Najprv v kóde z nainštalovaného modulu importneme objekt
Torch
:import Torch from 'react-native-torch';
Blesk fotoaparátu rozsvietime a zhasneme volaním funkcie
.switchState(state)
nad objektomTorch
, kdestate
je hodnota typuboolean
. Aktualizujeme teda funkciutoggleState()
vo vytváranom komponente aplikácie:const toggleState = function () { .switchState(!isOn); Torch.play(); dingsetIsOn(!isOn); ; }
Device doesn’t have a Torch
Prípad, kedy zariadenie nie je vybavené bleskom, bude zastupovať emulátor. Pozrime sa teda na spustenie aplikácie na ňom.
Ak aplikáciu spustíme, tak sa spustí normálne. Ak sa však pokúsime baterku zasvietiť, skončíme s hláškou
Possible Unhandled Promise Rejection
a so správouError: Bad argument passed to camera service
.Táto chyba priamo súvisí s kamerou, kedy dochádza k požiadavke o jej ovládanie na zariadení, ktoré ale nemá blesk.
Fragment kódu, ktorý slúži na ovládanie blesku vo funkcii
toggleState()
teda obaľme do volaniatry-catch
tak, ako je to uvedené v dokumentácii modulureact-native-torch
. To znamená, že z funkcie musíme spraviť asynchrónnu funkciu a počkáme si na výsledok volaniaTorch.switchState()
pomocou kľúčového slovaawait
:const toggleState = async function () { try { await Torch.switchState(!isOn); setIsOn(!isOn); catch (e) { } console.log(e); }; }
Upozornenie používateľa
V kóde sme síce situáciu o neexistencii blesku vyriešili bez toho, aby beh aplikácie zlyhal, musíme však o vzniknutej situácii informovať aj používateľa. Na to nám totiž rozhodne nebude stačiť vypisovanie do konzoly cez
console.log()
. A nebude nám stačiť ani vypisovanie cezconsole.warn()
aleboconsole.error()
, ktoré sa síce na obrazovke zariadenia zobrazia, ale v produkčnej aplikácii sa už zobrazovať nebudú.Na upozornenie používateľa môžeme samozrejme použiť niekoľko spôsobov. My sa pozrieme na používanie toast-ov a alert-ov.
Android Toast
(slide) Toast poskytuje používateľovi jednoduchú spätnú väzbu o aktuálnej činnosti v podobe malého vyskakovacieho upozornenia (z anlg. popup). Na obrazovke vyplní len toľko miesta, koľko potrebuje na zobrazenie správy. Nedá sa naň nijako kliknúť ani s ním ďalej interagovať, pričom interakcia s pôvodnou aplikáciou funguje bez zmien. Toast po chvíli sám zmizne.
(slide) React Native pomocou svojho ToastAndroid API poskytuje podporu pre prácu s toast-ami v systéme Android pomocou JS modulu. Tento modul v základe obsahuje metódu
.show(message, duration)
, ktorá má podobne ako v systéme Android tieto parametre:message
- správa, ktorá má byť pomocou toast-u zobrazená, aduration
- časové trvanie, počas ktorého má byť toast zobrazený, a to buďToastAndroid.SHORT
aleboToastAndroid.LONG
Pre použitie toast-u v našej aplikácii upravíme kód funkcie
toggleState()
tak, že v prípade vzniku výnimky v dôsledku chýbajúcej podpory pre kameru, zobrazíme toast s príslušnou správou:// import ToastAndroid first import { ToastAndroid } from "react-native"; const toggleState = async function () { try { await Torch.switchState(!isOn); setIsOn(!isOn); catch (e) { } .show( ToastAndroid"No camera available. Go and buy a device \ with some and come back later.", .SHORT ToastAndroid; ) }; }
Multiplatformný Toast
Uvedené riešenie však bude fungovať len na platforme Android. Ak by sme chceli toast použiť naprieč rozličnými platformami, potrebujeme nainštalovať potrebný treťostranový modul, ktorý podporu toast-ov na tieto platformy zabezpečí. Našťastie máme k dispozícii na výber hneď niekoľko riešení, ako napr.:
- react-native-simple-toast - poskytuje chýbajúcu podporu React Native Toast komponentu ako pre Android, tak aj pre iOS, alebo
- react-native-toast-message - ktorý poskytuje animovaný toast komponent a má široké možnosti konfigurácie komponentu
Poznámka
Samozrejme sa nejedná o úplný zoznam modulov, ktoré umožňujú vytvárať toast-y naprieč platformami. Ďalšie moduly si viete vyhľadať vo vyhľadávači npm balíkov na adrese www.npmjs.com alebo tipy nájdete aj v Awesome zoznamoch, ako napr. v tomto.
Keďže použitie modulu
react-native-simple-toast
je v podstate identické, ako je tomu v prípade použitia natívneho ToastAndroid API z rámca React Native, ukážeme si, ako budú vyzerať toast-y, ak použijeme modulreact-native-toast-message
. V krátkosti si teda ukážeme jeho použitie.Modul teda do projektu najprv nainštalujeme:
$ yarn add react-native-toast-message
Aby sme toast-y mohli zobrazovať, pridáme najprv komponent
Toast
do komponentu aplikácie:return ( <View style={styles.container}> <Pressable onPress={toggleState}> <Image source={image} /> </Pressable> <Button ={toggleState} onPress={isOn === true ? 'Turn Off' : 'Turn On'} title/> <Toast ={function (ref) { ref.setRef(ref); Toast }}/> </View> ; )
Následne už len aktualizujeme funkciu
toggleState()
, kde v prípade, že zariadenie nemá baterku, zobrazí sa toast:const toggleState = async function () { try { .play(); dingawait Torch.switchState(!isOn); setIsOn(!isOn); catch (e) { } .show({ Toasttype: 'error', text1: 'No camera available', text2: 'Go and buy a device with some and come back later.' ; }) }; }
Alert
Toast je jednoduchý a neobťažujúci spôsob notifikovania používateľa, ktorý si od neho nevyžaduje žiadnu interackiu. Na rodziel od neho si dialógové okná vyžadujú okamžitú pozornosť, ktorá je nutná pred ďalším fungovaním aplikácie.
(slide) Na prácu s dialógovými oknami poskytuje rámec React Native modul
Alert
. Výstražné dialógové okná, tzv. alerty, poznáme zo štandardného JavaScript-u v prehliadači. V rámci React Native ho reprezentuje API, ktoré funguje na platformách Android aj iOS. V používaní pre jednotlivé platformy existuje niekoľko rozdielov, ktoré sa dočítate v dokumentácii modulu.Pomocou modulu
Alert
je možné vytvárať výstražné dialógové okná, ktoré sa skladajú z:- titulku / nadpisu,
- správy, a
- voliteľne zo zoznamu tlačidiel s možnosťou vlastného ošetrenia ich stlačenia
Ak by sme teda chceli výstražné dialógové okno použiť v našej aplikácii, odstránime použitie komponentu
Toast
a vo funkciitoggleState()
vložíme vyvolanie výstražného okna takto:// update the import for Alert import { Alert } from "react-native"; const toggleState = async function () { try { await Torch.switchState(!isOn); setIsOn(!isOn); catch (e) { } .alert( Alert'No camera available', 'Go and buy a device with some and come back later.' ; ) }; }
Samozrejme modul
Alert
nie je jediný modul, pomocou ktorého je možné vytvárať výstražné dialógové okná. Ďalšie moduly nájdete opäť napr. vo vyhľadávači www.npmjs.com alebo v niektorom z Awesome zoznamov.
Ukončenie aplikácie
Ak sa používateľ bude pokúšať kliknúť či už na tlačidlo alebo obrázok na zariadení, ktoré neobsahuje baterku, resp. blesk (napr. v emulátore), zobrazí sa mu vytvorené upozornenie, ktoré sme vytvorili pomocou komponentu
Alert
. Vzhľadom na to, že na prítomnosti blesku je postavená celá aplikácia, nie je tento prístup veľmi praktický. Vhodnejšie by bolo napríklad aplikáciu rovno vypnúť, keď príde na to, že blesk nemá.Priama podpora pre vypnutie aplikácie v React Native však nie je. Túto funkcionalitu nám však zabezpečí externý modul s názvom react-native-exit-app. Nainštalujeme ho príkazom:
$ yarn add react-native-exit-app
Upozornenie
Je pravdepodobné, že bude potrebné znovu zostaviť celý projekt. Preto najprv vojdite do priečinku
android/
a spustite príkaz:$ ./gradlew clean
Následne sa vráťte do koreňového priečinku aplikácie a zostavte aplikáciu znova príkazom:
$ yarn run android
Pred použitím najprv z modulu
react-native-exit-app
importneme objektRNExitAPP
:import RNExitApp from 'react-native-exit-app';
Následne vo funkcii
toggleState()
aktualizujeme ošetrenie stlačenia tlačidlaOK
v dialógovom výstražnom okne ukončením aplikácie. To je možné zabezpečiť volanímRNExitApp.exitApp();
.const toggleState = async function () { try { .play(); dingawait Torch.switchState(!isOn); setIsOn(!isOn); catch (e) { } .alert( Alert"No camera available", "Go and buy a device with some and come back later.", [ {text: "Quit", onPress: function () { .exitApp(); RNExitApp, }, } ]; ) }; }
Test Before Run
Aktuálne teda funguje všetko ako má. Ak sa však zamyslíme nad fungovaním, tak nie je veľmi praktické, aby používateľ aplikáciu musel spustiť a až po kliknutí na obrázok alebo tlačidlo došlo k vyhodnoteniu, či je alebo nie je blesk k dispozícii. Toto naozaj nie je UX, ktorý by sme chceli mať.
Ak sa zamyslíme, tak vieme, že kód sa vykonáva v rámci funkcie zhora nadol, pričom funkcia musí vrátiť view komponentu. Ak teda na začiatku kódu vložíme fragment, ktorým overíme, či máme alebo nemáme blesk k dispozícii, vyriešili by sme tento problém.
Ikona aplikácie
Todo:
- vlozit obrazok ikonky z emulatora
- obrazok pre densities
(slide) Každá aplikácia nainštalovaná v zariadení, má aj svoju ikonu, pod ktorou ju môžeme nájsť v zozname nainštalovaných aplikácií. Aktuálne používaná ikona je predvolená, pretože sme ju zatiaľ nijako nenastavovali. To urobíme v tomto kroku.
V priečinku
android/
sa okrem konfigurácie a zdrojových kódov nachádzajú aj zdroje (resources) aplikácie. Medzi zdroje patrí aj ikona aplikácie, tzv. spúšťača aplikácie. Tie sa nachádzajú v priečinkuandroid/app/src/main/res/
.(slide) V tomto priečinku sa nachádzajú priečinky s rozličnými postfixmi na základe rozlíšení cieľových zariadení. Rozličné zariadenia sú totiž dodávané s rozličnými rozmermi obrazoviek (napr. mobilné zariadenia, tablety, telky). Okrem toho je však aj veľkosť jedného pixelu na rozličných zariadeniach rozdielna. To znamená, že existujú zariadenia, ktoré na jeden (štvorcový) palec dokážu zobraziť 160 pixelov, ale sú iné zariadenia, ktoré na ten istý (štvorcový) palec dokážu zobraziť 480 pixelov.
Qualifier DPI Description ldpi
~120dpi low-density screens mdpi
~160dpi medium-density screens, baseline density hdpi
~240dpi high-density screens xhdpi
~320dpi extra-high-density screens xxhdpi
~480dpi extra-extra-high-density screens xxxhdpi
~640dpi extra-extra-extra-high-density uses nodpi
all Resources for all densities. These are density-independent resources. The system does not scale resources tagged with this qualifier, regardless of the current screen’s density. tvdpi
Resources for screens somewhere between mdpi and hdpi; approximately 213dpi. This is not considered a “primary” density group. It is mostly intended for televisions and most apps shouldn’t need it—providing mdpi and hdpi resources is sufficient for most apps and the system will scale them as appropriate. If you find it necessary to provide tvdpi resources, you should size them at a factor of 1.33*mdpi. For example, a 100px x 100px image for mdpi screens should be 133px x 133px for tvdpi. Aby sme sa veľmi nenamakali a neupravovali ikonu pre každý jeden typ zvlášť, môžeme na to použiť on-line nástroj Android Asset Studio. Ten obsahuje niekoľko nástrojov, pričom jedným z nich je práve nástroj na tvorbu ikon spúšťačov. Zrejme po vzore tohto online nástroja vzniklo Asset Studio, ktoré je súčasťou aj Android Studia.
(slide) Prejdeme teda do Launcher Icon Generator-a, kde nahráme vlastnú ikonu:
Keď budeme spokojní so všetkými úpravami, klikneme na tlačidlo Download ZIP. Stiahneme k sebe balík s upravenými ikonami pre jednotlivé rozlíšenia. Vo vnútri balíka sa nachádza priečinok
res/
, ktorý rozbalíme cezres/
priečinok v našom projekte.Poznámka
Miesto, kde definujeme, ktorá ikona sa v skutočnosti použije ako ikona aplikácie, sa nachádza v manifeste aplikácie (v súbore
AndroidManifest.xml
). Konkrétne sa jedná o atribút elementu<application>
v tvare:android:icon="@mipmap/ic_launcher"
Conclusion
- Na to, aby sme problém so spustením špecifického kódu po spustení kontroléru vyriešili, potrebujeme poznať a porozumieť životnému cyklu kontajnera. A ten si predstavíme nabudúce.