Porttautuva koodi mobiilissa

“Write once, run anywhere” oli Javan silver bullet -mantra aikanaan. Eli kirjoitat koodin kerran, käännät sen kerran ja ajat missä vaan tuetussa ympäristössä ilman että ohjelmasi tarvitsee liiemmin tietää ajonaikaisesti mikä käyttöjärjestelmä / rauta ympäristössä on käytössä. No, vaikkei tuohon ole vieläkään – 18 vuotta myöhemmin – ole ihan päästy, on Javan ja vaikkapa Pythonin kaltaisten tulkattujen/scriptauskielten kanssa useimmiten paljon helpompaa elää monialustaympäristössä kuin natiivikoodin. Mutta entä jos halutaankin kehittää natiivisovellus jossa uudelleenkäytetään mahdollisimman suuri osa koodista sen sijaan että N alustaa varten tehdään N toteutusta? Vaikka nykyisten mobiililaitteiden rautaspeksejä (kotitehtävä: montako 25MHz i386 CPU:ta tarvitaan tuottamaan Samsung Galaxy S4:n CPU-teho?) ihmetellessä ei parhaalla omallatunnollakaan voi sanoa resurssien puutteen pakottavan natiivikoodiin, on sen käyttö esim. Android-alustallakin perusteltua sovelluksissa joiden on puristettava se viimeinenkin pisara suorituskykyä irti laitteesta.

Luonnollisesti kaikenlaisiin sovellustyyppeihin porttautuvaa koodia on turha yrittää ujuttaa; jos sovellus on 80%:sti käyttöliittymää eikä ole tarjolla/ei haluta käyttää kaikilla kohdealustoilla toimivaa porttautuvaa UI-kirjastoa, ei kannata väkisin lyödä päätään seinään vaan kirjoittaa toteutukset kiltisti alustan natiivi-API:a käyttäen – tai valita teknologiaksi HTML5 joka sopii webmäisiin lomakesovelluksiin kuin nyrkki silmään. Ym. UI-kirjastoa käyttämällä saatetaan myös – sen toteutuksesta toki riippuen – menettää alustan oma look-and-feel. Ihan hihasta ravistettuna porttautuvan arkkitehtuurin puolesta / vastaan listat voisivat näyttää vaikkapa tältä:

Vastaan:

  • Väkisin yritetty porttautuvuus tekee arkkitehtuurista kömpelön ja lisää turhaa kompleksisuutta
  • Alustan natiiveja ominaisuuksia saatetaan menettää (hyvässä ja pahassa)
  • Käytettäväksi valittu yhteinen ohjelmointikieli ei välttämättä ole tuttu kaikille projektin jäsenille

Puolesta:

  • Koodin joutuu kirjoittamaan vain kerran eli kehityskustannus pienenee
  • Bugit joutuu korjaamaan vain kerran
  • Koodipohjasta tulee merkittävästi pienempi jolloin sen ylläpidettävyys paranee ja siihen on nopeampaa perehdyttää uusia tekijöitä
  • Ohjelmiston luonteen salliessa paljon koodia kierrättävä arkkitehtuuri on hyvin elegantti

Esimerkkiprojekti: MMark13 – mobiilia suorituskykytestausta

Käytän esimerkkinä kuluneen vuoden aikana hiljalleen syntynyttä harrasteprojektiani MMark13, joka – hyvin tiivistetysti – on mobiililaitteiden CPU/GPU suorituskyvyn mittaamiseen tarkoitettu työkalu. Vastaavalla idealla (joskin merkittävästi isommalla tiimillä & budjetilla :) ) rakennettu sovellus löytyy Desktop-puolelta, monelle tuttu suomalaista tekoa oleva Futuremark:in 3DMark. Ja ei, en ole suoraan rinnastamassa harrastelijatuotostani PC-maailman (Ja Futuremark:han puuhaa parasta aikaa myös mobiilibenchmarkingia, Androidille se jo ilmestyikin! -toim.) uraauurtavaan tuotteeseen.. no joka tapauksessa, projekti lähti liikkeelle halusta hioa/päivittää OpenGL ES 2.0 taitoja ja havaittuani ettei tuossa vaiheessa (alkuvuosi 2012) juuri vastaavia sovelluksia ollut tarjolla (paitsi kaupallinen ja maksullinen GLBenchmark 2.5 – joskin tuolloin vain iOS:lle), valitsin kyseisen sovellusalueen jo siksikin että porttautuvan arkkitehtuurin hyväksikäyttäminen laajalti tarjosi ainutlaatuisen edun: kun jokaisella alustalla ajettava koodi on 100% sama niiltä osin jotka grafiikan piirtoon / mittauksiin vaikuttavat, voidaan tuloksia verrata 1:1 toisiinsa alustojen välillä ilman että tarvitsee napista Javan tehottomuudesta Androidilla.

 

MMark13 koodin rakenne

 

Koodin uudelleenkäytön suunnittelussa on hyvä lähteä liikkeelle siitä että kartoittaa tarkasti kohdealustansa ja niiden tarjoamat asiat ja sitten hahmottelee niiden pohjalta suurimman yhteisen nimittäjän. Valitsin kohdealustoikseni iOS (Applen laitteet) ja Qt (Android, kaikki merkittävät desktop-käyttöjärjestelmät, Meego, Blackberry10, Symbian, Sailfish OS, Ubuntu Phone, luultavasti myös Tizen ja Firefox OS). Kun alustat ovat tiedossa, aloittaa voi vaikka ohjelmointikielestä; se on valinta jota alemmalle tasolle ei juuri pääse. C olisi aina varma valinta, mutta puhtaalla C:llä syntyy tulosta kovin hitaasti ja dynaamisten tietorakenteiden / merkkijonojen / jne käsittely on melko kömpelöä. Valitsinkin siksi pykälää korkeamman abstraktiotason eli C++:n. Ohjelmointikielen version valintaan kannattaa paneutua myös hetken eikä sännätä käyttämään heti uusinta; itse en uskaltanut vielä tähän projektiin valita tuoreinta C++11 versiota vaikka se oliskin tarjonnut muutamat elämää helpottavat asiat kuten “auto” tyypin muuttujille, sisäänrakennetun säiekirjaston ja paljon muuta. Sittemmin olen perehtynyt tarkemmin C++11 feature support matriisiin merkittävillä kääntäjillä (GCC, clang, MSVC++) ja vaikuttaa että aika on kypsä sen käyttöönotolle.

Ohjelmointikielen valinnan jälkeen seuraava looginen askel on kartoittaa APIen/ulkoisten kirjastojen tarve ja koettaa vaikkapa proof-of-concept -hengessä varmistaa että kirjastovalinnat täyttävät tarpeet. MMark13 -projektissa tarvitsin säikeistystä, joten käytin hyväkseni tietoa että kaikki kohdealustani ovat UNIX-perillisiä ja siten tarjoavat POSIX threads (pthreads) paketit. Tarvittiin myös JSON kirjastoa; pienellä googlauksella löysin “jsoncpp” paketin jonka koodi/dokumentaatio oli poikkeuksellisen laadukkaan oloista ja joka istui suoraan tarpeisiini. Kenties tuosta löydöksestä riemuitessani kirjoitin seuraavan askeleen eli tuloslaskelma-JSON lähetyksen palvelimelle abstraktion läpi siten että kirjoitin alustoille omat toteutuksensa sen sijaan että olisin käyttänyt ilmiselvää ratkaisua libcurlia. Tajusin mokani vasta projektin loppumetreillä enkä rupea yleensä korjaamaan jotain joka toimii, joten saivat jäädä. Lisäksi otin mukaan simppelin C++ MD5-toteutuksen. Halusin toteuttaa softani käyttöliittymän alustariippumattomasti siten että se käyttäytyy kaikilla laitteilla samalla tavalla ja myös näyttää samalta. Etsinkin melko laajalti OpenGL-pohjaista Widget-kirjastoa mutta löytämäni paketit olivat joko aivan järjettömiä bloatteja tai sitten erittäin huonolaatuisen näköistä koodia (usein molempia) että päädyin kirjoittamaan hyvin lightweight toteutuksen aivan alusta erään intensiivisen viikonlopun aikana. Eli ainakin yksi pyörä tuli keksittyä uusiksi – toisaalta aikaa ei tuohon uponnut paljoa, lopputulos miellyttää silmää, homma oli erittäin hauskaa ja lisäksi vieläpä opin paljon.

Lisäksi tarvittiin seuraavat asiat alustariippuvasti: softan bootstrapping, softa/hardisinformaation penkomista laitteelta, joitain sekalaisia pikkujuttuja sekä resurssifilejen lukeminen systeemistä – tähän olisi voinut käyttää ihan fread():ia mutta halusin toisaalta käyttää Qt:n mainiota resource systeemiä jonka kanssa tuo taas ei toimi. Alla muutama konkreettinen koodiesimerkki alustariippuvasta koodin jaosta:

CommonFunctionsQT.cpp:

std::string RandomUuid()
{
    // .mid(1,36) strips the curly braces added by toString(), duh
    return std::string(QUuid::createUuid().toString().mid(1,36).toUtf8());
}

CommonFunctionsIOS.cpp:

std::string RandomUuid()
{
    CFUUIDRef theUUID = CFUUIDCreate(NULL);
    CFStringRef cfuuid = CFUUIDCreateString(NULL, theUUID);
    CFRelease(theUUID);
    NSString* uuid = (NSString*)cfuuid;
    [uuid autorelease];

    return std::string([uuid UTF8String]);
}

Kurkistetaan vielä korkealla tasolla ohjelmiston toimintaa ja sitä miten alustariippuva ja porttautuva osa koodia pelaavat yhteen. iOS-buildissa tarvittava wrapperkoodi on luonnollisesti Objective-C(++):aa; kokemus osoitti ettei sen ja C++ -maailman sekoittaminen keskenään ole triviaalia tai kovin eleganttia, ja kehotankin eristämään kyseisen rajapinnan mahdollisimman pienelle alalle. Käytännössä toimiva pattern on antaa Objective-C++ koodille yksisuuntainen has-a -patternin mukainen suhde porttautuvaan C++ koodiin ja rakentaa iOS-specific toteutus C++ luokalle joka hoitaa callbackien tarvitseman alustariippuvan koodin. Qt maailma on natiivisti C++:aa, joten siellä ei tarvittu taikatemppuja. Ohjelman toimintalogiikka pääpiirteittäin:

  1. Alustariippuvainen osa ottaa vastaan inputit, muuttaa niiden datatyypit alustariippumattomaan muotoon ja välittää ne eteenpäin allaolevalle porttautuvalle osalle. Käytännössä inputit ovat:
    • Redraw timer. iOS:ssa CADisplayLink, Qt:ssä QTimer.
    • Käyttäjän kosketukset. iOS:ssa UITouch*, Qt:ssa QTouchEvent.
  2. Alustariippumaton osa päivittää tilan / menussa ollessa UI:n tilan touchien / kuluneen ajan avulla
  3. Uuden tilan perusteella piirretään uusi frame sekä mm. aloitetaan fysiikkalaskenta seuraavaa framea varten
  4. Tarvittaessa kutsutaan abstraktoituja callbackeja kun tarvitaan alustariippuvaa toiminnallisuutta; esimerkiksi kun ladataan testin vaatimia tekstuureita levyltä tai halutaan lähettää tulokset serverille

Jollekulle on saattanut tätä lukiessa tulla mieleen että mitenkäs se Windows Phone sitten? WP8 pois jättämiseen kohdealustojen joukosta on oikeastaan vain yksi syy – OpenGL APIn puute. Vaikka ymmärtääkseni WP8 hardis on OpenGL ES 2.0 yhteensopivaa, Microsoft ei tapansa mukaan tarjoa standardia rajapintaa vaan pakottaa kehittäjät porttaamaan koodinsa Direct3D:lle. Ja koska softani tärkeimpiä ominaisuuksia on olla suoraan vertailukelpoinen ympäristöjen välillä, ei tuo oikein ollut optio. Jos Googlen ANGLE projektista tulee ikina luotettava port WP:lle *tai* jostain taivaasta putoaa OpenGL ajuri, teen ilomielin myös WP-buildin. Tämän vuoden aikana on tarkoitus suoltaa ulos buildit ainakin Blackberry10:lle, Sailfish OS:lle sekä Ubuntu Phonelle riippuen siitä saadaanko moisia laitteita käsiimme.

Hyvää kevättä kaikille!

Linkkejä

Lisää luettavaa:

Push-viestit ja push-palvelin – mitä ne ovat?

Viimeisen kahden vuoden aikana push-viestien osuus mobiiliviestinnässä on kasvanut räjähdysmäisesti uusien älykkäämpien palvelujen myötä. Seuraavassa pyrimme avaamaan mitä push-viestit ovat sekä niiden hyötyjä ja mahdollisuuksia. Tulemme julkaisemaan myöhemmin myös push-viestintäteknologiaa ja -arkkitehtuuria tarkemmin käsittelevän artikkelin.

Push-viestejä voitaisiin kuvata esimerkiksi seuraavalla virkkeellä:

Push-viestit ovat viestejä, jotka laitteeseen saapuessaan lähes poikkeuksetta herättävät käyttäjän huomion. Käyttäjä voi viestin otsikosta riippuen joko unohtaa sen tai perehtyä siihen ja saada mahdollisesti lisää tietoa asiasta.

Kuvauksen mukaisesti push-viestejä voitaisiin verrata tekstiviesteihin, sillä lisäyksellä, että ne aina liittyvät puhelimelle ladattuun sovellukseen.

Mainonnan ja markkinoinnin näkökulmasta push-viestit eroavat merkittävästi tekstiviesteistä tai muista digitaalisista viestintämuodoista. Digitaalinen mainonta tekstiviestien avulla saattaa monien mielestä olla tunkeilevaa ja sähköpostin välityksellä tapahtuvana persoonatonta sekä harvoin tunteita herättävää. Push-viestit sen sijaan saapuvat aina käyttäjän sallimana, näkyvät reaaliaikaisesti laitteessa ja voivat sisältää monipuolista interaktiivista sisältöä.

Henkilökohtainen merkityksellisyys

Yksilön profilointi on perinteisessä mainonnassa usein pulmallista ja sen toteutus sekä järkevästi että käytännöllisesti on hankalaa, sillä käyttäjien taustat pitää kartoittaa ja sen perusteella jakaa käyttäjät lokeroihin. Käyttäjien profiilitietojen muuttuminen puolestaan ei välttämättä koskaan saavuta palveluiden tarjoaa. Tällainen tilanne saattaa olla kaikille vahingollista. Mainostaja tekee turhaa työtä ja tuhlaa resurssejaan. Viestin saajan osalta roskaviestinnäksi muuttuneen yhteydenottojen käsittely voidaan kokea jopa ärsyttäväksi, mikä saattaa herättää negatiivisia tunteita palvelun tarjoajaa kohtaan.

Push-viestien vastaanottamisen sallimisen mahdollisuus mobiilisovelluksessa estää turhien viestien saapumisen loppukäyttäjille. Viestien lähettämisen salliminen myös ennakoi vastaanottavampaa suhtautumista asiasisältöön. Mobiilisovellus, joka on yhteydessä push-palveluun, voi kerätä ja pitää ajantasalla käyttäjien palvelutietoja, listaa kiinnostuksen kohteista ja sekä esimerkiksi paikkatietoja – käyttäjän sen salliessa. Erityisesti paikkatietojen hyväksikäyttö on vielä vähän käytetty “se suuri” mahdollisuus; paikkatietoisuus yhdistettynä käyttäjien kiinnostuksien kohteisiin tuo merkityksellisyyttä ja korostaa palvelun tarjoajan kunnioitusta yksilöä kohtaan.

Push-viestit saavuttavat kohdeyleisön välittömästi

Ihmisillä on nykyään hyvin usein monia sähköpostitilejä: todennäköisesti tietty tili varattuna henkilökohtaiseen viestintään ja jokin toinen tai toiset tilit yleisempään viestintään, kuten rekisteröitymisiin ja muihin harvemmin käytettyihin palveluihin. Viestin ja loppukäyttäjän kohtaaminen saattaa tapahtua vasta päivien tai viikkojen kuluttua itse lähetystapahtumasta, koska käyttäjät eivät välttämättä seuraa aktiivisesti kaikkia tilejään.

Push-viestit saavuttavat vastaanottajan viimeistään muutaman minuutin sisällä lähetyksestä. Käyttäjien voidaan olettaa saaneen ja huomioineen viestin lähes välittömästi, sillä puhelin värisee, soittaa mahdollisesti merkkiäänen ja ruudulla tapahtuu visuaalinen päivitys.

Pushin avulla sisältöä mobiiliviestintään

Niin massaviestit kuin käyttäjien profiloinnin kautta yksilöidyt viestit kannattaa muotoilla huolellisesti ja sisällyttää niihin jotain, joka oikeuttaa välittömän yhteydenoton käyttäjiin.

Pelkkä tekstitieto,esimerkiksi vaikkapa “Liikkeemme on auki tänäänkin klo 9-18” voi olla paikallaan sillöin tällöin muistuttamassa palvelun olemassaolosta. Suositeltavampaa olisi kuitenkin antaa käyttäjille arvokkaampaa informaatiota, jota epush-viestipalvelua käyttämättömät eivät tietäisi. Esimerkiksi “Muotisuunnittelijamme on tänään liikkeessämme klo 18 asti antamassa henkilökohtaisia vinkkejä. Skumppaa 50 ensimmäiselle!” -tyyppinen viesti tuo lisäarvoa viestiin ja on myös käyttäjille syy olla liittyneenä viestipalveluun. Varsinkin lyhytaikaiset kaikille tarjottavat tiedotteet ja edut houkuttelevat palvelusta kiinnostuneet liittymään palveluun saadakseen tiedon tapahtumista ensimmäisten joukossa.

Push-viestivaihtoehdot

Push-viestit ovat perusidealtaan samankaltaisia kaikissa laitteissa: viesti saapuu, se mahdollisesti avataan ja siihen sidottu mobiilisovellus käynnistyy ja näyttää lisätietoa asiasta.

Applen iOS-laitteilla push-viestit tulevat laitteen ruudulle ja käyttäjä voi reagoida siihen välittömästi tai palata asiaan myöhemmin uudelleen viestikeskuksen kautta. Näkyvän viestisisällön lisäksi viestiin liitetään usein myös käyttäjälle näkymätöntä tietoa, kuten mikä merkkiääni soitetaan viestin saapuessa tai mitä dataa palveluun halutaan välittää sisällönpäivittämisen mahdollistamiseksi.

Windows Phone -laitteille on tarjolla puolestaan usean tyyppisiä push-viestejä, joista perusvaihtoehto (“toast”) on samankaltaisin muiden alustojen push-viesteihin verrattuna. Windows Phone -laitteelle on mahdollisuus lähettää myös raw- ja tile-viestejä. Raw-viestit tarjoavat mahdollisuuden palvelulle syöttää tietoa (esimerkiksi kuponki) mobiilisovellukseen taustalla, ilman että sovelluksen pitää hakea tietoa erikseen.

Tile-viesteissä puolestaan palvelu voi syöttää sovellustiileen (vastaa muilla alustoilla suurin piirtein ikonia työpöydällä) taustakuvia, tekstejä ja numerotietoa. Tämän avulla voidaan toteuttaa esimerkiksi käyttäjän työpöydän uutissovelluksen ikonin sisällönmuutos tai vastaava tilapäivitys.

Android-laitteilla mahdollisuuksia on useita. Käytännössä kehittäjä voi päättää mitä tehdään push-viestin tullessa. Yleisin käytäntö kuitenkin on, että käyttäjälle näytetään notifikaatti, jonka hän voi avata silloin kun on siihen sopiva hetki. Voidaan kuitenkin tehdä monimutkaisempiakin toteutuksia — esimerkiksi käsketään laite lataamaan jokin iso tiedosto ja vasta sen jälkeen ilmoitetaan käyttäjälle notifikaatilla. Käyttäjälle ei ole pakko ilmoittaa push-viestistä mitään, vaan se voi pelkästään olla taustalla tapahtuvaa logiikkaa.

Toimintaympäristö

Push-viestipalvelun käynnistämisen jälkeineen tapahtuva viestien lähetys voi parhaimmillaan olla varsin yksinkertaista ja suoraviivaista. Palvelun tarjoaja luo uuden push-viestin syöttämällä lähettävässä palvelussa lomakkeeseen viestin tiedot. Lähetysnapin painamisen jälkeen tiedot siirtyvät push-viestipalvelimelle, joka lähettää viestin edelleen Applen, Googlen ja Microsoftin kautta mobiililaitteille. Edellä kuvattu toimintatapa vaatii kuitenkin sen, että palvelun kehittäjä on joko itse kehittänyt push-palvelimen viestien välittämiseen tai käyttää tarjolla olevia kaupallisia vaihtoehtoja.

Qvik on toteuttanut push-palvelimen ja tarjoaa sitä mielellään kaikkien asiakkaiden käyttöön. Jatkamme Push-teknologiasta ja viestintäarkkitehtuurista tarkemmin seuraavassa artikkelissa.

 

Kuva 1. Push -viestipalvelin lähettää viestit mobiilikäyttäjille

 

NPG Card julkaistu Windows Phone:lle

Night People Groupin suosittu jäsenkorttisovellus on saatavilla nyt myös Windows Phone -laitteisiin Windows Phone Store:sta!

Sovellusta käyttämällä voi saada jäsenille kohdistettuja etuja NPG:n yökerhoissa ja ravintoloissa. Edut näkyvät sovelluksessa uutisina ja sähköisinä etukuponkeina. Sovellus tarjoaa myös käytännön tietoja tulevista tilaisuuksista yhteystietoineen, paikkatiedot kartalla sekä virtuaalisen jäsenkortin oikeine nimineen ja voimassaoloaikoineen.

NPG Card pohjautuu Qvik Oy:n lanseeraamaan Qvik Card -white label -alustaan, joka voidaan räätälöidä persoonallisesti tilaajan tarpeiden ja brändin mukaiseksi.

Windows Phone:lle tehty Qvik Card eroaa vastaavista iOS- ja Android-sovelluksista huomattavasti ulkoasultaan ja käyttöliittymälogiikaltaan – säilyttäen kuitenkin alkuperäisen toiminnallisuuden.  iOS- ja Android -versioissa “ajankohtaista”, “kupongit”, “membertarjoukset”, “tapahtumat” ja “ravintolat” ovat erillisissä näkymissään, jotka haetaan erikseen Facebook-tyylisestä sivuvalikosta. Käyttäjä avaa ensin valikon ja valitsee sitten, mihin osioon haluaa siirtyä.

Windows Phone -versio käyttää hyväkseen Panorama-näkymää, joka esittää kaikki edellä mainitut toiminnot rinnakkain. WP-lopputulos on grafiikkaintensitiivisempi ja kenties luonnollisempi käyttää kuin muut versiot. Pyyhkäisyliikkeiden pintaan nostattama sisältövirta auttaa isompien asiakokonaisuuksien välillä luovimista.

Sovellus on saanut myönteisen vastaanoton: artikkelia kirjoitettaessa enemmistö arvostelijoista antoi sille arvosanaksi 5 tähteä.

Windows Phone markkinaosuus kasvaa ripeästi

Nyt

Suomessa Elisan myydyin puhelin vuonna 2012 henkilöasiakkaiden kategoriassa oli Nokian Windows Phone Lumia 800 ja yrityspuolella se oli toisena. Myös Soneralla Lumia 800 oli myydyin puhelin vuonna 2012.

StatCounter ilmoittaa Windows Phonen osuuden olleen Suomessa n. 18% joulukuussa 2012, ja nyt tammikuun alussa 20.24%, joten kasvu näyttää jatkuvan vahvasti.

Syksyn Windows Phone 8 -julkistuksen ja sen myötä myyntiin tulleiden WP8-puhelimien myynti näyttää lähteneen hyvin liikkeelle useiden lähteiden mukaan. Vaikka WP-laitteiden markkinaosuus maailman laajuisesti oli muutama kuukausi sitten marginaalista, muutos tilanteeseen on odotettavissa: Microsoftin Steve Balmerin mukaan myynti oli marraskuussa nelinkertaista ja jouluviikolla viisinkertaista verrattuna vuotta aiempaan tilanteeseen.

Vahvistamattomien tietojen mukaan myynti Kiinassa ja USA:ssa on erittäin hyvää eritoten Nokian Lumia-malliston ansiosta. Palkittua Nokian Lumia 920-puhelinta on kehuttu maailman innovatiivisimmaksi ja laitteen kysyntä on ollut huikeaa muihin saman käyttöjärjestelmän laitteisiin verrattuna.

Tulevaisuus

Ennustaminen on hankalaa, kuten vaikkapa IDC:n ennusteet osoittavat. IDC:n ennustukset Windows Phonen kohdalla ovat heitelleet maailmanlaajuisesta 11.4%:n osuudesta aina 19 prosenttiin. Vertailun vuoksi sanottaneen, että Apple iPhonen markkinaosuus maailmassa lienee noin 15%.

Selvää on kuitenkin, että suomalaiset ovat ottaneet Windows Phonen ja Nokian omakseen sekä ostavat laitteita innokkaasti.

Kuva 1. StatCounter Q4/2012 – Suomi.

iPad Mini -arvostelu

Ensimmäinen iPad julkaistiin tammikuussa 2010. Aikaa on siis kulunut vasta vähän vajaat kolme vuotta, mutta julkaisusta alkaneen tablettivallankumouksen takia aika tuntuu huomattavasti pidemmältä ja paljon on vettä virrannut julkaisun jälkeen. Suurin muutos tablettimarkkinoilla iPadin julkaisun jälkeen ovat olleet halvat minitabletit Amazon Kindle Fire ja Google Nexus 7. Nyt Apple lähtee mukaan minitablettitaistoon ei-niin-halvalla iPad  Minillä.

Otin viikonlopun ajaksi testiin iPad Minin 16-gigaisen WiFi-version ja testasin, onko uutukaisesta mihin ja mihinkään.

Onko minun käteni todella iso, vai onko iPad Mini?

Ensi tuntuma

Ensi tuntuma iPad Miniin on melkein maaginen: se on kevyt, erittäin ohut ja tuntuma on “arvokas”. Samanlaista tunnetta ei välitä iPad Minin Android vastine Google Nexus 7, joka on pienestä koostaan huolimatta varsin pulska ja painava. Myös sen ulkokuori natisee kun laitetta käsittelee. Tuo arvokkuuden tuntuma on todennäköisesti syy, miksi Apple on hinnoitellut iPad Minin melkein 100 euroa kalliimmaksi kuin mitä Google on laittanut hintalapuksi Google Nexus 7:lle.

Kannettavuus on iPad Minissä huippuluokkaa: se sujahtaa talvitakin povitaskuun näppärästi, eikä sitä edes huomaa kantavansa mukanaan.

Näyttö

Retina iPadiin tottuneelle iPad Minin pienempi näytöntarkkuus on heti huomattavissa, ja teksti näyttää hiukan sumuiselta. Latasin iBooksista testin vuoksi pari kirjaa ja yhden sarjakuvan. Kirjoissa näyttö ei varsinaisesti haitannut, mutta sarjakuvissa tekstien näkemin vaati huomattavaa keskittymistä. Zoomailuun ei kuitenkaan tarvinnut turvautua. Verkkosivuilla huomasin zoomailevani huomattavasti enemmän kuin Retina iPadilla.

Käyttö

Kolmannen sukupolven Retina iPad (eli se ensimmäinen Retina), kärsii hiukan nopeusongelmista, johtuen näytön suuresta koosta. Nuo nopeusongelmat ovat poissa iPad Minissä: kuten myös samalla suunnilleen samalla raudalla toimivassa iPad 2:ssa, applikaatiot avautuvat sukkelaan ja isotkin pdf-tiedostot ovat selattavissa nopeasti iBooksissa.

Peleistä testasin Suomalaisen Remedyn Death Rally -peliä, jota olen aiemmin testannut iPhone 4:lla ja kaikilla aiemmilla iPadeilla. iPad Minillä pelattuna pelikokemus oli tähän astisista laitteita paras. Näyttö oli tarpeeksi iso, mutta laite on niin kevyt, että sitä jaksaa kannatella pidemmänkin aikaan. Voidaan siis sanoa, että homma pelittää.

Pähkinänkuoressa

Olin ennen testirupeaa hiukan skeptinen minitablettien tarpeellisuudesta, testi ei aivan kokonaan saannut mieltäni muutettua, mutta ei minitabletit aivan turhia ole. iPad Mini on rahansa arvoinen laite ja varsinkin sisäisellä verkkoyhteydellä varustettuna laite olisi varsin kätevä paljon tienpäällä oleville.

Retina iPadin omistajille iPad Mini ei tuota mainittavaa lisäarvoa, mutta esimerkiksi iPod Touch tai iPad 1 olisi jo varsin perusteltua korvata iPad Minillä. Muihin minitabletteihin verrattuna iPad Minin iso näyttö, mutta pieni koko antaa mielesätni sellaisia etuja, joista kannattaa maksaa muutama euro enemmän.

 

iPad Mini kehittäjän näkökulmasta

Apple julkaisi eilen tukun uusia tuotteita, joiden mukana oli myös kokonaan uusi iOS-laite, iPad Mini. Tässä hiukan mietteitä kehittäjän näkulmasta.

iPad Mini on raudaltaan ja pikseleiltään sama kuin iPad2, eli sovellukset jotka toimivat iPad2:ssa toimivat myös iPad Minissä. Ainoat isommat erot ovat iPad Minin LTE-tuki, Siri ja luonnollisesti koko.

Internet-huhut olivat yhdessä vaiheessa sitä mieltä, että iPad Mini olisi kuvasuhteeltaan 16:9, joka olisi ollut sovelluksille huomattavasti isompi remontti, kuin iPhone 5 yhteensopivuuden tekeminen iPhone-sovelluksissa. Näin ollen kehittäjät voivat huokaista helpotuksesta, kun nykyiset sovellukset rullaavat enemmän tai vähemmän samalla tavalla kuin iPad 2:ssa.

Tervetuloa iPad Mini.

 

OpenGL ES 3.0 tulee – oletko valmis?

Aivan lyhykäisyydessään viimeaikojen uutisvirrasta poimittuna, Khronos Group on hiljattain julkaissut OpenGL ES 3.0 standardin speksin. ARM satsaa kovasti raudallaan sekä softatyökaluillaan mobiiligrafiikkaan ja toivon mukaan ensimmäiset laitteet nähdään jo pian!

Poimintoja tärkeimmistä uusista ominaisuuksista:

  • Alustariippumaton tekstuurien pakkaus on nyt osa standardia. Erittäin suuri helpotus cross-platform softan tekijöille.
  • Geometry instancing; monta kopiota samasta geometriasta (helppo esimerkki: metsän puut) voidaan nyt piirtää säästäen väylän kaistaa kun geometria tarvitsee lähettää vain kerran.
  • Occlusion queries: rautatuki artefaktien näkyvyyden selvittämiseen. Nopeuttaa ja suoraviivaistaa dramaattisesti vaikkapa lens flarejen yms. efektien toteuttamista.
  • Floating point, depth jne tekstuurit pakolliseksi osaksi speksiä
  • Ja mikä parasta, 3.0 speksi on 100% taaksepäin yhteensopiva 2.0 kanssa.

Lähteet:

 

Ehta modaalidialogi iOS:lla


Muista kehitysympäristöistä iOS-maailmaan tulevasta voi tuntua oudolta Cocoa Touchin modaalidialogien puute. Vaikkakin on mahdollista rakentaa kaiken muun päälle piirtyvä dialogi joka oletukselta (ja tämä on ohitettavissa) saa kaiken syötteen, dialogin näyttävä kutsu ei blokkaa vaan palaa välittömästi ja dialogin sulkeutuminen on otettava kiinni asynkronisella callbackilla (‘delegate’). Edes perustyökalu UIAlertView ei käyttäydy kuin muiden alustojen – vaikkapa MFC, Javascript, Symbian Series60/Series80, Java AWT/Swing, Qt, Android, GTK, jne.. – stock komponentit MessageBoxit ja InputDialogit.

Tämänkaltaista UI paradigmaa voi kuitenkin paitsi kaivata, myös tarvita; oletetaan etta ollaan rakentamassa iOS -toteutusta cross-platform sovellukseen jossa täytyy toteuttaa metodi vaikkapa seuraavasti:

std::string AskUserInput()
{
  // Semantiikka: kysy käyttäjältä syöte popup dialogilla 
  //   ja palauta annettu teksti
}

Miten tämä toteutetaan iOS:lla? Nostetaan kädet pystyyn, otetaan projektin arkkitehti Skypen päähän ja anotaan API:in muutosta joka mahdollistaisi syötteen kyselyn asynkronisen käsittelyn? Miksei, mutta jos yo. mekanismi on jo toteutettu viidelle muulle alustalle, on edessa iso muutostyö ja paljon hampaita kiristeleviä ihmisiä. Turha asynkronia näin yksinkertaisessa asiassa hankaloittaa sekä pirstaloittaa arkkitehtuuria.

Ongelman ratkaisu lähtee UI frameworkin toiminnan ymmärtämisestä. Käytännössä kaikissa moderneissa käyttöliittymäkirjastoissa on 1-N UI säiettä jotka palvelevat käyttöliittymää ns. event loopin [tapahtumakieriö?! -toim.] kautta. Event loop ottaa inputteja komponenteilta, timereilta tai vaikkapa muilta säikeiltä alustakohtaisten viestinvälitysmekanismien välityksellä ja tarjoilee niitä kiinnostuneille kuuntelijoille. Käytännössä jokaisella säikeellä on tasan yksi (tai nolla, jos kyseessä ei ole UI:ta palveleva säie) event loop, ja yleisesti mobiilikäyttöjärjestelmissä UI:ta palvelee vain yksi säie kerrallaan. Käyttöliittymä kumminkin toimii jouhevasti niin kauan kuin tätä säiettä ei varata kerralla liian pitkäksi aikaa; pitkäkestoinen laskenta täytyy joka jakaa pieniin osiin tai tehdä muissa säikeissä.

Event loopiin perustuvat järjestelmät sallivat yleensä event looppien sisäkkäisen ajamisen (nesting); tällöin vanha event loop aktivaatio pysähtyy eikä jatka ennenkuin sisempi loop aktivaatio loppuu. Tätä voidaan hyväksikäyttää asynkronian poistamiseksi; API-metodin sisällä ajetaan uusi aktivaatio, kuunnellaan asynkronista vastausta ja lopetataan aktivaatio kun vastaus on saatu. Tällöin APIa kutsuva metodi blokkaa koko suorituksen ajan. On kuitenkin erotettava tämä semaforin odottamisesta; säiehän ei ole idlena vaan suorittaa sisempää event loop aktivaatiota.

Rakennetaan esimerkkitoteutus iOS:lle. Halutaan tehda seuraavanlainen kutsu:

-(void) requestAndLogInput {
  InputDialog* dlg = [InputDialog dialog];
  [dlg showModal];
  NSLog(@"Dialog input was = %@", [dlg getInput]);
}

Aloitetaan dialogin luomisesta. Tähän käytetään normaalia Cocoa Touch boilerplatea:

+(InputDialog*) dialog {
    NSArray* nibViews = [[NSBundle mainBundle] loadNibNamed:@"InputDialog"
                                                      owner:nil
                                                    options:nil];
    InputDialog* dlg = [[[nibViews objectAtIndex:0] retain] autorelease];

    return dlg;
}

Määritellään metodi jolla dialogi näytetään modaalisti – se asettuu päällimmäiseksi ja blokkaa kunnes dialog on suljettu. iOS:lla event loop tunnetaan nimellä Run loop, ja sitä vastaavat APIt ovat NSRunLoop sekä Core Foundationin CFRunLoop*:

-(void) showModal {
    // Lisätään dialogimme keywindow'n ylimmän lapsen ylimmäksi lapseksi,
    // jolloin dialogi päätyy päällimmäiseksi view stackiin
    UIWindow* keyWindow = [[UIApplication sharedApplication] keyWindow];
    UIView* topmostView = [keyWindow.subviews objectAtIndex:0];
    [topmostView addSubview:self];

    // Sijoitetaan dialogi suunnilleen keskelle ruutua    
    CGSize s = topmostView.bounds.size;
    self.center = CGPointMake(s.width / 2, (s.height / 2) - 70);

    // Ajetaan nested run loop aktivaatio jolloin showModal kutsu blokkaa
    CFRunLoopRun();
}

Lopuksi määritellään dialogin sulkeva IBAction:

-(IBAction) okPressed {
    // Poistetaan dialogi näkyvistä
    [self removeFromSuperview];

    // Pysäytetään sisempi run loop aktivaatio; kontrolli palaa 
    // ulommalle ja showModal -kutsu palaa
    CFRunLoopStop(CFRunLoopGetCurrent());
}

Valmista! Ja koska kyseessä  ovat erilliset run loop aktivaatiot eivätkä erilliset run loopit, esimerkiksi timerit jatkavat eloaan ja autorelease pool on jaettu aktivaatioiden välillä.

 Esimerkkiprojekti Xcode 4.5 -projektina. 40kB zip

 

Jo yli puolet iPhoneista päivitetty uusimpaan iOS 6.0 käyttöjärjestelmään

iPhonen käyttäjät ovat päivittäneet puhelimiaan ahkerasti. Alle kahdessa viikossa on iOS 6.0:n osuus noussut kuuteenkymmenen prosenttiin kaikista iPhoneista ja iPadeissa vastaavat luku on 45% (lähde: BGR).

Samaan aikaan Androidilla vain hiukan yli 25% käyttäjistä on päivittänyt laitteensa 4.x.x käyttöjärjestelmiin (lähde: developer.android.com). Suurin osa käyttäjistä on jymähtänyt Gingerbreadiin, joka ilmestyi jo kaksi vuotta sitten. Syy niheään päivitykseen löytyy laitevalmistajista, jotka tarjoavat erittäin hitaasti ja huonosti päivityksiä vanhempiin laitteisiin (ja myös uudempiinkin). Apple puolestaan tukee laitteita takautuvasti huomattavasti ahkerammin ja uusin iOS 6.0 oli tarjolla heti nyt jo kolme vuotta vanhaan iPhone 3gs puhelimeen (iPad 1 tosin tipahti hiukan harmillisesti kyydistä pois).

iPhone-kehittäjille käyttäjien päivitysinto tarkoittaa sitä, että uusien käyttöjärjestelmien tuomat edut päästään hyödyntämään nopeammin. iOS 5.0 mukana tulleet storyboardit nopeuttavat kehitystyötä ja iOS 6.0 mukana viimeisimmätkin navigaatiokomponentit muuttuivat kustomoitavaksi niin, että omien viritysten tekeminen ei ole enää tarpeellista.

Nykyisellä vauhdilla jo ensi keväänä on perusteltua tähdätä iOS 6.0+ käyttöjärjestelmille suunnattujen applikaatioiden tekeminen.