Jul 28

Sorry, this entry is only available in Español.

VN:F [1.9.8_1114]
Rating: 0.0/5 (0 votes cast)
VN:F [1.9.8_1114]
Rating: +1 (from 1 vote)
Tagged with:
Jun 06

Tomorrow at 10AM PST, 7PM Spanish time, starts the Apple Worldwide Developer Conference, at Moscone West in San Francisco, California and will last until Friday 11th. It is expected with great enthusiasm because all of the new things that are expected to be presented, one of them the official iPhone 4.0, although it was earlier presented by Gizmodo, they paid 5.000$ for a supposed iPhone 4.0 found in a bar and that at the end Apple reclaim as their own, it’s still generating rumors. Will there be some modifications to the model shown or will it be the real iPhone 4.0?

Not only the phone will be presented but other many things might see the light:

  • iPhone OS 4.0.
  • Apple TV.
  • Mac OS X 10.6.4.
  • Safari 5
  • Versión gratis del MobileMe

The venue can be followed in many blogs and we hope there will be too some live streaming. Here there are some places where might be posible to follow it.

Blogs

GDGT Live
Gizmodo
MacRumors Live
The Apple Blog
CNET Live

Streams
Watch Apple WWDC 2010 event live online on CrunchGear
Watch WWDC 2010 live streaming on Twit Live TV
Watch 2010 WWDC iPhone HD event on LiveTechEvents

Information obtained from various places in the Internet.

VN:F [1.9.8_1114]
Rating: 0.0/5 (0 votes cast)
VN:F [1.9.8_1114]
Rating: 0 (from 0 votes)
Tagged with:
May 23

VN:F [1.9.8_1114]
Rating: 5.0/5 (1 vote cast)
VN:F [1.9.8_1114]
Rating: +1 (from 1 vote)
Tagged with:
May 16

Today I will explain how we can play a sound when a button is pressed, in fact, what I will explain can be used in many other situations and not only for buttons, because what I will do is to create a SystemSoundID which is used, among another things, to play short (30 seconds or less) sounds. But as an example, I will use a button.

To be able to reproduce sounds we will need to add the AudioToolbox Framework to our project.

Imagine we have a UIViewController and the view it is controlling, add a UIButton to the view using Interface Builder or do it programmatically, as you like most. If you haven’t added yet the Framework to the project, do it now, once you have done it we have to import it to our view controller.

In the header file (.h) of our controller add a variable of type SystemSoundID and a method which will be called when the button is pressed.

#import <UIKit/UIKit.h>
#import <AudioToolbox/AudioToolbox.h>
 
@interface testKeyboardViewController : UIViewController <UITextFieldDelegate> {
 
	SystemSoundID buttonSoundID;
}
- (IBAction)buttonPressed;
 
@end

Now we need a sound file, with the sound we want, for example call it ButtonSound.caf, now, and in the viewDidLoad of our controller add the following lines to create the reference to our sound.

- (void)viewDidLoad {
    [super viewDidLoad];
	NSString *path = [[NSBundle mainBundle] pathForResource:@"ButtonSound" ofType:@"caf"];
	AudioServicesCreateSystemSoundID((CFURLRef)[NSURL fileURLWithPath:path], &buttonSoundID);	
}

As you can see in the code, we need the path for our file, if you have add the file to your group Resources in Xcode, the code above should work for you. Take a look at NSBundle if that doesn’t work to look for another method that allows you to find the path to the file.

With this we have the reference to the sound, now we only need to play it when we need, in this case, we want to play it when the button is pressed. Add to the method that is called when the button is pressed, the following lines

- (IBAction)buttonPressed {	
	AudioServicesPlaySystemSound(buttonSoundID);
}

Now you should be hearing the sound when you press the button.

When you don’t need anymore the sound, you can use the following function to remove the reference, for example in the viewDidUnload of our controller.

- (void)viewDidUnload {
	AudioServicesDisposeSystemSoundID(buttonSoundID);
}

I hope that this post is useful and now you are able to add all kind of short sounds to your application to give it a bit more of life.

VN:F [1.9.8_1114]
Rating: 5.0/5 (2 votes cast)
VN:F [1.9.8_1114]
Rating: +2 (from 2 votes)
Tagged with:
May 05

Es una de las preguntas más frecuentes en los foros de programación iPhone.

Por qué cuando ponemos <img src=”miFoto.jpg” /> no sale nada si tenemos miFoto.jpg entre nuestros ficheros de recursos añadidos en XCode?

Supongamos que el código que usamos para cargar el html del nuestro UIWebView es el siguiente:

NSString *html = @"<html><body><img src='miFoto.jpg' /></body></html>";
[miUIWebView loadHTMLString:html baseURL:nil];

Con esto vemos que no se muestra ninguna imagen. El problema está en que UIWebView no sabe donde buscar la foto. Nosotros le hemos dicho la foto que queremos pero no hemos dicho donde tiene que buscarlo, para eso tenemos el parámetro baseURL.

Nuestra imagen está entre nuestros ficheros de recursos por lo que la UIWebView tiene que ir a buscar la imagen entre los ficheros de recursos y para eso tenemos que pasar el path de la carpeta de recursos vía el parámetro baseURL.

Entonces, la versión correcta del código sería el siguiente:

NSString *path = [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
NSString *html = @"<html><body><img src='miFoto.jpg' /></body></html>";
[miUIWebView loadHTMLString:html baseURL:path];

Y todo esto que se ha explicado también es válido en el caso de que queramos incluir scripts externos o ficheros CSS.

Sorprendentemente hay gente que no conoce esta solución tan simple y hacen “cosas raras” sólo para poder mostrar fotos.

Una forma poco común de mostrar imágenes es convertirlos a base64 y usar la esquema data:URI para mostrarlos en una página web.

Ejemplo:

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoA
AAAKCAYAAACNMs+9AAAABGdBTUEAALGPC/xhBQ
AAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0S
U1FB9YGARc5KB0XV+IAAAAddEVYdENvbW1lbnQAQ3Jl
YXRlZCB3aXRoIFRoZSBHSU1Q72QlbgAAAF1JREFUGNO9zL
0NglAAxPEfdLTs4BZM4DIO4C7OwQg2JoQ9LE1exdlYvBBeZ7
jqch9//q1uH4TLzw4d6+ErXMMcXuHWxId3KOETnnXXV6M
Jpcq2MLaI97CER3N0vr4MkhoXe0rZigAAAABJRU5ErkJggg==" alt="Red dot" />

Esto en la mayoría de los casos no se usa pero también tiene su utilidad en diferentes entornos. Por ejemplo antes de la versión 3.0 de iPhone OS no podíamos adjuntar imágenes a los emails desde nuestro código y muchos lo solucionaron parcialmente pasando la imagen como texto (en base 64).

VN:F [1.9.8_1114]
Rating: 5.0/5 (1 vote cast)
VN:F [1.9.8_1114]
Rating: 0 (from 0 votes)
Tagged with:
Apr 29

En este arículo/tutorial vamos a ver en detalle cómo obtener la posición GPS del iPhone, que problemas podemos tener durante la obtención de las coordenadas y cómo podemos solucionar estos problemas.

Primero de todo si queremos usar el GPS en nuestras aplicaciones tenemos que añadir el CoreLocation a nuestro proyecto. Para eso hacemos click derecho en el grupo “Frameworks” del nuestro proyecto y seleccionamos “Add > Existing Frameworks…”.

Esto nos abrirá la ventana para seleccionar el framework a añadir. Buscamos el “CoreLocation.framework” y lo añadimos al proyecto.

Con esto tenemos todo configurado para empezar a picar código que use el GPS.

En nuestro código tenemos que incluir las cabeceras de las funciones GPS:

#import <CoreLocation/CoreLocation.h>
#import <CoreLocation/CLLocationManagerDelegate.h>

asdad—————————————-

Para obtener las coordenadas tenemos que usar el “CLLocationManager” e implementar el protocolo “CLLocationManagerDelegate“.

El CLLocationManager se inicializaría así:

CLLocationManager *gpsManager = [[CLLocationManager alloc] init];
[gpsManager setDelegate:self];
[gpsManager setDesiredAccuracy:kCLLocationAccuracyBest];
[gpsManager startUpdatingLocation];

Con startUpdatingLocation decimos al location manager que empiece a leer del dispositivo GPS.

Ahora veamos los métodos del protocolo a implementar. Nuestro gpsManager llamará a estos métodos cuando obtenga coordenadas nuevas.

//Se llama cada vez que hay una nueva coordenada
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
    //Hacer algo con newLocation (mostrar la posición en el mapa o lo que sea
}
 
//Se llama cuando se produce algún error en la obtención de datos GPS
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
   if ([error code]==kCLErrorDenied)
       NSLog(@"El usuario ha denegado el acceso a GPS");
  else
       NSLog(@"Se ha producido algún error interno");
}

Con estos métodos ya tenemos todo para leer las coordenadas. En el parámetro newLocation del primer método nuestro “Location Manager” enviará las coordenadas nuevas y nosotros las usuaríamos para hacer X en nuestro programa.

El segundo método se lamará cuando haya algún error. El error puede ser debido a que el usuario haya denegado el acceso al GPS o por otro motivo (ver la documentación para ver los posibles constantes de error existentes).

Hasta aquí lo más básico.

En una aplicación real con sólo esto no sería suficiente.

El primer problema está en la precisión de las coordenadas obtenidas. A la que se pide al locaton manager que empiece a obtener coordenadas (stratUpdatingLocation) este comienza a enviar las coordenadas que obtiene mediante triangulación de las antenas de telefonía móvil y mientras tanto intenta sincronizarse con los satélites para obtener coordenadas más precisas.

Esas primeras coordenadas que obtiene pueden ser muy imprecisas (pueden a llegar a tener un error de más de 10Km) y muchas veces es mejor que nuestro programa los ignore para no engañar al usuario. Para eso en el método donde leemos las nuevas coordenadas tenemos que filtrar los que no tienen la precisión suficiente para nuestro programa.

Para eso se usa la propiedad horizontalAccuracy (que se da en metros) del nuestro objeto de  tipo CLLocation.

Veamos un ejemplo:

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
	//Si el error de la nueva coordenada es mayor o igual a 100 metros usar la coordenada
	if (newLocation.horizontalAccuracy &lt;= 100.0 ){
               ;//Usar la nueva coordenada
	}
 
}

Con esto solucionamos el posible problema que pudieramos tener con la precisión.

Otro problema que puede haber tiene que ver con la cache de coordenadas que mantiene el sistema operativo.
El location manager nos puede enviar, al principio, coordenadas que ha obtenido hace muchas horas. Entonces también tenemos que controlar eso si queremos tener siempre datos frescos. Para eso tenemos que medir el tiempo que ha pasado desde que se ha obtenido una coordenada. El método anterior con este arreglo se quedaría así:

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
        //Obtenemos la fecha de obtención de la coordenada
	NSDate* newLocationeventDate = newLocation.timestamp;
 
        //Obtenemos el tiempo (en segundos) que ha pasado desde que se obtenido nuestra coordenada
	NSTimeInterval howRecentNewLocation = [newLocationeventDate timeIntervalSinceNow];
 
        //Si el error es menor u igual a 100 metros y la coordenada se ha obtenido en los útlimos 20 segundos
	if (newLocation.horizontalAccuracy &lt;= 100.0 &amp;&amp; howRecentNewLocation &lt; -0.0 &amp;&amp; howRecentNewLocation &gt; -20.0){
		;//Usar coordenada
	}
 
}

Con esto solucionamos el problema de la cache. Pero hay un detalle más a tener en cuenta y es que puede que el GPS manager nunca llegue a obtener las coordenadas con la precisión que queremos nosotros y hacer que nos quedemos a esperar a esa coordenada para siempre.
Para eso se ha de programa un timer. No voy a explicar detalles de como programarlo pero la idea consiste en que un timer llame a un método pasado N segundos (nuestro timeout definido para el gps). Ese método que se ejecutará N segundos después y comprobará si en esos N segundos se ha obtenido alguna coordenada si es que si entonces no hay problema, si es que no, entonces debería notificar al usuario o a algún subsistema del programa que deje de esperar al gps o que cambie la precisión requerida o cualquier otra cosa más que se nos ocurra.
Aquí va un pseudocódigo:

...
[NSTimer scheduledTimerWithTimeInterval: 13.0 target:self selector:@selector(gpsTimeOut:) userInfo:nil repeats: NO];
...
-(void) gpsTimeOut: (NSTimer *) theTimer {
	if ([self seHaObtenidoCoordenada] != YES){
               //Hacer lo que sea si en 13 segundos no se ha obtenido una coordenada
       }
}

Con esto cerramos este minitutorial sobre el uso de GPS. Si tenéis preguntas no dudéis en formularlos en los comentarios.

VN:F [1.9.8_1114]
Rating: 5.0/5 (5 votes cast)
VN:F [1.9.8_1114]
Rating: +4 (from 4 votes)
Tagged with:
Apr 27

En este artículo vamos a explicar como encontrar el identificador (no confundirlo con el número de serie) del iPhone (iPod y iPad)  también conocido como “device id”.

Tenemos que seguir los siguientes pasos:

  1. Conectar nuestro dispositivo al ordenador (Mac o Windows).
  2. Abrir el iTunes.
  3. Seleccionar nuestro dispositivo en la lista de dispositivos.

    .
  4. Seleccionar la pestaña Resumen y hacer click sobre el texto “Número de serie”. Al hacer esto el número de serie cambiará y mostrará el identificador.

    Después del click en “Número de serie” debería ver el identificador:


Finalmente, si queremos copiar el identificador vamos al menú: Edición > Copiar (mientras el identificador este visible).

Si estamos en un sitio donde no tenemos acceso a nuestro ordenador pero si tenemos acceso a Internet podemos conectarnos a AppStore y descar una de las aplicaciones especializadas que nos muestran nuestro device id y permiten enviarlo fácilmente. Dos de esas aplicaciones son: Info – UDID y Info – UDID Sender.

Si tiene preguntas no dude en contactar con nosotros.

VN:F [1.9.8_1114]
Rating: 4.3/5 (9 votes cast)
VN:F [1.9.8_1114]
Rating: +1 (from 5 votes)
Tagged with:
Apr 27

In order to find your device id you have to:

  1. Connect the device to your computer (Mac or Windows).
  2. Open the iTunes.
  3. Select your device.

    .
  4. Go to summary tab and click on “Serial Number”. You’ll notice that the “Serial Number” changes to “Identifier”.

    After clicking on the “Serial Number” we must see something like this:

Finally if you want to copy the id: click on Edit > Copy (while the Identifier is visible).

If you haven’t access to your computer but you have Internet connection you can download some free specialized apps (Info – UDID or Info – UDID Sender) from AppStore which can provide you with your device id information.

VN:F [1.9.8_1114]
Rating: 3.4/5 (5 votes cast)
VN:F [1.9.8_1114]
Rating: +1 (from 1 vote)
Tagged with:
Feb 07

En nuestro caso si lo son. Cono ya sabreís de los posts anteriores (1 y 2) hemos empezado a anunciar ZenTap Pro en el Facebook.

En este post les daré los datos de los resultados obtenidos.

Llevamos aproximadamente dos semanas anunciándonos con presupuesto diario de sólo 2$. Hemos puesto como puja máxima por click 0,2$. Con esta configuración obtenemos de media 13 clicks al día sobre el anuncio y unos 13.000 impresiones.

También hacemos un seguimiento de la gente que viene vía anuncios. De esos 13 que nos llegan de media unos 3 hacen click sobre el botón “Ir a Itunes para comprar”.

Desde que llevamos esta mini camapaña hemos aumentado las ventas entre 1 y 2 unidades.

¿Vale la pena?

En nuestro caso si que vale. Zentap vale 2,99$ (2$ limpios para nosotros). Entonces con que una persona lo compre ya nos compensa el anuncio.

En el caso que no nos compensase en forma de ingresos tal vez valiera la pena perder un poco de dinero pero extender el uso de la app.

Otra cosa a tener en cuenta lo llamativa que es tu app. En nuestro caso en el anuncio ponemos “Type faster on your iPhone” y esto llama mucho la atención (y la app lo cumple).

Resumiendo, si tienes una aplicación entre las manos que cuesta más de 0,99$ y tiene algo llamativa vale la pena anunciarse en el facebook.

¿Que experiencias habéis tenido vosotros, os ha compensado anunciarse en el facebook?

VN:F [1.9.8_1114]
Rating: 0.0/5 (0 votes cast)
VN:F [1.9.8_1114]
Rating: 0 (from 0 votes)
Tagged with:
Jan 21

Hoy voy a explicar como se puede comprimir ficheros (formato zip) desde el código.
Es muy útil saberlo porque se usa muchisimo. A la que queramos que el usuario pueda descargar contenidos desde nuestro programa (por ejemplo la galería de fotos que haya creado) o subir grupos de ficheros a Internet vamos a necesitar poder crear zips.
Vamos a ello.
Para crear los zip lo más cómodo (a día de hoy) es usar ZipArchive. Ziparchive es un wrapper para la librería minizip.

Si descargaís el ZipArchive este ya contiene los ficheros de la librería minizip.

Instalación

  1. Descargar el ZipArchive y descomprimirlo.
  2. Crear un nuevo grupo llamado “minizip” en vuestro proyecto.
  3. Añadir los ficheros de la carpeta minizip al grupo minizip de vuestro proyecto.
  4. También añadir los fichero ZipArchive.h y ZipArchive.mm a vuestro proyecto.
  5. Incluir la libreria libz en los frameworks de su proyecto (botón derecha “Add Existing Frameworks”. Libz suele estar en la siguiente carpeta: /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOSNUMERO.sdk/usr/lib. Al escribir este post usaba el siguiente fichero: libz.1.2.3.dylib.

Con esto ya tendremos todo preparado para usar ZipArchive desde nuestro código.

Uso

Ejemplo de compressión de ficheros:

#import "ZipArchive.h"
#define DOCUMENTS_FOLDER [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"]
...
ZipArchive *zip = [[ZipArchive alloc] init];
//Creo el fichero zip en la carpeta Documents de mi app
BOOL ret = [zip CreateZipFile2:[DOCUMENTS_FOLDER stringByAppendingString:@"zipEjemplo.zip"]];
 
//Añado el fichero /Documents/prueba.txt al zip
ret = [zip addFileToZip:[DOCUMENTS_FOLDER stringByAppendingString:@"/prueba.txt"] newname:@"prueba.txt"];
 
//Añado el fichero /Documents/prueba2.txt dentro la carpeta PrimeraCarpeta en el zip
ret = [zip addFileToZip:[DOCUMENTS_FOLDER stringByAppendingString:@"/prueba2.txt"] newname:@"PrimeraCarpeta/prueba.txt"];
 
//Al poner en el new name @"PrimeraCarpeta/prueba.txt" automáticamente se creará la carpeta PrimeraCarpeta en el zip.
 
//Finalmente cerramos el zip y liberamos la memoria
if( ![zip CloseZipFile2] ){
	//Si llegamos aquí es que ha habido un error
}
[zip release];

Ejemplo de como descomprimir un zip (este ejemplo está en la documentación oficial):

#import "ZipArchive.h"
#define DOCUMENTS_FOLDER [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"]
...
       ZipArchive* za = [[ZipArchive alloc] init];
        if( [za UnzipOpenFile:[DOCUMENTS_FOLDER stringByAppendingString:@"zipEjemplo.zip"]] ) {
                BOOL ret = [za UnzipFileTo:[DOCUMENTS_FOLDER stringByAppendingString:@"/miCarpeta"] overWrite:YES];
                if( NO==ret ){
                        // Gestión de errores
                }
                [za UnzipCloseFile];
        }
        [za release];

Con esto termino este mini artículo sobre zips en el iPhone.
Para dudas/preguntas/correciones podéis usar los comentarios o el foro.

VN:F [1.9.8_1114]
Rating: 0.0/5 (0 votes cast)
VN:F [1.9.8_1114]
Rating: +2 (from 2 votes)
Tagged with:
preload preload preload