View online

Powered by TCPDF (www.tcpdf.org)
Academiejaar 2013–2014
Faculteit Ingenieurswetenschappen en Architectuur
Valentin Vaerwyckweg 1 – 9000 Gent
Ontwikkelen van een mobiele
betaaloplossing
Masterproef voorgedragen tot het behalen van het diploma van
Master in de industriële wetenschappen: informatica
Dieter LAMBRECHT
Promotoren: Geert VAN HOOGENBEMT
Joury GOKEL (J4S BVBA)
Begeleider:
Christof AMEYE (J4S BVBA)
Woord vooraf
Vooreerst mijn oprechte dank aan mijn interne promotor Geert Van hoogenbemt. Met zijn wijze
raad en waardevolle commentaar leidde hij dit project in goede banen en werd het op tijd inleveren van deze scriptie haalbaar.
Verder wil ik ook mijn dank betuigen aan het bedrijf J4S zonder wie dit leervolle en boeiende
onderwerp niet mogelijk was. Mijn dank gaat speciaal uit naar mijn externe promotor Joury
Gokel voor zijn waardevolle raad en suggesties die voor een meerwaarde zorgden. Zijn bijzondere kennis over de betalingswereld leidde ook tot verrassende achtergrondinformatie. Daarnaast wil ik ook mijn begeleider Christof Ameye bedanken bij wie ik steeds terecht kon met
problemen. Met zijn deskundige begeleiding heeft hij mij fantastisch geholpen en zijn ervaring
leidde vaak tot interessante besprekingen. Ook aan de rest van het team in Kortrijk een woord
van dank voor de toffe werksfeer en de vele leuke momenten. Het team in Hasselt wil ik ook
bedanken voor de tips en informatie in verband met betaalkaarttransacties.
Ten slotte nog een speciaal woord van dank aan mijn familie voor de niet te onderschatten
morele steun en taaltips.
Dieter Lambrecht
Anzegem
Abstract
Het doel van dit project is om een mobiele betaaloplossing te ontwikkelen die toelaat om een
virtuele eenheid tussen twee partijen te verhandelen. Deze eenheid heeft een bepaalde waarde.
Dit kan echt geld zijn, maar ook evengoed spaarpunten of een eigen bedachte valuta voor bijvoorbeeld een drankbonnetjessysteem. Iedere partij moet op een veilige, gebruiksvriendelijke
manier kunnen betalen en ontvangen.
De consument kan met de mobiele applicatie op websites betalen (e-commerce-transacties)
en/of in de winkel direct betalen (commerce-transacties) aan de handelaar die ook zo’n applicatie heeft. De consumenten kunnen onderling ook eenvoudig (kleine) bedragen uitwisselen
wanneer ze elkaar tegenkomen (face-to-face-transacties).
Voor de handelaar wordt het een all-in-one-oplossing. De applicatie biedt namelijk ook de mogelijkheid om op de klassieke manier via betaalkaarten geld te ontvangen van de klanten die de
mobiele toepassing nog niet gebruiken.
Overview
The main goal of this project is to develop a mobile payment solution which allows two parties
to trade a virtual amount. This amount has a certain value. It can be real money, savings, or
even a self-invented currency for a beverage ticket system. Each stakeholder has to be able to
pay and receive in a secure and user-friendly way.
The consumer can pay with the mobile app on websites (e-commerce transactions) and/or directly in a store (commerce transactions) to the merchant who also has such an app. The consumers can easily pay small amounts to each other when they meet (face-to-face transactions).
It’s an all-in-one solution for the merchant. The same application also offers the opportunity to
let customers pay with regular payment cards when they don’t have the mobile app yet.
Inhoudsopgave
Woord vooraf .............................................................................................................................I
Abstract .................................................................................................................................... II
Inhoudsopgave ....................................................................................................................... III
Lijst met afkortingen .............................................................................................................. V
Inleiding..................................................................................................................................... 1
1
Elektronisch betalingsverkeer in België ......................................................................... 3
2
Analyse .............................................................................................................................. 5
2.1
Structuur van het bestaande platform ...................................................................... 5
2.2
Algemeen ................................................................................................................. 5
2.3
Back end ................................................................................................................... 5
2.3.1
Online Banking e-Payments-principe .................................................................. 5
2.3.2
Transactie- versus Transferobjecten ..................................................................... 5
2.3.3
Person-To-Person-betalingen ............................................................................... 5
2.3.4
Veiligheid ............................................................................................................. 5
2.4
3
4
Front end .................................................................................................................. 5
2.4.1
Algemeen ............................................................................................................. 5
2.4.2
Spelers in het verhaal ........................................................................................... 5
2.4.3
Model van de mobiele applicatie.......................................................................... 5
2.4.4
Value- versus item-transfer .................................................................................. 5
2.4.5
Functionaliteit van de handelaar........................................................................... 5
2.4.6
Functionaliteit van de consument ......................................................................... 5
Implementatie van de back end ...................................................................................... 6
3.1
Algemeen ................................................................................................................. 6
3.2
Transferlogica .......................................................................................................... 6
3.3
Sms-service en notificatieregistratie ...................................................................... 12
3.4
Protobuf.................................................................................................................. 13
3.5
Flyway.................................................................................................................... 16
Implementatie van de front end .................................................................................... 18
4.1
HTML 5- versus native applicatie ......................................................................... 18
4.2
Algemeen ............................................................................................................... 19
4.3
Support library ....................................................................................................... 21
5
4.4
Data Access Object ................................................................................................ 21
4.5
Navigatie tussen activities...................................................................................... 23
4.6
Asynchrone taken ................................................................................................... 26
4.7
ZXing ..................................................................................................................... 30
4.8
Opslag van data op het toestel................................................................................ 31
4.9
Notificaties ............................................................................................................. 33
4.10
ProGuard ................................................................................................................ 36
4.11
Europay Mastercard Visa-ondersteuning ............................................................... 37
4.12
Android Wear......................................................................................................... 38
4.13
iBeacons ................................................................................................................. 40
4.14
Overgang naar iOS ................................................................................................. 41
4.15
Testen ..................................................................................................................... 42
Retrospectie..................................................................................................................... 44
5.1
Eigen beoordeling .................................................................................................. 44
5.2
Extra mogelijke uitbreidingen en verbeteringen .................................................... 44
Conclusie ................................................................................................................................. 45
Lijst met figuren ..................................................................................................................... 46
Lijst met tabellen .................................................................................................................... 47
Lijst met codefragmenten ...................................................................................................... 48
Referentielijst .......................................................................................................................... 49
Lijst met afkortingen
APACS
API
AJAX
B2C
BC/MC
BCC
BTC
C2B
CRUD
CSS
CTAP
DAO
EMV
GICC
GUI
GUID
HTML
HTTPS
ID
JPA
JSON
MPOS
NFC
OBeP
ORM
P2P
PC
PKI
PTP
QR
SD
SDK
SSL
SQL
SVA
TCP
UI
URL
USB
VO
XML
Association for Payment Clearing Services
Application Programming Interface
Asynchronous JavaScript and XML
Business-To-Consumer
Bancontact/Mister Cash
Bank Card Company
Business-To-Consumer
Consumer-To-Business
Create, Read, Update and Delete
Cascading Style Sheet
Common Terminal Acquirer Protocol
Data Access Object
Europay MasterCard Visa
German ISO 8583 Credit Card
Graphical User Interface
Global Unique Identifier
HyperText Markup Language
HyperText Transfer Protocol Secure
Identificatie
Java Persistence API
JavaScript Object Notation
Mobile Point Of Sale
Near Field Communication
Online Banking e-Payments
Object-Relational Mapping
Person-To-Person
Protocol Converter
Public Key Infrastructure
Person-To-Person
Quick Response
Secure Digital
Software Development Kit
Secure Socket Layer
Structured Query Language
Stored Value Account
Transmission Control Protocol
User Interface
Uniform Resource Locator
Universal Serial Bus
Value Object
eXtensible Markup Language
Inleiding
De huidige betalingsmethoden zijn complex en niet gebruiksvriendelijk. Bovendien vereisen ze
soms extra hardware en/of vragen ze confidentiële informatie van de klant. Denk hierbij aan
volgende probleemsituaties. Wanneer iemand cash wil betalen, heeft die persoon muntstukken
nodig om het bedrag exact te kunnen passen of krijgt hij vaak veel wisselgeld terug. Dit is niet
gebruiksvriendelijk. Bij elektronisch betalen heeft een handelaar meerdere (dure) betaalapparaten nodig indien hij verschillende betalingsmogelijkheden wil aanbieden. Ook bij online-betalingen is er extra hardware nodig, namelijk een digipass of een kaartlezer. Bij sommige webwinkels wordt er rechtstreeks om kredietkaartgegevens gevraagd (confidentiële informatie).
Een betalingsmethode moet veilig en gebruiksvriendelijk zijn. De huidige methodes voldoen
echter maar aan één van deze twee criteria. Een veilige methode is meestal niet echt gebruiksvriendelijk en een gebruiksvriendelijke methode is minder veilig. In deze masterproef wordt er
geprobeerd om een betaaloplossing te ontwikkelen die toch aan beide criteria voldoet.
Op dit moment heeft een groot deel van de wereldbevolking bijna altijd een smartphone bij de
hand. Het Europees gemiddelde is 48 procent (Smartphonegebruik, 2013). In de toekomst zullen mobiele technologieën steeds meer invloed op ons leven hebben. Een gebruiksvriendelijke
en veilige betaaloplossing ontwikkelen voor zo’n apparaat is dan ook een ideale keuze.
Deze masterproef gebeurt in samenwerking met J4S [jforce]. Het is een bedrijf dat zich specialiseert in betalingssoftware. Sinds 2009 is het begonnen met het ontwerpen van elektronische
betaaloplossingen. Het bedrijf heeft onder andere een eigen platform ontworpen voor het verwerken van betaalterminaltransacties en biedt dit aan als een service aan zijn klanten. Hierbij
aansluitend heeft het een anti-fraudesysteem ontwikkeld dat op basis van een berekening een
risicoprofiel bepaalt en beslist of de transactie doorgelaten wordt of niet. Het bedrijf biedt ook
een eigen e-wallet-platform aan. Bij dit platform sluit dit project aan. (J4S, 2013)
Het e-wallet-platform, Stored Value Account (SVA), bevat de accountgegevens en de virtuele
waardebalans van de gebruikers. Het ondersteunt de omzetting van echt geld naar de virtuele
eenheid en omgekeerd. Een mogelijk toepassingsgebied is bijvoorbeeld een festival: de gebruiker kan ‘drankbonnetjes’ (virtuele waarde) aankopen met echt geld. Dit geld komt op een bankrekening van de aanbieder van de software. De gebruiker krijgt hiervoor virtuele bonnetjes op
zijn virtuele waarderekening in de plaats en kan hiermee dan aan de organisator van het festival
betalen.
Momenteel is het op dit platform enkel mogelijk om een Business-To-Consumer- (B2C-) en
Consumer-To-Business-betaling (C2B-betaling) uit te voeren. Dit wil zeggen dat het enkel mogelijk is om als consument aan een handelaar of omgekeerd te betalen. Deze twee termen worden verder onder de naam B2C of BTC (in programmacode) gebruikt. De consument heeft
hierbij een account met een virtuele waardebalans, maar de handelaar niet. Een device (= een
betaalapparaat van de handelaar) zorgt ervoor dat het te betalen bedrag van de rekening van de
1
betaler wordt afgetrokken. Periodiek wordt dan berekend hoeveel eenheden een handelaar ontvangen heeft en wordt dit omgerekend en uitbetaald op zijn bankrekening.
De opdracht bestaat uit twee grote delen. Het eerste deel is het uitbreiden van het SVA-platform
zodat het mogelijk wordt om op een eenvoudige en veilige manier mobiel te betalen en om
Person-To-Person-betalingen (P2P-betalingen) uit te voeren op het platform. Bij een P2P-betaling wordt een virtuele waarde van de account van de betaler afgetrokken en opgeteld bij de
account van de ontvanger. In het voorbeeld van het festival wordt het bijvoorbeeld mogelijk
om toe te laten dat gebruikers drankbonnetjes doorgeven aan elkaar. Het tweede deel is de ontwikkeling van een mobiele applicatie die van de nieuwe functionaliteit van de back end gebruik
maakt en meteen de gebruiksvriendelijkheid van de uitgewerkte betaaloplossing aantoont.
Het is de bedoeling dat de mobiele applicatie wordt gebruikt door zowel handelaars als consumenten. De consumenten kunnen onderling (P2P) en ook aan handelaars (C2B) via de virtuele
waarde (e-money) betalen. De handelaar heeft hierbij extra functionaliteit ter beschikking. Zo
kan hij met de app ook betaalkaarten accepteren door een kaartlezer aan zijn smartphone te
koppelen.
De mobiele applicatie is modern en vernieuwend. Zo is er gekeken of het mogelijk is om de
applicatie onmiddellijk via webtechnologieën cross-platform te maken. De net aangekondigde
preview van Android Wear wordt ook onder de loep genomen. Hierbij is er gekeken welke
stappen er nodig zijn om de notificaties op een smartwatch weer te geven. Om de gebruiksvriendelijkheid nog te verhogen, wordt er slim gebruik gemaakt van iBeacons en sms. Indien
handelaars een beacon aan de kassa plaatsen, wordt de app automatisch opgestart en afgesloten
wanneer de gebruiker het bereik van de beacon binnen- en buitenwandelt. Een gebruiker kan
er ook voor kiezen om via sms op de hoogte te worden gehouden van de status van de betaling.
Het eerste hoofdstuk van deze scriptie bevat een beschrijving van het elektronisch betalingsverkeer in België en vervolgens een situering van dit project binnen dat verhaal. Het tweede
hoofdstuk bevat een grondige analyse van de te verrichten uitbreidingen aan het SVA-platform
en van de te ontwikkelen mobiele applicatie. Er wordt ook dieper ingegaan op de veiligheid van
het ontwerp. De implementatie van beide delen wordt in hoofdstuk 3 en 4 behandeld. Hierbij
worden ook enkele nieuwe technologieën uitgelegd, wordt er verantwoording van implementatiekeuzes gegeven en worden er enkele problemen en hun oplossing behandeld. In het laatste
hoofdstuk is er ten slotte nog een eigen beoordeling van het resultaat en worden enkele mogelijke uitbreidingen voorgesteld.
2
1
Elektronisch betalingsverkeer in België
In dit hoofdstuk wordt er aandacht besteed aan het elektronisch betalingsverkeer in België (Figuur 1.1). Een consument vraagt bij zijn bank naar keuze een betaalkaart aan. Een Belgische
bank is, in tegenstelling tot in het buitenland, echter niet de issuer die de betaalkaartnummers
verdeelt. Hiervoor is er in België een extra partij, namelijk Bank Card Company (BCC), ondertussen overgenomen door Atos.
Een handelaar sluit een contract af met een acquirer om kaartbetalingen te kunnen ontvangen.
Betalingen worden via een betaalterminal verricht. Dit kan een fysiek toestel zijn, of softwarematig bijvoorbeeld op een smartphone worden nagebootst. De betaalterminals spreken met de
acquirer via een bepaald protocol dat meestal verschilt per land. Dit is natuurlijk voor terminalmakende bedrijven en handelaars niet praktisch. Voor iedere regio moet er een specifieke
terminal gemaakt worden. Sommige acquirers in België zijn ook in andere landen actief en
hebben als standaard een ander protocol gekozen. Hierdoor worden er verschillende protocollen
actief gebruikt in België en heeft de handelaar een andere terminal nodig indien hij wenst te
veranderen van acquirer of verschillende acquirers wil ondersteunen.
Een oplossing hiervoor is om te werken met een extra tussenliggende partij. Het specifieke
protocol dat de terminal ondersteunt wordt bij die partij omgezet naar het gebruikte protocol
van de acquirer. Een voorbeeld van zo’n partij is J4S met Protocol Converter (PC). Hierdoor
kan er ook dynamisch worden omgeschakeld naar een andere acquirer indien bijvoorbeeld de
eerste offline is. De handelaar heeft hiervoor wel contracten met verschillende acquirers nodig.
Er zijn twee mogelijke geldstromen. Ofwel is de betaalterminal Atos-specifiek en kan hij rechtstreeks met de Atos-acquirer spreken ofwel is hij dit niet. Indien wel, blijft het betalingsverkeer
volledig binnenlands via Bancontact/Mister Cash (BC/MC). Indien niet, loopt het via de PC
naar een acquirer waarmee de handelaar een contract heeft.
De acquirer wil controleren of er genoeg geld op de rekening van de betaler staat. Hiervoor
moet hij zich bij de bank van de betaler gaan informeren. De acquirer kan enkel via de issuer
te weten komen bij welke bank het kaartnummer hoort. In België heeft Atos hierbij het voordeel
dat het ook de issuer is (Banksys en BCC, 2007), dus kan het rechtstreeks aan de bankgegevens
voor nationaal verkeer. Voor internationaal verkeer doet het wel een beroep op de brands (Mastercard of Visa) om de bankgegevens van de kaart te weten te komen. De andere acquirers gaan
echter altijd via de brands voor deze informatie. Van zodra de acquirer de bank van de betaler
weet, kan hij nagaan of er genoeg geld op de rekening staat en de betaaltransactie laten doorgaan.
In de laatste stap (niet meer weergegeven op de figuur) wordt door de acquirer het verschuldigde bedrag aan de bank gevraagd zodat het geld van de rekening van de klant op de rekening
van de acquirer komt. Uiteindelijk betaalt de acquirer periodiek een totaalsom terug op de
rekening van de handelaar.
3
Ter vergelijking is in de figuur ook nog eens het SVA-platform opgenomen. De consument kan
kiezen of hij wil betalen via e-money (virtuele waarde) met de mobiele applicatie waarbij de
communicatie met het SVA-platform verloopt of via een betaalkaart. De handelaar kan met
dezelfde applicatie ook betalingen via betaalkaarten aanvaarden. De app communiceert hiervoor via het Mobile Point Of Sale-protocol (MPOS-protocol) van J4S naar de PC en zo gaat de
Europay MasterCard Visa-transactie (EMV-transactie) verder naar de acquirer.
Figuur 1.1: Elektronisch betalingsverkeer in België
4
2
Analyse
2.1 Structuur van het bestaande platform
2.2 Algemeen
2.3 Back end
2.3.1 Online Banking e-Payments-principe
2.3.2 Transactie- versus Transferobjecten
2.3.3 Person-To-Person-betalingen
2.3.4 Veiligheid
2.4 Front end
2.4.1 Algemeen
2.4.2 Spelers in het verhaal
2.4.3 Model van de mobiele applicatie
2.4.4 Value- versus item-transfer
2.4.5 Functionaliteit van de handelaar
2.4.6 Functionaliteit van de consument
5
3
Implementatie van de back end
3.1 Algemeen
Tijdens de implementatiefase wordt er zoveel mogelijk gebruik gemaakt van de reeds bestaande
SVA-API om dubbele code te vermijden. De API om te authenticeren (inloggen) en om de
waardebalans op te vragen bestaat al en wordt dus opnieuw gebruikt. Ook de topdown-service
om een B2C-transactie te verrichten en een logobject weg te schrijven wordt opnieuw gebruikt
bij een B2C-transfer. Voor de logica rond het OBeP-principe en P2P-betalingen is er echter nog
niets aanwezig in het systeem. Er is voor gezorgd dat de geschreven code zo goed mogelijk
aansluit bij de stijl van het bestaande project.
3.2 Transferlogica
Domeinmodel
Voor alle logica rond transferobjecten zijn er nieuwe klassen toegevoegd. Een eerste soort zijn
de transferdomeinklassen. Voor het persisteren van de objecten van deze klassen, wordt er gebruik gemaakt van de Java Persistence API (JPA) en als implementatiebibliotheek Hibernate.
Alle domeinklassen zijn geannoteerd met JPA-annotaties. Zo kan er gemakkelijk van ObjectRelational Mapping-implementatie (ORM-implementatie) veranderd worden.
@Entity
@Table(name = "sva_transfer")
@Inheritance(strategy=InheritanceType.JOINED)
public abstract class Transfer extends GenericEntity {
@Column(unique=true)
private String sharedUniqueID;
@ManyToOne
private Account goodsSenderAccount;
@Temporal(TemporalType.TIMESTAMP)
private Date timestamp;
@OneToOne(cascade=CascadeType.PERSIST)
private TransferDetails details;
private String description;
@Enumerated(EnumType.STRING)
private TransferState state;
}
// …
Codefragment 3.1: Implementatie van de transferklasse
De transferklasse (Codefragment 3.1) erft over van GenericEntity. Deze laatste zorgt ervoor dat
overervende klassen een attribuut ‘id’ met een @Id-annotatie krijgen. Dit attribuut wordt ge-
6
bruikt door Hibernate om het primaire ID van het databankrecord in op te slaan. Om dit databank-ID niet te hoeven blootstellen aan de buitenwereld, wordt er een Global Unique Identifier
(GUID) aangemaakt bij creatie van het transferobject (sharedUniqueID-attribuut). Dit is een
random, uniek ID dat gebruikt wordt om informatie over het transferobject op te vragen. Het is
dan ook dit ID dat door de ontvanger aan de betaler wordt doorgegeven. Het gebruik van een
GUID is veiliger omdat databank-ID’s meestal incrementeel gegenereerd worden door de
databanksoftware. Door nu gewoon bijvoorbeeld het getal een of twee bij een huidig ID te
tellen, zou iemand informatie van de volgende transfer, die nog niet voltooid is, kunnen opvragen.
Business-logica
Om operaties op de transferdomeinobjecten uit te voeren (bv. creatie van een nieuw object en
objecten ophalen), wordt er een transferrepository, transferservice en transferresource aangemaakt (Figuur 3.1). Dit zijn respectievelijk repository-, service- en resource-klassen. Hierbij
wordt er actief gebruik gemaakt van het Spring Framework. De transferresource en de transferservice gebruiken dependency injection (Codefragment 3.2). Bij het opstarten van de serverapplicatie worden de geannoteerde klassen geïnstantieerd en op de Spring context geplaatst.
Hierbij worden de autowired-attributen ook ingevuld met de overeenkomstige referenties. In
het codefragment wordt bijvoorbeeld het transferRepository-attribuut automatisch ingevuld
met een referentie naar het juiste implementatieobject door het Spring Framework. In de transferresource wordt dit ook toegepast om een verwijzing te krijgen naar het transferserviceobject.
Figuur 3.1: Implementatieschema van de transferlogica
De transferresource klasse zelf is ook geannoteerd met @Transactional. Dit zorgt ervoor dat
iedere methode (webservice-aanvraag) van de klasse in een aparte transactie wordt behandeld.
Pas wanneer de aanvraag succesvol is afgehandeld, worden de wijzigingen effectief gecommit
naar de databank. Dit vermijdt inconsistentie van data bij complexe operaties die halverwege
onderbroken worden door een opgetreden fout.
7
@Repository
public class JpaTransferRepository extends JpaGenericRepository<Transfer>
implements TransferRepository {
// …
}
@Service
public class TransferServiceImpl implements TransferService {
@Autowired
TransferRepository transferRepository;
}
// …
Codefragment 3.2: Dependency injection met annotaties
Transferrepository
De transferrepository is verantwoordelijk voor het persisteren en ophalen van de transferobjecten. Data persisteren is met de hulp van Hibernate zeer eenvoudig, maar doordat de transferdomeinobjecten een redelijk complexe klassenstructuur hebben, is data ophalen ingewikkelder.
Afhankelijk van het feit of het om een B2C-transfer of om een P2P-transfer gaat, is de ontvanger
(Codefragment 3.3) een device van de handelaar (een handelaar dus) of een rekening van de
betaler (een consument). Om compatibiliteitsredenen met het bestaande systeem wordt er nog
altijd over een device van de handelaar gesproken. Dit komt er in de praktijk op neer dat een
handelaar zijn smartphone registreert op het SVA-platform als een geldig toestel waarmee B2Ctransfers aangemaakt mogen worden. Bij het ophalen van de transfergeschiedenis zorgt het zonet genoemde verschil voor moeilijkheden.
@Entity
@Table(name = "sva_btctransfer")
public class BTCTransfer extends Transfer {
@ManyToOne
private Device goodsReceiverDevice;
}
// …
@Entity
@Table(name = "sva_ptptransfer")
public class PTPTransfer extends Transfer {
@ManyToOne
private Account goodsReceiverAccount;
}
// …
Codefragment 3.3: Implementatie van de B2C-transfer en de P2P-transfer klasse
8
Als voorbeeld schetsen we de volgende situatie.
Een consument wil zijn recentste transfers bekijken.
Mogelijke transferobjecten die aan deze situatie voldoen zijn P2P-transfers waarin hij zelf de
ontvanger of de betaler is of B2C-transfers waarin hij de betaler is. Op het eerste gezicht zou
de eenvoudige query (Codefragment 3.4) moeten werken. In het codefragment verwijzen de
twee parameters ‘userR’ en ‘userS’ naar hetzelfde userobject van de aanvrager.
SELECT t
FROM Transfer t
WHERE t.goodsReceiverAccount.user = :userR OR
t.goodsSenderAccount.user = :userS
Codefragment 3.4: Niet-werkende transfergeschiedenisquery
Hibernate kan echter het attribuut ‘goodsReceiverAccount’ niet vinden. Dit komt omdat er een
transfer opgevraagd wordt en deze heeft dit attribuut niet omdat dit is gedefinieerd in P2Ptransfer. Er zou met andere woorden iets moeten bestaan zoals een instanceof-operator en een
downcast zoals in Java om de query te kunnen uitvoeren.
Een tweede ‘mogelijke’ weg naar het einddoel is via een native Structured Query Languagequery (native SQL-query). Deze complexe query (Codefragment 3.5) joint zelf de nodige tabellen en bevat alle informatie om een transferobject samen te stellen. Er wordt nu niet meer
op objectniveau gewerkt, maar rechtstreeks op databankniveau.
SELECT *
FROM sva_transfer transfer
LEFT JOIN sva_btctransfer btctransfer ON transfer.id = btctransfer.id
LEFT JOIN sva_ptptransfer ptptransfer ON transfer.id = ptptransfer.id
LEFT JOIN sva_transferdetails transferdetails
ON transfer.details_ID = transferdetails.id
LEFT JOIN sva_emoneytransferdetails emoneytransferdetails
ON transferdetails.id = emoneytransferdetails.id
LEFT JOIN sva_account senderaccount
ON senderaccount.id = transfer.goodssenderaccount_ID
LEFT JOIN sva_account receiveraccount
ON receiveraccount.id = ptptransfer.goodsreceiveraccount_ID
LEFT JOIN sva_device receiverdevice
ON receiverdevice.id = btctransfer.goodsreceiverdevice_ID
WHERE (ptptransfer.id IS NOT NULL AND receiveraccount.userID = ?) OR
senderaccount.userID = ?
Codefragment 3.5: Native SQL-query voor de transfergeschiedenis van een consument
9
Het probleem hierbij is echter dat er verschillende kolommen zijn met dezelfde naam (bv. ID)
zodat Hibernate niet meer weet welke kolom bij welk objectattribuut hoort. Dit is ook zo wanneer er enkele kolommen opnieuw worden benoemd zodat er geen dubbele namen zijn. Een
oplossing hiervoor is om bij de klassen zelf een mapping te definiëren via een complexe annotatienotatie (@SqlResultSetMapping) waarbij iedere kolom aan het juiste attribuut gekoppeld wordt. Deze werd echter niet doorgevoerd omdat dit een globale configuratie is op de
klasse zelf.
De uiteindelijke oplossing bestaat uit het uitvoeren van twee eenvoudige query’s na elkaar. De
ene haalt de P2P-transfers op en de andere de B2C-transfers. Deze worden dan uiteindelijk
samengevoegd. De query’s voor de transfergeschiedenis worden dynamisch gecreëerd via een
CriteriaBuilder. Deze laat toe om objectsgewijs een query samen te stellen. Deze manier van
werken maakt het mogelijk om gemakkelijk meer of minder predicaten in de where-clausule
van de query toe te voegen. Zo kan er strenger en minder streng worden gefilterd zonder voor
ieder scenario een individuele query te moeten opstellen.
Bij de standaardquery voor een consument die de P2P-transfers ophaalt, is er echter nog een
probleem. Als de query de bovenste ‘whereClauses’ (Codefragment 3.6) gebruikt, worden niet
alle juiste resultaatrijen teruggegeven.
// Predicaat die te weinig rijen oplevert.
Predicate whereClauses = cb.or(
cb.equal(rootP.get("goodsReceiverAccount").get("user"), userParamR),
cb.equal(rootP.get("goodsSenderAccount").get("user"), userParamS)
);
// Predicaat die alle rijen oplevert.
whereClauses = cb.or(
cb.equal(rootP.join("goodsSenderAccount", JoinType.LEFT)
.get("user"), userParamS),
cb.equal(rootP.get("goodsReceiverAccount").get("user"), userParamR)
);
Codefragment 3.6: Foutieve (bovenste) en juiste (onderste) predicaten van de transfergeschiedenisquery
Een diepere analyse van de achterliggende werking van Hibernate leidde tot het ontdekken van
de volgende oorzaak. Als een consument al zijn transfers opvraagt, bevatten deze ook de door
hem geannuleerde transfers waarvan de zender nog niet gekend is in het systeem. Op het eerste
gezicht, leidt dit niet echt tot een probleem. De query kijkt of de user van de ontvangende
rekening gelijk is aan de aanvrager en of de aanvrager gelijk is aan de user van het verzendende
rekening. Het eerste deel van de of-uitdrukking zou moeten ‘true’ geven als resultaat. In de
databank bevat de ontvangende rekening-kolom echter de waarde null. Door die null-waarde
behoort de rij niet tot het eindresultaat omdat de volledig where-uitdrukking in de Hibernate
query ‘onderbroken’ wordt. De reden hiervoor is dat Hibernate de query achter de schermen
omvormt tot een SQL-query.
10
De uitdrukking
rootP.get("goodsSenderAccount").get("user")
wordt vervangen door een inner join (op gelijke ID’s van het goodsSenderAccount_ID-veld
van de transfertabel en het ID-veld van de accounttabel) en een where-uitdrukking om de gebruikers te vergelijken. Bij een SQL-query worden joins eerder uitgevoerd dan de where-clausule. Aangezien het een inner join is, verdwijnt de rij uit het resultaat omdat de on-voorwaarde
niet voldaan is (wegens de null-waarde). Pas na de join-fase, wordt de where-uitdrukking op de
resterende rijen uitgevoerd.
Het hierboven geschetste probleem kan als volgt opgelost worden. Er moet specifiek aan Hibernate meegedeeld worden dat de query naar een left join moet worden omgezet (onderste
clausule in het codefragment) in plaats van naar een normale inner join. Zo wordt de rij wel
behouden en kan probleemloos de where-clausule worden uitgevoerd.
Transferservice en transferresource
In de transferservice gebeurt er foutcontrole. Indien er een fout is opgetreden zoals bijvoorbeeld
als een verplicht attribuut van een object niet is ingevuld, wordt er een service-exceptie opgegooid. Dit is een object van de klasse ‘ServiceException’. Deze bevat de informatie over de
fout onder de vorm van een enum. Deze heeft verschillende foutconstantes, elk met een specifieke betekenis. Een voorbeeld hiervan is ServiceError.TRANSFER_NOT_FOUND. Dit betekent dat een transfer niet kan gevonden worden op basis van het meegegeven transfer-GUID.
Deze service-excepties worden opgevangen en gemapt op een Protobuf-foutbericht. Dit wordt
dan als antwoord naar de aanvrager teruggestuurd.
Authorisatiecontrole gebeurt op twee plaatsen. Enerzijds wordt er gebruik gemaakt van Spring
Security bij de transferresource en anderzijds gebeurt er in de services zelf nog een fijnere selectie. Iedere gebruiker in het systeem is aan een bepaalde rol gekoppeld. De twee gebruikte
rollen in dit project zijn visitor (de consument) en vendor (de handelaar). Aan een rol worden
er rechten toegekend zoals bijvoorbeeld ‘create_transfer’ en ‘accept_transfer’. Diezelfde rechten worden ook afgedwongen bij de webservice-methodes (Codefragment 3.7) via een
@PreAuthorize-annotatie. Bij een aanvraag gaat de server na of de geauthenticeerde gebruiker de juiste rechten heeft, dan kan de server op basis hiervan de aanvraag weigeren of deze
verderzetten. Soms is er een fijnere selectie nodig zoals bijvoorbeeld bij de creatie van een
transfer. Zowel een visitor als een vendor hebben het recht om een transfer aan te maken. Wanneer een werknemer bij een handelaar een nieuwe transfer probeert aan te maken, moet er gecontroleerd worden of dit gebeurt via een geldig geregistreerd toestel van de handelaar en of de
werknemer wel effectief werkt bij die handelaar. Deze verfijnde controle gebeurt in de transferservice en kan eventueel de aanvraag via een ‘ServiceError’ weigeren.
11
@POST
@Path(value = RestConstants.CREATETRANSFER_PATH)
@PreAuthorize("hasAuthority('" + RightConstants.CREATE_TRANSFER + "')")
public CreateTransferResponse createTransfer(@Context HttpServletRequest
httpServletRequest, CreateTransferRequest request) {
// …
}
Codefragment 3.7: Authorisatie van een webservicemethode
3.3 Sms-service en notificatieregistratie
Een van de mogelijkheden voor notificaties in de mobiele applicatie (zie 4.9) is dat de gebruiker
via sms wordt verwittigd wanneer een transfer voltooid is. Het SVA-platform moet deze berichten dus kunnen versturen. De gebruiker moet zich ook kunnen inschrijven om sms-notificaties te ontvangen bij een transfer. Deze twee implementaties worden hieronder verder besproken.
Voor het versturen van de sms’en, wordt er een nieuwe service aan SVA toegevoegd, namelijk
de sms-service. Deze is verantwoordelijk voor het verzenden van de sms-berichten naar de gebruikers. De service verstuurt zijn sms’en via Clickatell. Dit is een sms bulk provider die toelaat
om sms’en over de hele wereld te versturen. Dit kan zeer eenvoudig en programmatisch via hun
HTTPS XML API (Clickatell, 2013). Om een sms-bericht te versturen moet de sms-service van
SVA gewoon een HTTPS-aanvraag naar Clickatell sturen. In de HTTP-body van de aanvraag
worden identificatiedetails, gsm-nummer van de ontvanger en het te versturen bericht via een
eXensible Markup Language-structuur (XML-structuur) vermeld (Codefragment 3.8). De identificatievariabelen en instellingen zijn in een properties-bestand ingevuld. Bij het opstarten van
de server wordt deze configuratie via autowiring in een resource bundle voor de sms-service
beschikbaar gemaakt.
data=<?xml version="1.0"?>
<clickAPI>
<sendMsg>
<api_id>%s</api_id>
<user>%s</user>
<password>%s</password>
<to>%s</to>
<text>%s</text>
</sendMsg>
</clickAPI>
Codefragment 3.8: HTTP-body van de sms-aanvraag
Een gebruiker moet ook kunnen aangeven dat hij een sms-bericht wil ontvangen wanneer de
transfer voltooid is. Deze informatie wordt opgeslagen in een nieuw koppelobject, namelijk
12
TransferObservation (Codefragment 3.9). Een TransferObservation bevat een verwijzing naar
de gebruiker, de transfer en om algemeen te blijven, naar de wijze waarop hij op de hoogte wil
gehouden worden. Dit kan bijvoorbeeld via een e-mail of via een sms zijn. Als laatste is er een
TransferObservationRepository toegevoegd. Deze ondersteunt de mogelijkheid om alle observatieobjecten die aan een bepaalde transfer gekoppeld zijn, op te vragen. De transferservice
overloopt deze dan en bepaalt aan de hand van het type of er een sms of een e-mail moet verzonden worden via de sms- of e-mailservice.
@Entity
@Table(name = "sva_transferobservation")
public class TransferObservation extends GenericEntity {
@ManyToOne
private User user;
@ManyToOne
private Transfer transfer;
@Enumerated(EnumType.STRING)
private NotificationType notificationType;
}
// …
Codefragment 3.9: De klasse TransferObservation
3.4 Protobuf
Protobuf is een mechanisme om gestructureerde data te serialiseren en te deserialiseren zodat
ze gemakkelijk via communicatiekanalen verstuurd kunnen worden. Het is taal- en platformonafhankelijk.
De gestructureerde data worden eenmalig gedefinieerd in een zogenaamd ‘proto’-bestand. Dit
stelt een protocol buffer message type voor. Het is een beschrijving van de structuur van een
bericht. De Protobuf-compiler genereert hieruit de overeenkomstige klasse in een gekozen taal.
Via deze klassen kunnen dus protocol buffer messages (binaire streams) aangemaakt worden.
Eerst wordt er een object van de klasse gecreëerd. Ten tweede worden de attributen ingevuld
en als laatste wordt er gevraagd om dit object te serialiseren tot een stream. Deze binaire stream
stuurt men bijvoorbeeld door via het Transmission Control Protocol (TCP) of plaatst men in de
body van een HTTP-bericht. Aan de ontvangstzijde zet men de gegenereerde stream weer om
tot een object en kan men de data gemakkelijk lezen.
Een protocol buffer message is gelijkaardig aan een XML- of JavaScript Object Notation-bericht (JSON-bericht). Het stelt een geserialiseerd object voor. Bij XML en JSON is dit een
‘lange’ tekststring terwijl dit bij een protocol buffer message een binaire string is. Parsen van
de stream tot een object gaat hierdoor bij Protobuf zeer snel, want parsen van tekst is veel trager
dan parsen van binaire strings. De grootte van het verstuurde bericht is ook kleiner dan bij XML
13
en JSON. Bij de laatste twee gaan er veel tekstbits verloren aan indicatie van de meegestuurde
data. Denk hierbij aan de <element>-tags bij XML en de objectnotatie {attribuutnaam:
…, …} bij JSON. Hieronder nog even een kleine vergelijking (Codefragment 3.10).
<!-- XML voorbeeld -->
<person>
<name>John Doe</name>
<email>[email protected]</email>
</person>
<!-- JSON voorbeeld -->
{name: "John Doe", email: "[email protected]"}
<!-- Protobuf voorbeeld -->
0A 08 4A 6F 68 6E 20 44 6F 65 12 10 6A 64 6F 65 40 65 78 61 6D 70 6C 65
2E 63 6F 6D
Codefragment 3.10: Vergelijking van een XML-, JSON- en Protobuf-bericht
(eigen bewerking van Protocol Buffers, 2012)
Het eerste voorbeeld is een XML-bericht. Er wordt een persoonsobject met twee attributen over
het netwerk verstuurd. In het tweede voorbeeld is hetzelfde in een JSON-bericht voorgesteld.
In het derde voorbeeld is het voorgesteld als een protocol buffer-bericht (hier hexadecimaal
voorgesteld, ieder groepje is een byte). Het XML-bericht is 69 bytes lang zonder witruimte, het
JSON-bericht is zonder witruimte 42 tekens lang en het Protobuf-bericht is slechts 28 bytes
lang. Parsen van het Protobuf-bericht duurt ongeveer 100-200 nanoseconden terwijl de XMLversie 5000-10000 nanoseconden duurt.
Een groot voordeel aan Protobuf is dat de berichtenstructuur onafhankelijk van een specifieke
taal wordt vastgelegd. De Protobuf-compiler genereert de gewenste klassen in een willekeurige
taal. Zo kan bijvoorbeeld een webservice geschreven in Java communiceren met een client die
geschreven is in c++ zonder dat er zelf platformspecifieke code moet geschreven worden. Nog
een voordeel is dat er gemakkelijk aan een berichttype nieuwe velden kunnen toegevoegd worden zonder dat bestaande code ‘breekt’. Niet gebruikte velden worden simpelweg genegeerd.
Soms kan de mindere leesbaarheid van de berichten als een nadeel gezien worden. Dit komt
omdat een Protobuf-bericht een binaire string is. Voor publieke webservices kan dit een nadeel
zijn naar gebruiksvriendelijkheid toe. Snel even naar een antwoord van een API-call kijken is
hier moeilijk. Bij de SVA-API is dit toch een voordeel omdat berichten lezen en schrijven naar
de SVA-webservice moeilijker wordt voor buitenstaanders. (Protocol Buffers, 2012)
In de uitbreiding van SVA is er dus gebruik gemaakt van Protobuf aangezien het niets anders
dan voordelen met zich meebrengt. Hieronder (Codefragment 3.11) is de protobuf message type
beschrijving van een transferobject weergegeven. Bij een attribuut kan worden aangegeven of
14
het verplicht of optioneel is. In de documentatie van Protobuf wordt aangeraden om ieder attribuut optioneel te maken en een eigen validatie te voorzien voor de verplichte attributen. Een
verplicht attribuut in de toekomst naar optioneel veranderen kan voor problemen zorgen. Sommige (oudere) Protobuf-lezers beschouwen het bericht dan als incompleet en kunnen het weigeren. Daarom is in de implementatie van de uitbreiding ieder attribuut als optioneel aangeduid.
Als protobuf bibliotheek/compiler is er gebruik gemaakt van Protostuff. Deze software is een
specifieke Javabibliotheek en genereert eenvoudiger Javaklassen dan de officiële compiler. Bij
de Protostuff-klassen kan er gewoon met setters worden gewerkt terwijl bij de officiële compilergegenereerde klassen de data via een builderobject ingevuld moeten worden.
Protobuf biedt geen ondersteuning voor overerving bij klassen. Er zijn twee goede oplossingen
hiervoor (Protocol Buffer Polymorphism, 2010). Eén ervan maakt echter gebruik van het ‘extend’ keyword van Protobuf, maar dit wordt niet ondersteund door de Protostuff compiler.
Daarom wordt deze oplossing ook niet verder behandeld. De tweede oplossing is wel mogelijk
en is als volgt toegepast. Er wordt voor zowel Transfer, BTCTransfer en PTPTransfer een Protobuf-bericht type aangemaakt, namelijk TransferVO, BTCTransferVO en PTPTransferVO. De
laatste twee Value Objects (VO’s) bevatten hun eigen specifieke attributen die niet in TransferVO voorkomen. Er wordt in TransferVO een optioneel attribuut voorzien voor zowel BTCTransferVO en PTPTransferVO. Op eenzelfde moment is er maar één van deze twee attributen
bij een bericht ingevuld. Om gemakkelijk onderscheid te maken wordt er een attribuut toegevoegd dat het ingevulde attribuut aanduidt. Hiervoor wordt er een enum gebruikt.
15
package be.j4s.payment.products.sva.backend.cc.common.protomessages;
option
import
import
import
import
import
import
optimize_for = LITE_RUNTIME;
"LoggedInUser.proto";
"LoggedInMerchant.proto";
"TransferState.proto";
"TransferDetails.proto";
"PTPTransfer.proto";
"BTCTransfer.proto";
message TransferVO {
optional string shared_unique_id = 1;
optional LoggedInUserVO goods_sender = 2;
optional TransferDetailsVO details = 3;
optional int64 timestamp = 4;
optional string description = 5;
optional TransferStateVE state = 6;
// inheritance
enum TransferTypeVE
{
PTPTRANSFER = 1;
BTCTRANSFER = 2;
}
optional TransferTypeVE transfer_type_VE= 7;
optional PTPTransferVO PTP_transfer_VO = 8;
optional BTCTransferVO BTC_transfer_VO = 9;
}
Codefragment 3.11: Inhoud van het transfer proto-bestand
3.5 Flyway
Bij grote projecten wordt er voor de geschreven programmacode vaak gebruik gemaakt van
versiebeheersoftware zoals Subversion en Git. Zo is er exact geweten welke code bij welke
versie van de software hoort. Bij grote projecten met een databank, is de databankstructuur
dynamisch. Updates of patches zorgen voor uitbreidingen/wijzigingen van de databank en uiteindelijk weet niemand meer welke staat/versie de databankstructuur heeft. Flyway is een databankmigratiebibliotheek die zorgt voor versiebeheer van de structuur van een databank. Flyway maakt gebruik van een eigen metadata-tabel met de naam SCHEMA_VERSION. Deze
tabel wordt door de bibliotheek gebruikt om de staat van de databankstructuur bij te houden.
Bij de start van de applicatie moeten enkel deze codelijnen (Codefragment 3.12) helemaal vooraan vermeld worden. Bij het opstarten van het programma, wordt de logica van Flyway uitgevoerd. Iedere versie/migratie van de databankstructuur wordt in een SQL-script vastgelegd. De
naam van het script is van de vorm: Vx__y.sql waarbij x een versienummer en y een beschrijving is. Alle migratiescripts worden in de src/main/resources/db/migration map geplaatst. Tijdens het opstarten scant Flyway deze map en sorteert alle scripts op versienummering. Deze
16
wordt vergeleken met de huidige versie van de databank en indien er nieuwe scripts zijn, worden de migraties uitgevoerd zodat de databank de meest recente structuur heeft. Iedere nieuwe
update wordt in de metadata tabel vemeld. (Flyway, 2014)
Flyway flyway = new Flyway();
flyway.setDataSource(url, user, password);
flyway.migrate();
Codefragment 3.12: Code om Flyway te gebruiken in een programma (Flyway, 2014)
In SVA wordt er gebruik gemaakt van Flyway. De tabellen worden dus niet automatisch via
Hibernate gegenereerd. Voor de tabellen in verband met de Transferobjecten is er een nieuw
migratie SQL-bestand met een verhoogd versienummer aangemaakt en in de migration-map
geplaatst. Dit bestand bevat als inhoud de SQL-query’s om de transfertabellen aan te maken en
om de nieuwe rechten met hun koppelingen aan rollen toe te voegen.
17
4
Implementatie van de front end
4.1 HTML 5- versus native applicatie
Tijdens de analysefase is er onderzocht of het mogelijk is om de applicatie via webtechnologieën al onmiddellijk cross-platform te maken. Het is niet direct mogelijk om de mobiele applicatie als een normale website te bouwen omdat de applicatie toegang nodig heeft tot de hardware van het apparaat (bv. sms, camera, EMV-device) en een browser niet al deze mogelijkheden ter beschikking kan stellen. Het gebruik van hardware verloopt altijd via native code en is
platformafhankelijk. Dit komt omdat ieder mobiel platform (iOS, Android, Windows Phone)
deze functionaliteit via een eigen framework ter beschikking stelt. Het is echter wel mogelijk
om via een hybride methode te werken (Building Cross-Platform Apps, 2013).
Bij de hybride methode worden enkel de zaken die native toegang vereisen in platformafhankelijke code geschreven. De rest wordt zoveel mogelijk met behulp van webtechnologieën gebouwd. Het voordeel om de applicatie in HyperText Markup Language 5 (HTML 5), Cascading
Style Sheet (CSS) en JavaScript te bouwen, is dat ieder mobiel platform hiervoor ondersteuning
biedt. De web-bestanden en de native code worden samen in één native applicatie gebundeld.
De web-bestanden worden in een native webview getoond en via JavaScript is het mogelijk om
te interageren met de native geschreven componenten. Deze techniek is veelbelovend naar de
toekomst toe omdat ontwikkelaars in tegenstelling tot nu, op een algemene manier de UI en de
interactie met de applicatie kunnen beschrijven onafhankelijk van een specifiek platform.
Om het hierboven geschreven proces toch zoveel mogelijk te automatiseren, wordt er gebruik
gemaakt van een platform, namelijk Apache Cordova. Hiermee kan men een algemeen project
aanmaken dat onder andere een ‘www’-map bevat (Apache Cordova, 2014). Het is de bedoeling
dat alle webspecifieke bestanden in deze map komen. Via de commandline tools van Apache
Cordova is het mogelijk om dan de platformspecifieke bundels geautomatiseerd aan te maken.
Hiervoor gebruikt het achter de schermen de platformspecifieke Software Development Kit’s
(SDK’s) om een overeenkomstig project aan te maken met een webview en deze te builden tot
een native uitvoerbare applicatie.
Apache Cordova biedt ook heel wat standaard plug-ins aan. Dit zijn native geschreven klassen
waarmee vanuit JavaScript wordt geïnterageerd. Deze voeren dan platformspecifieke code uit
om bijvoorbeeld de hardware aan te spreken. Een voorbeeld hiervan is de camera plug-in. Zonder zelf iets van native code te moeten schrijven, kan de camera via deze plug-in vanuit Javascript worden aangesproken. Het is ook mogelijk om eigen plug-ins te schrijven. Deze moet dan
wel zelf voor elk gewenst platform geschreven worden. Zo zou voor de mobiele applicatie een
eigen plug-in moeten geschreven worden die met de EMV-lezer interageert.
De UI van de applicatie is niet zomaar een normale website. Mobiele toestellen hebben verschillende schermformaten met verschillende pixeldichtheden. Hierdoor moet er bijvoorbeeld
rekening gehouden worden met schalen en responsive layout. Dit wordt gemakkelijk opgelost
18
door gebruik te maken van een UI-framework zoals jQuery Mobile. Deze voorziet in allerlei
lay-out componenten (bv. knoppen, navigatiemenu’s, panelen). Om gemakkelijk browseronafhankelijk Asynchronous JavaScript and XML-aanroepen (AJAX-aanroepen) te kunnen uitvoeren, wordt er gebruik gemaakt van jQuery.
In theorie is het dus mogelijk om de volledige applicatie zoveel mogelijk platform onafhankelijk te maken. In de praktijk brengt het toch enkel nadelen met zich mee. Het aanspreken van
een eigen Cordova plug-in is complexer dan in een native applicatie. De applicatie heeft ook
niet de platformafhankelijke native look and feel. Door de ‘zware’ HTML-rendering oogt de
applicatie niet vloeiend en start ze ook trager op dan de native applicatie. Omwille van performantie is bijvoorbeeld Facebook naar platformspecifieke native applicaties overgeschakeld
(King, 2012).
In het ontwerp van de mobiele applicatie is er redelijk wat hardwaretoegang nodig. Hierom en
omwille van performantieredenen is er uiteindelijk gekozen om de mobiele client als een native
Androidapplicatie uit te werken.
4.2 Algemeen
De ontwikkeling van de mobiele applicatie is een nieuw project. Er is gekozen voor een native
Android applicatie. Hierbij is er veel aandacht besteed aan de mogelijkheid tot uitbreiden en de
flexibiliteit van de app. Zo zijn alle geschreven klassen in Java packages geordend. Alle tekststrings worden vanuit een XML-bestand geladen. De app is daardoor al onmiddellijk bruikbaar
voor meerdere talen. Het enige dat er nog moet gebeuren is nieuwe XML-bestanden aanmaken
met daarin de vertalingen. Android selecteert dan automatisch het juiste XML-bestand (met de
juiste taal) afhankelijk van de ingestelde lokale instellingen van het toestel. De GUI-lay-out van
de applicatie is ook zoveel mogelijk in XML-bestanden beschreven. Dit zorgt voor een goede
scheiding van de GUI en de ‘code behind’. Alle gebruikte icoontjes zijn beschikbaar in verschillende groottes zodat ze er op ieder scherm ongeveer even groot uitzien en performant kunnen gerendered worden. Het heeft bijvoorbeeld geen zin om een afbeelding te renderen waarvan maar de helft van het aantal pixels effectief op het scherm kan worden getoond.
Het ontwerp en de implementatie van de GUI volgen zoveel mogelijk de algemene stijlregels
van Android. Deze worden de laatste tijd door Android sterk gepromoot (Design, 2014) zodat
alle apps een gezamenlijke native look and feel hebben. Dit is ook gebruiksvriendelijker voor
de eindgebruiker. Het hoofdscherm (Figuur 4.1) is het startpunt van de volledige applicatie (na
het inloggen). Het bevat alle nuttige informatie op een enkel scherm. De swipable tabbladen en
de navigation drawer zorgen ervoor dat alle nuttige informatie op een enkele activity (scherm)
beschikbaar is zonder daarbij de gebruiker met allerlei details te overladen. Verder is er door
heel de applicatie up-navigatie voorzien en wordt er actief gebruik gemaakt van de actionbar
(Figuur 4.2).
19
De applicatie is ontwikkeld om op zoveel mogelijk verschillende Androidversies te kunnen
draaien. De vereiste minimumversie voor de betalingsapplicatie is Android 2.3 (API-niveau 9).
Dit komt doordat de gebruikte bibliotheek om QR-codes te detecteren dit vereist. Google verzamelt statistieken in verband met de Androidversies via zijn Google Play Store app (Dashboards, 2014). Ruw geschat kan worden afgeleid dat de applicatie op 97 % van de Androidtoestellen zou moeten draaien.
Figuur 4.1: Hoofdscherm voor de consument (links) en de uitgeklapte navigation drawer (rechts)
1
3
2
Figuur 4.2: Voorbeeld van up-navigatie (1) en een spinner (2) in de actionbar (3)
20
4.3 Support library
Iedere Androidversie brengt nieuwe features met zich mee. In de algemene stijlregels zoals nu
beschreven, wordt aangeraden om bepaalde componenten zoals een actionbar en notificaties
(Figuur 4.10) te gebruiken. Het probleem is dat sommige van die componenten pas in latere
Androidversies zijn ingevoerd en dus niet werken op oudere versies. Een voorbeeld hiervan is
de actionbar. Die is pas beschikbaar vanaf Android 3.0. Om toch de meest recente stijlkenmerken te kunnen gebruiken bij oudere Androidversies zijn er support libraries beschikbaar.
Er zijn verschillende ondersteuningsbibiliotheken. Iedere bibliotheek biedt een aantal functionaliteiten aan van nieuwere Androidversies tot aan een bepaalde oudere versie. In de app is er
gebruik gemaakt van de v4- en v7 support library. Dit betekent dat de v4-bibliotheek compatibiliteit biedt voor een aantal componenten tot aan Android API level 4. De v7 support library
biedt functionaliteit aan teruggaand tot aan API level 7. Uit de v4-bibliotheek worden onder
andere de klassen Fragment en NotificationCompat gebruikt om gemakkelijk met fragments en
notificaties te kunnen werken. De v7-library is gebruikt om de actionbar met de daaraan gekoppelde acties te kunnen gebruiken. (Support Library, 2014)
Hieronder wordt als voorbeeld nog eens kort het gebruik van de v7-bibliotheek gedemonstreerd.
Een nieuwe activity erft nu niet meer over van de klasse Activity, maar van de klasse ActionBarActivity uit de ondersteuningsbibliotheek (Setting Up the Action Bar, z.j.). Om in code zaken aan de actionbar te wijzigen, kan er bijvoorbeeld in de onCreate-methode getSupportActionBar() in plaats van getActionBar() opgeroepen worden. Als laatste instelling moet
er verwezen worden naar een comptabiliteitsthema voor de activity in de Android manifest. Dit
kan globaal voor de hele applicatie in één keer worden ingesteld zodat iedere activity daarvan
gebruik maakt. (Codefragment 4.1).
<application <!-- … -->
android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
<!-- … -->
</application>
Codefragment 4.1: Verwijzen naar een support library thema
4.4 Data Access Object
De mobiele applicatie maakt gebruik van een Data Access Object (DAO). Het is een object dat
alle logica bevat om gegevens op te halen en weg te schrijven. De applicatie is hierdoor volledig
ontkoppeld van het domeinmodel van SVA. Dit heeft als voordeel dat de applicatie los van
SVA kan ontwikkeld worden. Wijzigingen zoals bijvoorbeeld weglaten van attributen of hervormingen in het domeinmodel van SVA hebben geen impact op de globale werking van de
mobiele applicatie. De applicatie steunt volledig op een interface van een DAO en een eigen
21
klassenmodel. De interface ligt eenduidig vast en het is de DAO-implementatie die ervoor zorgt
dat de data aangeleverd en verwerkt worden zoals afgesproken. Hoe en op welke manier die
implementatie aan deze informatie komt, weet de applicatie dus niet. Het gebruik van een interface zorgt er ook voor dat er gemakkelijk van DAO-implementatie kan gewijzigd worden.
Zo kan de app bijvoorbeeld aan een ander platform gekoppeld worden en is het alleen de DAOimplementatie die moet gewijzigd worden. Wijzigingen aan bestaande SVA-code leiden ook
enkel tot aanpassen van de DAO-implementatie.
De app haalt zijn data van het SVA-platform. Hiervoor is er een implementatie van de DAOinterface geschreven die communiceert met SVA en de antwoorden daarvan omzet naar de eigen modelklassen. In de code (Codefragment 4.2) is de geïmplementeerde methode te zien om
de info van een transfer op te halen. De te versturen data worden eerst naar een Protobuf-object
omgezet. De logica om dit te doen, zit gescheiden in een aparte klasse, namelijk TransferAssembler. De kennis om een aanvraag te verrichten aan de SVA-server zit in de klasse RESTRequester. Deze heeft een methode requestPOST die de aanvragen verstuurt. Als laatste wordt het
ontvangen Protobuf-object naar een modelobject omgezet en aan de applicatie teruggegeven.
De requestPOST-methode is een generieke geparametriseerde methode die een POST HTTPSaanvraag naar de SVA-server verzendt. De twee parameters P en R zijn het invoer- en uitvoer
Protobuf-object. Om een HTTPS-request te versturen maakt deze methode gebruik van de in
Java voorziene klasse HttpsURLConnection. De RESTRequester is gemakkelijk configureerbaar via een properties-bestand zodat de klasse zelf niet opnieuw moet gecompileerd worden.
@Override
public Transfer getTransfer(String transferID) throws DAOException {
try {
GetTransferRequest requestDataObject =
TransferAssembler.buildGetTransferRequest(transferID);
GetTransferResponse responseDataObject = new
GetTransferResponse();
restRequester.requestPOST(RestConstants.GETTRANSFER_ABS_PATH,
requestDataObject, responseDataObject);
return TransferAssembler.buildTransfer(responseDataObject);
}
catch (RESTRequesterException e) {
throw new DAOException("Server access error", e);
}
}
Codefragment 4.2: Een geïmplementeerde methode van de DAO-interface
22
4.5 Navigatie tussen activities
In de applicatie wordt er tussen verschillende schermen genavigeerd. In Android wordt een
scherm met de klasse Activity voorgesteld. Alles begint dus bij de login-activity (Figuur 4.3).
Hierin kan de gebruiker zijn logingegevens invullen. Na authenticiteitscontrole wordt er naar
het hoofdscherm genavigeerd. Voor de rest van de app is het hoofdscherm het centrale gedeelte.
Na een bepaalde reeks handelingen wordt er altijd terug naar dit scherm genavigeerd. Activities
worden constant aangemaakt en afgebroken.
Figuur 4.3: Login activity
Eerste probleem
Sommige objecten hoeven slechts eenmalig aangemaakt te worden en moeten op verschillende
plaatsen in de applicatie toegankelijk zijn. Denk hierbij aan het DAO-object en een user-object
met informatie over de ingelogde gebruiker. Deze objecten constant doorgeven van de ene
activity naar de andere is niet echt een optie. Er zijn twee verschillende oplossingen voor dit
probleem.
Een eerste oplossing is dat Android toelaat om een globaal contextobject te creëren dat vanuit
elke activity in de applicatie bereikbaar is. Dit object is van het type Application. Door nu via
overerving van de Application-klasse een nieuwe klasse met eigen functionaliteit aan te maken,
wordt het mogelijk om het DAO en userobject ergens in de applicatie aan te spreken. In de
Android Manifest-file wordt naar de nieuwe klasse verwezen en bij initialisatie van de app,
zorgt Android ervoor dat er één object van dit type aangemaakt wordt.
23
De tweede oplossing is om gebruik te maken van een eigen geschreven singleton-klasse met
dezelfde extra toegevoegde functionaliteit. Door het statische instantie-attribuut van de singleton-klasse, is er ook een object met de eigen functionaliteit beschikbaar over heel de applicatie.
In deze applicatie is voor de eerste oplossing gekozen omdat het gebruik van singletons subtiele
problemen met zich meebrengt en afgeraden wordt (Singletons vs. Application Context in
Android, 2010).
Tweede probleem
Bepaalde schermen zoals bijvoorbeeld het keuzescherm van een betalingswijze worden opnieuw gebruikt in verschillende schermen flows. Dit wil zeggen dat de zonet opgesomde activity
een verschillend ouderscherm kan hebben naargelang de handelingen van de gebruiker.
Standaard ‘up’-navigatie in Android werkt als volgt (Codefragment 4.3). Ten eerste moet de
up-knop in de actionbar in de onCreate-methode zichtbaar gemaakt worden. Vervolgens wordt
er code aan het klikevent van deze knop gekoppeld. Het is de navigateUpFromSameTask-methode die ervoor zorgt dat de ouder-activity opnieuw wordt geladen en dat de huidige activity
wordt afgesloten. Hiervoor wordt er gekeken naar de klassennaam van de ouderactivity die
gespecificeerd is in de manifest-file. Het probleem is nu als er daar twee ouders zouden gedefinieerd zijn, Android niet kan weten welke activity nu juist als ouderactivity moet geladen
worden.
// Code in een Activity klasse
@Override
public void onCreate(Bundle savedInstanceState) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
NavUtils.navigateUpFromSameTask(this);
return true;
}
return super.onOptionsItemSelected(item);
}
<!-- Code toevoegen in de manifest file -->
<activity <!-- … -->
android:parentActivityName="com.example.myfirstapp.MainActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.example.myfirstapp.MainActivity" />
</activity>
Codefragment 4.3: Code voor standaard up-navigatie (Providing Up Navigation, z.j.)
24
De oplossing is om de up-navigatie in code na te maken zodat meerdere ouders wel mogelijk
zijn. Het volgende codefragment (Codefragment 4.4) geeft de code die nodig is om van een
activity naar een andere activity te gaan (voorwaarts navigeren). In dit voorbeeld bevindt deze
code zich in de loginactivity en zorgt ze ervoor dat de hoofdactivity geladen wordt. De oplossing voor het probleem van meerdere ouders maakt gebruik van deze standaardnavigatie, maar
ze bevat nog wat extra lijnen code en een extra instelling.
Intent intent = new Intent(this, ActivityMain.class);
startActivity(intent);
Codefragment 4.4: Code voor standaardnavigatie tussen activities
Als voorbeeld (Codefragment 4.5) van de uiteindelijke oplossing wordt er naar de activity ‘ActivityChooseMethod’ gekeken. Deze bevat een lijst van knoppen waarmee de gebruiker een
betaalwijze kan selecteren. Deze activity kan de gebruiker van uit de hoofdactivity (ActivityMain) en vanuit de activity om een nieuwe transfer aan te maken (ActivityNewTransfer) oproepen. De ene flow is dus van de betaler en de andere flow is van de ontvanger.
Het eerste stukje code (Codefragment 4.5) moet in ActivityMain toegevoegd worden. Dit is
code voor standaardnavigatie van ActivityMain naar ActivityChooseMethod. Bij de overgang
wordt er nu echter een gegeven meegestuurd, namelijk een constante die de naam bevat van de
activity die ActivityChooseMethod oproept. In ActivityChooseMethod wordt deze parameter
opgehaald en in een variabele callingActivityName gestoken.
Wanneer nu op de up-knop geklikt wordt, wordt het onderste stukje code van het codefragment
in ActivityChooseMethod uitgevoerd. Deze bevat opnieuw een standaard navigatiemanier via
een intent en er wordt afhankelijk van de waarde van callingActivityName naar de juiste klasse
genavigeerd. Als we nu deze code zouden uitvoeren zonder de intent-vlag, dan zou er gewoon
verder naar een nieuwe instantie van ActivityMain genavigeerd worden. Om dit te vermijden
wordt met een vlag aangegeven dat Android pas een nieuwe instantie mag aanmaken wanneer
het alle tussenliggende activities en de ouderactivity zelf heeft afgesloten.
Via deze methode wordt exact hetzelfde resultaat nagebootst als met de navigateUpFromSameTask-methode. Op dezelfde manier is het bijvoorbeeld ook mogelijk om van het allerlaatste
scherm in de flow (betalingsbevestiging-activity) naar het hoofdscherm terug te keren.
25
// Code voor in ActivityMain
Intent intent = new Intent(this, ActivityChooseMethod.class);
intent.putExtra(BasicConstants.INTENT_EXTRA_KEY_CALLING_ACTIVITY_NAME,
BasicConstants.ACTIVITY_NAME_MAIN);
startActivity(intent);
// Code voor in ActivityChooseMethod
Class c;
if (BasicConstants.ACTIVITY_NAME_MAIN.equals(callingActivityName)) {
c = ActivityMain.class;
}
else {
c = ActivityNewTransfer.class;
}
Intent intent = new Intent(this, c);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
Codefragment 4.5: Oplossing voor up-navigatie met meerdere ouderactivities
4.6 Asynchrone taken
Een activity wordt in de onCreate-methode van de Activity-klasse aangemaakt. Op die plaats
wordt normaal gezien de lay-out uit het XML-bestand geladen en aan de view van de activity
toegevoegd. Dit gebeurt op de User Interface-thread (UI-thread) van de applicatie. Die is verantwoordelijk voor de UI en voor het verwerken van gebruikersinvoer. In de applicatie moeten
vaak nog data van de SVA-server worden opgehaald en dynamisch in de View van de Activity
worden ingevuld (denk hierbij aan een scherm dat de laatste 10 transfers toont). Aangezien data
ophalen van een server een blokkerende operatie kan zijn (de internetverbinding kan wegvallen)
leidt dit tot een niet-vlotreagerende GUI en kan dit zelfs tot niet-reagerende activities leiden
(Keeping Your App Responsive, z.j.).
Android controleert of applicaties altijd responsief zijn. Indien gebruikersinvoer niet binnen de
vijf seconden wordt verwerkt (doordat er een zware berekening bezig is of een blokkerende
operatie), wordt er een boodschap op het scherm getoond (Figuur 4.4) en wordt aan de gebruiker
gevraagd of hij de app wil sluiten.
De oplossing voor dit probleem is dus om zware/mogelijke blokkerende taken op een aparte
thread te laten uitvoeren. In de mobiele applicatie wordt tijdens de onCreate-methode eerst een
bezig-met-laden-indicator (Figuur 4.5) getoond en daarna wordt de data-aanvraag op een aparte
thread gestart. De gebruiker kan zien aan de loading-indicator dat er nog een taak in de achtergrond bezig is en dat hij eventjes moet wachten. Wanneer de asynchrone taak afgewerkt is
(wanneer de data van de server afgehaald zijn), wordt dan de loading-indicator door de effectieve data vervangen.
26
Figuur 4.4: Melding wanneer de applicatie niet meer reageert (Keeping Your App Responsive, z.j.)
Figuur 4.5: Hoofdactivity met loading indicator
Om eenvoudig een nieuwe achtergrondthread aan te maken, voorziet de Android API in een
AsyncTask-klasse. Deze klasse bevat al volledig de logica om een nieuwe thread aan te maken.
Eigen functionaliteit kan beschreven worden door gewoon van deze klasse over te erven en de
template methods in te vullen. Er zijn drie belangrijke methodes die hier van toepassing zijn.
De doInBackground-methode, onPostExecute-methode en de onCancelled-methode. De eerste
bevat de code die in de aparte thread wordt uitgevoerd. De tweede methode bevat de code die
wordt uitgevoerd nadat de doInBackground-methode succesvol is afgerond. De returnwaarde
van de doInBackground-methode wordt als parameter aan de onPostExecute-methode meegegeven. Indien de taak geannuleerd is, wordt de derde methode aangeroepen in plaats van de
tweede. Deze krijgt ook de returnwaarde van de eerste methode als parameter. Zowel de onPostExecute-methode als de onCancelled methode worden weer op de UI-thread uitgevoerd.
27
In de app zijn er redelijk veel taken die op de achtergrond voltooid moeten worden. Een bepaalde taak kan ook op verschillende plaatsen worden opgeroepen en de acties die op de UIthread uitgevoerd moeten worden, verschillen dus ook per plaats wanneer de taak voltooid is.
Om dit gemakkelijk te laten verlopen en te implementeren is er een nieuwe abstracte klasse
toegevoegd, namelijk TaskCallbackTask(Codefragment 4.6).
De nieuwe klasse erft over van AsyncTask. De klasse AsyncTask is een geparameteriseerde
klasse. Ze bevat drie parameters. De eerste is het type van de parameter van de doInBackground-methode. De tweede is het type van de parameter van de onProgressUpdate-methode.
Deze wordt hier niet gebruikt. Het doel van deze methode is om de status in de UI aan te geven.
De parameter is een zelf afgesproken waarde van een bepaald type die de status voorstelt. Een
voorbeeld van een type zou een integer kunnen zijn die van 0 tot 100 gaat. De derde parameter
is het type van de teruggeefwaarde van de doInBackground-methode.
De klasse TaskCallbackTask heeft een attribuut van het type TaskCallback. Dit is een interface
(Codefragment 4.7) die twee methodes beschrijft. De eerste methode wordt opgeroepen wanneer de taak succesvol afgewerkt is en de tweede indien er een fout is opgetreden. Door andere
TaskCallback-implementaties aan de constructor van TaskCallbackTask mee te geven, kan dus
het gewenste gedrag bij voltooiing of bij het falen van een taak worden ingevuld. Iedere nieuwe
DAO-taak moet nu enkel nog de doInBackground-methode en het parametertype invullen.
public abstract class TaskCallbackTask<P> extends AsyncTask<P, Integer,
Object> {
private TaskCallback callback;
public TaskCallbackTask(TaskCallback callback) {
this.callback = callback;
}
@Override
protected abstract Object doInBackground(P... param);
@Override
protected void onPostExecute(Object result) {
if (callback != null) {
callback.taskCallback(result);
}
}
@Override
protected void onCancelled(Object error) {
if (callback != null) {
callback.taskFailed((Exception) error);
}
}
}
Codefragment 4.6: De abstracte klasse TaskCallbackTask
28
public interface TaskCallback {
void taskCallback(Object result);
void taskFailed(Exception exception);
}
Codefragment 4.7: De interface TaskCallback
De meeste van de asynchrone taken in de applicatie zijn serveraanvragen die over het netwerk
worden verstuurd. Daarom is er speciaal voor deze groep taken nog een abstracte klasse (Codefragment 4.8) gedefinieerd. Deze voegt nog een extra attribuut toe, namelijk een verwijzing
naar het DAO-object dat iedere overervende klasse sowieso nodig heeft als het een aanvraag
wil doen.
public abstract class DAOTask<P> extends TaskCallbackTask<P> {
protected DAO dao;
public DAOTask(TaskCallback callback, DAO dao) {
super(callback);
this.dao = dao;
}
@Override
protected abstract Object doInBackground(P... param);
}
Codefragment 4.8: De abstracte klasse DAOTask
Als laatste is er nog een voorbeeld (Codefragment 4.9) van een implementerende klasse van
DAOTask. De klasse GetTransferDetailsTask haalt asynchroon de gegevens van een bepaalde
transfer op. De parameter die wordt meegegeven is het gedeelde unieke ID van de transfer. Via
de constructor krijgt het taskobject een referentie naar een callback en een referentie naar een
willekeurige DAO-object. Het enige dat de implementatie van de klasse nog moet voorzien, is
de code die in de doInBackground-methode uitgevoerd moet worden.
In een activity zelf kan nu een taak zeer eenvoudig gestart worden (Codefragment 4.10). Om
de transferdetails op te vragen wordt er gewoon een nieuw object van de taakklasse aangemaakt.
In de constructor wordt een referentie naar een callbackobject en het DAO-object meegegeven.
Wanneer de taak voltooid is of wanneer er een fout is opgetreden, wordt de juiste overeenkomstige methode opgeroepen.
29
public class GetTransferDetailsTask extends DAOTask<String> {
public GetTransferDetailsTask(TaskCallback callback, DAO dao) {
super(callback, dao);
}
@Override
protected Object doInBackground(String... param) {
try {
return dao.getTransfer((String) param[0]);
} catch (DAOException e) {
cancel(false);
return e;
}
}
}
Codefragment 4.9: De klasse GetTransferDetailsTask
new GetTransferDetailsTask(this, appContext.getDAO())
.execute(transferID);
Codefragment 4.10: Code om een asynchrone taak te starten
4.7 ZXing
Voor het genereren, scannen en decoderen van QR-codes is er gebruik gemaakt van de ZXingbibliotheek. Dit is een Java bibliotheek die naast QR-codes ook nog met heel wat andere barcodes kan werken. Omdat coderen en decoderen ‘zware’ berekeningen zijn, worden deze op
een aparte thread (via een implementatie van TaskCallbackTask) uitgevoerd. Het gedeelde
unieke ID wordt bij het aanmaken van een transfer naar een QR-code omgezet (Figuur 4.6). Bij
het scannen van de QR-code, wordt deze opnieuw gedecodeerd.
30
Figuur 4.6: Activity met de QR-code
4.8 Opslag van data op het toestel
De meeste informatie in de applicatie is afkomstig van de SVA-server. Er is echter ook nood
aan lokale persistente opslag in de mobiele applicatie. Android biedt verschillende mogelijkheden (Storage Options, z.j.) aan voor het opslaan van data op het toestel. Afhankelijk van de
soort en de hoeveelheid data is de ene manier beter dan de andere.
Shared Preferences
Een eerste mogelijkheid is het gebruik van Shared Preferences. Via deze manier kunnen er
gemakkelijk key-value-paren van een primitief type worden opgeslagen. Iedere activity heeft
zijn eigen Shared Preference. Deze kan binnen een activity via de getPreferences-methode worden opgevraagd. Om een globale Shared Preference tussen verschillende activities te creëren,
moet dit opslagobject via de getSharedpreferences-methode worden opgevraagd waarbij als
parameter een unieke naam wordt meegegeven. In het voorbeeld (Codefragment 4.11) wordt er
gebruik gemaakt van een globale SharedPreference die een paar specifieke instellingen van de
applicatie op het toestel bijhoudt. De code demonstreert hoe de laatst gebruikte gebruikersnaam
van een SharedPreference kan worden opgevraagd en daarin worden weggeschreven. Nog iets
31
wat in de settings SharedPreference wordt opgeslagen, is de device serial van de handelaar. Dit
is een extra beveiliging zodat enkel geregistreerde toestellen B2C-transfers kunnen aanmaken.
// Opvragen waarde van een sleutel
SharedPreferences preferences = getSharedPreferences(BasicConstants
.SHARED_PREFERENCES_FILE_NAME_SETTINGS, MODE_PRIVATE);
String usernameValue = preferences.getString(BasicConstants
.SHARED_PREFERENCES_KEY_USERNAME, "");
// Opslaan van een waarde bij een sleutel
SharedPreferences.Editor editor = preferences.edit();
editor.putString(BasicConstants.SHARED_PREFERENCES_KEY_USERNAME, editTextUsername.getText().toString());
editor.commit();
Codefragment 4.11: Gebruik van Shared Preferences voor opslag van de username
Bestand
Een tweede manier voor persistente opslag is data rechtstreeks naar een bestand op het toestel
wegschrijven. Android maakt onderscheid tussen interne opslag en externe opslag (Saving Files, z.j.). Externe opslag werd vroeger gezien als opslagruimte op een verwijderbaar medium
zoals bijvoorbeeld een Micro Secure Digital-kaartje (Micro SD-kaartje). Tegenwoordig wordt
er nu vaak ook al externe opslag, die niet verwijderbaar is, op de toestellen voorzien. Kleine
app specifieke, private data worden het best op de interne en grote (publieke) bestanden op de
externe opslagruimte opgeslagen. Data die op de interne opslagruimte opgeslagen zijn, worden
mee verwijderd wanneer de gebruiker de applicatie van het toestel verwijdert. Ten slotte is er
ook nog de interne en externe cache. Dit is een speciale map die bedoeld is om tijdelijke bestanden op de interne of de externe opslagruimte op te slaan. Wanneer Android opslagruimte
tekort komt of als de app wordt verwijderd, dan worden bestanden in deze cache mappen verwijderd. In de applicatie wordt zowel interne als externe opslag gebruikt.
De interne opslag wordt gebruikt om een lokale geschiedenis van EMV-transacties bij te houden. Zo kan de handelaar informatie over de laatste tien EMV-transacties bekijken. Deze informatie wordt in een bestand op de interne opslagruimte opgeslagen, want het bestand mag niet
leesbaar zijn door derden en andere applicaties aangezien het betaalinformatie bevat. Toegang
krijgen tot deze bestanden in de applicatie kan via de methodes openFileInput en openFileOutput. Deze methodes geven als returnwaarde een FileInputStream en een FileOutputStream
waarmee dan gewerkt kan worden zoals in normale Java applicaties.
Op het QR-codegenereerscherm, is er een actie toegevoegd om de QR-code te delen. Dit maakt
het mogelijk om een betaling uit te voeren waarbij beide personen zich niet meer in dezelfde
ruimte bevinden. Deze actie opent via een impliciete intent een willekeurig gekozen (door de
gebruiker) applicatie die in staat is om een afbeelding te delen. Het is echter niet mogelijk (Sending Simple Data, z.j.) om de QR-code als bitmapobject met de intent naar de andere applicatie
32
mee te geven. De afbeelding wordt eerst naar de externe opslagruimte (toegankelijk voor andere
applicaties) geschreven. Aangezien de afbeelding tijdelijk is en steeds overschreven wordt wanneer een nieuwe QR-code wordt gedeeld, is er gekozen voor de externe cache map. Het is nu
het pad naar de afbeelding dat bij de intent bijgevoegd wordt. De gekozen applicatie kan nu via
dit pad aan de afbeelding geraken. Om in de applicatie een verwijzing naar de cachemap te
krijgen, wordt de getExternalCacheDir-methode gebruikt. Deze geeft een object terug van het
type File dat het pad bevat. Nu kan er weer een FileOutputStream voor een bestand in die map
aangemaakt worden en kan de afbeelding naar deze stream geschreven worden.
Databank
Voor de volledigheid wordt er nog even vermeld dat er ook een derde mogelijkheid is. Android
biedt volledige ondersteuning voor SQLite databanken. Deze zijn enkel toegankelijk via een
gekozen naam binnen de applicatie. SQLite is een zeer kleine databankbibliotheek. Het maakt
geen gebruik van een apart serverproces, maar leest en schrijft rechtstreeks naar het databankbestand (About SQLite, z.j.).
4.9 Notificaties
Wanneer de betaler op ‘betalen’ duwt, krijgt hij onmiddellijk feedback (Figuur 4.7) als de betaling succesvol is. Een ontvanger blijft echter vastzitten op het QR-codescherm omdat er zich
een tijdsperiode bevindt tussen de generatie van de QR-code en het inscannen en accepteren
door de betaler. Dit kan van lange duur zijn indien de ontvanger beslist heeft om de QR-code
te delen (bv. via e-mail). Hiervoor worden er twee verschillende notificatieoplossingen ingebouwd.
Figuur 4.7: Bevestigingsscherm van een betaling
33
Een eerste mogelijkheid is specifiek voor de situatie wanneer beide personen zich in dezelfde
ruimte bevinden. Betalen duurt dan zeker niet langer dan een (halve) minuut. Op het QR-code
scherm wordt er periodiek nagegaan of de betaling voltooid is. Dit wordt met een timer gerealiseerd. Een timer voert periodiek de run-methode van een object op een aparte thread uit. In
deze methode wordt er nagegaan of de transfer voltooid is of niet. Er wordt opnieuw met een
callback interface gewerkt om het gedrag gemakkelijk te kunnen aanpassen. Wanneer de betaling voltooid is, wordt er automatisch naar het betalingsbevestigingsscherm overgegaan.
De tweede implementatie is er een voor langere tijdsperiodes. De ontvanger kan aanduiden dat
hij via een sms wil verwittigd worden wanneer de betaling voltooid is. Er is specifiek voor een
sms-bericht gekozen omwille van de gebruiksvriendelijkheid van de applicatie. De app zou
even goed een service kunnen starten die periodiek in de achtergrond controleert (ook wanneer
de applicatie niet meer actief is) of de betaling al voltooid is en indien wel, een notificatie tonen.
Dit zorgt echter voor een bijkomende en blijvende vertraging van het systeem, ook wanneer de
gebruiker de app al heeft afgesloten. Daarom is er voor de volgende elegante oplossing gekozen.
Wanneer de gebruiker op de sms-knop duwt, registreert hij zich op de server zodat hij verwittigd
wordt. Daarna mag de gebruiker gewoon verder werken met de applicatie en zelfs de applicatie
afsluiten. Wanneer de betaling voltooid is, stuurt de SVA-server een sms-bericht (Figuur 4.8)
naar alle personen die zich geregistreerd hebben. De inhoud van het sms-bericht is een URL
die als parameter het gedeelde unieke ID bevat.
Figuur 4.8: Sms-bericht van SVA met daarin het transfer-ID
In de Androidapplicatie is er een activity aangemaakt die een overzicht van de betaling weergeeft (Figuur 4.9). Deze activity kan nu aan de URL gekoppeld worden (Codefragment 4.12)
zodat de overzichtsactivity wordt opgestart als de gebruiker op de URL klikt. Dit is mogelijk
omdat de sms-applicatie een willekeurige activity start via een impliciete intent met een URL.
Android selecteert hierbij de best passende activity die URL’s kan verwerken. Door filters bij
de overzichtsactivity in de manifest te specificeren, wordt aangegeven welke URL’s deze kan
verwerken en of die dus al dan niet mag opgestart worden. De URL heeft als schema (protocolaanduiding) HTTPS. Oorspronkelijk was het de bedoeling om een eigen schema te gebruiken
(bv. de naam van de applicatie). Dan zou de URL er als volgt uitgezien hebben.
paynow://sharedUniqueID
34
Bij Android werd deze URL echter in sommige applicaties niet als URL herkend en was hij dus
niet meer aanklikbaar. Er is nog een bijkomend gebruiksvoordeel van HTTPS. Indien de binding op een of andere manier toch zou falen, wordt de browser geopend en komt de gebruiker
op een online versie van het overzicht terecht.
Figuur 4.9: Transferoverzichtscherm
<activity <!-- … -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="https"
android:pathPrefix="www.j4s.be/paynow" />
</intent-filter>
</activity>
Codefragment 4.12: Intentfiltering op de HTTPS-URL in de manifest file
Omdat een notificatie tonen nog altijd mooier is dan een URL in een sms-bericht is het volgende
aan de applicatie toegevoegd. Wanneer er een sms-bericht op een toestel toekomt, kondigt
Android dit via een broadcast-bericht aan. Er is aan de applicatie een overervende broadcast
receiver klasse toegevoegd (Codefragment 4.13) die getriggerd wordt op zo een broadcastbericht van Android. Wanneer nu een sms-bericht binnenkomt, worden alle broadcast receivers
een voor een uitgevoerd. De toegevoegde klasse controleert of het sms-bericht voldoet aan de
notificatie-URL. Indien wel, wordt het broadcasten onderbroken en wordt er een notificatie
(Figuur 4.10) getoond. Indien niet, wordt het bericht gewoon aan de volgende broadcast receiver doorgegeven. Aan een broadcast receiver kan er ook een prioriteit toegekend worden. Door
35
deze de hoogste prioriteit (integerwaarde 999) te geven, wordt deze SMSBroadcastReceiver als
eerste uitgevoerd. Aan de notificatie is uiteindelijk een pendingintent gekoppeld met een intent
dat ook het betalingsoverzichtsscherm toont wanneer op de notificatie wordt gedrukt.
Figuur 4.10: De notificatie die verschijnt wanneer een betaling voltooid is
<receiver android:name="be.j4s.payment.products.paynow.classes
.SMSBroadcastReceiver" android:enabled="true" android:exported="true">
<intent-filter android:priority="999">
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
Codefragment 4.13: Aankondiging van de SMSBroadcastReceiver in de manifest file
4.10 ProGuard
Bij Android worden de gecompileerde code, de gebruikte bibliotheken en andere resources in
een apk-bestand gebundeld. Het is dit bestand dat manueel of via Google Play wordt verspreid
en geïnstalleerd. ProGuard is een tool die de code verkleint, optimaliseert en minder leesbaar
maakt. Het verwijdert niet-gebruikte klassen en methodes en vervangt lange namen van bijvoorbeeld klassen en methodes door korte, betekenisloze namen zoals ‘a’, ‘b’ en ‘c’. Dit maakt
reverse enginering moeilijker en zorgt voor een kleinere bestandsgrootte (ProGuard, z.j.). Als
voorbeeld wordt de ongetekende applicatie voor en na het gebruik van ProGuard vergeleken.
De grootte van het apk-bestand is van 2,6 naar 0,8 MB gedaald.
De tool wordt standaard enkel gebruikt bij de release-modus van de applicatie. Het heeft immers in de meeste gevallen geen zin om code onleesbaar te maken aangezien dit enkel het debuggen vermoeilijkt. De uitvoering van deze tool genereert onder andere een bestand met de
gebruikte mapping tussen de oude en nieuwe namen. Deze is nodig indien een gebruiker van
een release-versie een stacktrace doorstuurt. Die is onleesbaar en kan met behulp van ProGuard
en het mapping-bestand weer leesbaar gemaakt worden zodat de ontwikkelaar eenvoudig kan
zien waar de applicatie gecrasht was.
Er is ook een betalende variant, namelijk DexGuard (Saikoa, 2014). Deze biedt nog meer
mogelijkheden zoals bijvoorbeeld encryptie van hardgecodeerde strings, encryptie van belangrijke klassen en detectie van codewijzigingen, maar deze is hier niet gebruikt.
36
4.11 Europay Mastercard Visa-ondersteuning
De handelaar kan met de mobiele applicatie ook geld via betaalkaarten ontvangen. Hiervoor
wordt er een EMV-lezer (Figuur 4.11) aan de smartphone gekoppeld. De smartphone communiceert bidirectioneel met dit toestel via de audio jack. Om antwoorden te kunnen ontvangen,
heeft de Androidapplicatie de record audio-permissie nodig.
De app functioneert nu als een betaalterminal. Om het betalingsproces vlot te laten verlopen
wordt er visuele feedback op het scherm (Figuur 4.12) gegeven. Om het inpluggen van het
device te detecteren wordt er gebruik gemaakt van een broadcast receiver. Er wordt namelijk
door Android een broadcast intent verstuurd bij in- en uit pluggen van een audio jack. In tegenstelling tot de sms-broadcast receiver, wordt de audio jack broadcast receiver dynamisch
geregistreerd en geannuleerd in de onResume en onPause methodes. Het heeft geen zin om deze
broadcast receiver door Android te laten uitvoeren indien het betalingsscherm niet op de voorgrond draait. Voor de rest wordt er een luisterklasse geregistreerd als luisteraar bij de MPOSbibliotheek en wordt het EMV-betalingsproces gestart. Wanneer de klant zijn betaalkaart insteekt en zijn pincode intoetst worden er verschillende callback-methodes opgeroepen die de
GUI aanpassen.
Figuur 4.11: De EMV-lezer (PAYware Mobile e105, 2013)
37
Figuur 4.12: Het EMV-betalingsscherm
4.12 Android Wear
Android Wear is een verbreding van het Android platform met nieuwe functionaliteit specifiek
voor draagbare accessoires zoals bv. een smartwatch. Het platform (Android Wear, z.j.) is tijdens deze masterproef aangekondigd en er is een beperkte preview beschikbaar gesteld. In deze
versie is het enkel mogelijk om de notificatiefunctionaliteit te testen. Hieronder wordt er onderzocht welke stappen en wijzigingen er nodig zijn om de betalingsnotificatie van de mobiele
applicatie op een smartwatch te laten weergeven.
Op het moment van schrijven zijn er nog geen smartwatches die werken op Android Wear
beschikbaar. Gelukkig is er wel een bijgeleverde emulator om bepaalde zaken uit te testen. Een
smartwatch (hier nu de emulator) moet gekoppeld worden aan een smartphone. Dit is zeer eenvoudig via de instellingenapplicatie (Figuur 4.13). De app zorgt ervoor dat de smartphone met
de smartwatch kan communiceren.
Figuur 4.13: Android Wear Preview applicatie
38
Standaard kunnen notificaties van de smartphone automatisch al op de smartwatch worden getoond (Figuur 4.14). De gebruiker moet hiervoor deze optie in de instellingenapplicatie van
Android Wear aanvinken. Een notificatie wordt aan de main stream (of ook context stream)
toegevoegd (Design Principles, 2014). Deze bestaat uit verschillende cards die elk interessante
informatie tonen. Door eenvoudige, verticale swipe-bewegingen, kan er tussen de verschillende
cards worden genavigeerd. De eerste is deze van de mobiele betalingsapplicatie (Figuur 4.15).
Aan een card kunnen er ook acties gekoppeld worden. Bij een notificatie-card is dit de ‘open’actie en deze voert de meegeleverde intent uit. Acties zijn bereikbaar door naar links te swipen.
Om nu het betalingsoverzicht op de smartphone op te starten, volstaat het om op het cirkelvormige icoon (Figuur 4.15) te klikken. Om een card/notificatie te verwijderen wordt er op het
linkse scherm (Figuur 4.15) naar rechts geswipet.
Figuur 4.14: Android Wear emulator met een notificatie van de applicatie zichtbaar op het hoofdscherm
Figuur 4.15: Een card uit de main stream met bijhorende actie
De Android Wear notificatie API voorziet heel wat nieuwe mogelijkheden om normale
smartphone notificaties te verfijnen zodat ze speciaal voor de smartwatch gebruiksvriendelijker
worden. Zo is het mogelijk om verschillende notificaties te groeperen zodat ze individueel via
39
een stack in een card op de smartwatch worden getoond terwijl er maar een overzichtsnotificatie zichtbaar is op de smartphone. Er kan ook een achtergrond worden toegevoegd die onder de
card verschijnt wanneer deze zichtbaar is. Het is ook mogelijk om meerdere pagina’s en een
voice replay-actie toe te voegen. Bij deze laatste optie kan de gebruiker een bericht inspreken
dat dan als tekst naar de applicatie wordt verzonden.
Later dit jaar worden er nieuwe API’s beschikbaar gesteld. Zo wordt het bijvoorbeeld mogelijk
om activities rechtstreeks op het horloge te draaien, data tussen smartphone en smartwatch te
versturen en de horlogespecifieke sensors te gebruiken.
4.13 iBeacons
Een beacon is een klein apparaatje (Figuur 4.16) dat periodiek een signaal verstuurt (Estimote,
2014). Smartphones kunnen naar deze signalen luisteren en weten zo dat ze in de buurt van een
bepaalde beacon zijn. Met deze informatie kunnen ze dan allerlei acties uitvoeren. Indien er
gebruik wordt gemaakt van meerdere beacons in eenzelfde ruimte, kan er zelfs een exacte
locatie worden berekend aan de hand van de sterkte van de ontvangen signalen. De signalen
reiken van een paar centimeter tot zeventig meter.
Figuur 4.16: Afbeelding van een iBeacon (Estimote, 2014)
Achter de schermen maakt de beacon eigenlijk gewoon gebruik van Bluetooth Low Energy.
Het apparaatje zendt een signaal uit in de peripheral-rol (Bluetooth Low Energy, z.j.). Dit zijn
dan zogenaamde advertisements (aankondigingen). De smartphone vervult de central-rol (zoeken naar aankondigingen). De signalen worden op 2,4 GHz uitgezonden.
Er zijn twee algemene functies mogelijk, namelijk ranging en monitoring. Bij de eerste worden
alle beacons in de gaten gehouden en wordt een afstand van de smartphone tot iedere beacon
berekend. Bij de tweede wordt een specifieke beacon gevolgd en wordt er verwittigd wanneer
de gebruiker binnen de range van een beacon komt en weer buiten de range gaat.
40
Deze technologie is op de mobiele applicatie uitgeprobeerd. Het is de bedoeling dat de verkoper
een beacon aan de kassa plaatst. Wanneer de gebruiker nu aan de kassa komt (binnen de radius
van de beacon), wordt de applicatie automatisch opgestart. Wanneer de gebruiker de kassa verlaat, wordt de applicatie afgesloten indien ze ongebruikt is gebleven (wanneer de gebruiker
bijvoorbeeld cash heeft betaald).
Hiervoor is er gebruik gemaakt van de Estimote SDK. Deze heeft echter de beperking dat de
applicatie zich in de voorgrond of in de achtergrond moet bevinden alvorens de luisteraars worden opgeroepen (en er gescand wordt). De SDK van Radius Networks heeft deze functionaliteit
wel, maar deze is betalend (Radius Networks, 2014). Daarom werd er zelf een Android service
geschreven die deze functionaliteit ter beschikking stelt en gebruik maakt van de Estimote SDK.
4.14 Overgang naar iOS
In deze sectie wordt er gekeken hoe gemakkelijk/moeilijk het is om een native Android applicatie om te zetten naar een native iOS applicatie.
Android en iOS zijn twee verschillende platformen die ook een andere programmeertaal gebruiken. In Android wordt software meestal in Java geschreven, terwijl dit in iOS Objective-C
is. Dit wil dus zeggen dat alle geschreven code sowieso naar Objective-C moet omgevormd
worden. Beiden bieden ook een eigen framework aan waardoor code die specifiek op het
Android framework steunt (zoals GUI-code) weinig of zelfs geen overeenkomst met het iOS
framework heeft.
Een voordeel van het gebruik van Protobuf is dat de berichtenstructuur tussen client en server
taalonafhankelijk is vastgelegd. Een Protobuf-compiler genereert zelf de taalspecifieke klassen.
In de lijst compilers/bibliotheken van derden is er één terug te vinden die Objective-C klassen
kan genereren. Voor deze klassen is er dus geen extra werk bij het porten naar iOS.
Voor niet-frameworkspecifieke Androidcode (business logic) zoals bijvoorbeeld de eigen modelklassen kan er gebruik gemaakt worden van de tool J2ObjC. Dit is een open source tool dat
Java code naar Objective-C vertaalt (Google, z.j.). Er wordt sterk benadrukt dat de tool enkel
bruikbaar is voor niet-framework-code. UI-code en andere zaken die afhankelijk van het platform zijn, moeten manueel volgens de API van het iOS-platform herschreven worden. Aan de
bibliotheek wordt nog actief gewerkt en er worden steeds meer zaken van de Java runtime
ondersteund.
41
4.15 Testen
In de beginfase van het ontwikkelingsproces is er voornamelijk manueel getest. Steunend op
een DAO-object, dat de data uit het geheugen ophaalt, is de basiswerking van de mobiele applicatie geschreven. Om de realiteit zo goed mogelijk te benaderen is er een willekeurige vertraging aan iedere aanvraag toegevoegd. Dit maakt het testen van de asynchrone taken eenvoudiger. Om de foutafhandeling specifiek te testen, is het geheugen-DAO omgewisseld met een
nieuwe geheugen-DAO die altijd een fout opgooit. Op het einde van deze fase zijn er enkele
testen geschreven die gebruik maken van het Android Testing Framework. Dit zit standaard in
het Android framework en maakt onderliggend gebruik van JUnit. Het bevat extra functionaliteit om Androidspecifieke logica te testen (Testing Fundamentals, z.j.).
In de tweede fase wordt de SVA-code geïmplementeerd. Op het einde van deze fase is de
RESTDAO aan de mobiele applicatie toegevoegd. Daarmee gebeurt iedere data-aanvraag aan
SVA. De SVA-software luistert echter tijdens debugging enkel op de localhost van de computer
en aanvaardt dus geen connecties van buitenaf. Om deze beperking te omzeilen wordt er gebruik gemaakt van port forwarding. Deze functionaliteit zit in Google Chrome. De browser
wordt op de mobiele toestellen en op de computer opgestart. De mobiele toestellen worden via
een Universal Serial Bus-kabel (USB-kabel) met de computer verbonden. Na het inschakelen
van de USB-debugging optie en het accepteren van de computer op de mobiele toestellen, verschijnen ze in het overzichtsscherm op de computer (Figuur 4.17). Nu kan via de knop ‘port
forwarding’ iedere lokale aanvraag op het mobiele toestel op poort 8099 naar de computer op
poort 8099 worden doorgestuurd. In het configuratiebestand van de RESTRequester-klasse
moet nu enkel nog worden ingevuld dat iedere aanvraag tijdens debugging naar de localhost op
poort 8099 van het mobiele toestel moet. Via deze opstelling is er in deze fase ook het meeste
manueel getest.
42
Figuur 4.17: Google Chrome met port forwarding
Op het einde van het project is de code van de mobiele applicatie opgeschoond en zijn er nog
enkele testen toegevoegd zodat alle formulieren automatisch getest kunnen worden. Als allerlaatste zijn er nog functionele testen geschreven voor de uitbreidingen van het SVA-platform.
Hierbij worden alle normale situaties gesimuleerd en getest en worden alle foutscenario’s afgegaan en gecontroleerd of er een foutmelding wordt teruggegeven.
43
5
Retrospectie
5.1 Eigen beoordeling
Zoals reeds vroeger vermeld, is er tijdens de ontwerp- en ontwikkelingsfase al met mogelijke
uitbreidingen rekening gehouden. Het resultaat van deze masterproef vormt een stevige basis
voor alle items die in het uitgebreid voorstel en in het analysehoofdstuk beschreven staan. Doordat er op bepaalde plaatsen zo generiek en abstract mogelijk gewerkt is, kunnen de uitbreidingen zonder al te veel codewijzigingen worden toegevoegd. Er zijn ook een aantal nieuwe items
geïmplementeerd en onderzocht zoals bijvoorbeeld sms- en e-mailnotificatie, de integratie van
de app met Android Wear en interactie met de veelbelovende iBeacons. Dit alles zorgt voor
een nog betere gebruiksvriendelijkheid voor de eindgebruiker.
5.2 Extra mogelijke uitbreidingen en verbeteringen
Een eerste uitbreiding die nog niet is besproken, is het gebruik van de getrouwheidsmodule van
SVA. Deze kan aan de mobiele applicatie worden gekoppeld zodat de handelaar bij het aanmaken van een transfer zijn klanten onmiddellijk kan belonen met bijvoorbeeld kortingsbonnen of
spaarpunten, dit ter vervanging van een klantenkaart.
Aan de mobiele applicatie zou er een globaal instellingenmenu kunnen worden toegevoegd.
Via dit menu kan de gebruiker dan allerlei items naar eigen wens configureren. Enkele mogelijke instellingen zijn het maximum aantal lokaal bijgehouden EMV-transacties, het wel of niet
bijhouden van de gebruikersnaam op het loginscherm en het polling-interval bij het QR-codescherm dat controleert of de betaling is voltooid.
Momenteel moet de gebruiker iedere keer inloggen wanneer de applicatie wordt opgestart omdat gebruikersnaam en wachtwoord niet worden opgeslagen. Een verbetering is om een access
token bij te houden dat een bepaalde tijd geldig is (en wel mag opgeslagen worden). Met dit
token kan de gebruiker zich dan voor een bepaalde periode authenticeren bij de server. Omdat
de gebruiker dan niet altijd meer moet inloggen, zou iemand anders die toegang heeft tot de
smartphone, transfers kunnen uitvoeren. Een veilige oplossing hiervoor is om de applicatie of
het access token af te schermen met een pincode. Nog veiliger is om het access token rechtstreeks met de pincode te encrypteren. Om te authenticeren via een access token, moet er wel
ondersteuning van de server zijn. Momenteel zit deze functionaliteit nog niet in het SVA-platform. Daarom zijn deze verbeteringen in deze masterproef niet geïmplementeerd. De serverondersteuning staat wel gepland in de nabije toekomst.
44
Conclusie
Het concept uitgewerkt in deze masterproef maakt het mogelijk om op een veilige en gebruiksvriendelijke manier mobiel te betalen. Het resultaat is een stevige fundering voor de vele mogelijke uitbreidingen die er zijn. Doordat er op veel plaatsen zo generiek en abstract mogelijk
is gewerkt, kunnen uitbreidingen in de toekomst zonder veel wijzigingen van bestaande code
eenvoudig worden uitgevoerd.
De mobiele applicatie is uiteindelijk een native Androidapplicatie geworden omwille van de
nodige hardwaretoegang en de mindere gebruikerservaring van de UI indien er via webtechnologieën wordt gewerkt. Bij het porten naar iOS is de business-logica via een bestaand programma gemakkelijk om te zetten, maar de platformspecifieke code zoals de UI moet echter
manueel opnieuw worden geschreven in Objective-C. De notificaties die verschijnen wanneer
een betaling voltooid is, zijn ook zichtbaar op een smartwatch indien de smartphone eraan gekoppeld is. Als laatste wordt de app automatisch opgestart en afgesloten door middel van een
iBeacon wanneer de gebruiker zich dicht bij de kassa bevindt.
Met de ontwikkelde betaaloplossing kan via de mobiele applicatie op een eenvoudige manier
betaald worden. Een handelaar kan hierbij ook bank- en kredietkaarten accepteren als betaalmiddel door een EMV-lezer aan zijn smartphone te koppelen. De nieuwe geschreven serverlogica is niet beperkt om enkel aangesproken te worden via mobiele clients. Het is bijvoorbeeld
ook mogelijk om transfers aan te maken via een computerprogramma. Zo kan een webshop
dezelfde API aanspreken en een QR-code tonen op de betalingspagina. De bezoeker kan dan
betalen op de normale manier door deze code met zijn smartphone in te scannen en de transfer
te bevestigen.
De geschreven code werd in de eerste fasen grondig manueel getest en naar het einde van het
project zijn er automatische tests geschreven. Het is de bedoeling dat de geschreven SVA-code
in de nabije toekomst als een module aan de klant wordt aangeboden en in productieomgevingen wordt gebruikt.
45
Lijst met figuren
Figuur 1.1: Elektronisch betalingsverkeer in België .................................................................. 4
Figuur 3.1: Implementatieschema van de transferlogica ........................................................... 7
Figuur 4.1: Hoofdscherm voor de consument (links) en de uitgeklapte navigation drawer
(rechts) ...................................................................................................................................... 20
Figuur 4.2: Voorbeeld van up-navigatie (1) en een spinner (2) in de actionbar (3) ................. 20
Figuur 4.3: Login activity......................................................................................................... 23
Figuur 4.4: Melding wanneer de applicatie niet meer reageert (Keeping Your App
Responsive, z.j.) ....................................................................................................................... 27
Figuur 4.5: Hoofdactivity met loading indicator ...................................................................... 27
Figuur 4.6: Activity met de QR-code ....................................................................................... 31
Figuur 4.7: Bevestigingsscherm van een betaling .................................................................... 33
Figuur 4.8: Sms-bericht van SVA met daarin het transfer-ID ................................................. 34
Figuur 4.9: Transferoverzichtscherm ....................................................................................... 35
Figuur 4.10: De notificatie die verschijnt wanneer een betaling voltooid is ............................ 36
Figuur 4.11: De EMV-lezer (PAYware Mobile e105, 2013) ................................................... 37
Figuur 4.12: Het EMV-betalingsscherm .................................................................................. 38
Figuur 4.13: Android Wear Preview applicatie ....................................................................... 38
Figuur 4.14: Android Wear emulator met een notificatie van de applicatie zichtbaar op het
hoofdscherm ............................................................................................................................. 39
Figuur 4.15: Een card uit de main stream met bijhorende actie ............................................... 39
Figuur 4.16: Afbeelding van een iBeacon (Estimote, 2014) .................................................... 40
Figuur 4.17: Google Chrome met port forwarding .................................................................. 43
46
Lijst met tabellen
47
Lijst met codefragmenten
Codefragment 3.1: Implementatie van de transferklasse ........................................................... 6
Codefragment 3.2: Dependency injection met annotaties .......................................................... 8
Codefragment 3.3: Implementatie van de B2C-transfer en de P2P-transfer klasse ................... 8
Codefragment 3.4: Niet-werkende transfergeschiedenisquery .................................................. 9
Codefragment 3.5: Native SQL-query voor de transfergeschiedenis van een consument ......... 9
Codefragment 3.6: Foutieve (bovenste) en juiste (onderste) predicaten van de
transfergeschiedenisquery ........................................................................................................ 10
Codefragment 3.7: Authorisatie van een webservicemethode ................................................. 12
Codefragment 3.8: HTTP-body van de sms-aanvraag ............................................................. 12
Codefragment 3.9: De klasse TransferObservation ................................................................. 13
Codefragment 3.10: Vergelijking van een XML-, JSON- en Protobuf-bericht (eigen
bewerking van Protocol Buffers, 2012) ................................................................................... 14
Codefragment 3.11: Inhoud van het transfer proto-bestand ..................................................... 16
Codefragment 3.12: Code om Flyway te gebruiken in een programma (Flyway, 2014) ......... 17
Codefragment 4.1: Verwijzen naar een support library thema ................................................ 21
Codefragment 4.2: Een geïmplementeerde methode van de DAO-interface ........................... 22
Codefragment 4.3: Code voor standaard up-navigatie (Providing Up Navigation, z.j.) .......... 24
Codefragment 4.4: Code voor standaardnavigatie tussen activities ......................................... 25
Codefragment 4.5: Oplossing voor up-navigatie met meerdere ouderactivities ...................... 26
Codefragment 4.6: De abstracte klasse TaskCallbackTask ..................................................... 28
Codefragment 4.7: De interface TaskCallback ........................................................................ 29
Codefragment 4.8: De abstracte klasse DAOTask ................................................................... 29
Codefragment 4.9: De klasse GetTransferDetailsTask ............................................................ 30
Codefragment 4.10: Code om een asynchrone taak te starten ................................................. 30
Codefragment 4.11: Gebruik van Shared Preferences voor opslag van de username .............. 32
Codefragment 4.12: Intentfiltering op de HTTPS-URL in de manifest file ............................ 35
Codefragment 4.13: Aankondiging van de SMSBroadcastReceiver in de manifest file ......... 36
48
Referentielijst
A Touch-Optimized Web Framework. (2014). Geraadpleegd op 26 april 2014 via
http://jquerymobile.com
About SQLite. (z.j.). Geraadpleegd op 13 april 2014 via http://www.sqlite.org/about.html
Alex, B., Taylor, L. & Winch, R. (2014). Spring Security Reference. Geraadpleegd op 26 april
2014 via http://docs.spring.io/spring-security/site/docs/3.2.3.RELEASE/reference/htmlsingle
Android Wear. (z.j.). Geraadpleegd op 22 april via
http://developer.android.com/wear/index.html?utm_source=ausdroid.net
Apache Cordova Documentation. (2014). Geraadpleegd op 26 april 2014 via
http://cordova.apache.org/docs/en/3.4.0/
Banksys en BCC worden Atos Worldline. (2007). Geraadpleegd op 28 april 2014 via
http://www.mijnkaart.be/index/nl_BE/5148722/5150688/Banksys-en-BCC-worden-AtosWorldline.htm
Bluetooth Low Energy. (z.j.). Geraadpleegd op 1 mei 2014 via
http://developer.android.com/guide/topics/connectivity/bluetooth-le.html
Building Cross-Platform Apps with HTML5. (2013). Geraadpleegd op 26 april 2014 via
https://software.intel.com/en-us/html5/articles/building-cross-platform-apps-with-html5
Clickatell (2013). XML API Specification V 2.4.9 [pdf]. Geraadpleegd op 13 april 2014 via
https://www.clickatell.com/downloads/xml/Clickatell_XML.pdf
Dashboards. (2014). Geraadpleegd op 10 april 2014 via
http://developer.android.com/about/dashboards/index.html
Design. (2014). Geraadpleegd op 11 april 2014 via
http://developer.android.com/design/index.html
Design Principles of Android Wear. (2014). Geraadpleegd op 23 april 2014 via
http://developer.android.com/wear/design/index.html
Estimote (2014). Estimote Beacons: real world context for your apps. Geraadpleegd op 1 mei
2014 via http://estimote.com
Flyway. (2014). Geraadpleegd op 6 april 2014 via http://www.flywaydb.org/getstarted
49
Google (z.j.). A Java to iOS Objective-C translation tool and runtime. Geraadpleegd op 23
april 2014 via http://j2objc.org
J4S (2013). Wie is J4S [brochure]
Keeping Your App Responsive. (z.j.). Geraadpleegd op 12 april 2014 via
http://developer.android.com/training/articles/perf-anr.html
King, R. (2012). Facebook’s Mark Zuckerberg knocks HTML5 in favor of native apps.
Geraadpleegd op 21 april 2014 via http://www.zdnet.com/facebooks-mark-zuckerbergknocks-html5-in-favor-of-native-apps-7000004082/
PAYware Mobile e105. (2013). Geraadpleegd op 26 april 2014 via
http://ca.verifone.com/products/hardware/mobile-devices/payware-mobile-e105
ProGuard. (z.j.). Geraadpleegd op 22 april via
http://developer.android.com/tools/help/proguard.html
Protocol Buffer Polymorphism. (2010). Geraadpleegd op 11 april 2014 via
http://www.indelible.org/ink/protobuf-polymorphism/
Protocol Buffers. (2012). Geraadpleegd op 10 april 2014 via
https://developers.google.com/protocol-buffers/docs/overview
Providing Up Navigation. (z.j.). Geraadpleegd op 11 april 2014 via
http://developer.android.com/training/implementing-navigation/ancestral.html
Radius Networks (2014). Android Beacon Library. Geraadpleegd op 1 mei 2014 via
http://developer.radiusnetworks.com/ibeacon/android
Red Hat (2014). Hibernate Reference Documentation. Geraadpleegd op 26 april 2014 via
http://docs.jboss.org/hibernate/orm/4.3/manual/en-US/html
Saikoa (2014). DexGuard. Geraadpleegd op 22 april via http://www.saikoa.com/dexguard
Saving Files. (z.j). Geraadpleegd op 13 april 2014 via
http://developer.android.com/training/basics/data-storage/files.html
Sending Simple Data to Other Apps. (z.j.). Geraadpleegd op 13 april 2014 via
http://developer.android.com/training/sharing/send.html
Setting Up the Action Bar. (z.j.). Geraadpleegd op 12 april 2014 via
http://developer.android.com/training/basics/actionbar/setting-up.html
50
Singletons vs. Application Context in Android. (2010). Geraadpleegd op 11 april 2014 via
http://stackoverflow.com/questions/3826905/singletons-vs-application-context-in-android
Smartphonegebruik in België stijgt met 7 procent. (2013). Geraadpleegd op 12 oktober 2013
via http://www.vandaag.be/entertainment/122722_smartphonegebruik-in-belgie-stijgt-met-7procent.html
Spring Framework Reference Documentation. (2014). Geraadpleegd op 26 april 2014 via
http://docs.spring.io/spring/docs/4.0.3.RELEASE/spring-framework-reference/htmlsingle
Storage Options. (z.j.). Geraadpleegd op 12 april 2014 via
http://developer.android.com/guide/topics/data/data-storage.html
Support Library. (2014). Geraadpleegd op 12 april 2014 via
http://developer.android.com/tools/support-library/index.html
Testing Fundamentals. (z.j.). Geraadpleegd op 21 april 2014 via
http://developer.android.com/tools/testing/testing_android.html
51