Flutter en Dart Mobile Apps

Flutter & Dart – Mobile Apps

Auteur: Danny Holstein

Binnen BEE-2B is er het idee om in de toekomst mobiele applicaties te ontwikkelen. Er is gekozen om met het mobiele framework Flutter te werken dat gebruik maakt van de programmeertaal Dart. Met Flutter kunnen er applicaties gemaakt worden voor zowel iOS als Android. Naast het verdiepen in het Flutter framework heb ik code uitgetest dat in dit nieuwe blogbericht wordt behandeld.

De voor- en nadelen van Flutter en alternatieven

Een alternatief is om native applicaties te maken met Kotlin (tegenwoordig ook multi-platform – voor Android, maakt gebruik van Java) of Swift (voor iOS en maakt gebruik van Objective-C). Een voordeel van een native applicatie is de snelheid en dat er toegang is tot alle hardware features van een mobiel apparaat. Dit is vooral van belang bij grafische games. Het nadeel van native applicaties is dat er 2 code repositories zijn om te onderhouden: de een voor Kotlin en de ander voor Swift.

Een voordeel van Flutter is dat dit cross-platform is en er dus 1 code repository is voor zowel iOS als Android. Dit laatste wil zeggen dat er minder code is om te onderhouden. Een nadeel is dat niet alle hardware features toegankelijk zijn met cross-platform frameworks. Door de meerdere lagen van het framework zullen de prestaties minder zijn dan bij native applicaties. Wanneer er nieuwe features worden geïntroduceerd, dan moet het framework zich hierop aanpassen en dit kan soms even duren.

Wel is een cross-platform framework beter wanneer het een nieuwe applicatie betreft. Ook hebben iOS en Android ‘eigenaardigheden’ die specifiek zijn voor dat platform. Een cross-platform framework kan de eigenaardigheden van een platform overbruggen.

Beginnen met Flutter & Dart

Om met Flutter te beginnen is er ten eerste Android Studio nodig waarmee mobiele apparaten geëmuleerd worden. Ten tweede is de Flutter SDK nodig (SDK = Software Development Kit). Met het commando flutter doctor is in de terminal te controleren of de SDK goed is geïnstalleerd. Tenslotte is te testen of de Flutter SDK benaderbaar is vanaf andere locaties met het commando: flutter --version

Op Internet zijn er naast de officiële documentatie en tutorials ook andere voorbeelden te vinden. Al snel is te merken dat er veel ingebouwde Widgets zijn in het Flutter framework. Wanneer er een Flutter applicatie wordt gemaakt dan is vrijwel alles een widget. De widgets zijn grofweg op te delen in 2 categorieën, namelijk structurele widgets (Scaffold, Container, Row, Column en anderen) en functionele widgets (Button, Text, Image en anderen). De verschillende widgets hebben ook verscheidene properties voor de kleur, stijl, uitlijning, postionering, etc.

De Dart programmeertaal doet veel denken aan een mix van JavaScript en Java. Dart is static typed en dat wil zeggen dat op een later moment een bepaald datatype niet in een ander datatype kan veranderen. Een uitzondering daarbij is het datatype dynamic, maar het is aanbevolen om dit in uitzonderlijke situaties te gebruiken. Er is makkelijk te wennen aan de syntax – in Dart zijn er geen arrays zoals in bijvoorbeeld JavaScript, maar er is wel List dat dezelfde mogelijkheden biedt.

Nog voordat ik met Flutter begon dacht ik dat de verschillende pagina’s van mobiele applicaties objecten waren. Dit blijkt in de praktijk anders te zijn, want mobiele applicaties hebben routes die gebruik maken van een stack. Een stack (te vertalen als stapel) heeft het gedrag: ‘als laatste erin, als eerste eruit’. Om een pagina toe te voegen aan de stack wordt de push-methode gebruikt. En om een pagina weer van de stack te halen wordt de pop-methode gebruikt. Een alternatief is om een library te gebruiken voor de router.

Naast het feit dat er rekening gehouden moet worden met router en de stack, moet er ook rekening gehouden worden met Stateless en Statefull widgets. In Stateless widgets kan alleen data worden getoond en kan de state en de data niet veranderen. In Statefull widgets is er wel een verandering mogelijk van de data en de state. Dus wanneer er een nieuwe pagina of onderdeel wordt toegevoegd, dan is het beter om vast te stellen of dit Stateless of Statefull moet zijn.

Mijn eerste Flutter applicatie – Laden van CSV bestand

Voor een Angular project had ik al code geschreven om een CSV-bestand te laden. De afkorting CSV staat voor Comma Separated Values. CSV-bestanden dienen om grote hoeveelheden data op een relatief makkelijke manier te importeren en te exporteren. In grote lijnen was deze code over te nemen en aan te passen voor Dart. Mijn eerste Flutter applicatie heeft 3 routes/pagina’s:

  1. Een homepagina met een knop om een CSV-bestand te laden.
  2. Een overzichtspagina waar alle records van het CSV-bestand worden getoond.
  3. Een detailpagina waar alle waardes van 1 CSV-record worden getoond.

Voor de rest heeft de applicatie (de Scaffold widget) een lichtblauwe kleur gekregen. Wanneer een CSV-bestand succesvol is geladen, dan wordt deze op de overzichtspagina (en dus nieuwe route) getoond met de methode pushReplacementNamed. De data uit het CSV-bestand wordt doorgegeven over de route met een Map en dit is vergelijkbaar met object literals zoals in JavaScript.

De doorgegeven data hierboven wordt in de overzichtspagina ontvangen. Er wordt een Map verwacht waarvan de key een string is, namelijk: ‘csvData’ en als value wordt een CsvData-object verwacht. Het vraagteken geeft aan dat de data ook null kan zijn. In de regels daaronder (niet afgebeeld hieronder) volgen tests of het ontvangen CsvData-object niet null is en van het juiste data-type is.

Flutter route overview

Op een vergelijkbare manier wordt de data van een enkel CSV-record doorgegeven aan de detailpagina. Dit wordt eveneens met een Map gedaan en er wordt ook het datatype gecontroleerd. Om terug te gaan naar de vorige pagina is er in Flutter een AppBar-widget dat al kant-en-klare functionaliteit heeft om dit te doen. Omdat een CSV-bestand veel data kan bevatten, is het mogelijk om op de overzichts- en detailpagina naar beneden te swipen. Zie de afbeelding hieronder voor het uiteindelijke resultaat:

Flutter app eerste applicatie

Tweede applicatie – inloggen met Keycloak

Om Flutter en Dart uit te testen voor een praktischere applicatie, is geprobeerd om vanuit de applicatie verbinding te maken met de Keycloak server en zijn Realm. Op de website https://pub.dev/ zijn meerdere pakketten te vinden die aan Flutter en Keycloak gerelateerd zijn. Hierbij is het zaak om op te letten op het aantal downloads en hoe lang het geleden is dat het pakket is geüpdatet.

Na een aantal experimenten met andere pakketten, is er uiteindelijk voor het pakket keycloak_wrapper gekozen. De meeste pakketten op pub.dev hebben een uitgebreide readme, installatie-instructies en voorbeelden. De instellingen van het Keycloak-realm ontbraken in de documentatie en hiervoor is een andere online bron geraadpleegd. Tot nu toe heb ik alleen Keycloak-realms ingesteld voor .NET en Angular applicaties, waardoor een Flutter applicatie een heel nieuw terrein was. Na wat ‘trail-and-error’ is het toch gelukt om verbinding te maken. Er worden hele andere instellingen gebruikt voor Web origins en redirects voor zowel URI als post logout.

Er is tijd verloren gegaan doordat ik probeerde verbinding te maken met een lokale Keycloak instance die gebruik maakt van HTTP (localhost) in plaats van HTTPS. Het bleek zo te zijn dat Flutter applicaties geen (onveilige) verbindingen over ‘normale’ HTTP meer toestaan. Dit komt de snelheid van ontwikkeling van Flutter applicaties niet ten goede, maar gelukkig heeft de BEE-ogranisatie zelf een Keycloak server voor testdoeleinden die gebruik maakt van HTTPS.

Op basis van de teruggegeven organization uit het Keycloak token wordt extra informatie uit een WebAPI gehaald. Hiervoor is in Flutter een extra HTTP-pakket nodig dat toegevoegd wordt aan dependencies. Om de code overzichtelijk te houden, wordt er gebruik gemaakt van generics voor de services die verbinding maken met de WebAPI (zoals: getById, getAll, create, update en delete).

Gelukkig zijn er in Flutter meerdere pakketten beschikbaar op pub.dev die handig van pas komen. Een vraag die tijdens het experimenteren bij mij opkwam dat was: hoe zijn objecten en services in de hele applicatie te delen? Na wat zoeken bleek hier een pakket voor te zijn, namelijk get_it, waarmee objecten, services en andere zaken als Singleton geregistreerd kunnen worden. Om de applicatie te verfraaien is er het pakket flutter_spinkit waarmee makkelijk laadschermen gemaakt kunnen worden.

Voor veel applicaties is het van belang om formulieren te maken waaruit data naar een WebAPI verzonden kan worden en uiteindelijk opgeslagen. Om zaken uit te testen is een simpel formulier gemaakt met een tekstveld en dropdown. De velden voor een Form widget hebben allemaal een validate en onSave property die respectievelijk validatie en het opslaan van data mogelijk maakt. De waardes uit het Form zijn te verkrijgen via een Global key: dat is een key/sleutel die toegang biedt tot het widget en de objecten die met het widget zijn geassocieerd. Het uiteindelijke resultaat waarbij is ingelogd door een gebruiker is in de afbeelding hieronder te zien.

Flutter application Keycloak

Tot slot

Het was een leuke en interessante exercitie om me te verdiepen in Flutter en Dart. Veel code is er nog niet gezien en veel applicaties zijn er nog niet gemaakt. Toch is de leercurve van Flutter en Dart minder steil dan bijvoorbeeld bij Angular het geval is. Met andere woorden: het Flutter framework en de Dart programmeertaal zijn vrij snel onder de knie te krijgen, zeker door de hoeveelheid online-bronnen en de uitstekende officiële documentatie.

Flutter voldoet aan de definitie van framework vooral als het om de grote hoeveelheid widgets gaat. Dit framework bevat echter geen kant-en-klare functionaliteit om HTTP-requests te maken en hiervoor moet het http pakket worden toegevoegd. Andere pakketten en libraries zijn te vinden op pub.dev. Eveneens is de documentatie op pub.dev zeer goed en dit komt de ontwikkeling van applicaties alleen maar ten goede. BEE-2B gaat in ieder geval verder aan de slag met Flutter. Misschien zal ik in een toekomstig blogbericht het Flutter framework verder behandelen.

Leave a Reply

*