Crossplatform Android en iOS-apps ontwikkelen

Marco den Teuling
0

Inhoudsopgave

Met crossplatform ontwikkeltools maak je apps die op Android, iOS en andere besturingssystemen kunnen draaien. Dat vergroot niet alleen je doelgroep, maar zorgt er ook voor dat apps klaar zijn voor toekomstige ontwikkelingen. We vergelijken verschillende ontwikkeltools, van gratis tot prijzige teamoplossingen.

In hun standaardwerk over C stelden Kernighan en Richie al dat een ‘net’ geschreven C-programma zonder grote aanpassingen voor verschillende platformen te compileren zou moeten zijn. Maar zo simpel bleek het helaas niet te zijn. Het was al snel duidelijk dat er een framework nodig is en een abstractielaag om de eigenaardig­heden van de besturingssystemen en grafische interfaces in te kapselen.

Die frameworks moeten voor mobiele apparaten flexibeler zijn dan voor desktops, waar Windows al tientallen jaren dominant is. Op de mobiele markt hebben we inmiddels al veel verschillende systemen gezien, zoals Palm OS, Symbian, Blackberry, Windows CE/Mobile, Android en iOS. Bovendien kunnen smartphones steeds meer. Daarnaast worden web­applicaties steeds belangrijker als extra platform.

We werpen een blik op verschillende crossplatform ontwikkeltools: Qt, RAD Studio van Embarcadero, Microsofts Xamarin voor .Net, Adobe PhoneGap en zijn opensource-variant Cordova, Telerik NativeScript, Facebook React Native, NS Basic en Unity.


Windows praktijkhandboek

Maak een eigen rescue-systeem, bewerk Windows-images met DISM en meer in het Windows Praktijkhandboek.


Eén ding lukt geen van deze crossplatform-frameworks: je ontkomt er als ontwikkelaar niet helemaal aan om je bezig te houden met het host-besturingssysteem. Als niet tenminste één persoon in het ontwikkel­team weet hoe Android of iOS functioneren, als niemand op zijn minst enige basiskennis heeft van de native toolchain, dan knalt het project vroeg of laat tegen een muur op.

Een voorbeeld daarvan vind je bij de manifestbestanden, waarin onder andere details staan over machtigingen. De crossplatformtools genereren wel bruikbare versies, maar in de praktijk zorgen speciale eisen er steeds weer voor dat apps niet werken. Alleen als je het beveiligingsmodel van het betreffende besturingssysteem kent, kun je de foutmeldingen goed doorgronden. Maar het loont ook de moeite om een blik te werpen op de Human Interface Design Guidelines, waarin de makers van besturingssystemen vastleggen wat ze bij het design van de GUI-stack eigenlijk voor ogen hebben gehad.

Qt als voorbeeld

Het crossplatform-ontwikkelen werd populair door Nokia. De Finnen beschikten op een gegeven moment over een hele verzameling aan ondersteunde besturings­systemen. Die omvatte het langlopende Java-gebaseerde Series 40, het wijdverbreide, maar ook complexe op C++ gebaseerde Symbian, plus Meamo en later MeeGo voor high-end toestellen. Ontwikkelaars moesten in het ergste geval hun creaties tot viermaal toe opnieuw ontwikkelen. Je kunt je voorstellen hoeveel enthousiasme dat op dat moment opleverde. Om de problemen te verminderen, verwierf Nokia het bedrijf TrollTech, de makers van crossplatform-klassieker Qt.

Qt demonstreert enkele erg interessante aspecten van crossplatform-tools. Bij het uitvoeren is een Qt-applicatie een native app, die alleen verschilt van een normale app (ontwikkeld met de toolchain van de aanbieder van het besturingssysteem) omdat hij een groep extra bibliotheken bij zich heeft. De ontwikkelaar maakt in zijn code gebruik van die Qt-bibliotheken, die een abstractielaag bieden en meer gemak.

Qt is niet alleen interessant door de omvangrijke bibliotheek, die bijna alle toepassingen omvat van netwerkcode tot XML. Qt biedt bovendien diverse programmeertaaluitbreidingen. Die vergemakkelijken het ontwerpen van stabiele applicaties, bijvoorbeeld met het signal-slot-systeem dat communicatie tussen objecten stroomlijnt.

Om een normale C++-compiler te kunnen inzetten gebruikt Qt een truc, namelijk een meta-compileromgeving die bestaat uit een soort parser genaamd Moc. Die analyseert de door de ontwikkelaar geschreven C++-code en vervangt niet-standaard elementen automatisch door passende code. Het resultaat van dat proces is standaardconforme code die Qt door de toolchain van het betreffende besturingssysteem laat omzetten in een native applicatie.

Dergelijke ‘vertaalcompilers’ hebben bovendien als voordeel dat ontwikkelaars met weinig moeite native delen kunnen invoegen. Ze beperken wel de portabiliteit van het complete programma, dus pas ze bij voorkeur alleen toe voor ondersteunde platforms via preprocessors of conditionele compilatie.

 


Ontvang gratis informatie over programmeren, tools en talen, schrijf je in voor de nieuwsbrief:

Ontvang elke week het laatste IT-nieuws, de handigste tips en speciale aanbiedingen.

 

Interpretatie bij uitvoer

Klassieke programmeertalen werden gecompileerd en waren daarna beschikbaar in de vorm van machinetaal. Zo werden de bronnen van het doelplatform maximaal benut. Ontwikkelaars moesten ze echter voor elke hardware-architectuur weer afzonderlijk compileren. Dat was bijvoorbeeld lastig in de begintijd van Microsofts mobiele besturingssystemen omdat Redmond zowel ARM-, MIPS- als SH3-processors ondersteunde. Ontwikkelaars moesten niet alleen drie gecompileerde versies aanbieden, maar kregen ook te maken met gebruikers die per ongeluk een incompatibele versie installeerden.

Een methode om dat te vermijden zijn interpretatieve programmeertalen, zoals de klassieker BASIC. Daarbij voert een interpreter de code uit bij het starten van het programma. Omzetting naar een andere architectuur betekent in dat geval meestal het porteren van de interpreter. De programmacode zelf hoeft niet echt aangepast te worden.

Ook Java werkt op die manier, zij het met een tussenstap. De programmacode wordt dan wel verwerkt door een compiler, maar die zet het om naar machine­-onafhankelijke tussencode (bytecode). Daardoor is die niet gebonden aan Java, want de tussencode kan ook door compilers van andere programmeertalen gegenereerd worden. Moderne runtimes voor tussencode zijn geen pure inter­preters, want ze optimaliseren de code en zetten die met een Just-In-Time-compiler (JIT-compiler) geheel of gedeeltelijk om naar machinecode.

Dat werkt allemaal redelijk goed. Maar het motto van Java-bedenker Sun, ‘Write Once Run Anywhere’, werd voor mobiele toepassingen al snel omgedoopt tot ‘Write Once Debug Anywhere’. Dat kwam onder andere doordat producenten de Java-­specificaties allemaal op hun eigen specifieke manier interpreteerden en uitwerkten. Een ander nadeel is dat het lastiger is om native code te integreren.

Uiteindelijk heeft de door Sun ingevoerde scheiding tussen runtime en ontwikkelcode zich ook niet op alle mobiele platforms doorgezet om onafhankelijk van het besturingssysteem te kunnen ontwikkelen. Dat is alleen gelukt bij Java op de desktop en op veel procescomputers. Android heeft een Java-basis, maar alleen om verschillende processorarchitecturen te ondersteunen.

Microsoft gaat iets anders te werk. Bij zowel .Net als Xamarin wordt een tussencode gebruikt, maar de runtime en tussen­code-compatibiliteit worden gecombineerd in een monolitische app, die in die vorm in de Store belandt. Dat vermindert compatibiliteitsproblemen en vergemakkelijkt het integreren van native segmenten.

Browsers en WebViews

In de tussentijd worden de Java- en .Net-frameworks steeds meer de loef afgestoken door op JavaScript gebaseerde uitvoeromgevingen zoals PhoneGap en Facebooks React Native. Die zijn handig voor ontwikkelaars die sowieso webapps moeten ontwikkelen. Oorzaak van dat succes is de universele beschikbaarheid van webbrowsers.

Zo’n beetje elk mobiel en embedded besturingssysteem heeft wel een volwaardige browser. Omdat nagenoeg elke website op zijn minst een JavaScript-framework laadt, moeten die browsers een virtuele JavaScript-machine bieden. De browsers zorgen ervoor dat de besturingssystemen webapps kunnen draaien dankzij een besturingselement met de naam WebView dat in de app-interface kan worden verwerkt. Daardoor heeft elke app toegang tot een JavaScript-inter­preter.

Het bedrijf Nitobi gebruikte die techniek om het portable framework PhoneGap te realiseren, evenals het gerelateerde opensourceproject Cordova. Adobo kocht dat bedrijf later op. De apps die ermee worden gemaakt, zijn wat het besturingssysteem betreft native. Ze bestaan uit een WebView en extra resources met het eigenlijke programma in de vorm van JavaScript. De meerwaarde van het framework zit hem in de aanvullende tools. Die combineren de door de ontwikkelaar geschreven code en de WebView, compileren dat en maken er een pakket van dat geschikt is voor een app-store. PhoneGap biedt daarnaast verschillende clouddiensten en een normaliter betaalde buildserver om iOS-apps te compileren zonder Mac.

WebViews brengen drie problemen met zich mee. Ten eerste is de performance niet altijd ideaal. Ten tweede is het moeilijk tot onmogelijk om native bedienings­elementen toe te voegen. Dat is nog overkomelijk, omdat voor PhoneGap de jQuery-gebruikersinterface min of meer standaard is geworden. Die kennen gebruikers al van ontelbare andere toepassingen. Het derde probleem weegt zwaarder: het integreren van fragmenten native code. Het is bij WebViews wel mogelijk om propriëtaire JavaScript-functies te schrijven, maar in de praktijk is dat bepaald niet makkelijk.

De markante blauwe en groene knoppen van jQuery Mobile zijn in recentere versies vervangen door neutralere widgets.

Nieuwe generatie

De twee generatie JavaScript-frameworks zoekt een andere oplossing voor die nadelen. NativeScript en React Native combineren PhoneGap met een eigen runtime gebaseerd op Googles V8-JavaScript-­engine. Die is inmiddels zodanig geoptimaliseerd dat hij meer dan genoeg performance biedt.

De producenten hebben daar ‘stubs’ aan toegevoegd, waarmee dan rechtstreekse interactie tussen de code en het besturings­systeem mogelijk is. De gebruikers­interface ontstaat niet meer in een WebView, maar wordt bij het uitvoeren opgebouwd uit native besturingselementen. Apps zien er dus weer zo uit zoals op het platform gebruikelijk is. Bovendien zijn interfaces beschikbaar om native code te integreren.

Lastig bij die oplossing is wel om de afwijkende bedieningsconcepten van de verschillende platformen op elkaar af te stemmen. Daarvoor bieden de frameworks eigen meta-talen, waarin de ontwikkelaar zijn gebruikersinterface specificeert. Bij NativeScript is dat een XML-dialect, bij React Native is het JSX. In beide gevallen kun je ook dynamische GUI’s realiseren via DOM-transacties, maar dat brengt veel werk met zich mee.

Bekeken ontwikkeltools

QT

QT

Qt is de ‘oudgediende’ bij C++-frameworks. De code wordt door een compiler met de naam Moc verwerkt voordat hij naar de native compiler van het betreffende doelplatform gaat. Voordelen daarvan zijn de hoge performance van de uiteindelijke applicatie en de uitstekende C++-integratie. Voor ontwikkelaars betekent dit dat ze native API’s met vrij weinig of mini­male moeite kunnen integreren. Een ander voordeel is de enorme omvang van de bijbehorende standaardbibliotheken. Qt is bovendien erg breed inzetbaar. Er is nauwelijks een ander crossplatform framework dat op zoveel platforms draait en dat ook nog eens (voor het grootste deel) opensource is.

Maar Qt heeft ook zijn eigenaardigheden. De combinatie van C++ en de eigen JavaScript-GUI-stack QML leidt tot inconsistenties. Die worden versterkt doordat er twee geheel verschillende benaderingen zijn voor het programmeren van grafische besturingselementen. Een bijkomend nadeel is de ietwat precaire licentieregeling. Veel componenten zijn opensource, terwijl veel andere alleen tegen betaling gebruikt mogen worden. De Qt Company heeft bovendien het Indie-programma afgeschaft, waardoor het framework nogal prijzig is.

Bij het integreren van plug-ins moet je er verder op letten dat de Qt-methode om de bedienings­elementen te creëren meestal is gebaseerd op OpenGL. Het geheel van bedieningselementen wordt in een buffer gerenderd, waarna het op het scherm verschijnt. Dat bemoeilijkt het integreren van native bedieningselementen aanzienlijk.

Bekijk deze software

Embarcadero RAD Studio

Embarcadero RAD Studio

De ondergang van het ooit marktdominante Borland houdt IT’ers al langere tijd bezig. In het boek ‘In search of stupidity’ wijdt Merril R. Chapman zelfs een heel hoofdstuk aan het bedrijf. Maar het lijdt geen twijfel dat Borlands erfenis onder de naam Embarcadero nog steeds voortleeft. RAD Studio is daarin een alles-in-1-product dat ontwikkel­omgeving, clouddienst, database en meer aanbiedt. Het product is echter allesbehalve gunstig geprijsd.

De verschillende onderdelen komen uit dezelfde stal en zijn dan ook goed geïntegreerd. Er zijn diverse wizards die veelvoorkomende taken automatiseren. Die verbindende aanpak heeft echter ook een groot nadeel: als de onderneming het loodje legt, kun je als ontwikkelaar alleen triest toekijken en je intellectuele eigendom proberen te redden. Het wegvallen van clouddiensten heeft in het verleden al verschillende projecten de das omgedaan.

De IDE is bovendien erg eigenzinnig en biedt twee GUI-stacks die zich volkomen anders gedragen. Het kan bovendien lastig zijn ontwikkelaars te vinden. Delphi wordt zelfs in het zo op systeemtechniek verzotte Oost-Europa ingehaald door andere programmeertalen en het C++-dialect van Borland is tevens ongebruikelijk.

De ondersteuning voor Linux is op dit moment nog dramatisch slecht. Als je FireMonkey-­applicaties onder Linux wilt uitvoeren, heb je een in Ulan Ude ontwikkeld en afzonderlijk aan te schaffen product nodig. Dat werkt momenteel alleen met Delphi, omdat de C++-compiler onder Linux alleen commandline-applicaties vervaardigt.

Bekijk deze software

Telerik NativeScript

Telerik NativeScript

Het Bulgaarse Telerik biedt de Java­Script-ontwikkelomgeving Native­Script voor mobiele toepassingen. De code draait niet in een WebView, maar in een runtime. Die is door de Telerik-ontwikkelaars gemaakt voor interactie met het onderliggende besturingssysteem.

Je kunt daardoor de native besturingselementen van de GUI-stack van het betreffende platform gebruiken. NativeScript biedt de mogelijkheid om de gebruikersinterface te definiëren in een aan XML verwante taal. Dat vereenvoudigt het porteren. De runtime maakt daar een widget-structuur van. Een goedgemaakte NativeScript-app verschilt daardoor nauwelijks van een volledig native app en is bovendien automatisch te porteren tussen Android en iOS.

Het grote voordeel van Native­Script is de kapitaalkrachtige grondlegger, die het bovendien hoofdzakelijk moet hebben van dienstverlening voor ontwikkelaars. Dat is een belangrijk verschil met Facebook, dat React Native financiert. De vroegere neiging van de aanbieder om eigen diensten te verkopen is ondertussen minder geworden. De comfortabel te bedienen cloudgebaseerde IDE is per mei 2018 verdwenen. In plaats daarvan kun je een toolchain op de opdrachtprompt gebruiken die werkt met Microsofts gratis Visual Studio Core.

Daarnaast is er het desktopprogramma Sidekick. Dat kan de eerder via de cloud aangeboden compilatie op de lokale machine uitvoeren met geïnstalleerde SDK’s. Als je Sidekick via de cloud laat compileren, kun je ook zonder Mac een iOS-app maken, maar dan gaat de code naar de servers van Telerik.

Bekijk deze software

Unity

Unity

Unity is de quasi-standaard voor game­development die het zelf ontwikkelen van engines economisch bijna onhaalbaar heeft gemaakt. Het product is crossplatform, een in Unity ontwikkelde game draait op bijna alle platforms. Het belangrijkste voordeel is duidelijk: als je voor die engine kiest, kun je de vrijgekomen tijd en moeite steken in het verbeteren van het spelconcept. Zeker voor kleine ontwikkelaars is dat verstandig omdat die qua resources niet kunnen wedijveren met Ubisoft, Electronic Arts en consorten.

De API-omvang is indrukwekkend en omvat alles wat een game­developer nodig heeft. Ervaren ontwikkelaars zijn overal te vinden en relatief goedkoop. Daar bovenop komt nog een Asset Store, waar je bijna alles vindt van afbeeldingen tot muziek. Talloze aanbieders van producten op het gebied van games bieden die bovendien in de vorm van Unity-uitbreidingen. Voor VR is de engine min of meer de standaard geworden.

Een minpunt is de afhankelijkheid van een enkel bedrijf. De engine is niet opensource, dus je bent afhankelijk van het reilen en zeilen van het (op dit moment financieel gezonde) bedrijf Unity.

Het tweede nadeel is de meer dan eigenzinnige IDE. Een game ontstaat in de vorm van een groep scenes. Daar wordt pas later via verschillende programmeertalen intelligentie aan toegevoegd. Voor het maken van klassieke bedrijfsmatige toepassingen is het product dan ook niet geschikt. Als je een spreadsheetprogramma probeert te maken met Unity, begeef je je op een heilloze weg.

Bekijk deze software

Meer over andere crossplatform ontwikkeltools en de eigen tools van Apple en Google, plus een vergelijkende tabel vind je in c’t magazine 7/8, 2018.

Is het de moeite waard?

Voor 3D-games bieden die frameworks ondanks alle optimalisaties en JIT-compilers eigenlijk te weinig performance. Het ontwikkelen van een eigen game-engine is voor gewone producenten bedrijfsmatig niet haalbaar. Daarbij komt de game-engine Unity van pas, die bijna als bijzaak crossplatformmogelijkheden biedt.

Daarbij kan het voor kleinere projecten waarbij portabiliteit wordt gevraagd dan efficiënter zijn om de app niet in een framework te proppen, maar gewoon een eigen compacte oplossing te realiseren. Die implementeer je dan in C en koppel je via de native interfaces direct aan de platformspecifieke ontwikkelomgevingen.

Een voordeel van een crossplatformsysteem is dat je code niet afhankelijk is van het succes of falen van een besturingssysteem. Ten tweede vergemakkelijken frameworks de door investeerders graag geziene ondersteuning van Android en iOS bij projecten.

Maar je ruilt het ene kwaad in voor het andere. Je bent niet meer afhankelijk van de maker van het besturingssysteem, maar wel van die van het framework. Als je bijvoorbeeld voor Embarcadero koos, kon je alleen met stomheid toekijken hoe het door de vorige directie begonnen afbraakwerk werd voortgezet en het bedrijf de grond in geboord werd. Maar ook voor een nieuwere tool als Googles Android- en iOS-framework Flutter is het bijvoorbeeld maar afwachten hoe dat uitpakt.

Die afhankelijkheid heb je minder bij opensourceproducten. Een bijzonder voorbeeld daarvan is Qt, dat via een stichting is beschermd tegen een mogelijk faillissement van de producent.

Lees meer over nieuwe ontwikkelingen in c't 05/2024

Conclusie

Er zijn nog meer overwegingen als we naar crossplatform ontwikkeltools kijken, zoals koppelingen met SDK’s, integratie met clouddiensten, beschikbaarheid van ontwikkelaars en licentievoorwaarden.

De keuze voor een bepaald crossplatform framework is er niet een om lichtzinnig te maken, daarvoor is een overstap te kostbaar. Achteraf porteren van het ene framework naar een ander staat bijna gelijk aan een complete rewrite.

In de praktijk bieden de frameworks een verhoging van de productiviteit: de meeste ontwikkelaars hoeven zich alleen maar bezig te houden met de cross­platform programmeeromgeving en slechts een enkeling hoeft zich uitvoerig te verdiepen in Android of iOS. Bovendien bieden veel frameworks de mogelijkheid ook een web-app of een desktopversie te ontwikkelen – of een variant voor het op steeds meer apparaten draaiende Linux.

(Tam Hanna, c’t magazine)

Deel dit artikel

Marco den Teuling
Marco den TeulingHad als eerste eigen computer ooit een 16-bit systeem, waar van de 48 kilobyte toch echt niet ‘genoeg voor iedereen’ was. Sleutelt graag aan pc’s, van de hardware tot het uitpluizen van de BIOS-instellingen. Vindt ‘Software as a Service’ een onbedoeld ironische naamgeving.

Lees ook

Dit kun je verwachten als je ChatGPT als hacking-tool wilt gebruiken

Kun je ChatGPT gebruiken als hacking-tool? We neigden naar de duistere kant en onderzochten of de assistentie van een AI van elke scriptkiddie een eli...

Raspberry Pi GPIO pinnen: een overzicht van de aansluitingen

Een kleine Raspberry Pi board is zo volgepakt met alle componenten dat er geen ruimte meer over was om de 40 GPIO pinnen van informatie te voorzien. O...

0 Praat mee
avatar
  Abonneer  
Laat het mij weten wanneer er