Category Archives: Tutoriaalit

OUYA, Android-konsoli

Kesälomalta paluu sorvin ääreen voi olla raskasta tai hauskaa… Kesälomalla hankittujen lelujen kanssa siitä onneksi saa hauskaa.

OUYA on Kickstarter-rahoituksen avulla luotu Android 4.1 -konsoli, jossa pyörivät kaikki normaalit Android-applikaatiot ilman suurempaa vaivaa. Konsoliin saa helposti ladattua SDK:n, jonka avulla ohjainta voi käyttää applikaatioissaan, mutta hiirellä ja näppäimistölläkin voi konsolia suoraan käyttää.

OUYA ei ole kovin tehokas konsoli eikä pelitarjonta ole vielä kovin laaja, tätä artikkelia kirjoitettaessa vain 384 peliä, mutta 99$ hintansa puolesta se on hyvä hankinta arcade pelien pelaamiseen olohuoneen sohvalla kavereiden kanssa.

Yrityksille OUYA tarjoaa halvan ja helpon ratkaisun tarjota interaktiivista sisältöä asiakasnäyttöihin. Valmiin applikaation kääntäminen ja asentaminen OUYA:lle on hyvin helppoa. Kehittäminen OUYA-konsolille ei ole yhtään sen vaikeampaa kuin mille tahansa muulle Android-laitteelle. Toki pieniä muutoksia joudutaan tekemään käyttöliittymään, jotta normaalisti kosketusnäytölle tarkoitettua applikaatiota voi käyttää peliohjaimella tai hiirellä. Kosketusnäytön korvaaminen hiirellä tai muulla ohjaimella johtaa helposti hyvin heikkoon käyttökokemukseen.

 

Asentaaksesi minkä tahansa applikaation OUYA:lle pitää sinun voida ladata applikaation .apk-tiedosto Internetistä. Mene OUYA:n kotinäkymän MAKE-valikkoon ja sisäänrakennetulla Internet-selaimella lataa APK-tiedosto. Tämän jälkeen palaa päävalikkoon, mene MANAGE-valikkoon, valitse SYSTEM ja siellä valitse ADVANCED. Tämä on jokaiselle Android-käyttäjälle tuttu asetukset-valikko Androidissa. Mene listassa alaspäin ja valitse Storage, jonka sisällä valitse Download. Täältä löydät juuri lataamasi APK-paketin ja asentaminen onnistuu ohjaimen O-napilla. Tämän jälkeen applikaatio löytyy samasta MAKE-valikosta kuin OUYA:n Internet-selain.

Samaan MAKE-valikkoon tulevat myös applikaatiot, jotka itse kehität ja asennat tietokoneen ADB:n avulla microUSB:n kautta.

Kehittäminen OUYA:lla

Kaikki OUYA-konsolit toimivat applikaatioiden kehittämiseen ilman maksuja tai muutoksia konsoliin. Jotta saat OUYA:n toimimaan normaalissa Android-kehitysympäristössäsi Macilla sinun täytyy vain lisätä kolmannen osapuolen USB Hex ID (0x2836) adb_usb.ini -tiedostoon .android-hakemistossa ja käynnistää ADB uudelleen. Tarkemmat ohjeet myös Windows-koneille on katsottavissa videona OUYA developers -sivustolta. Tämän jälkeen OUYA-konsolisi näkyy Eclipsessä ja ADB:ssä samalla tavalla kuin mikä tahansa muu Android-laite.

Seuraavaksi lataa OUYA Development kit (ODK) osoitteesta https://devs.ouya.tv/developers/odk, kopioi libs\-hakemistosta ouya-sdk.jar ja lisää se omaan Android-projektiisi. Tämän jälkeen ohjaimen komennot saa kiinni oman Activity -luokkasi onKeyDown() ja onGenericMotionEvent() -metodeista.

Tein tätä artikkelia varten yksinkertaisen applikaation, joka käyttää ODK:ta siirtelemään ImageView:tä FrameLayoutin sisällä.

Ota ohjain käyttöön Activity-luokan onCreate()-metodissa:

@Override
protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	OuyaController.init(this);
}

Tunnista ohjaimen komennot:

@Override
public boolean onKeyDown(final int keyCode, KeyEvent event) {
	switch (keyCode) {
		case OuyaController.BUTTON_O:
			Log.d(TAG, "OUYA button O");
			break;
		case OuyaController.BUTTON_U:
			Log.d(TAG, "OUYA button U");
			break;
		case OuyaController.BUTTON_Y:
			Log.d(TAG, "OUYA button Y");
			break;
		case OuyaController.BUTTON_A:
			Log.d(TAG, "OUYA button A");
			break;
	}
	return true;
}
@Override
public boolean onGenericMotionEvent(final MotionEvent event) {
// Joystick
	if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
		float LS_X = event.getAxisValue(OuyaController.AXIS_LS_X);
		float LS_Y = event.getAxisValue(OuyaController.AXIS_LS_Y);
	}
	return true;
}

Tämän jälkeen voit tehdä ohjaimen antamilla komennoilla mitä itse haluat.
Koko koodin ja Eclipse projektin saat ladattua Githubista:
https://github.com/Androidkehitys/OUYA

Onnea pelikehitykseen! Palataan leikkimään telkkujen kanssa, kun Cromecast saapuu postissa.

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

 

Windows Phone -sovelluskehitys Androidin ja iPhonen rinnalla

Windows Phonen astuminen iOS:n ja Androidin rinnalle on saanut aikaan hieman hämmennystä joidenkin loppukäyttäjien ja sovellusten tilaajienkin mielissä. Siinä missä iOS (iPhone/iPad), Android ja jopa poistuva Symbian muistuttavat toisiaan yleisasultaan – kukin tietenkin erottautuen omilla pienillä eroavaisuuksillaan – Windows Phone on tietoisesti suuntautunut erilleen muista omalla Metro-suunnittelukielellään.

Ohje: maassa maan tavalla

Suunnitellessa uutta sovellusta mille tahansa alustalle, yleispätevänä ohjenuorana voitaneen antaa:

Kunkin tyyppisen mobiililaitteen käyttäjä haluaa systemaattisen käyttäjäkokemuksen ja käyttöjärjestelmälle tunnusomaisen sekä varsin yhdenmukaisen ulkoasun sovelluksille. Sovelluksen käyttöönotto on tällöin mahdollisimman luontevaa eikä vaadi syvällistä perehdytystä.

Tämä halu kumpuaa usein niin käyttäjien puolelta kuin myös käyttöjärjestelmien toimittajilta! Jotkut palvelujen kehittävät mieltävät ajattelevansa käyttäjän parasta pyrkimällä mahdollisimman yhdenmukaiseen käyttöliittymään laitteen käyttöjärjestelmästä riippumatta, mutta päätyvät tekemään käyttäjälle karhunpalveluksen. On poikkeustilanne, että ihmiset käyttävät samaa sovellusta eri käyttöjärjestelmillä, mutta varmaa, että he käyttävät sitä muiden saman käyttöjärjestelmän sovellusten lomassa.

Suunniteltaessa sovellusta usealle alustalle täysin samaa konseptia ei siis voi aina käyttää. Vaikka iPhone ja Android-sovellukset voivat muistuttaa toisiaan hämmentävän paljon, niillä on eronsa. WP:llä erot ovat muihin alustoihin verrattuna huomattavat.

Esimerkki

Alla käytännön vertailuesimerkki IMDB-sovelluksesta Applen iPhonelle ja Windows Phonelle.

Kuva 1. iPhone versio IMDB:n sovelluksesta.

Kuva 2. WP-versio IMDB-sovelluksesta.

Edellä esitetyt kuvat osoittavat selvästi, että iPhonen käyttäjät eivät pitäisi WP:n tyylisestä sovelluksesta puhelimessaan (mikäli se edes pääsisi Applen App Storeen), eivätkä vastaavasti Windows Phone -käyttäjät halua iPhone/Android-tyylistä sovellusta laitteilleen. Toisilleen vieraat esitystavat vaativat sovelluksen arkkitehdilta jo konseptin varhaisessa vaiheessa ydinidean hahmottamiskykyä ja näkemystä mitä kukin loppukäyttäjä haluaa siltä.

Microsoftin sivuilta löytyy (englanniksi) esimerkkejä erilaisista sovellustyypeistä Windows Phonella.

Päätelmä

Metro-tyyliohjeita noudattavat Windows Phone -sovellukset ovat niin toimintalogiikaltaan kuin ulkoasultaan selvästi erilaisia kuin iOS/Android-taustaiset sovellukset, vaikka tarjottava toiminnallisuus olisi sama.

Windows Phonen tarjoaman visuaalisesti rikkaan Panorama-näkymän avulla yritysten brändäys ja yleensäkin halutut teemat sovelluksissa voidaan saada muita alustoja vahvemmin esille (kuva 2). Tämä toki vaatii ylimääräisen graafisen aineiston luomista.

Vaikka Windows Phonella vältetään käyttöliittymäelementtien ylimääräisiä koristeita, kuten liukuvärejä, tekstuureita, varjostuksia ja kiiltoefektejä, sisältö pyritään vastaavasti tuomaan esiin niin, että lopputulos voi hyvin olla kauniimpi kuin muilla alustoilla.

 

 

Apuohjelmia iOS-designereille

Xcode on asennettu, mitä nyt? Tässä kokoelma apuohjelmia ja muita resursseja, jotka helpottavat iOS-sovellusten kehitystä ja erityisesti käyttöliittymäsuunnittelua.

Templaattikokoelmat

Omnigraffle on suosikkityökaluni rautalankojen laatimiseen. Da5id:n kokoelma on paras tietämäni iOS-templaatti OmniGrafflelle.

Tuotantokelpoista jälkeä tarvittaessa Teehan & Lax:n Photoshop-kokoelma on mainio. Kannattaa malttaa nähdä sen verran vaivaa, että tekee 1x-grafiikat sille tarkoitetun tyylipohjan avulla, niin kuvat pysyvät mahdollisimman tarkkoina.

Liveview (ilmainen)

Liveview näyttää iPhone tai iPadin ruudulla valitun alueen tietokoneen työpöydältä. Tämä on hyödyllistä, jos haluaa tarkistaa, miltä grafiikat näyttävät retina-näytöllä ja että tekstit ovat varmasti luettavissa.

Sovelluksen avulla voi toteuttaa myös yksinkertaisen wizard of oz -demon operoimalla näkymiä tietokoneelta ja antamalla puhelimen käyttäjän käteen.

iExplorer (ilmainen)

 iOS-laitteissa ei ole tiedostojenhallintaa. Joskus on kuitenkin hyödyllistä nähdä, mitä tiedostoja minnekin kertyy. iExplorer on Mac-ohjelma, jolla pääsee selaamaan puhelimensa tiedostorakennetta.

xScope (29,99 $)

xScope tarjoaa vastaavan toiminnallisuuden kuin Liveview. Lisäksi sen avulla voi mittailla eri elementtien kokoja tietokoneen näytöltä ja lisätä apuviivoja. Tuleepa mukana virtuaalinen viivoitinkin. Apuviivoista on apua esim. Xcodessa, jonka omat viivat toimivat vähän kankeasti.

Ostin sovelluksen aikoinaan alennusmyynistä. Täysi hinta on hieman tyyris. Jos tarvitset vain viivoitinta, katso Free Ruler. Se on ilmainen, mutta toimii vähän bugisesti uusilla käyttöjärjestelmillä.

Mittaamisesta puheen ollen: itse käytän jatkuvasti kuvakaappausnäppäinkomentoa eri asioiden koon mittaamiseen. Painamalla komento + shift + 4 voi ottaa kuvakaappauksen halutusta näytön alueesta. Ominaisuutta voi käyttää myös elementtien kokojen selvittämiseen – ja kun painaa esciä ennen kuin päästää hiireen irti, säästää maailman turhalta kuvaruutukaappaukselta.

Hex color picker (ilmainen)

 Kuvakaapparin lisäksi Mac OS X:ssä on mainio pipettityökalu värien poimimiseen. Sen käyttöliittymä on peruja Next-ajoilta, ja pelkään pahoin, että moni ei edes tiedä sen olemassaolosta. Suurennuslasia klikkaamalla voi valita haluamansa värin kuin Photoshopin pipetillä. Ja mikä parasta, tämä toimii myös ohjelmien välillä.

Kätevää on myös siirtää värejä sovellusten välillä raahaamalla värin valitsimen alalaitaan.

Mac OS X:n värivalitsinta voi tehostaa asentamalla Hex color picker -laajennuksen. Sen avulla saa näkyviin suoraan värin heksa-arvon, mikä on hyödyksi myös web-suunnittelussa.

Skitch (ilmainen)

 Vakavamielisempään kuvakaappausten ottamiseen kannattaa hankkia Skitch. Se on yksi ohjelmista, joita ei voi suositella kylliksi. Kuvakaappausten ottamisen lisäksi Skitchillä voi tehdä niihin kätevästi merkintöjä: tekstiä, nuolia, vapaita tuherruksia. Paras puoli on kuvien jakaminen. Jos kuvan raahaa pois Skitchistä, siitä luodaan automaattisesti tiedosto kovalevylle ilman että kuvaa joutuisi itse erikseen tallentamaan.

Jos haluaa vaikkapa lisätä Jiraan kuvakaappauksen löytämästään bugista, ei tarvitse ensin tallentaa tiedostoa ennen kuvan lataamista selaimeen ja sitten etsiä uudelleen avaa-dialogissa, vaan riittää, että raahaa sen selaimeen suoraan Skitchistä. Kuvien lataaminen kaikkien nähtäville skitch.comiin käy sekin yhdellä klikkauksella.

Screenshot Journal (1,59 €)

Tietokoneen lisäksi kuvakaappauksia tulee helposti ottaneeksi valtavat määrät puhelimelta. Valitettavasti Apple on katsonut viisaaksi näyttää kuvakaappaukset samassa läjässä puhelimella otettujen valokuvien kanssa. Apuun tulee Screenshot Journal, joka poimii kuvakaappaukset erilleen kuvavirrasta ja tarjoaa keinoja kuvien hallintaan.

Jos tykkää nahkaefekteistä ja tikkauksista, sovellukseen kannattaa tutustua jo niiden vuoksi. Ovat keskimääräistä hienommat.

Kuvansiirtäjä

Mac OS X:n mukana tuleva kuvansiirtäjä ei ole tainnut saada ainuttakaan päivitystä sitten ensimmäisen Mac OS X -version, ja käyttöliittymä on muutamilta osin rasittava. Jos puhelimelta haluaa noutaa kuvakaappauksia, se on kuitenkin kevyempi vaihtoehto kuin iPhoto. Jos tiedät Kuvansiirtäjää paremman vaihtoehdon, kerro toki kommenteissa!

iOS-Simulator Cropper (ilmainen)

Laitteella kuvakaappauksien ottaminen on kaikesta huolimatta vähän jähmeää. Käyttöohjeita, promokuvia yms. varten on usein kätevämpää  ottaa kuvakaappaukset suoraan Xcoden Simulator-ohjelmasta. iOS-Simulator Cropper ottaa kuvakaappauksen pelkästään simulaattorissa pyörivästä ohjelmasta, nimeää sen halutulla tavalla ja lisää haluttaessa kuvan ympärille iPhone-kuoret kiiltoineen kaikkineen.

Myös status barin poistaminen kuvan ylälaidasta onnistuu helposti, jos vaikka haluaa lisätä kuvakaappaukset App Storeen Applen ohjeiden mukaan ilman palkkia.

iPhone Configuration Utility (ilmainen)

Sovellusten ja provisiointiprofiilien asentaminen onnistuu periaatteessa iTunesilla, mutta sillä on paha tapa synkronoida valtavia datamassoja joka välissä heti kun se löytää koneeseen kytketyn puhelimen. Kätevämpi työkalu on Applen tarjoama iPhone Configuration Utilyty. Sen avulla voi mm. asentaa .IPA-muotoisia sovelluksia laitteelleen, kun sellainen tarve tulee. Saatavilla myös Windowsille.

Quicklook plugin for provisioning profile files (ilmainen)

Provisiointiprofiilien kanssa tappelu on iOS-kehityksessä väistämättä vastaantuleva hupi. Tuskaa vähentää, jos voi kätevästi varmistua, että sovelluksen pitäisi teoriassa asentua halutulle laitteelle. Tämä kätevä lisäpalikka antaa Finderille kyvyn näyttää suoraan, mitkä testilaitteet sovelluksen provisiointiprofiiliin on lisätty.

UDID (ilmainen)

Jotta voisi varmistua, että oma puhelin on tuettu, pitäisi tietää puhelimen UDID-koodi. Sen saa selvitettyä iTunesilla, mutta Apple on tehnyt sen siinä määrin hankalaksi, että on usein helpompaa neuvoa ihmisiä asentamaan puhelimeen sovellus tätä varten. UDID on yksi näistä. Parempiakin saattaa olla.

Picturesque (11,99 €)

Törmäsin Picturesquehun vasta, mutta se näyttää lupaavalta. iPhone-sovelluksia tykätään usein esitellä heijastuksin je perspektiivitempuin kuorrutettuina. Picturesque tekee nämä yleisimmät efektit helposti ja antaa tallentaa kuvat myös läpinäkyvällä taustalla. Kätevä, jos kaipaat vapautusta Photoshopista.

 

Mobiiliselaimen tunnistaminen CSS:llä

Selainten tunnistaminen tulee monesti kuvioihin silloin, kun joko sivun tyylejä, logiikkaa tai sisältöä muokataan sopimaan erikokoisille näytöille tai mobiiliselaimelle. Tähän on olemassa monenlaisia tekniikoita, ja tässä blogipostauksessa esittelen tavan tehdä tämä CSS-sääntöjen avustuksella.

Media Queryn käyttö

CSS:ssä pystyy määrittämään CSS-tyylien säännöt sen perusteella, minkä levyinen ikkuna tai laite on.Tämä onnistuu CSS:n media query -ominaisuuden avulla alla kerrotulla tavalla. Parametreina voidaan käyttää esimerkiksi laitteen leveyttä ja korkeutta sekä pikselitiheyttä.

1. CSS-tyylitiedoston aktivoiminen headissa ehtojen perusteella

<link rel="stylesheet" media="screen and (min-device-width: 320px) and (min-device-pixel-ratio:2)" href="retina-styles.css"/>

2. CSS-säännön aktivointi ehtojen perusteella

@media screen and (min-device-width: 320px) and (max-device-width: 480px) and (min-device-pixel-ratio:2) and (-webkit-min-device-pixel-ratio:2) and (-moz-min-device-pixel-ratio:2) {
display:block;
}

3. CSS-tiedoston sisällyttäminen toiseen CSS-tiedostoon

@import url(styles-retina-iphone.css) screen and (min-device-width: 320px) and (max-device-width: 480px) and (min-device-pixel-ratio:2) and (-webkit-min-device-pixel-ratio:2) and (-moz-min-device-pixel-ratio:2)

Mobiilikehityksen kannalta tärkeimpiä parametrejä ovat:
min-device-width ja max-device-width, jotka rajoittavat tyylin käyttöä tietyn levyisille näytöille. Näillä saadaan sivuston tyylit mukautumaan mobiilinäytölle.

min-device-pixel-ratio tarkoittaa näytön “pikselitiheyttä”. Tyypillisen tietokoneen näytön ja peruspuhelimen arvo on 1, mutta esimerkiksi iPhone 4:llä ja iPhone 4S:llä tämä arvo on 2. Selitys tälle on ns. retina-näytössä: näytön koko on iPhone 3G:ssä ja iPhone 4:ssä on sama, mutta näytön leveys ja korkeus on kaksinkertainen. Tällöin sivustolla olevat kuvat näkyvät iPhone 4:n tarkemmalla näytöllä pikselöityneenä ja epätarkkoina, sillä käytetyn grafiikan resoluutio on liian pieni. Tämän säännön avulla voidaankin saada käyttöön tarkemmat grafiikat siihen pystyville näytöille.

@media handheld on kiinnostava parametri, mutta sen selaintuki on valitettavan rajallinen. Esimerkiksi Safari jättää tämän parametrin kokonaan huomiotta, joten parametri ei tunnista iPhonea. Tätä parametria en siis suosittele käytettävän.

orientation tarkoittaa puhelimen asentoa, eli onko puhelin vaaka- vai pystysuunnassa. orientation:landscape tarkoittaa että puhelinta pidetään vaakasuunnassa, kun taas orientation:portrait tarkoittaa pystysuuntaa.

Media query CSS3:n tuoma uusi ominaisuus, joka on jo kuitenkin nykyään erittäin laajasti tuettu. Ajantasaisen listan tuetuista selaimista löydät caniuse.com-sivustolta.

Media Queryt Qvikin kotisivuilla

Qvikin kotisivuilla on käytetty media queryjä sovittamaan sivuston ulkoasu näytön koon mukaiseksi. Sivustolla käytetään kolmea eri moodia: täysileveä, portrait ja mobiili. Täysileveässä moodissa käytettävät tyylit määritellään niin, että sen leveys on vähintään 1024 pikseliä:


@media screen and (min-device-width:1024px) {
...
}

Tällä leveydellä sivun kokonaisleveys on 1000 pikseliä. Yksi sivuston käyttöliittymäelementeistä on neljän, kiinteän leveyden laatikon ‘gridi’ joka näyttää kokoleveällä näytöllä tältä:

Jos tämä osuus näytettäisiin tällaisenaan pienemmällä näytöllä, boksit joko leikkaantuisivat, tai niitä joutuisi skrollaamaan ja zoomaamaan. Esimerkiksi tableteille (kuten iPad pystymoodissa, jonka leveys 768px) on tässä tapauksessa käytännöllistä esittää tämä gridi eri tavalla. Tyylitiedostossa nämä tyylit määritellään seuraavasti:


@media screen and (min-device-width:321) and (max-device-width:999) {

}

Tällä tavalla määritellyt tyylitiedostot näkyvät esimerkiksi iPhonen vaakatilassa ja iPadin pystytilassa. Alla kuvankaappaus Qvikin kotisivuilla:

Laatikot on asetettu 2×2 gridiin, jolloin ne ovat luettavia. Koska laatikoiden tarkoitus on tässä tapauksessa pysyä tasalevyisenä, niin ne eivät vie enää koko ruutua tilaa. On kuitenkin täysin mahdollista tehdä niin, että kaksi laatikkoa veisivät aina sen 50% ikkunan leveydestä. Tällöin niiden leveys määritellään CSS:ssä prosenttilukuna sen containerista.

Qvikin sivut on tehty myös näyttämään käytännölliseltä myös mobiililaitteella, eli 320px tai kapeammilla näytöillä:

Lisätietoa media queryjen käytöstä löytyy englanniksi W3C:n sivuilta.

Mobiilisovellus web-tekniikoilla: perusteet

Perinteisillä web-tekniikoilla on nykyään mahdollista tehdä natiivisovelluksen kaltaisia, puhelimen tai tabletin näytöllä paremmin käytettäviä sovelluksia. Tällöin sovellus on käytettävissä puhelimen web-selaimella, tai se voidaan paketoida natiiviapplikaatioksi esimerkiksi PhoneGap -kirjaston avulla. Web-applikaation ero (mobiilioptimoituun) web-sivustoon on natiiviapplikaation kaltaiset komponentit, mahdollinen offline-tila sekä animoidut siirtymät näkymien välilä. Lisäksi web-applikaatio voi sisältää puhelimen natiiviominaisuuksia hyödyntäviä toimintoja, kuten esimerkiksi kameraa tai kiihtyvyysanturia.

Tässä artikkelissä kuvataan mobiiliapplikaation kehityksen perusteet – olettaen että lukija on tutustunut web-kehityksen saloihin etukäteen. Jos et ole ennen tehnyt web-sivustoja, niin Google on listannut oivia web-tutoriaaleja, joilla pääsee helposti alkuun. Suomenkielistä sisältöä kaipaaville sisältöä on vähän hankalammin löydettävissä, mutta esimerkiksi Haaga-Helian verkkojulkaisusivuilta löytyy aiheesta kohtuullisesti suomenkielistä sisältöä.

Mobiiliapplikaation luonti

Esimerkiksi iOS- ja Android-ympäristöt tarjoavat mahdollisuuden lisätä web-applikaation työpöydälle. Tällöin iOS:llä web-applikaatio näkyy ohjelmanvaihtonäkymässä, ja sillä on ikoni ja ns. splashscreen natiivisovelluksen tapaan. Alla on esimerkkipohja puhtaalle mobiiliapplikaatiolle:

<!DOCTYPE html>
<html>
    <head>
        <title>Testiohjelma</title>
        <meta name="viewport" content="width=device-width, initial-scale=1;maximum-scale=1;user-scalable=no;">

        <meta name="apple-mobile-web-app-capable" content="yes"/>
        <meta name="apple-mobile-web-app-status-bar-style" content="black"/>

        <link rel="apple-touch-startup-image" href="images/startup.png">

        <link rel="apple-touch-icon" href="phone-icon.png"/>
        <link rel="apple-touch-icon" sizes="72x72" href="pad-icon.png"/>
        <link rel="apple-touch-icon" sizes="114x114" href="phone-icon-retina.png"/>
        <link rel="apple-touch-icon" sizes="144x144 href="pad-icon-retina.png"/>
    </head>
    <body>
        Tekstiä.
    </body>
</html>

Web-applikaation asetukset laitetaan <head> -tagien sisälle. Tämä esimerkki määrittää web-applikaatiota seuraavasti:

<meta name="viewport" content=""> määrittää sovelluksen näkyvän alueen asetukset: sivu on aina laitteen näkymän levyinen, sekä pysty- että vaakasuunnassa käytetty. Tyypillisellä web-sivustolla on zoomausominaisuus, joka kuitenkin on monesti mobiiliapplikaatiossa epätoivottu ominaisuus. Tässä esimerkissä tämä toiminnallisuus on disabloitu määrittämällä viewportille user-scalable=no. Lisää viewport-metatagin käytöstä löytyy esimerkiksi Mozilla developer networkin dokumentaatiosta (englanniksi).

<meta name="apple-mobile-web-app-capable"> ja <meta name="apple-mobile-web-app-status-bar-style"> ovat Applen iPhonessa ja iPadeissa toimivat meta-tägit. Näistä ensimmäinen aktivoi applikaatiomaisen käytön, jolloin ohjelmaa käytettäessä Safari piilottaa sen osoitepalkin. Lisäksi kun ohjelma lisätään kotinäytölle ja avataan klikkaamalla ko. lisättyä applikaatioikonia, ohjelma avataan kokoruutunäkymään ilman ylä- ja alapalkkia.

<link rel="apple-touch-icon"> määrittää ohjelman ikonin kun sen lisää työpöydälle. Nimestään huolimatta se toimii myös Android-laitteilla versiosta 2.1 eteenpäin. Esimerkissä on lisätty ikoni useammalle eri koolle – esimerkiksi 114×114 on ikoni iPhonen retina-näytölle, jossa ikonin standardikoko on juuri 114 x114. Uuden retina-iPadin kuvakkeen koko on oletettavasti 144×144, mutta tätä tietoa ei ole vielä vahvistettu. Lisätietoa ikoneiden määrittämisestä ja muista Mobile Safarin web-applikaatioiden asetuksista löytyy Applen Safari Web Content Guidesta.

Mobiiliohjelman kehitys

Mobiilisovelluksen käyttöliittymät ohjelmoidaan käyttäen HTML, CSS ja JavaScript -tekniikoita. HTML on kuvauskieli, joka jäsentää sisällön ja CSS luo sisällölle tyylit. JavaScriptillä tuodaan sisältöön elämää – esimerkiksi animaatiota tai transitioita. On teoriassa mahdollista kehittää mobiiliohjelmistoja puhtaasti käyttämällä näitä tekniikoita, mutta käytännössä kannattaa kuitenkin ottaa käyttöliittymän luonnin tueksi jokin valmiista mobiilikehitysframeworkeista.

Suosituimpia mobiiliframeworkeja ovat Sencha Touch, jQuery Mobile, The M-Project ja jQTouch. Nämä kaikki tarjoavat erilaisen valkoiman komponentteja, jotka tuovat mobiilimaisen vaikutelman web-applikaatioon: näkymien välisiä transitioita, erilaisia listanäkymiä, ajax-lomakkeita jne.

Web-applikaatioiden perinteisenä heikkoutena on nähty se, ettei niistä pääse käsiksi ohjelmistojen natiiveihin ominaisuuksiin. Tähän on kuitenkin ilmestynyt JavaScript-työkaluja, joiden avulla pääsee yleisimpiin ominaisuuksiin – näistä tunnetuimpia ovat PhoneGap ja Trigger.io. Molemmista pystyy esimerkiksi avaamaan puhelimen kameran ja yhteystiedot. Dokumentaatiota kannattaa kuitenkin tutkia tarkkaan, sillä jokainen ominaisuus on tuettu vain tietyillä alustoilla.

Manuaalinen muistinhallinta “for dummies” iOS-alustalla osa 2

Edellisessä osassa esiteltiin tapa yksinkertaistaa muistinhallintaa tekemällä luokkamuuttujista propertyja. Tällä kertaa syvennytään hieman siihen miten ja milloin Objective-C kutsuu retain ja release metodeja objekteille. Lopuksi vielä muutama huomautus objektien säilömisestä kokoelmien sisällä.

Alla olevassa EsimerkkiYksi.h tiedostossa on esitelty muuttuja minunTeksti, josta on tehty property. Objective-C luo propertyille automaagisesti mutator-metodit eli metodit joilla muuttujan sisältöä voidaan helposti manipuloida.

EsimerkkiYksi.h

@interface EsimerkkiYksi : NSObject {
  NSString *minunTeksti;
}

@property(nonatomic,retain) NSString *minunTeksti;

-(void)esimerkkiMetodi;

@end

Alla olevassa Esimerkki.m tiedostossa on havainnollistettu miten minunTeksti objektia voidaan käsitellä gettereilla ja settereilla.

EsimerkkiYksi.m

@implementation EsimerkkiYksi
@synthesize minunTeksti;

-(void)esimerkkiMetodi {
   //Asettaa minunTeksti muuttujaan tekstin "Mun teksti!"
   self.minunTeksti = [NSString stringWithString: @"Mun teksti!"];

   //Tekee saman asian eri syntaksilla.
   [self setMinunTeksti: [NSString stringWithString: @"Mun teksti!"]];

   NSLog(@"Teksti: %@", minunTeksti);

   NSString *toinenTeksti;

   //Asettaa toinenTeksti muuttujan viittaamaan minunTeksti muuttujaan.
   toinenTeksti = self.minunTeksti;
   NSLog(@"Toinen teksti: %@", toinenTeksti);

   //Sama asia eri syntaksilla.
   toinenTeksti = [self minunTeksti];
   NSLog(@"Toinen teksti: %@", toinenTeksti);
}

@end

Ohjelmoija voi myös korvata muuttujiensa mutator-metodit haluamillaan. Yläpuolella olevaan EsimerkkiYksi luokan tapauksessa metodit voisi kirjoittaa auki seuraavanlaisesti:

-(NSString*)minunTeksti {
   return minunTeksti;
}

-(void)setMinunTeksti:(NSString*)uusiTeksti {
   //Nostaa uusiTeksti muuttujan retainCounttia yhdellä. "Ottaa vastuun objektista"
   [uusiTeksti retain];

   //Vapauttaa minunTeksti muuttujan.
   [minunTeksti release];

   //Asettaa minunTeksti muuttujan.
   minunTeksti = uusiTeksti;
}

Jos kyseiset metodit sisällytetään luokkaan niitä kutsutaan aina, kun minunTeksti muuttujaa pyydetään tai asetetaan self notaation kautta. Mahdollisia ongelmatilanteita syntyy jos setterin sisällä kutsutaan retain ja release metodeja väärissä järjestyksissä. Toinen asia mikä pitää muistaa luodessa omia mutator-metodeja on se, ettei niiden sisällä pidä koskaan käyttää self notaatiota.

Alla esimerkki tilanteesta, jossa ohjelma menee loputtomaan looppiin, koska ohjelmoija käyttää getter-metodin sisällä self notaatiota. Jos olet epävarma on parasta olla muokkaamatta propertyille luotuja mutator-metodeja.

//EI NÄIN!!!!
-(NSString*)minunTeksti {
   return self.minunTeksti;
}

Tapauksissa, joissa objekteja säilötään esimerkiksi NSArray tai NSDictionary kokoelmien sisällä on huomioitavaa, että sisään syötettäville objekteille kutsutaan automaattisesti retain metodia. Muistivuotojen välttämiseksi kokoelmiin tulee syöttää vain autoreleasettuja objekteja, ellei objektin oleteta säilyvän kokoelman tuhoutumisen jälkeen. Alla esimerkki kokoelmien käytöstä.

-(void)populoiArray {
   //EI NÄIN!!!
   NSString *testi = [[NSString alloc] initWithString: @"Testi teksti!"];
   self.testiArray = [NSArray arrayWithObject: testi];

   //testi muuttuja ei ole autoreleasettu. Muistivuoto syntyy, kun testArray tuhotaan.
}

-(void)populoiToinenArray {
   //NÄIN
   NSString *testi = [NSString stringWithString: @"Testi teksti!"];
   self.testiArray = [NSArray arrayWithObject: testi];

   //testi muuttuja on autoreleasettu, testiArray ottaa sen haltuun ja vapauttaa sen, kun testArray tuhotaan.
}

Aloittelijan opas säikeisiin (threads) iOS-alustalla

Välillä iOS-ohjelmoinnissa törmää tilanteisiin, joissa ohjelman täytyy suorittaa paljon asioita ennekuin jokin tieto voidaan näyttää käyttäjälle. Nämä asiat voivat olla esimerkiksi XML-tiedoston parsiminen, viestit palvelimelle tai raskaat laskentarutiinit. Käyttäjän näkökulmasta on tärkeää, ettei käyttöliittymä jäädy missään vaiheessa siitä huolimatta, kuinka paljon ohjelma käsittelee tietoa. Jos ohjelma suorittaa kaiken yhdessä säikeessä voi käyttökokemus jäädä heikoksi. Tämän takia useat ohjelmointikielet Objective-C mukaan lukien tarjoavat mahdollisuuden suorittaa asioita samanaikaisesti säikeissä.

Säikeet eli threadit saattavat alussa kuulostaa monimutkaisilta. Objective-C:ssä threadien käyttö on onneksi hyvin yksinkertaista. Helpoin tapa tehdä ohjelmatasi monisäikeinen on käyttää NSObject luokan mukana tulevaa performSelectorInBackground:withObject: metodia. Se mahdollistaa minkä tahansa metodin suorittamista taustalla ilman, että käyttöliittymä jäätyy metodin suorituksen ajaksi.

Alla on yksinkertaistettu esimerkki luokasta, joka suorittaa taustalla paljon laskentaa.

MinunLaskuri.h

@interface MinunLaskuri : NSObject {
  //Tyhjä
}

-(void)laskeMiljoonaan;

@end

MinunLaskuri.m

@implementation MinunLaskuri

-(id)init {
  if ( (self = [super init]) ) {
    [self performSelectorInBackground: @selector(laskeMiljoonaan) withObject: nil];
  }
  return self;
}

-(void)laskeMiljoonaan {
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

  for (int i = 0; i < 1000000; i++) {
    NSString *teksti = [NSString stringWithFormat: @"numero on %i", i];
    NSLog(@"Laskurin %@", teksti);
  }

  [pool release];
}

@end

Alla oleva rivi luo uuden taustasäikeen ja suorittaa luokan metodin nimeltä laskeMiljoonaan kyseisessä säikeessä jäädyttämättä käyttöliittymää. Metodille annetaan
tässä tapauksessa parametriksi nil, koska se ei ota vastaan mitään parametreja.
[self performSelectorInBackground: @selector(laskeMiljoonaan) withObject: nil];

Seuraavat tärkeät huomioitavat ovat rivit:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[pool release];

Muistinhallinnan kannalta on tärkeää, että jokaisessa ohjelman säikeessä on ainakin yksi NSAutoreleasePool-objekti, joka ottaa vastaan autoreleasetut objektit vapauttaen ne automaattisesti muistista. Kun kirjoittaa metodia, joka suoritetaan taustasäikeessä kannattaa lisätä heti alkuun ja loppuun kyseiset rivit. Tämän jälkeen voi rauhassa koodailla metodin sisälle mitä haluaa. Yläpuolella olevassa esimerkkitapauksessa metodi laskee miljoonaan ja printtaa konsoliin jokaisen numeron.

Lisää tietoa säikeistä löytyy Applen sivuilta

Manuaalinen muistinhallinta “for dummies” iOS-alustalla – Osa 1

Manuaalinen muistinhallinta voi tuntua alussa haastavalta aloittelevalle ohjelmoijalle. Useissa ohjelmointikielissä vastuu muistinhallinnasta on siirretty garbage collectorille, joka hoitaa muistinhallintaa automaattisesti. Apple lisäsi iOS 5.0 version myötä alustalleen ARC:n (Automatic Reference Counting), joka estää tehokkaasti mm. muistivuotoja ja olioiden vapauttamisesta johtuvia kaatumisia. ARC ei tuo Objective-C:lle garbage collectoria vaan se lisää olioille tarvittavat retain ja release kutsut ennen ohjelman kääntämistä. Xcode 4.2 tarjoaa työkalun, jolla olemassa olevia projekteja voi konvertoida ARC-yhteensopiviksi. ARC:n voi myös kytkeä pois päältä tiedostokohtaisesti.

Jos et kuitenkaan pysty tai halua käyttää projektissasi ARC:tä voit noudattaa muutamaa ohjenuoraa, jotka estävät turhia muistivuotoja ja kaatumisia.

Luokkamuuttujat.

Kun luot uuden luokkamuuttujan voit yksinkertaistaa muistinhallinnan tekemällä siitä propertyn ja asettamalle propertylle retain parametrin. Heti tämän jälkeen kannattaa lisätä luokan dealloc metodin sisälle kutsun, jolla vapautetaan muuttuja. Sen jälkeen voit unohtaa muistinhallinnan kyseisen muuttujan osalta.

On vain yksi asia mikä pitää muistaa. Aina kun asetat muuttujaan tietoa käytä self notaatiota ja vain autoreleasettuja olioita. Käyttämällä self notaatiota autoreleasetulle objektille kutsutaan samalla retain metodia, koska propertyyn oli asetettu retain parametri. Kun ottaa tavaksi luoda luokan metodien sisällä vain autoreleasattuja objekteja välttyy monilta ikäviltä muistivuodoilta. Tällöin ohjelmoijan ei täydy koskaan kutsua manuaalisesti olioiden retain ja release metodeja, koska kaikki tarvittava on hoidettu propertyn esittelyssä ja luokan dealloc metodissa.

Alla havainnollistava esimerkki aiheesta.

EsimerkkiYksi.h

@interface EsimerkkiYksi : NSObject {
  NSString *muuttujaYksi;
}

@property (nonatomic,retain) NSString *muuttujaYksi;

-(void)minunMetodi;

EsimerkkiYksi.m

@implementation
@synthesize muuttujaYksi;

-(void)minunMetodi {
  self.muuttujaYksi = [NSString stringWithString: @”Testi teksti”];
}

-(void)dealloc {
  [muuttujaYksi release];
  [super dealloc];
}
@end

Lisää tietoa muistinhallinnasta iOS-alustalla löytyy Applen sivuilta

iOS5-uutuus: UIPagingViewController

iOS5:n mukana tuli uusia mahdollisuuksia muokata valmiiden komponenttien ulkoasua. Lisäksi sovelluskehittäjille tuli tarjolle kokonaan uusia komponentteja. Vaikka nämä komponentit eivät toimi vanhemmilla versioilla, jossakin vaiheessa on perusteltua vaatia käyttäjiltä iOS5-versiota sovelluksen asentamiseksi tai päivittämiseksi. Jo nykyäänkin jotkin sovellukset vaativat toimiakseen iOS5-version – etunenässä Applen omat sovellukset.

Esittelenkin nyt teille uuden komponentin nimeltään UIPagingViewController, joka lisää samanlaisen sivunvaihtoefektin kuin iBooks-applikaatiossa on ollut käytössä alusta asti. Kuvankaappaus lopputuloksesta näkyy kuvassa 1.

Lopputulos

Continue reading iOS5-uutuus: UIPagingViewController