Requerimientos
- Conocimientos de Javascript
- iOS Development Program License: iOS SDK, Xcode
- Titanium Studio (necesitas registrarte, totalmente gratis)
- SQLite Database Browser o SQLiteStudio
- Mac OS X 10.6 o Posterior (Solo necesario en el desarrollo para iPhone)
Info Adicional
- Titanium Mobile Kitchen Sink
- Working with Local Data
- Short iPad/ iPhone image size guide
- Third-party Tools
- Titanium Appcelerator vs PhoneGap vs Adobe Air for Mobile
Hoy en día el desarrollo de App móviles ha adquirido un gran auge, siendo uno de los temas de mayor atención por parte de los desarrolladores. Esto como consecuencia nos lleva al afán por aprender aquellos lenguajes en los cuales se basan las plataformas móviles más comunes, dígase Android, iPhone, Blackberry, etc.
Lo cual muchas veces nos resulta tedioso si estamos acostumbrado a un lenguaje en específico; es por eso que surgen tecnologías como Titanium Mobile, PhoneGap, Adobe Air, Corona SDK, entre otras, para brindarnos la facilidad de desarrollar aplicaciones móviles usando nuestros conocimientos sobre lenguajes como Javascript, o herramientas web como el HTML/CSS.


De las tecnologías anteriormente mencionadas estaremos utilizando Titanium Mobile, desarrollada por Appcelerator (www.appcelerator.com) quien recientemente compró Aptana (desarrolladores de uno de los IDE más reconocidos basado en Eclipse), la cual para mi es la que te ofrece un ambiente puramente nativo comparada con las demás, ya que estas básicamente te montan tu App en un Web View (Página Web) con un API que te ofrece acceso los componentes de la plataforma móvil en que estas desarrollando, como es el caso de PhoneGap. Pero hay algo bueno en PhoneGap y es que tiene el mayor soporte de plataformas móviles en el mercado, pero no entraremos en detalles por ahora.
Volviendo a Titanium Mobile, este nos permite desarrollar aplicaciones para iPhone, Android y Blackberry (Beta solo para usuarios con suscripción pagada) de manera gratis. Para instalar Titanium Mobile es fácil, en los requerimientos están los links necesarios pero en el caso de que necesiten una ayudita más amplia pueden ver este link: http://wiki.appcelerator.org/display/guides/Getting+Started+with+Titanium o www.appcelerator.com para que tengan una mayor idea de que se trata Titanium Mobile.
Para este tutorial crearemos un App simple donde podremos registrar y listar datos usando una base de datos Sqlite viendo de esta forma las funciones más comunes del API de Titanium Mobile. Esta vez nos centraremos solo en el desarrollo para iPhone, ya en otros tutoriales hablaremos de Android. Como pudieron ver en los requerimientos se necesita una suscripción en el iOS Development Program de Apple, el cual cuesta unos $US 99 anuales y trae consigo la instalación de certificados y otras herramientas para tu Mac, cuyo proceso no cubro aquí pero sin problemas pueden enviarme un mail y les ayudo con eso.
Una vez descargado e instalado el Titanium Studio, lo ejecutamos (nos pedirá por primera vez nuestro ID y Password obtenidos al registrarnos) y procedemos a crear un proyecto nuevo en el menu File > New > Titanium Mobile Project.

Nos aparece la ventana para la creación de un nuevo proyecto donde especificamos los datos básicos del proyecto:

- Project name: Nombre del proyecto y del App
- App id: Id del app usado para empaquetar/distribuir el App, esto vendría siendo al package name en Android.
- Titanium SDK: la versión del SDK de Titanium usada para compilar el proyecto
- Deployment targets: plataformas para las cuales crearemos el App
Hacemos clic en finish. Ahora Titanium Studio creara la estructura del proyecto y nos presenta la ventana de propiedades del mismo, muy parecida a la ventana anterior:

Observando la estructura del proyecto podemos ver lo siguiente:

- Build folder: en este folder es donde titanium genera el código nativo del App, es decir los archivos en Ojective-C, Java. Este folder puede ser ignorado por el usuario ya que es solo usado por Titanium para compilar tu App.
- Resources folder: en este se guardan todo los archivos con nuestro código, imágenes, base de datos pre-creadas por nosotros, etc.
- tiapp.xml : es el archivo de configuracion de nuestro App, el cual contiene todas la propiedades anteriormente proporcionadas.
Habiendo entendido los primeros pasos, ya estamos listos para concentrarnos en el código. En la creación del proyecto, Titanium ya nos crea un App funcional, el cual contiene dos tabs y dos labels. Todo esto lo podemos ver en el archivo app.js, el cual es el archivo principal y punto de inicialización de toda App creada con Titanium.
// background color del master window
Titanium.UI.setBackgroundColor('#000');
// creamos el tabgroup
var tabGroup = Titanium.UI.createTabGroup();
//
// creamos el tab principal y le asignamos un ventana
//
var win1 = Titanium.UI.createWindow({
title:'Tab 1',
backgroundColor:'#fff'
});
var tab1 = Titanium.UI.createTab({
icon:'KS_nav_views.png',
title:'Tab 1',
window:win1
});
var label1 = Titanium.UI.createLabel({
color:'#999',
text:'I am Window 1',
font:{fontSize:20,fontFamily:'Helvetica Neue'},
textAlign:'center',
width:'auto'
});
win1.add(label1);
//
// creamos otro tab y le asignamos una ventana
//
var win2 = Titanium.UI.createWindow({
title:'Tab 2',
backgroundColor:'#fff'
});
var tab2 = Titanium.UI.createTab({
icon:'KS_nav_ui.png',
title:'Tab 2',
window:win2
});
var label2 = Titanium.UI.createLabel({
color:'#999',
text:'I am Window 2',
font:{fontSize:20,fontFamily:'Helvetica Neue'},
textAlign:'center',
width:'auto'
});
win2.add(label2);
//
// agregamos los tabs al tabgroup
//
tabGroup.addTab(tab1);
tabGroup.addTab(tab2);
// abrimos el tabgroup
tabGroup.open();
Para nuestra App este archivo no cambiara tanto, ya que trae la estructura básica que necesitamos. Una vez modificado quedara de esta manera:
//incluimos demas ventanas y utilidades
Titanium.include('insertar.js','listar.js');
// background color del master window
Titanium.UI.setBackgroundColor('#fff');
// creamos el tabgroup
var tabGroup = Titanium.UI.createTabGroup();
//
// creamos el tab principal y le asignamos la ventana de insertar
//
var win1 = insertarWin();
var tab1 = Titanium.UI.createTab({
icon:'KS_nav_views.png',
title:'Insertar',
window:win1
});
//
// creamos otro tab y le asignamos la ventana de listar
//
var win2 = listarWin();
var tab2 = Titanium.UI.createTab({
icon:'KS_nav_ui.png',
title:'Listar',
window:win2
});
//
// agregamos los tabs al tabgroup
//
tabGroup.addTab(tab1);
tabGroup.addTab(tab2);
// abrimos el tabgroup
tabGroup.open();
El código en si es muy descriptivo. Lo primero es que incluimos los archivos donde tendremos definidas cada una de las ventanas correspondientes a cada tab mediante la función Titanium.include(), la cual es muy parecida a la función include() en PHP. Luego creamos las ventanas que veremos en cada tab, estas reciben un objeto Titanium.UI.Window que retornaremos en las funciones insertarWin() y listarWin(), definidas en los archivos incluidos al principio.
Otra forma de crear la ventana es haciendo una referencia a otro archivo mediante la propiedad ‘url’ del objeto Titanium.UI.Window, pero para mayor performance al cargar las ventanas es recomendable hacerlas creando una función que nos devuelva una ventana, ya que de esta forma la ventana se carga con todo su contenido, es decir que de hacerlo asignando un archivo en la propiedad url la ventana se carga primero y luego se carga su contenido, lo cual hace que veamos una ventana vacía y luego los elementos que contiene.
De todas manera no hay de que preocuparse si tu ventana es sencilla y lo haces de la segunda forma ya que este ‘delay’ se apreciaría si la ventana contiene muchos elementos en ella, como en el caso de un tableView.
CREANDO LA BASE DE DATOS
Una vez creada la estructura de nuestro archivo principal procederemos a crear nuestra base de datos ya que la estructura de esta nos ayudara a comprender los siguientes pasos. Para esto abrimos nuestro gestor de SQLite preferido (ver enlaces en requerimientos), en mi caso uso SQLite Database Browser pero pueden usar otro cualquiera. Procedemos a crear la base de datos y quedara con la siguiente estructura:

Una vez creada la base de datos la guardamos como ‘developers.sqlite’ o ‘developers.db’ en la carpeta Resources de nuestro proyecto.
CREANDO LA SECCION DE INSERTAR NUEVO DEVELOPER
Creamos ahora el archivo ‘insertar.js’ en el cual llevaremos a cabo todo el proceso de insertar un nuevo developer en la BD. Básicamente tendremos un formulario en el cual se llenen los datos correspondiente a cada campo en la base de datos.
var insertarWin = function() {
//creamos la ventana
var win = Titanium.UI.createWindow({
title : 'Insertar',
backgroundColor : '#fff'
});
var vista = Ti.UI.createScrollView({backgroundColor : 'transparent',width:320,height:480,top:5});
win.add(vista);
//logo de developers.do
var logo = Ti.UI.createImageView({
image : 'images/logo.jpg',
width : 128,
height : 88,
top : 300,
center:{x:(win.width/2),y:50}
});
vista.add(logo);
//creamos los textfields
var nombre = Ti.UI.createTextField({hintText:'Nombre',height:30, width:300,top:130,left:10,borderStyle:Ti.UI.INPUT_BORDERSTYLE_ROUNDED});
vista.add(nombre);
var apellido = Ti.UI.createTextField({hintText:'Apellido',height:30, width:300,top:170,left:10,borderStyle:Ti.UI.INPUT_BORDERSTYLE_ROUNDED});
vista.add(apellido);
var empresa = Ti.UI.createTextField({hintText:'Empresa',height:30, width:300,top:210,left:10,borderStyle:Ti.UI.INPUT_BORDERSTYLE_ROUNDED});
vista.add(empresa);
var url = Ti.UI.createTextField({hintText:'URL',height:30, width:300,top:250,left:10,borderStyle:Ti.UI.INPUT_BORDERSTYLE_ROUNDED});
vista.add(url);
//creamos el boton de insertar
var insertar_btn = Ti.UI.createButton({title:'Insertar', width:200,height:40,center:{x:(win.width/2),y:320},borderStyle:Ti.UI.INPUT_BORDERSTYLE_ROUNDED});
vista.add(insertar_btn);
//click
insertar_btn.addEventListener('click',function(e){
if(nombre.value == '' || apellido.value == ''){
alert('Favor llenar el Nombre y el Apellido.');
return;
}
//insertamos dev en la bd
insertarDev({
nombre:nombre.value,
apellido:apellido.value,
empresa:empresa.value,
url:url.value
});
});
win.addEventListener('focus', function(e) {
vista.scrollTo(0, -5);
});
nombre.addEventListener('blur',function(e){
vista.scrollTo(0, -5);
});
apellido.addEventListener('blur',function(e){
vista.scrollTo(0, -5);
});
empresa.addEventListener('blur',function(e){
vista.scrollTo(0, -5);
});
url.addEventListener('blur',function(e){
vista.scrollTo(0, -5);
});
vista.addEventListener('scroll',function(e){
if(e.dragging){
win.fireEvent('focus');
}
});
//retornamos el objeto de la ventana
return win;
}
Lo primero es que creamos el objeto de la ventana que estaremos viendo en el tab de insertar, luego le agregamos el logo de Developers.do junto con los textfields y el botón de insertar. En el caso del botón le agregaremos a este un listener para el momento en que sea presionado.
La cuestión es que cuando sea presionado el botón validamos si el nombre y el apellido no están vacíos y si así es procedemos a insertar en la base de datos mediante la función insertarDev(), definida en funciones.js, la cual recibe como parámetro un objeto con los datos contenido en cada textfield. En el caso de ocurrir un error presentamos una alerta mediante alert() la cual es un alias del objeto Titanium.UI.AlertDialog.
//insertar developers en la db
var insertarDev = function(datos) {
if( typeof (datos) === 'object') {
try {
//instalamos la bd
var db = Ti.Database.install('developers.db', 'developers');
//insert
db.execute('INSERT INTO developers (nombre, apellido, empresa, url) VALUES(?,?,?,?)', datos.nombre, datos.apellido, datos.empresa, datos.url);
db.close();
alert('Developer insertado!');
} catch(e) {
alert(e);
}
} else {
return false;
}
};
En la función insertarDev() podemos ver como realizar un insert en la base de datos que creamos anteriormente. Titanium Mobile cuenta con dos funciones principales para acezar la base de datos, Titanium.Database.install() la cual es útil si vas a utilizar una base de datos ya integrada con tu App, como es nuestro caso, ya que esta función copia la base de datos desde la carpeta Resources a la carpeta interna llamada ‘database’. Hay que tener en cuenta que si la base de datos ya existe en la carpeta de ‘database’ la función abre la base de datos y nos retorna un objeto Titanium.Database.DB con el cual podemos acezar la BD.
Por otro lado tenemos Titanium.Database.open(), esta función abre una base de datos ya existente en la carpeta ‘database’ y en el caso de no existir crea una nueva (vacía) y nos retorna un objeto Titanium.Database.DB. Algo que debemos tener en cuenta es que cada vez que terminemos de trabajar con la base de datos debemos cerrar la conexión con esta mediante la función .close() del objeto Titanium.Database.DB, ya que una BD en SQlite es un archivo de texto que en operaciones de escritura (INSERT, UPDATE, etc.) se bloquea permitiendo un solo acceso hasta que la conexión sea cerrada. Si no lo hacemos entonces cuando tratemos de ejecutar otra operación recibiremos una excepción del tipo “DatabaseObjectNotClosed”.


CREANDO LA SECCION DE LISTAR DEVELOPERS
Luego de haber insertado varios datos en la BD queremos listarlo, para lo cual crearemos otro archivo llamado ‘listar.js’. Aquí presentaremos un tableview con cada developer en la BD, así como eliminar un registro de la misma.
var listarWin = function() {
//creamos la ventana
var win = Titanium.UI.createWindow({
title : 'Listar',
backgroundColor : '#fff'
});
//botones
var Eliminar_btn = Titanium.UI.createButton({
title : 'Eliminar'
});
var Listo_btn = Titanium.UI.createButton({
title : 'Listo'
});
//agregamos el Eliminar_btn
win.rightNavButton = Eliminar_btn;
//creamos el tableview
var tableview = Ti.UI.createTableView({
minRowHeight : 60,
maxRowHeight : 70,
editable : true
});
//agregamos el tableview a la ventana actual
win.add(tableview);
//cargamos la lista de
var cargarLista = function() {
//arreglo con los datos del tableview
var datos = [];
//instalamos la bd
var db = Ti.Database.install('developers.db', 'developers');
var filas = db.execute('SELECT * FROM developers');
//para alternar el color a cada fila
var c = 0;
var rowbg = '#fff';
//iteramos cada resultado
while(filas.isValidRow()) {
//asignamos el color de fondo de la fila
rowbg = (c % 2 == 0) ? '#fff' : '#edf4fc';
//cramos el row
var row = Ti.UI.createTableViewRow({
height : 'auto',
textAlign : 'left',
width : '100%',
className : 'dos_colores',
backgroundColor : rowbg
});
//asignamos el id del DEV a cada fila
row.dev_id = filas.fieldByName('id');
var nombre_completo = Ti.UI.createLabel({
text:filas.fieldByName('nombre') + ' '+ filas.fieldByName('apellido'),
width:'auto',
height : 'auto',
left : 15,
top : 10,
textAlign : 'left',
font : {
fontSize : 18,
fontWeight : 'bold'
},
color : '#000'
});
var empresa = Ti.UI.createLabel({
text:filas.fieldByName('empresa'),
width:'auto',
height : 'auto',
left : 15,
top : 30,
textAlign : 'left',
font : {
fontSize : 15
},
color : '#000111'
});
var url = Ti.UI.createLabel({
text:filas.fieldByName('url'),
width:'auto',
height : 'auto',
left : 15,
top : 45,
bottom:10,
textAlign : 'left',
font : {
fontSize : 15
},
color : '#000111'
});
//agremos labels al row
row.add(nombre_completo);
row.add(empresa);
row.add(url);
datos.push(row);
c++;
filas.next();
}
//liberamos resources
filas.close();
db.close();
tableview.data = datos;
}
/*****************************************************************************
*EventListeners
****************************************************************************/
//currentwindow focus event
win.addEventListener('focus', function(e) {
//cargamos la lista
cargarLista();
});
//delete eventlistener
tableview.addEventListener('delete', function(e) {
var resultado = eliminarDev(e.rowData.dev_id);
});
//eliminar click event
Eliminar_btn.addEventListener('click', function(e) {
win.rightNavButton = Listo_btn;
tableview.editing = true;
});
//listo click event
Listo_btn.addEventListener('click', function(e) {
win.rightNavButton = Eliminar_btn;
tableview.editing = false;
});
//retornamos el objeto de la ventana
return win;
}
Como podemos ver creamos un tableview y lo agregamos a la ventana actual. Un tableview esta conformado por una serie de tableview rows (Titanium.UI.TableViewRow), los cuales crearemos con los datos de cada developer en la BD y los asignaremos al tableview mediante la propiedad ‘data’ del objeto Titanium.UI.TableView. Para cargar la lista de developers creamos una función que llamaremos cada vez que hagamos focus en la ventana (refresquemos la ventana).
En esta función simplemente ejecutamos un SELECT lo cual nos devuelve un resultset que iteraremos creando un tableviewrow y almacenándolo en un arreglo en cada iteración. Como podemos ver en el while() usamos la funcion .isValidRow() del objeto resultset la cual nos devuelve true siempre que la fila actual sea valida. Para iterar el resultset hacia la siguiente fila usamos la función .next() del objeto la cual nos devuelve false cuando ya no hayan mas filas en el resultset y por consecuencia .isValidRow() devolvera false terminando de esta forma el loop. Al final del loop cerramos el resultset para liberar memoria y también la conexión con la BD, para luego llenar el tableview con los tableviewrows que hemos creado en el loop.
Otra de las cosas nuevas que vemos en ‘lista.js’ es la oportunidad de borrar tanto un tableviewrow como un récord de la BD. Para esto creamos dos botones ‘Eliminar’ y ‘Listo’ que intercambiaremos en el navigation bar. La eliminación de un tableview row se lleva a cabo poniendo el tableview en estado de edicion.
Para eliminar el record de la BD usaremos el evento ‘delete’ del tableview ejecutado cuando se elimina un tableviewrow. Para esto creamos una función eliminarDev() que recibe como parámetro el id del record a eliminar, este id se lo hemos asignado a una variable cualquiera creada en el objeto del tableviewrow que en nuestro caso la nombramos como ‘dev_id’, de la siguiente forma:
//asignamos el id del DEV a cada fila
row.dev_id = filas.fieldByName(‘id’);
Y el código para eliminarDev() queda de la siguiente manera:
//eliminar dev en la db
var eliminarDev = function(dev_id) {
if( typeof (dev_id) != 'number') {
return false;
}
try {
//instalamos la db desde la carpeta resources
var db = Ti.Database.install('developers.db', 'developers');
db.execute('DELETE FROM developers WHERE id = ' + dev_id);
//close db
db.close();
return true;
} catch(e) {
alert(e);
}
};

De esta forma el código de nuestra App esta listo. Lo único que nos falta es cambiar el splash screen presentado al iniciar la App y el icono de la misma, para esto sustituimos las imágenes en Resources/iphone. Algo que hay que tener en cuenta con el iPhone es que a partir del iOS 4 existe la Retina Display, la cual presenta una mayor resolución.
Por esta razón debemos incluir dos imágenes de diferente resolución por cada imagen que vayamos a utilizar en el proyecto si queremos que cuando nuestra App este corriendo en un iPhone con retina las imágenes no se vean de mala calidad. Para esto por cada imagen que vayamos a utilizar incluimos otra del doble de resolución y con el mismo nombre de la original pero con el post-fijo ‘@2x’. Una ves hecho esto estamos listo para probar en nuestro iOS Device o publicar en el App Store, proceso que no cubro en este tutorial pero que sin problemas puedo ayudar si necesitan una mano con eso.
CODIGO FUENTE
José Gustavo Rodríguez Baldera
Ing. Telemático
Web & Titanium Mobile Developer @ GonzoTech, Inc
http://twitter.com/gbaldera














