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
© Copyright 2024 ExpyDoc