SVEUČILIŠTE U ZAGREBU FAKULTET ELEKTROTEHNIKE I RAČUNARSTVA
DIPLOMSKI RAD br. 1258
Razvoj višeplatformskih mobilnih aplikacija korištenjem radnog okvira
Flutter Neven Pavelić
Zagreb, lipanj 2019.
Sadržaj Uvod ................................................................................................................................. 1
1. Višeplatformski razvoj mobilnih aplikacija ................................................................ 2
1.1. Arhitektura okvira baziranih na web tehnologijama ............................................ 2
1.2. Arhitektura okvira baziranih na preslikavanju .................................................... 3
1.3. Arhitektura okvira baziranih na vlastitom iscrtavanju ......................................... 3
2. Radni okvir Flutter ..................................................................................................... 5
2.1. Arhitektura radnog okvira Flutter ....................................................................... 7
2.2. Programski jezik Dart......................................................................................... 8
2.3. Grafičke komponente radnog okvira Flutter ....................................................... 9
2.4. Razvojni alati radnog okvira Flutter ................................................................. 13
3. Implementacija višeplatformske aplikacije ............................................................... 14
3.1. Implementacija uvodnog ekrana ....................................................................... 17
3.2. Implementacija ekrana liste gradova ................................................................. 22
3.3. Implementacija ekrana s kartom lokacija .......................................................... 27
3.4. Implementacija ekrana s detaljima lokacije ...................................................... 31
Zaključak ........................................................................................................................ 33
Literatura ......................................................................................................................... 34
Sažetak ............................................................................................................................ 35
Summary ......................................................................................................................... 36
Skraćenice ....................................................................................................................... 37
Privitak ............................................................................................................................ 38
1
Uvod
Mobilne aplikacije su vrlo popularne u današnje vrijeme. Dva operacijska sustava koja
trenutno dominiraju na tržištu mobilnih uređaja su mobilni operacijski sustavi Android i
iOS te ako mobilna aplikacija želi biti uspješna ona mora biti dostupna na oba navedena
sustava. No, svaki mobilni operacijski sustav ima posebne alate, programske jezike te
načine izrade aplikacije. Zbog toga je za klasičan razvoj aplikacija za Android i iOS
potrebno napraviti dvije različite aplikacije koje rade istu stvar, ali na specifičan način koji
ovisi o operacijskom sustavu. To dovodi do značajnog povećanja napora i troškova koji su
potrebni za razvoj jedne takve aplikacije. Zbog toga, tijekom godina je razvijen velik broj
radnih okvira koji su pokušali ublažiti ili riješiti taj problem pomoću višeplatformskog
razvoja aplikacija. Jedan od modernijih višeplatformskih mobilnih radnih okvira je Flutter,
koji će se istraživati u ovom radu. Flutter omogućava razvoj aplikacija za Android i iOS na
moderan i brz način te ima odlične alate za razvoj i razvojnu dokumentaciju. Također,
Flutter se fokusira na poboljšanje performansi i izgleda mobilnih višeplatformskih
aplikacija. Svim time Flutter pokušava ubrzati i poboljšati razvoj mobilnih aplikacija te
postati dominantan radni okvir za razvoj mobilnih aplikacija.
2
1. Višeplatformski razvoj mobilnih aplikacija
Mobilne aplikacije nisu prve koje koriste višeplatformski razvoj. Prenosivost programa na
različite sustave bio je cilj mnogim programskim jezicima, operacijskim sustavima i
radnim okvirima, kao što su operacijski sustav Linux i programski jezik Java.
1.1. Arhitektura okvira baziranih na web tehnologijama
Među prvim radnim okvirima za razvoj višeplatformskih mobilnih aplikacija bili su
PhoneGap, Apache Cordova i Ionic. Oni su bili bazirani na web tehnologijama te su
pomoću HTML-a i JavaScripta definirali web stranice koje se prikazuju korištenjem
komponente za prikaz weba u mobilnim aplikacijama - WebView. To omogućava
jednostavnost upotrebe te iskoristivost postojećih web stranica za razvoj mobilne
aplikacije. No, jedna od loših strana takvog pristupa je otežano korištenje autohtonih
mobilnih komponenata koje nisu prisutne na webu kao što su kamera, Bluetooth, GPS,
senzori itd. Za pristup tim komponentama potrebno je koristiti most (engl. bridge) između
JavaScripta i autohtonih mobilnih komponenata što stvara probleme s performansama. Još
jedna loša strana tog pristupa je što su takve aplikacije izgledale i imale osjećaj web
aplikacija, a ne mobilnih aplikacija koje su korisnici navikli koristiti na svojim mobilnim
uređajima.
Slika 1.1 Arhitektura višeplatformskih mobilnih radnih okvira baziranih na web tehnologijama [6]
3
1.2. Arhitektura okvira baziranih na preslikavanju
Druga vrsta mobilnih višeplatformskih radnih okvira su radni okviri koji preslikavaju svoje
komponente u autohtone komponente mobilnog operacijskog sustava. Primjer takvih
radnih okvira su Xamarin i ReactNative. Oni ne koriste HTML za prikaz već imaju
definirane svoje komponente prikaza pisane u programskom jeziku tog radnog okvira (C#
za Xamarin i JavaScript za ReactNative). Te komponente se preko mosta između radnog
okvira i autohtonog sustava preslikavaju u autohtone komponente prikaza iOS ili Android
mobilnog operacijskog sustava. To poboljšava izgled i osjećaj (engl. look and feel)
aplikacije u odnosu na radne okvire bazirane na web tehnologijama, no loša strana je što
cijela komunikacija ide preko mosta, što negativno utječe na performanse.
Slika 1.2 Arhitektura višeplatformskih mobilnih radnih okvira baziranih na preslikavanju [6]
1.3. Arhitektura okvira baziranih na vlastitom iscrtavanju
Radni okvir Flutter ima drugačiji pristup. On sam iscrtava grafičke elemente korištenjem
autohtone mobilne komponente platna za iscrtavanje (engl. canvas). Prednost je što Flutter
ima potpunu kontrolu nad grafičkim elementima čime može postići poboljšan look and feel
i poboljšane performanse. Za komunikaciju s ostalim autohtonim mobilnim komponentama
Flutter koristi optimiziranu implementaciju mosta koja se zove platformski kanal (engl.
4
platform channel). Pošto se Flutter aplikacija prevodi u kod niske razine, korištenje mosta
u platformskom kanalu ne utječe toliko na performanse, kao ranije navedeni radni okviri
koji preko mosta komuniciraju s autohtonim komponentama koristeći programske jezike
kao što su JavaScript i C#.
Slika 1.3 Arhitektura radnog okvira baziranog na vlastitom iscrtavanju [6]
5
2. Radni okvir Flutter
Flutter je višeplatformski radni okvir otvorenog koda razvijen u kompaniji Google. Prvi
put je objavljen u svibnju 2017. godine, a prva stabilna distribucija objavljena je u prosincu
2018. godine. Flutter je prvotno bio namijenjen za razvoj Android i iOS mobilnih
aplikacija, ali najavljena je i podrška za web i desktop platforme. Također, predviđa se da
će se u budućnosti na Flutteru temeljiti razvoj aplikacija za Googleov novi nadolazeći
mobilni operacijski sustav Fuchsia.
Na službenoj web stranici radnog okvira Flutter, Google ističe 3 glavne prednosti:
Brz razvoj Flutter sadrži niz alata koji naveliko pomažu programeru i ubrzavaju razvoj. Najznačajniji
od tih alata je alat „vrućeg ponovnog učitavanja“ (engl. hot reload). Taj alat omogućava
programeru da nakon promjene programskog koda aplikacije u manje od sekunde ponovno
učita aplikaciju i primjeni svoje promjene bez gubitka stanja aplikacije. U usporedbi s
nekim drugim radnim okvirima kod kojih to može trajati i po nekoliko minuta, hot reload
značajno ubrzava proces razvoja aplikacije i povećava koncentraciju i produktivnost
programera koji odmah može vidjeti promjene koje je napravio. Jedna od glavnih stvari
koja čini tako nešto mogućim je uporaba programskog jezika Dart u radnom okviru Flutter.
Neki od ostalih dostupnih razvojnih alata su Flutter inspektor, Dart razvojni alati, Flutter
alati komandne linije te odlična podrška za nekoliko razvojnih okolina (IntelliJ Idea,
Android Studio, Visual Studio Code).
Izražajno i lijepo grafičko sučelje Iako sam iscrtava sve grafičke komponente, Flutter sadrži vjerne kopije autohtonih
mobilnih grafičkih komponenti koje je jako teško ili nemoguće razlikovati od pravih
autohtonih mobilnih grafičkih komponenti. Flutterova biblioteka je bogata raznim
grafičkim komponentama različitih stilova dizajna kao što su materijalni dizajn (engl.
material design) i iOS stilovi. Sve grafičke komponente također je moguće opsežno
uređivati i personalizirati i time napraviti vlastiti stil dizajna. Također, postoje i brojne
vanjske biblioteke s grafičkim elementima ako Flutterova kolekcija nije dovoljna. Sve
grafičke komponente, kao i ostatak Fluttera, su vrlo lake za korištenje i odlično
dokumentirane.
6
Odlične performanse Pošto Flutter sam iscrtava grafičke elemente koristeći grafičku knjižnicu za iscrtavanje 2D
grafike Skia, to omogućuje Flutter timu da optimizira performanse za brzo izvođenje.
Također, sam programski jezik Dart je isto u vlasništvu Googlea, tako da je moguće
nadograđivati programski jezik kako bi dodatno poboljšali performanse. Jedna od
funkcionalnosti programskog jezika Dart koja poboljšava performanse je korištenje AOT
(engl. ahead of time) kompajlera za prevođenje produkcijskih verzija aplikacije uz
primjenu tehnike „protresanja stabla“ (engl. tree shaking) u kojem se izbacuje nekorišteni
kod iz aplikacije.
Osim navedenih prednosti, istaknuo bih i odličnu Flutter zajednicu koja pruža mnogo
materijala za učenje i istraživanje kao što su instrukcijski članci i video materijali i velik
broj korisnih biblioteka koje mogu znatno pomoći u razvoju. To i je jedan od glavnih
razloga zašto je Flutter omiljen među programerima i lak za naučiti i koristiti. U Flutter
zajednici aktivno sudjeluju članovi Flutter tima, ali i velik broj vanjskih članova zajednice
koji znatno doprinose zajednici. Također, istaknuo bih vrhunsku dokumentaciju svih
dijelova Flutter radnog okvira, od službene dokumentacije na Flutterovoj stranici do
dokumentacije svih biblioteka.
7
2.1. Arhitektura radnog okvira Flutter
Arhitektura radnog okvira Flutter sastoji se od više slojeva. Na dnu se nalazi ugradbeno
sučelje (engl. Embedder) koje se ugrađuje u različite operacijske sustave podržane od
strane Fluttera, npr. mobilni operacijski sustavi Android i iOS. Ugradbeno sučelje
omogućava da se ostatak Flutterovog radnog okvira može bez problema koristiti na
autohtonim platformama na kojima se radi aplikacija te da Flutter se na tim platformama
Flutter može koristiti kao vanjska programska knjižnica. Povrh sloja ugradbenog sučelja
nalazi se Engine sloj koji koristi programske jezike C i C++ te grafičku knjižnicu za
iscrtavanje 2D grafike Skia pomoću koje Flutter iscrtava svoje komponente grafičkog
sučelja. Na vrhu se nalazi sloj okosnice (engl. Framework) napisan u programskom jeziku
Dart koji sadrži implementaciju komponenti na visokoj razini te omogućava programeru
korištenje Flutterovog sučelja koristeći programski jezik Dart.
Slika 2.1 Arhitektura radnog okvira Flutter [4]
8
2.2. Programski jezik Dart
Dart je objektno-orijentirani programski jezik koji kao i mnogi drugi poznati jezici koristi
sintaksu u stilu programskog jezika C. Dart je razvijen u Googleu, a njegova prva stabilna
1.0 verzija je izašla u studenom 2013. godine. Trenutno najnovija stabilna verzija je 2.3.0
koja je izašla u svibnju 2019. godine.
I Dart i Flutter su razvijeni od Googlea što omogućava Googleu da prilagođava jezik
samom radnom okviru Flutter i njegovim potrebama, čemu smo bili svjedoci u posljednjim
verzijama Darta. Jedna od Dartovih funkcionalnosti koja je jako važna za Flutter je to što
se Dart može prevoditi AOT (engl. ahead of time) ili JIT (engl. just in time). JIT
prevoditelj omogućava Flutteru jako brze promjene koda u aplikaciji tijekom razvoja
aplikacije, dok AOT prevoditelj omogućava prevođenje u kod niske razine za produkcijske
verzije aplikacije što znatno poboljšava performanse. Također, Dart ima vrlo brz garbage
collector što omogućava brzo uništavanje starih i stvaranje novih objekata, što kao rezultat
ima uglađenije animacije i stalnu brzinu od 60 okvira u sekundi (engl. frames per second,
fps). Također, Dartova sintaksa omogućava Flutteru da izbjegne korištenje XML-a ili
nekog sličnog jezika za označavanje (engl. markup language), što opet rezultira boljim
performansama te lakšem razvoju. Uz sve to, Dartova sintaksa je slična mnogim poznatim
programskim jezicima kao što su C, Java, C#, Swift, Kotlin, JavaScript te zbog toga većina
programera može jako brzo naučiti programirati u Dartu.
9
2.3. Grafičke komponente radnog okvira Flutter
Flutterova implementacija grafičkih komponenti uzima inspiraciju iz modernih okvira
grafičkih komponenti kao što je React. Kod tih okvira grafičko sučelje se deklarira
deklarativno, a ne imperativno. Zbog toga, moguće je napraviti grafičko sučelje koje je
funkcija stanja aplikacije, a stanje aplikacije se može pohraniti u objektu. I tada se svakom
promjenom objekta stanja aplikacije, aplikacija može ponovno iscrtati i prikazati promjene
koje su se dogodile u objektu stanja aplikacije. Poanta je ne koristiti kompliciranu logiku
da bi se prikazala neka promjena na grafičkom sučelju, nego postići da grafičko sučelje
promatra promjene stanja te se ažurira na temelju tih promjena. Naravno, u tom slučaju
nije efikasno ponovno iscrtati cijeli ekran. Zato su moderni okviri kao Flutter i React
razvili sustav virtualnog stabla grafičkih komponenti koje može izračunati koji dio stabla
se promijenio i ažurirati samo te grafičke komponente koje su se doista promijenile i koje
bi se trebale ponovno iscrtati.
Glavna grafička komponenta u Flutteru se zove Widget i ona je gradivni element za cijelu
aplikaciju. Sve grafičke komponente U Flutteru od jednostavnih tekstova i gumbi pa do
cijelih ekrana su Widget-i. Čak je i sama Flutter aplikacija Widget. Na temelju Widget-a
Flutter računa koje dijelove aplikacije treba ponovno iscrtati kada se dogodi promjena
stanja aplikacije.
Flutter, iako sam iscrtava cijelo grafičko sučelje, sadrži bogatu kolekciju raznih vrsta
grafičkih komponenti iz raznih dizajnerskih stilova kao što su materijalni dizajn i iOS
dizajn. Također, sve grafičke komponente moguće je detaljno uređivati i nadograđivati.
Sljedeći kod je primjer minimalne Flutter aplikacije:
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: Scaffold(body: Center(child: Text('Hello, world!'))),
),
);
Kôd 1.1 – Minimalna Flutter aplikacija
10
Sljedeća slika prikazuje izgled te minimalne Flutter aplikacije:
Slika 2.2 Izgled minimalne Flutter aplikacije
Sljedeći primjer koda prikazuje Flutter aplikacije brojača
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
11
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('You have pushed the button this many times:',),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
Kôd 1.1 – Minimalna Flutter aplikacija
12
A sljedeća slika prikazuje izgled aplikacije brojača:
Slika 2.3 Izgled jednostavne aplikacije brojača
13
2.4. Razvojni alati radnog okvira Flutter
Za razvoj Flutter aplikacija moguće je koristiti razvojna okruženja Android Studio, IntelliJ
Idea ili Visual Studio Code te svi imaju odličnu podršku. Uz sve to, Flutter ima odlične
alate komandne linije te je moguće razvijati aplikacija u tekstualnom editoru te je
izgrađivati koristeći alate komandne linije. Još neki od razvojnih alata koji pomažu u
svakodnevnom razvoju su Flutter Inspector koji omogućuje pregledavanje stabla Widget-a
te Dart DevTools koji omogućavaju pregledavanje izvještaja performansi aplikacije i
debugiranje.
Ja sam za potrebe ovog rada koristio Android Studio razvojnu okolinu te iOS simulator i
Android emulator i funkcioniralo je odlično.
Slika 2.4 Android Studio razvojno okruženje
14
3. Implementacija višeplatformske aplikacije
U sklopu ovog rada izrađena je višeplatformska mobilna aplikacija koja opisuje život
Nikole Tesle te gradove i lokacije povezane s njim. Aplikacija je razvijena korištenjem
radnog okvira Flutter te ju je moguće pokrenuti na Android i iOS mobilnim operacijskih
sustavima. Na sljedećoj slici (Slika 3.1) vidljiv je izgled implementirane aplikacije.
Slika 3.1 Izgled implementirane aplikacije
15
Implementirana aplikacija sastoji se od četiri glavna ekrana:
1. Uvodni ekran
2. Ekran liste gradova
3. Ekran s kartom lokacija
4. Ekran s detaljima lokacije
Uvodni ekran sadrži nekoliko stranica koje uvode korisnika u aplikaciju te opisuju kako se
aplikacija koristi te koje dijelove sadrži. Nakon uvoda dolazi ekran s listom gradova koji
prikazuje važne gradove u životu Nikole Tesla te njihov kratki opis. Ako prikazani grad
sadrži lokacije povezane s Nikolom Teslom, moguće je otvoriti ekran s kartom lokacija tog
grada. Na tom ekranu su na karti označene sve lokacije tog grada povezane s Nikolom
Teslom te njihove adrese. Za svaku lokaciju moguće je otvoriti ekran s detaljima lokacije
koji prikazuje detaljnije informacije o toj lokaciji kao što su ime lokacije, adresa, slika
lokacije te poglavlja teksta o toj lokaciji koja mogu sadržavati niz slika. Grafički dizajn
aplikacije, sustav za unošenje podataka te sučelje za dohvat podataka su bili zadani te se
neće obrađivati u ovom radu.
import 'package:flutter/material.dart';
import 'package:tesla_app/shared/colors.dart';
import 'package:tesla_app/shared/strings.dart';
import
'package:tesla_app/ui/onboarding/onboarding_screen.dart';
void main() => runApp(TeslaApp());
class TeslaApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: Strings.appName,
theme: ThemeData(fontFamily: 'Montserrat',
primaryColor: AppColors.colorPrimary),
home: OnboardingScreen(),
);
}
}
Kôd 3.1 – Kôd ulaznog dijela aplikacije – main.dart
16
Svaka Flutter aplikacija mora imati ulaznu točku kao što je prikazano u prethodnom kôdu
(Kôd 3.1). Svaka aplikacija je zapravo Widget komponenta. U Flutteru postoji nekoliko
već definiranih komponenti ta Widget aplikacije, a u ovom slučaju se koristi MaterialApp
pošto je aplikacija dizajnirana po uzoru na materijalni dizajn. Widget aplikacije utječe na to
kako će izgledati i ponašati se Widget komponente unutar aplikacije. MaterialApp
komponenta sadrži brojne parametre koji omogućuju promjenu raznih vrsta ponašanja
aplikacije, no u ovom slučaju se koristi samo nekoliko osnovnih. title predstavlja
naslov aplikacije koji će biti vidljiv u operacijskom sustavu. theme definira vizualnu temu
aplikacije pomoću parametara za izgled boja, teksta, pozadina i sličnih parametara. home
parametar aplikacije označava koji ekran će biti početni ekran aplikacije, a to je u ovom
slučaju uvodni ekran (OnboardingScreen).
Strings i AppColors su primjer programskih razreda koje sadržavaju neku vrstu
resursa. Moguće je i resurse kao što su boje i tekstovi koristiti izravno, no to nije dobra
praksa jer ako npr. promijenimo neku boju, bit će potrebno mijenjati boju na mnogim
mjestima. No, ako resurse pobrojimo u posebnom programskom razredu i onda koristimo
te definirane resurse umjesto izravnog korištenja, promjenu ćemo moći napraviti samo na
jednom mjestu i utjecati na sva mjesta koja koriste taj resurs. Također, na ovaj način je
lako moguće zamijeniti skup resursa, npr. u slučaju promjene jezika zamijeniti tekstove ili
u slučaju promjene teme zamijeniti boje – samo je potrebno promijeniti korišteni
programski razred s resursima. Primjer jednog takvog jednostavnog razreda vidljiv je u
nastavku (Kôd 3.1).
import 'dart:ui';
class AppColors {
static Color colorPrimary = Color(0xFF29476C);
}
Kôd 3.2 – Programski razred resursa za boje
17
3.1. Implementacija uvodnog ekrana
Uvodni ekran je ekran koji se otvara kada korisnik prvi puta otvori aplikaciju. Ekran se
sastoji od 3 stranice koje uvode korisnika u aplikaciju te objašnjavaju kako koristiti
aplikaciju te što ona sve omogućuje.
Slika 3.2 Izgled uvodnog ekrana aplikacije
Glavni dio svake stranice uvodnog ekrana su naslov stranice, opis stranice koji objašnjava
kako koristiti aplikaciju te slika koja ilustrira kako izgledaju glavni dijelovi aplikacije.
Osim toga, u gornjem desnom uglu nalazi se gumb za preskakanje koji preskače sve
stranice uvodnog ekrana i izravno ulazi u glavni dio aplikacije. Taj gumb je tu za slučaj da
korisnik ne želi gledati uvodni dio aplikacije. Na dnu uvodnog ekrana nalazi se gumb za
nastavak na sljedeću stranicu uvodnog ekrana. Izmjena stranica uvodnog ekrana također je
moguća povlačenjem prsta preko ekrana u lijevu (sljedeći ekran) ili desnu stranu
(prethodni ekran). Na zadnjoj stranici uvodnog ekrana gumb za nastavak na sljedeću
stranicu postaje gumb za ulazak u glavni dio aplikacije kojim korisnik zatvara uvodni
ekran i otvara prvi ekran glavnog dijela aplikacije, a to je ekran liste gradova.
18
U duhu objektno-orijentiranog programiranja, dobra je praksa modelirati podatke u
programske razrede. Stoga je i u ovom primjeru stranica uvodnog ekrana modelirana s
programskim razredom koji sadrži podatke o slici, naslovu i opisu stranice. Taj razred se
može vidjeti u Kôdu 3.3.
class OnboardingPage {
final String imagePath;
final String title;
final String description;
OnboardingPage(this.imagePath, this.title,
this.description);
}
Kôd 3.3 – Model stranice uvodnog ekrana
Slično kao i u slučaju Widget-a aplikacije, ekran je također samo još jedan Widget koji se
sastoji od jednostavnijih Widget-a koji sačinjavaju komponente tog ekrana. Prema tome,
potrebno je definirati Widget komponentu koja će predstavljati uvodni ekran. Definicija
uvodnog ekrana prikazana je u sljedećem isječku kôda (Kôd 3.4).
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:tesla_app/model/onboarding_page.dart';
import 'package:tesla_app/shared/colors.dart';
import 'package:tesla_app/shared/strings.dart';
import 'package:tesla_app/ui/cities/cities_screen.dart';
class OnboardingScreen extends StatelessWidget {
…
@override
Widget build(BuildContext context) {
…
}
}
Kôd 3.4 – Widget uvodnog ekrana
19
Pošto su u ovoj aplikaciji podaci stranice uvodnog ekrana statički, a ne dohvaćaju se
dinamički preko mrežnog poziva, njih je moguće definirati izravno u Widget-u ekrana na
sljedeći način:
class OnboardingScreen extends StatelessWidget {
final List<OnboardingPage> onboardingPages = [
OnboardingPage("assets/onboarding_01.svg", Strings.onboardingTitle1,
Strings.onboardingDescription1),
OnboardingPage("assets/onboarding_02.svg", Strings.onboardingTitle2,
Strings.onboardingDescription2),
OnboardingPage("assets/onboarding_03.svg", Strings.onboardingTitle3,
Strings.onboardingDescription3),
];
…
}
Kôd 3.5 – Definicija podataka uvodnih stranica
Osnovnu strukturu uvodnog ekrana moguće je dobiti sljedećim programskim kôdom:
final PageController pageController = PageController();
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.grey,
body: SafeArea(
child: Stack(
children: <Widget>[
PageView.builder(
itemBuilder: (context, position) {
return buildOnboardingPage(context, position);
},
itemCount: onboardingPages.length,
controller: pageController,
),
buildSkipButton(context),
],
),
),
);
}
Kôd 3.6 – Osnovna struktura uvodnog ekrana
20
Prvi element koje se koristi je Scaffold . To je komponenta koja se najčešće koristi kao
korijenska komponenta ekrana u Flutteru, a omogućava dodavanje nekih standardnih
komponenata mobilnih aplikacija kao što je navigacijska traka na vrhu aplikacije. Sljedeći
Widget koji se koristi je SafeArea koji se isto često koristi kao korijenski element i služi
da ograniči prostor za iscrtavanje tako da izbaci neželjeni prostor kao što su izrezi na
ekranu mobilnih uređaja, tako da se sve ostale komponente iscrtavaju ispod izreza, a ne
preko njega jer se dio aplikacije u tom slučaju ne bi vidio. Sljedeća komponenta je Stack
koji služi za iscrtavanje više komponenti jedne preko druge. To je u ovom slučaju
iskorišteno za iscrtavanje komponente za izmjenu stranica te iznad nje gumb za
preskakanje koji je prikazan preko stranica uvodnog ekrana i ne mijenja se sa stranicama.
Za izmjenu stranica iskorištena je komponenta PageView . Stranice uvodnog ekrana su
izgrađene pomoću buildOnboardingPage metode, dok je gumb za preskakanje
izgrađen pomoću buildSkipButton metode. U Flutteru je dobra praksa izdvajati
manje cjeline grafičkog sučelja u izdvojene metode, jer bi protivnom, ako bi sav kod bio u
jednoj velikoj cjelini, on postao vrlo nečitak. Također, ako se pojedini dijelovi grafičkog
sučelja izdvajaju u zasebne metode, moguće je ponovno iskoristiti tu metodu ako postoji
ista ili slična komponenta na tom ekranu, čime bi se spriječilo dupliciranje koda. Kod
metode za izgradnju stranice uvodnog ekrana prikazan je u nastavku:
Widget buildOnboardingPage(BuildContext context, int position) {
OnboardingPage onboardingPage = onboardingPages[position];
return Stack(children: <Widget>[
SvgPicture.asset(onboardingPage.imagePath, alignment:
Alignment.topCenter),
SizedBox.expand(
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
buildTitleText(onboardingPage),
buildDescriptionText(onboardingPage),
Container(margin: EdgeInsets.only(bottom: 24),
child: SizedBox(height: 40,
child: position != onboardingPages.length - 1 ?
buildNextButton() : buildGoButton(context),
))]))]);}
Kôd 3.7 – Metoda za izgradnju stranice uvodnog ekrana
21
Iz prikazane metode vidljivo je da se koristi model stranice uvodnog ekrana da bi se dobili
podaci o stranici na pojedinoj poziciji. Također je vidljivo da se koriste razne komponente
kao Stack, SizedBox, Column i Container kako bi se ostale komponente
razmjestile unutar ekrana te definirala njihova veličina i pozicija. Za prikaz slika koristi se
komponenta SvgPicture iz programske knjižnice flutter_svg. To je programska
knjižnica za iscrtavanje vektorske grafike iz datoteka vektorske grafike tipa SVG, koje se
koriste za prikaz ikona i ilustracija jer za njihov prikaz zauzimaju manje memorijskog
prostora od bitmap slika i bolje skaliraju svoju veličinu. Također se koristi još nekoliko
build metoda kako bi se izgradile komponente za prikaz teksta naslova i opisa te gumbi za
nastavak i završetak. U nastavku je prikazana metoda za izgradnju gumba za završetak:
RaisedButton buildGoButton(BuildContext context) {
return RaisedButton(
child: Text(
Strings.goButton.toUpperCase(),
style: TextStyle(
fontFamily: 'MontserratAlternates', fontWeight:
FontWeight.bold, fontSize: 12, color: Colors.white),
),
onPressed: () => openCitiesScreen(context),
shape: new RoundedRectangleBorder(borderRadius: new
BorderRadius.circular(20.0)),
color: AppColors.colorAccent,
);
}
void openCitiesScreen(BuildContext context) {
Navigator.pushReplacement(context, MaterialPageRoute(builder:
(context) => CitiesScreen()));
}
Kôd 3.7 – Metoda za izgradnju gumba za završetak uvoda
U izgradnji gumba za završetak koriste se komponente kao što su RaisedButton i
Text koje su završne komponente koje će iscrtati komponente gumbi i teksta. Također,
koriste se parametri i komponente za stiliziranje gumba (promjena veličine teksta, boje…).
Pritiskom na gumb za završetak poziva se metoda openCitiesScreen koja koristeći
komponentu Navigator navigira na sljedeći ekran izbacujući ekran uvoda iz povijesti
ekrana kako se ne bi mogli na njega ponovno vratiti, jer se on prikazuje samo na početku.
22
3.2. Implementacija ekrana liste gradova
Poslije uvodnog ekrana slijedi ekran liste gradova. Na tom ekranu su prikazani gradovi
povezani s Nikolom Teslom u nizu stranica tog ekrana. Stranice je moguć izmjenjivati
povlačenjem prsta preko ekrana u lijevu (sljedeći grad) ili desnu stranu (prethodni grad).
Glavni dijelovi stranica grada su slika koja predstavlja veličinu i važnost grada, naziv
grada te opis poveznice tog grada s Nikolom Teslom. Ako prikazani grad posjeduje
lokacije povezane s Nikolom Teslom, na stranici tog grada bit će vidljiv gumb za pregled
tih lokacija. Izgled ekrana liste gradova može se vidjeti na sljedećoj slici:
Slika 3.3 Izgled ekrana liste gradova
23
Na ovom ekranu ćemo također modelirati podatke grada u programski razred. Jedna
razlika u odnosu na uvodni ekran je ta da će na ovom ekranu podaci stizati dinamički preko
mrežnog poziva. Zbog toga je važno da taj model posjeduje metodu za deserijalizaciju, jer
će podaci stići serijalizirani u JSON formatu. Stoga će model grada biti modeliran na
sljedeći način:
class City {
final String id;
final String name;
final String description;
final bool hasData;
final int size;
final int position;
City(this.id, this.name, this.description, this.hasData, this.size,
this.position);
City.fromJson(Map<String, dynamic> json)
: id = json["id"],
name = json["name"],
description = json["description"],
hasData = json["hasData"],
size = int.parse(json["size"]),
position = int.parse(json["position"]);
}
Kôd 3.8 – Model grada s metodom za deserijalizaciju
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:tesla_app/model/city.dart';
final String baseUrl = "https://teslaapp-31457.firebaseio.com";
Future<List<City>> fetchCities() async {
final response = await http.get("$baseUrl/persons/Tesla/cities.json");
if (response.statusCode == 200) {
Map<String, dynamic> responseMap = json.decode(response.body);
List<City> cities = responseMap.values.map((json) =>
City.fromJson(json)).toList();
24
cities.sort((a, b) => a.position.compareTo(b.position));
return cities;
} else {
throw Exception('Failed to load cities');
}
}
Kôd 3.9 – Dohvat gradova preko mrežnog poziva
U gornjem kodu (Kôd 3.9) nalazi se isječak koda za dohvat gradova preko mrežnog
poziva. U tu svrhu koristimo knjižnice dart:http za rađenje mrežnog poziva koristeći
protokol HTTP te dart:convert za pretvaranje teksta u JSON formatu u dinamički
objekt. U isječku koda također je definiran bazni URI sučelja za dohvat podataka te put do
podataka o gradovima u JSON formatu. Zbog specifičnog oblika u kojem su podaci
pohranjeni na poslužitelju, potrebno je napraviti mapiranje i sortiranje dobivene liste
gradova. Na posljetku, ako je došlo do greške metoda baca iznimku, a ako je sve prošlo u
redu, metoda vraća listu gradova. Također, pošto mrežni poziv traje dosta vremena, metoda
za dohvat mora biti asinkrona (async) kako ne bi blokirala dretvu i grafičko sučelje dok
mrežni poziv ne završi.
class CitiesScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.colorPrimary,
body: SafeArea(
child: FutureBuilder<List<City>>(
future: apiService.fetchCities(),
builder: (context, snapshot) {
if (snapshot.hasData) {
List<City> cities = snapshot.data;
return buildCityPages(cities);
}
return Center(child: CircularProgressIndicator());
})),
);
}
Kôd 3.10 – Osnovna struktura ekrana liste gradova
25
Pošto je metoda za dohvat gradova asinkrona, nije moguće koristiti Widget-e na standardan
način kao u slučaju statičke liste podataka. Jedno od rješenja za asinkrone metode je
korištenje FutureBuilder Widget-a. On kao jedan od parametara prima asinkronu
metodu (future) te definira kako će se sučelje izgraditi u slučaju da nema podataka i u
slučaju da su podaci stigli. U ovom slučaju, ako ima podataka uzima se lista gradova i iz
nje se rade stranice gradova, a u slučaju da nema podataka prikazuje se komponenta
pokazatelja učitavanja CircularProgressIndicator koja je centrirana preko
cijelog ekrana.
Stack buildCityPages(List<City> cities) {
return Stack(children: <Widget>[
PageIndicatorContainer(
length: cities.length,
shape: IndicatorShape.circle(size: 6),
indicatorSpace: 4,
indicatorSelectorColor: Colors.white,
indicatorColor: Colors.grey,
pageView: PageView.builder(
itemBuilder: (context, position) {
return buildCitiesPage(context, cities[position], position);
},
itemCount: cities.length,
controller: pageController,
),
),
]);
}
Kôd 3.11 – Metoda za izgradnju stranica gradova
Metoda za izgradnju stranica gradova slična je metodi izgradnje stranica uvodnog ekrana,
no glavna razlika je da stranice gradova imaju kružne pokazatelje broja stranice na kojoj se
korisnik nalazi. To je postignuto korištenjem komponente PageIndicatorContainer
iz vanjske programske knjižnice page_indicator. Također, kao i uvodni ekran, ekran
liste gradova prikazuje slike korištenjem vanjske programske knjižnice flutter_svg .
26
String getImagePath(City city, int position) {
if (position == 0) {
if (city.hasData) {
return "assets/cities/first_city_with_locations.svg";
} else {
return "assets/cities/first_city_no_locations.svg";
}
} else {
if (city.hasData) {
if (city.size <= 1) {
return "assets/cities/small_city_with_locations.svg";
} else if (city.size == 2) {
return "assets/cities/medium_city_with_locations.svg";
} else {
return "assets/cities/large_city_with_locations.svg";
}
} else {
if (city.size <= 1) {
return "assets/cities/small_city_no_locations.svg";
} else if (city.size == 2) {
return "assets/cities/medium_city_no_locations.svg";
} else {
return "assets/cities/large_city_no_locations.svg";
}
}
}
}
Kôd 3.12 – Metoda za odabir slike grada
Za razliku od uvodnog ekrana koji ima 3 statički definirane slike s poznatim redoslijedom,
ekran liste gradova podatke dobiva dinamički preko mrežnog poziva te mora na temelju
podataka grada dinamički odrediti koju sliku upotrijebiti za taj grad u ovisnosti o veličini
grada, lokacijama grada te pozicijom grada unutar liste gradova.
27
3.3. Implementacija ekrana s kartom lokacija
Ako neki grad sadrži lokacije povezane s Nikolom Teslom, korisniku će za taj grad biti
prikazan gumb za pregled lokacija koji otvara ekran s kartom lokacija. Ovaj ekran
prikazuje kartu grada s označenim lokacijama povezanim s Nikolom Teslom. Za prikaz
karata koristi se usluga Google Maps. Osim karte s označenim lokacijama, na dnu ekrana
je prikazana kartica s osnovnim podacima trenutno odabrane lokacije. Kartice je također
moguće izmjenjivati povlačenjem prsta preko ekrana u lijevu (sljedeća lokacija) ili desnu
stranu (prethodni lokacija). Isto tako je moguće odabrati oznaku lokacije na karti da bi se
prikazala kartica te lokacije. Na karticama lokacije je prikazano ime lokacije, njena adresa
te gumb za otvaranje detalja te lokacije.
Slika 3.4 Izgled ekrana s kartom lokacija
28
Ekran s kartom lokacije, kao i ekran s listom gradova, dobiva podatke dinamički preko
mrežnog poziva. Prema tome, na isti način je potrebno definirati programski razred modela
s definiranom metodom za deserijalizaciju te kôd za dohvaćanje podataka putem mreže.
class Location {
final String id;
final String name;
final String address;
final String city;
final String type;
final double latitude;
final double longitude;
final String mainImage;
Location(this.id, this.name, this.address, this.city, this.type,
this.latitude, this.longitude, this.mainImage);
Location.fromJson(Map<String, dynamic> json)
: id = json["id"],
name = json["name"],
address = json["address"],
city = json["city"],
type = json["type"],
latitude = json["latitude"],
longitude = json["longitude"],
mainImage = json["mainImage"];}
Future<List<Location>> fetchLocationsForCity(String cityId) async {
final response = await
http.get("$baseUrl/persons/Tesla/locations/$cityId.json");
if (response.statusCode == 200) {
Map<String, dynamic> responseMap = json.decode(response.body);
List<Location> locations = responseMap.values.map((json) =>
Location.fromJson(json)).toList();
return locations;
} else {
throw Exception('Failed to load locations');
}
}
Kôd 3.13 – Model lokacije i dohvat preko mreže
29
Isto kao i kod ekrana liste gradova, koristi se FutureBuilder kako bi se riješio problem
asinkrone funkcije dohvata podataka putem mreže te se isto koristi vanjska programska
knjižnica page_indicator u kombinaciji s komponentom PageView kako bi se
ostvarila mogućnost promjene kartica. Jedna novost na ovom ekranu je to što na njemu
prosljeđujemo model objekt grada s prethodnog ekrana liste gradova. To se jednostavno
postiže tako da se u razredu ekrana s kartom lokacija definira članska varijabla grada te
konstruktor koji prima model objekt grada i postavlja vrijednost članske varijable grada.
class LocationsScreen extends StatelessWidget {
final City city;
LocationsScreen({Key key, @required this.city}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(city.name, style: TextStyle(fontFamily:
'MontserratAlternates', color: Colors.white)),
),
body: SafeArea(
bottom: false,
child: FutureBuilder<List<Location>>(
future: apiService.fetchLocationsForCity(city.id),
builder: (futureContext, snapshot) {
if (snapshot.hasData && snapshot.data.isNotEmpty) {
List<Location> locations = snapshot.data;
return _buildLocationsScreen(context, locations);
}
return Center(child: CircularProgressIndicator());
}),
),
);
}
Kôd 3.14 – Osnovna struktura ekrana s kartom lokacija
30
Najveća novost na ekranu s kartom lokacija je korištenje vanjske programske knjižnice
google_maps_flutter kako bi se prikazala karta grada koristeći uslugu Google
Maps. Ta knjižnica sadrži Widget GoogleMap kojeg je uz definiranje nekoliko
parametara vrlo jednostavno ubaciti u stablo komponenti ekrana. Definirani su parametri
za početnu lokaciju, postavke povećanja karte, isključivanje 3D funkcionalnosti,
postavljanje oznaka lokacija te postavljanje kontrolora (GoogleMapController) za
kasnije upravljanje kartama.
GoogleMap buildMapView(Location firstLocation, List<Location>
locations) {
return GoogleMap(
minMaxZoomPreference: MinMaxZoomPreference(14.0, 18.0),
initialCameraPosition:
CameraPosition(target: LatLng(firstLocation.latitude,
firstLocation.longitude), zoom: 15.0),
myLocationButtonEnabled: false,
rotateGesturesEnabled: false,
tiltGesturesEnabled: false,
myLocationEnabled: true,
onMapCreated: (GoogleMapController controller) {
_mapsController.complete(controller);
},
markers: locations
.map((location) => Marker(
markerId: MarkerId(location.id),
position: LatLng(location.latitude, location.longitude),
onTap: () =>
pageController.jumpToPage(locations.indexOf(location)),
))
.toSet(),
);
}
…
GoogleMapController controller = await _mapsController.future;
Location location = locations[position];
CameraPosition cameraPosition =
CameraPosition(target:LatLng(location.latitude, location.longitude));
controller.animateCamera(CameraUpdate.newCameraPosition(cameraPosition));
Kôd 3.15 – Korištenje GoogleMap widgeta
31
3.4. Implementacija ekrana s detaljima lokacije
Svaka kartica lokacije sadrži gumb za pregled detalja lokacije. Ako korisnik pritisne taj
gumb, otvara se ekran s detaljima lokacije. Na ekranu s detaljima lokacije u gornjem dijelu
ekrana nalazi se velika slika lokacije na kojoj se nalaze naziv lokacije, adresa lokacije te
tekstualne oznake vezane za lokaciju (iz kojeg grada dolazi, na koju poznatu osobu je
vezana i kojeg je tipa lokacije). Ispod slike lokacije nalazi se lista od jednog ili više
poglavlja opisa lokacije. Svako poglavlje opisa lokacije ima svoj naslov, tekst te može ili
ne mora imati jednu ili više slika. Ako postoji više slika na jednom poglavlju, slike su
horizontalno poredane jedna do druge te se mogu pomicati (engl. scroll) lijevo i desno.
Poglavlja se prikazuju jedno ispod drugog i ako ih ima više nego što se može prikazati na
ekranu, ekran se može pomicati gore i dolje. Također, u gornjem desnom uglu ekrana
nalaze se gumbi za podijeliti lokaciju preko društvenih mreža (engl. share) te za otvoriti
lokaciju u vanjskoj aplikaciji specijaliziranoj za prikaz karata i navigaciju (npr. Google
Maps ili Apple Maps). S gornje lijeve strane nalazi se gumb za izlazak s ekrana detalja
lokacije i povratak na ekran s kartom lokacija.
Slika 3.5 Izgled ekrana s detaljima lokacije
32
Ekran s detaljima lokacije dinamički dohvaća podatke o poglavljima preko mreže na isti
način kao i prethodni ekrani. Posebnost ovog ekrana je korištenje vanjskih biblioteka za
dijeljenje podataka preko društvenih mreža te za otvaranje vanjske aplikacije
specijalizirane za karte i navigaciju. Za dijeljenje podataka preko društvenih mreža koristi
se vanjska programska knjižnica share, dok se za pokretanje vanjskih aplikacija koristi
programska knjižnica url_launcher.
IconButton(
icon: Icon(
Icons.share,
color: Colors.white,
),
onPressed: () => Share.share("Check out ${location.name}.
It's located at ${location.address}"),
)
…
IconButton(
icon: Icon(
Icons.directions,
color: Colors.white,
),
onPressed: launchDirectionsUrl,
)
launchDirectionsUrl() async {
String googleUrl =
'https://www.google.com/maps/dir/?api=1${location.latitude},${location.lo
ngitude}';
String appleUrl =
'https://maps.apple.com/?sll=${location.latitude},${location.longitude}';
if (await canLaunch("comgooglemaps://")) {
print('launching com googleUrl');
await launch(googleUrl);
} else if (await canLaunch(appleUrl)) {
print('launching apple url');
await launch(appleUrl);
} else {
throw 'Could not launch url';
}}
Kôd 3.16 – Korištenje programskih knjižnica share i url_launcher
33
Zaključak
Iako je još relativno mlad radni okvir, Flutter je na mene ostavio jako dobar dojam. Najviše
mi se svidjela lakoća razvoja aplikacija. Tu lakoću razvoja omogućuju odlični razvojni
alati te odličan dizajn samog radnog okvira. Uz sve to, iz istog koda se može napraviti i
Android i iOS aplikacija, što znatno smanjuje trud potreban za razvitak aplikacije za obje
mobilne platforme. Također, pošto je to ista aplikacija, nema problema s različitom
implementacijom i nekonzistentnostima između Androida i iOS-a, uz poštivanje potrebnih
razlika između platformi. Osim toga, aktivno se radi i na podršci za nove platforme kao što
su desktop ili web i Googleov novi operacijski sustav Fuchsia. Flutter također ima odličnu
podršku zajednice, kako od Flutter razvojnog tima iz Googlea tako i iz vanjske zajednice
programera iz cijelog svijeta. No, iako je zajednica donijela dosta vanjskih programskih
knjižnica i komponente, ipak još neke stvari fale ili nisu do kraja implementirane. Ali,
vjerujem da je to zbog toga što je okvir još uvijek mlad i mislim da će se s vremenom
situacija samo poboljšavati. Moje mišljenje je da će Flutter kroz nekoliko godina postati
respektabilan način za razvoj višeplatformskih mobilnih i drugih aplikacija.
34
Literatura
[1] FLUTTER, Flutter, https://flutter.dev/ , 20.06.2019.
[2] FLUTTER, Flutter Documentation, https://flutter.dev/docs , 20.06.2019. [3] HACKERNOON, Why Flutter uses Dart,
https://hackernoon.com/why-flutter-uses-dart-dd635a054ebf, 20.06.2019. [4] GITHUB, The Engine architecture,
https://github.com/flutter/flutter/wiki/The-Engine-architecture , 20.06.2019. [5] MEDIUM, Multi vs Cross Platform in the age of Flutter,
https://medium.com/snapp-mobile/multi-vs-cross-platform-in-the-age-of-flutter-6e76920028b6 , 20.06.2019.
[6] HACKERNOON, What’s Revolutionary about Flutter, https://hackernoon.com/whats-revolutionary-about-flutter-946915b09514 , 20.06.2019.
[7] FLUTTER, Introduction to widgets, https://flutter.dev/docs/development/ui/widgets-intro , 20.06.2019.
[8] FLUTTER, Tools & techniques, https://flutter.dev/docs/development/tools , 20.06.2019.
35
Sažetak
Razvoj višeplatformskih mobilnih aplikacija korištenjem radnog okvira Flutter
Ovaj rad istražuje radni okvir Flutter za razvoj višeplatformskih mobilnih aplikacija koje se
mogu koristiti na više različitih mobilnih operacijskih sustava. Također, u sklopu rada je
osmišljena, razvijena i testirana višeplatformska mobilna aplikacija za mobilne operacijske
sustave Android i iOS koristeći navedeni radni okvir Flutter.
Ključne riječi: višeplatformski razvoj, mobilna aplikacija, Flutter, Android, iOS, Dart
36
Summary
Cross-platform mobile application development using the Flutter framework
This thesis explores the Flutter framework for development of cross-platform mobile
applications that can be used on multiple mobile operating systems. Also, as a part of the
thesis, a cross-platform mobile application for mobile operating systems Android and iOS
is designed, developed and tested using the Flutter framework.
Keywords: cross-platform development, mobile application, Flutter, Android, iOS, Dart
37
Skraćenice
HTML Hypertext Markup Language Hipertekst označni jezik AOT Ahead Of Time Prije vremena
JIT Just In Time Pravovremeno XML eXtensible Markup Language Proširivi označni jezik
fps frames per second Okviri u sekundi HTTP Hypertext Transfer Protocol Protokol prijenosa hiperteksta
SVG Scalable Vector Graphic Skalabilna vektorska grafika JSON JavaScript Object Notation JavaScript notacija objekta
URL Uniform Resource Locator Jedinstveni lokator resursa
38
Privitak
Instalacija programske podrške
Da bi se instalirali razvojni alati potrebni za razvoj Flutter aplikacije, potrebno je posjetiti
web-stranicu s adresom https://flutter.dev/docs/get-started/install i slijediti upute za
instalaciju potrebnih alata.
Prvo je potrebno instalirati Flutter SDK. Zatim je u komandnoj liniji potrebno pokrenuti
naredbu flutter doctor koja će nas obavijestiti o razvojnim alatima koji nedostaju.
Zatim je potrebno instalirati Android i iOS razvojne okoline ovisno o tome za koju
platformu želimo razvijati aplikaciju i na kojoj platformi želimo testirati aplikaciju. Na
poslijetku, potrebno je instalirati razvojno okruženje Android Studio / IntelliJ Idea ili
Visual Studio Code.
Nakon instalacije razvojnog okruženja i ostalih razvojnih alata spremni smo za pokretanje
aplikacije. Prvi je potrebno postaviti programski kod na odgovarajuće mjesto unutar
projekta otvorenog u razvojnoj okolini. Zatim je potrebno slijediti upute s web-stranice na
adresi https://flutter.dev/docs/get-started/test-drive?tab=vscode za pokretanje aplikacije.
Top Related