"iphone"
Wednesday, April 13, 2011

iPhone rakenduse tegemine

Eelmises postituses mainisin, et minu matemaatiliste valemite rakendust on praeguseks alla laetud 1000 korda, siinkohal siis valgustaks veidi tagamaid.

Ma ei teinud seda rakendust erilise eesmärgiga, soov oli vaid proovida läbi kogu töövoog alates sellest et on idee, kuni selleni, et rakendust saab AppStorest alla laadida. Idee teket täpselt ei mäleta, igatahes sai selleks matemaatika valemite kuvamine - sisuliselt on tegu spikriga, valid teema ning näed vastavaid valemeid (nt. ruutvõrrandi valemit). Kuna eeldatav sihtrühm krediitkaarti ei oma (tegu siiski kooliõpilastega), siis oli plaaniks teha rakendus tasuta ja selle eest mitte raha küsida.

C keeles ma suurt ei orienteeru, viimased katsetused jäid aastate taha kui tegin TTÜ’s mingeid kodutöid, seega sellele väga keskenduda ei tahtnud. Õnneks on praeguseks saada ka erinevaid toolkit‘e, mis võimaldavad mugavamalt hakkama saada. Minu esimeseks valikuks sai PhoneGap, mis on sisuliselt UIWebView wrapper. Teed HTML lehe, paned selle JavaScriptiga “elama” ja pakid rakenduseks kokku.

Twitterist sain vihje, et on olemas ka parem süsteem nimega Appcelerator, mis sisuliselt on sama, aga ainult UIWebView asemel pakub ehitusklotsidena kõiki native UI elemente ning selmet veebilehena asja kuvada, kompileerib eraldiseisvas failis oleva JavaScripti koodi iPhonele arusaadavaks - ühesõnaga veebilehe asemel kompileeritakse programm native app‘iks.

Struktuur

Rakenduse struktuur on väga lihtne. Põhivaade koosneb kahe elemendiga TabGroup objektist. Esimene element sisaldab “sisukorda”, teine valitud teema valemeid.

Sisukorravaade koosneb TableView elemendist, mille sees on üksikud TableViewRow elemendid. Kusjuures, igale reale on seatud eraldi “onclick” kuular, nii et kui mõnel real vajutada, avatakse valemite vaates vastavad valemid.

Valemite vaates on põhielemendiks WebView, mis kuvab lokaalseid HTML faile. Kõik valemid on GIF pildid, mis asuvad HTML failidega samas kaustas rakenduse sees. Uue teema valimisel näidatakse kasutajale aktiivsuse indikaatorit, mille kaotab WebView küljes olev onload sündmus.

Administreerimine

Valemite sisestamiseks kirjutasin lihtsa veebiliidese, mis võimaldab tekitada kategooriad ning nende alla valemeid sisestada. Kui valemid on sisestatud, käivitan täiendava skripti, mis genereerib rakenduse jaoks vajalikud HTML failid ning koostab ka JSON formaadis sisukorrafaili, mille alusel rakendus faile näidata oskab.

Sisukorrafaili sisu on järgmine:

[
    {
        "title": "Aritmeetika",
        "file": "f3f80b155d7d9af6c53bcfe23f1ea1a5.html"
    },
    {
        "title": "Algebra",
        "file": "589e1e9e690257c13858583381062e49.html"
    },
    {
        "title": "Võrrandite lahendid",
        "file": "54a2708351b891702815e787feed5f69.html"
    },
    {
        "title": "Planimeetria",
        "file": "7a1970deec26f4b79b4c245c03c5f345.html"
    },
    ......
]

Nii on rakenduse sisu lihtne uuendada - tuleb genereerida uued failid (iga kord on failinimed unikaalsed, et vältida puhverdamist) ja rakendus loeb need andmed kindla nimega JSON failist kenasti sisse.

Kood

Kood on kirjutatud täielikult JavaScriptis (lisaks standardsetele võimalustele on kasutusel Appceleratori API’id). Toon siin ära põhiloogika bloki, mis laeb JSON failist sisukorra ja genereerib selle alusel sisukorra tabeli read.

// funktsioon laeb sisukorrafaili ja genereerib
// massiivi tabeli rea elementidega
function generateIndex(){
    var data = [], json, rows = [], row,
        file = Titanium.Filesystem.getFile(
            Titanium.Filesystem.resourcesDirectory,
            "topics", "quefile.json");

    // lae failist JSON
    if (file.exists()) {
        json = file.read();
        try{
            data = JSON.parse(json);
        }catch(E){}
    }

    // koosta tabeli read
    for(var i=0; i<data.length; i++){
        if(!i){
            // globaalne muutuja
            firstpage = data[i].file;
        }
        row = Titanium.UI.createTableViewRow({
            title: data[i].title
        });

        // kuna tegu on tsükliga, loo lokaalne kontekst
        // kahjuks bind puudub, seega vaja nikerdada
        (function(f, t){
            row.addEventListener("click", 
                function(){displayPage(f, t)},
                false);    
        })(data[i].file, data[i].title);

        rows.push(row);

    }
    return rows;
}

Kusjuures rakenduse skriptiosa on ainult 99 rida pikk ja saaks ka veel lühemalt, kuna see on optimeerimata, sisaldab katsete käigus tekkinud jäänukelemente jne.

Valmis rakenduse saab iPhone, iPod ja iPad seadmesse laadida siit.

NB! Et saada õigus iseenda(!!!) telefonis rakendust katsetada ning hiljem valmis rakendus AppStore‘i üles laadida, tuli liituda Apple Developers programmiga, mille aastatasu on $99. Kusjuures, makset ei saa teha online vaid tuleb välja printida avalduse vorm, täita see ära (sh. kanda vormile krediitkaardi andmed) ja see faksida (!!!) Apple numbrile. Kasutasin faksimiseks online teenust, kuhu laadisin üles PDF faili (allkirja ei pannud ise, vaid kopeerisin eesti.ee portaalist enda rahvastikuregistri andmete juurest). Kahjuks ei kasutanud SEB virtuaalkaarti vaid reaalset kaarti ning et igaks juhuks vältida tulevasi probleeme panin kasutatud krediitkaardi hiljem kinni. SEB virtuaalkaardiga seda muret poleks tekkinud.

Tuesday, October 20, 2009

iPhone veebirakendused vol. 3

Eelmistest iPhone veebirakenduste postitusest kirjutasin, kuidas kasutada ära erinevaid iPhone brauseri poolt pakutud võimalusi, loomaks rakendustelaadseid veebilehti. Kuid siiani on nendelt rakendustel olnud üks häda - need töötavad ainult võrgus olles, offline annab rakendus veateate.

Õnneks on ka siin lahendus olemas, tuleb kasutada offline application caching API’t, mille toetus on olemas nii uuemates Firefoxides kui ka Safarites ning seega ka iPhone brauseris.

Lehe puhverdamiseks on esiteks tarvis luua puhvri manifest fail - selles kirjeldame ära, millised ressursid peaks brauser ära tõmbama. Kuna demorakenduses on kõik vajalik ainult HTML failis endas, siis midagi muud puhverdada polegi vaja.

myapp.manifest faili sisu:

CACHE MANIFEST
app.php

Selle jaoks, et manifesti fail oleks brauserile üheselt arusaadav, tuleks paika seada ka vastav mime-tüüp. Kui serveris on võimalik kasutada .htaccess faile, saab seda teha lisades manifesti faili kataloogis asuvasse .htaccess faili rea

AddType text/cache-manifest manifest

Ja viimasena oleks tarvis veebilehe koodis ära märkida, et puhverdamine on kasutusel. Kuna tegu on HTML5 featuuriga, peaks ka doctype olema vastav.

<!DOCTYPE HTML>
<html manifest=”myapp.manifest”>

Kui nüüd avada selline rakendus iPhone brauseriga ning lisada see telefoni töölauale, siis võib rakendust avada ka täiesti offline olekus, mis teeb rakendusest praktiliselt samaväärse kui AppStore’i kaudu hangitud rakendused on. Ainsa vahega, et installida on suhteliselt mugav - seda saab teha otse veebilehelt ning ilma igasuguse itunes kontota.

Selle jaoks, et kontrollida, kas veebileht on avatud otse brauserist või töölaualt (et vahet teha, kas näidata installimise juhendit või mitte), saab kasutada window.navigator omadust standalone.

if (window.navigator.standalone){
    // tee vajalikke asju
}else{
    // näita installimise juhendit
}

Näites kasutatud puhverdamine on suhteliselt primitiivne - võibolla tuleks vahepeal mingeid asju uuesti laadida või tuleks andmete sünkroniseerimiseks kontrollida, kas parasjagu ollakse online või offline jms.  Kõik see on võimalik, tasub lugeda täpsemat spetsifikatsiooni, mille leiad siit.
Wednesday, September 30, 2009

Veebirakendus iPhone jaoks, vol 2 - andmebaas

Eelmises iPhone veebirakenduse teemalises postituses oli juttu rakenduse olemuslikust küljest - kuidas teha veebilehte, mis telefonis käituks kui rakendus. Edasi aga räägiks, et mida selle rakendusega üldse teha saaks.

Üheks olulisemaks asjaks oleks ilmselt kasutaja andmete salvestamine, mingisugune profiili loomine - kui rakendus näeks täpselt samasugune välja kõikide kasutajate korral ja selles puuduks igasugune dünaamilisus, siis poleks rakendust üldse mõtet rakendusena vormistada, vaid piisaks tühipaljast veebilehest.

Andmeid (selle all pean silmas dünaamilisi andmeid, mitte veebilehte ennast) aga ei pea vastupidiselt üldlevinud arvamusele sugugi hoidma ainult serveri poole peal, kus rakenduse avades tõmmatakse serverist andmed telefoni brauserisse. Andmeid saab ka kohe brauseri poolel hoida.

Võimalik on näiteks kasutada eelmises postituses kirjeldatud DOM storage meetodeid (sessionStorage, localStorage), kuid iPhone brauser pakub sellest palju enamat. Nimelt Safari sisaldab endas ootamatult täisfunktsionaalset SQLite andmebaasi, mida saabki ülihästi andmete salvestamiseks kasutada.

Andmebaasiühenduse saab avada järgmiselt

db = openDatabase(db_name:String, db_version:String, db_description:String, 10000);

Päringud käivitatakse transaktsioonidena, kus algselt avatakse andmebaasi suhtes transaktsiooni objekt ning sellega viiakse läbi vajalikud päringud
db.transaction(function(tx) {
  tx.executeSql(sql:String, params:Array, result_callback:Function(tx, results), error_callback:Function(tx, error))
});

Näiteks uue tabeli loomine andmebaasi käiks nii
//CREATE TABLE my_table
tx.executeSql("CREATE TABLE my_table (id REAL UNIQUE, name TEXT)", 
  [], // No params to provide
  function(tx,result) { // results callback function
    alert('Success!');
  },
  function(tx,error) { // error callback function
    alert('Error creating table - ' + error.message);
  }
});

Andmete sisestamine käiks tavalise INSERT lausega
//INSERT ROWS TO my_table
tx.executeSql("INSERT INTO my_table (id, name) VALUES(?,?)", 
  [1,"minunimi"], // first param stands for "id" and the second for "name"
  function(tx,result) { // results callback function
    alert("Success!")
  },
  function(tx,error) { // error callback function
    alert('Error - ' + error.message);
  }
});

Ja andmete lugemine vastavalt SELECT lausega
//READ VALUES FROM my_table
tx.executeSql("SELECT * FROM my_table WHERE id=? AND name=?", 
  [1,"minunimi"], // first param stands for "id" and the second for "name"
  function(tx,result) { // results callback function
    if(result && result.rows){
      for (var i = 0; i < result.rows.length; ++i) {
        var row = result.rows.item(i);
        alert(row['name']);
      }
    }
  },
  function(tx,error) { // error callback function
    alert('Error - ' + error.message);
  }
});

Tähele tasub panna kuidas käib muutujate sisestamine SQL lausesse - selle jaoks tuleb vajalikku kohta sisestada küsimärk (?), ning selle järjekorrale vastavalt tuleb lisada SQL päringu järgmisse parameetrisse massiivi elemendiks tegelik väärtus. Nii ei pea muretsema andmete puhastamise pärast, seda teeb andmebaasi API ise.

Seda, et kui palju aplikatsiooni andmebaas mahtu kulutab ja kui palju mahtu veel alles on, saab telefonis kontrollida seadete menüüst. Settings->Safari->Databases->andmebaasi_nimi

Reeglina peaks andmebaasi suuruseks olema 5 MB. Puhtalt andmete mõttes on seda üsna palju - selle ruumi sisse saaks näiteks vabalt mahutada plain text formaadis kõik Sõrmuste isanda raamatud.

Nii, et kui siduda omavahel iPhone veebirakenduse, andmebaasi ja ühes varasemas postituses kirjeldatud graafikateegi (see töötab ka iPhone brauseris), on juba täiesti võimalik ehitada iPhone platvormile täisfunktsionaalseid aplikatsioone. Näiteks graafilisi mänge vms.

—-
Täiendus: Algselt jäi mainimata kes seda brauseri andmebaasi juba kasutavad. Seda teeb näiteks Gmail, kes salvestab kasutaja viimased kirjad brauseri andmebaasi. Seega kui avada telefonis Gmail, on koheselt kirjad ees. Alles peale baasis olevate kirjade kuvamist hakkab brauser serverist kontrollima, kas vahepeal on midagi juurde tulnud.

———
Veel üks täiendus: Versioon andmebaasiühenduse loomisel peaks hetkel olema “1.0”

Wednesday, September 23, 2009

Kuidas luua iPhone veebiaplikatsioone

Kuigi iPhone puhul on rohkem tuntud App Store kaudu laetavad aplikatsioonid (Eestis toodab selliseid näiteks Indilo), siis tegelikult võimaldab ka telefoni brauser aplikatsioonilaadseid asju jooksutada.

Nimelt on võimalik veebilehe HTML koodis telefonile teada anda, et seda lehte tuleks kasutada kui aplikatsiooni. See tähendab, et lehte vaadates eemaldatakse brauseri kasutajaliides (aadressiriba ja olekuriba) ning kogu ekraanipind eraldatakse veebilehele.

Kuna brauser võimaldab salvestada veebilinkide otseteid (koos sobiva ikooniga, mille saab samuti veebilehe poolt ette anda) telefoni töölauale, saavutamegi väga lihtsate vahenditega efekti, nagu oleks tegu tavalise aplikatsiooniga.

Taoline veebiaplikatsioon saab ka määrata “startup” pildi, mida näidatakse kasutajale lehe laadimisel peale telefoni töölaual oleva aplikatsiooni otsetee avamist.

Aga nüüd kõigest lähemalt.

Esiteks oleks vaja veebilehes anda brauserile märku, et tegu on aplikatsiooniga, selle jaoks saab HTML lehe päisesse seada mõned meta-sildid.

<meta content="yes" name="apple-mobile-web-app-capable"></meta>
<meta content="black-translucent" name="apple-mobile-web-app-status-bar-style"></meta>
<meta content="telephone=no" name="format-detection"></meta>
<link href="startup.png" rel="apple-touch-startup-image"></link>
<link href="icon.png" rel="apple-touch-icon"></link>
<meta name = "viewport" content = "width = device-width,maximum-scale=1.0,minimum-scale=1.0, initial-scale = 1.0, user-scalable = no"></meta> 

Esimene rida - apple-mobile-web-app-capable annab teada, et veebilehte tuleks käsitleda aplikatsioonina ning brauser peaks oma kasutajaliidese elemendid ära peitma. Aplikatsiooni staatust arvestatakse ainult siis, kui leht avatakse telefoni töölaual oleva otsetee kaudu, mitte brauseriga otse aplikatsiooni aadressile minnes.

Teine rida - apple-mobile-web-app-status-bar-style seab ainsa säilinud kasutajaliidese elemendi stiili - telefoni ülemine kitsas riba, mis näitab levi tugevust, kellaaega ja aku täituvust.

Kolmas rida format-detection keelab telefonil konverteerida lehel asuvaid numbreid klikitavateks telefoninumbriteks.

Neljas rida - apple-touch-startup-image määrab ära pildi (320x480 px, portrait), mida näidatakse lehe laadimisel.

Viies rida - apple-touch-icon määrab ära otsetee ikooni (57x57 px). Ikoon peaks olema tavaline png fail - telefon ise muudab selle nurgad ümaraks ja lisab kerge peegelduse.

Kuues rida - viewport määrab ära mitmed vajalikud seaded (need töötavad ka otse veebi kaudu lehe avades, mitte ainult otseteed kasutades), näiteks selle et kasutaja ei saa lehte ise suurendada ega vähendada.

CSS

Peamised kaks CSS definitsiooni mida kasutada, oleks body[orient=”landscape”] {} ja body[orient=”portrait”]{}, need nimelt võimaldavad määrata lehele eri stiile vastavalt telefoni orientatsioonile. Lisaks antud definitsioonidele on võimalik veel kasutada mitmeid -webkit algusega eristiile, mis töötavad ka tavalises Safari brauseris.

JavaScript

Lisaks tuttavale käsustikule lisab iPhone JavaScripti window objektile paar uut meetodit ja omadust, mis on siis seotud ekraani orientatsiooniga.

1. window.orientation - omadus, mis sisaldab endas hetke ekraani orientatsiooni. Väärtuseks on üks järgmisest massiivist [0, 90, -90]. Kui omaduse väärtus on 90, siis “Home” nupp jääb ekraanist paremale.

2. window.onorientationchange - sündmus, mis rakendub kui kasutaja keerab telefoni, nii et ekraani orientatsioon muutub.

Näitena, et kuidas kõike seda kokku panna valmistasin lihtsa veebilehe, mis käitub täpselt vastavalt kirjeldatule. Täiendavalt saab aplikatsioon aru, et kas seda vaadatakse veebivaades või aplikatsioonivaates ning käitub vastavalt (veebivaates näitab juhendit, kuidas aplikatsiooni “installida”).

Näite leiab siit (ava iPhone või iPod touch brauseris, lähtekoodi võid vaadata suvalise brauseriga).




My Tumblr Likes ♥