Bienvenidos

¡Espero que el contentido sea de tu agrado!

Tutorial Corona SDK

Iniciate en Corona SDK para crear aplicaciones y juegos impresionantes en multiples plataformas con r谩pidez tanto en el aprendizaje como el desarrollo.

CoreData: Compartir Modelo con el Watch Apple

En este tutorial se ve una introducci贸n a CoreData y posteriormente como se puede crear el modelo para que este compartirdo por diferentes entornos, por ejemplo para la extensi贸n para el Watch Apple.

Lector de C贸digos de Barras y QR

El objetivo de este tutorial ser谩 ver como se implementa un lector de c贸digos haciendo uso de AVFoundation en Swift.

SpriteKit con Swift

Adentrate en el mundo del desarrollo de videojuegos con SpriteKit

lunes, 25 de mayo de 2015

SpriteKit con Swift


1. Introducci贸n

Actualmente cuando se quiere desarrollar un videojuego lo primero a tener en cuenta es sobre que entorno, librer铆a o ayuda apoyarse para una mayor velocidad y f谩cil desarrollo. Hasta hace poco relativamente iOS solo contaba para el desarrollo de videojuegos con OpenGL y elementos de bajo nivel (supon铆a una dificultad y conocimientos previos enormes) y por otra parte framework o motores de terceros destacando Cocos2D. 

Pero desde que Apple introdujo en su SDK el framework SpriteKit todo esto ha cambiado. En este art铆culo aprenderemos los principales conceptos de SpriteKit para posteriormente profundizar con alg煤n ejemplo.

2. SpriteKit


SpriteKit es un framework o librer铆a que proporciona un motor de renderizado y f铆sicas e infraestructura para la creaci贸n de animaciones de im谩genes o sprites. SpriteKit usa un tradicional bucle de renderizado donde los contenidos de cada frame son procesados antes de que el frame sea renderizado. El juego determina el contenido de la escena y como estos contenido cambian en cada frame. SpriteKit hace el trabajo de renderizado de frames eficientemente usando el hardware gr谩fico. Est谩 optimizado para que las posiciones de los sprites puedan ser cambiadas en cada frame de la animaci贸n. 

SpriteKit por supuesto tambi茅n incluye otras funcionalidades muy 煤tiles para el desarrollo de juegos. Incluye un soporte para reproducir sonidos y simulaci贸n de f铆sicas. Adem谩s Xcode provee de soporte para SpriteKit proporcionando entorno para crear efectos y atlas de texturas en Xcode.  Esta combinaci贸n de librer铆a y herramientas hacen de SpriteKit una buena elecci贸n para juegos y otras app que este tipo de animaciones. (En caso de necesitar otro tipo de animaciones de la interfaz de usuario usar CoreAnimation).

2.1 Principales Clases


Principalmente existen las siguientes clases:

  • SKView: es el canvas , lienzo o vista sobre el que ese trabaja con las clases de SpriteKit.
  • SKScene: representa cada pantalla de nuestro juego, por ejemplo el men煤, opciones, escena de juego, de compras, etc.
  • SKNode: es la clase m谩s importante y representa cada elemento de nuestro videojuego como el personaje, l铆mites, disparos, etc. M谩s adelante veremos las diferentes subclases en las que se divide explicando para que es el uso de cada una, as铆 como algunos propiedades y m茅todos interesantes que ofrezcan.
  • SKAction: permite crear acciones que posteriormente se pueden aplicar a un SKNode (escalado, traslaciones, ...)
  • SKPhysics: clase encargada de agregar la f铆sica a un SKNode para que se vea afectado por la gravedad, choques, fuerzas, etc. 

A continuaci贸n vamos a ir viendo con m谩s detalle cada clase. 

2.1.1 SKView

Lo mismo que cuando se quiere trabajar con mapas es necesario hacer uso de MKMapView o en caso de contenido web con UIWebView si queremos mostrar contenido de SpriteKit debemos usar SKView. 

Hay varios par谩metros destacables que se pueden configurar de una SKView:

  • showsDrawCount: n煤mero de operaciones de pintado que requiere la escena.
  • showsNodeCount: n煤mero de SKNode en pantalla.
  • showsFPS : n煤mero de fotogramas por segundo que est谩 ofreciendo la app.
  • showsPhysics: para mostrar las f铆sicas, es decir realmente que colisiona. 
Normalmente hay que inicializar la vista del controlador como SKView en el m茅todo viewDidLoad  o por comodidad mediante el interfaz gr谩fico indicar que sea de tipo SKView. 

Fig. 1 SKView

2.1.2 SKScene

Las subclases de SKScene que se van creando a lo largo del desarrollo del videojuego representan las diferentes pantallas del mismo. Se trata de una subclase de SpriteKit. Siempre que se quiera mostrar elementos en pantalla ser谩 a trav茅s de una SKScene. A su vez para mostrar la SKScene hay usar la SKView que sirve de contenedor para todo lo que queramos utilizar de SpriteKit. De hecho es posible  gracias a SKView mezclar contenido de UIKit y SpriteKit (algo a m铆 intento un poco lioso y pesado, aunque viable). 

SKScene sigue un bucle de ejecuci贸n con los siguientes pasos:

  • M茅todo update
  • Se ejecutan las acciones
  • M茅todo didEvaluateActions
  • Se ejecutan las simulaciones f铆sicas
  • M茅todo didSimulatePhysics

En la imagen inferior vemos gr谩ficamente el bucle. 

Fig. 2. Bucle en SKScene (y en SKView)

Adem谩s de estos m茅todo otros a tener en cuenta ser铆an:

  • didMoveToView: se ejecuta una vez la vista es presentada en pantalla. En este m茅todo se incluyen en la escena todos los elementos que formar谩n parte de ella. 
  • touchesBegan/Moved/Ended/Cancelled: m茅todos disponibles en los SKNode para detectar toques sobre ellos. 

En la imagen inferior a帽adimos el c贸digo para crear y presentar una escena a la SKView del controlador. 
Fig. 3. A帽adir una escena a una SKView y presentarla

2.1.3 SKNode

Representa de forma abstracta pr谩cticamente la totalidad de los elementos que conforma el videojuego. A continuaci贸n mencionaremos cada uno de ellos as铆 como su funci贸n. 

  • SKSpriteNode: se utiliza para mostrar un sprite. No solo una imagen, sino colores o combinaci贸n de estos pudiendo modificar el alpha, la escala, rotaci贸n o color. 
  • SKTexture: permite mostrar una informaci贸n gr谩fica en pantalla. Principalmente se usa su inicializador el cual acepta un UIImage, aunque hay otro como con CGImage o NSData. Para poder mostrar el SKTexture en pantalla es necesario un SKSpriteNode que lo contenga. 
  • SKEmitterNode: nos permite incluir en la escena sistemas de part铆culas en 2D, fijas o animadas. Se pueden definir texturas, escala, rotaci贸n, 谩ngulo de emisi贸n, velocidad de emisi贸n y otros. Para todo esto se puede usar el editor de part铆culas que trae Xcode. 
  • SKVideoNode: permite incluir un video. Se puede hacer uso de AVPlayer para poder controlar la reproducci贸n, pausar, etc. 
  • SKShapeNode: permite mostrar formas geom茅tricas, cualquier CGPath. Para dichas formas permite definir el color de borde y color de relleno, o hacer efectos. 
  • SKLabelNode: lo mismo que usar el de UIKit pero permite acciones y efectos sobre el texto y soporta todas las fuentes disponibles en el sistema.
  • SKEffectNode: nos permite aplicar efectos de CoreImage a la estructura de nodos que dependen de este SKEffectNode. 
  • SKCropNode: ofrece la posibilidad de recortar contenido de un nodo en base a una m谩scara, es decir transparentar una capa inferior a trav茅s de una capa superior. 

Con todas estas clases se pueden crear estructuras jer谩rquicas m谩s complejas. 

2.1.4 SKAction

Es la clase que nos permite multitud de posibilidad a la hora de animar un SKNode.

  • Cambiar su posici贸n (traslaci贸n)
  • Cambiar su tama帽o (escalado)
  • Cambiar su visibilidad 
  • Cambiar sus texturas para aplicar animaciones fotograma a fotograma
  • Colorear el sprite
  • Reproducir sonidos 
  • Eliminar el nodo de la jerarquia 
  • Acciones personalizadas que podemos definir en un bloque(block) o secuencia (sequence).
  • Definir acciones infinitas o que se repiten un determinado n煤mero de veces

2.1.5 SKPhysics

La simulaci贸n de f铆sicas permite aplicar a los objetos irreales propiedades y comportamiento del mundo real, como la gravedad, masa, elasticidad, rozamientos, etc.

En SpriteKit esto se traduce en la clase SKPhysicsBody, que a la vez esta siempre conectada a un SKNode. Para configurar las propiedades del mundo virtual se cuenta con la clase SKPhysicsWorld, muy t铆picamente la gravedad por medio de gravity.

Hay que definir entre dos tipos de cuerpos f铆sicos:

  • Basados en volumen:permiten simular cuerpos que tiene un volumen y masa terminada. A su vez pueden ser din谩micos o est谩ticos.
  • Basados en bordes: no tienen ni volumen ni masa y normalmente se usan para definir los bordes de la pantalla. 

Para crear cuerpos basados en volumen tenemos tres inicializadores (y alguno m谩s):


  • bodyWithCircleOfRadius: para c铆rculos
  • bodyWithRectangleOfSize: para rect谩ngulos
  • bodyWithPolygonFromPath: para pol铆gonos

Y para cuerpos basados en bordes:


  • bodyWithEdgeLoopFromRect: crea los bordes definidos por un CGRect
  • bodyWithEdgeFromPoint:toPoint: crea el borde de un punto a otro
  • bodyWithEdgeLoopFromPath: crea el borde definido por un CGPath
  • bodyWithEdgeChainFromPath: crea un borde definido por un CGPath

Por 煤ltimo mencionar las propiedades m谩s importantes de los cuerpos f铆sicos:


  • mass: masa del objeto, la cual afecta directamente a las fuerzas as铆 como a la inercia.
  • friction: fricci贸n ofrecida por el objeto. Por defecto tiene un valor de 0.2
  • linearDumping y angularDumping: amortiguaci贸n linear y angular del objeto, y sirve para simular fricci贸n con el aire o agua.
  • restitution: cantidad de energ铆a que se pierde en una colisi贸n, es decir capacidad de rebote. Por defecto 0.2.
  • dynamic: define si el cuerpo se ve afectado o no por las fuerzas aplicadas sobre 茅l. En caso de que no sea din谩mico es est谩tico.
  • affectedByGravity: determina si la gravedad le afecta
  • allowsRotation: si el objeto puede rotar o no.

Decir que se pueden aplicar fuerzas y velocidades a los cuerpos mediante m煤ltiples m茅todos, aunque no los comentar茅 debido a que se alarga mucho el tutorial.

Por 煤ltimo respecto a f铆sicas comentar que como determinar la interacci贸n entre dos o m谩s cuerpos. Existen dos conceptos para esto:


  • Contacto o contact:nos sirve para conocer cuando dos objetos est谩n en contacto.
  • Colisi贸n o collision: mecanismo que evita que dos cuerpos compartan el mismo espacio f铆sico. El propio SpriteKit calcula el impulso resultante y se aplica.

A parte ya que puede que queramos que no todos interacciones con todos sino por grupos se definen:


  • categoryBitMask:define la categor铆a
  • collisionBitMask: define con qu茅 categor铆as de objetos puede colisionar
  • contactTestBitMask: define con qu茅 categor铆as de cuerpos puede entrar en contacto

Una vez definidos las m谩scaras sencillamente declaramos la escena como delegada del tipo SKPhysicsContactDelegate mediante la propiedad contactDelegate del SKPhysicsWorld e implementamos el m茅todo didBeginContact. 

Por 煤ltimo mencionar que permite la creaci贸n de diferentes tipos de uniones. Las uniones son sencillamente conexiones entre objetos y su ventaja es que son tenidas en cuenta por las fuerzas que se aplican en los cuerpos. Por mencionarlas tenemos: SKPhysicsJointFixed, SKPhysicsJointSliding, SKPhysicsJointSpring, SKPhysicsJointLimit y SKPhysicsJointPin. Cada una tiene un objetivo y ofrece distintas posibilidades. 


3. Mini Proyecto

En esta secci贸n se desarrollar谩 un peque帽o juego cuya principal funci贸n es poner en pr谩ctica los principales conceptos visto en la secci贸n anterior. Para ello se buscara lo siguiente a lo largo de la secci贸n:

  • Transiciones  entre escenas para implementar lo que ser铆a un men煤 y una escena de juego. 
  • Trabajar con SKNode: crear, a帽adirlo y animarlos.
  • A帽adir f铆sicas a los nodos. 

3.1 Creaci贸n del Proyecto y su puesta a punto

Para crear el proyecto nos situamos en la ventana de inicio de Xcode (si no se abre Window->Welcome To Xcode) y seleccionamos la plantilla Game perteneciente a iOS. A continuaci贸n introducimos el nombre, en mi caso Test, y el resto de elementos como se muestra en la Fig. 3. 

Fig. 3. Nuevo Proyecto

Una vez se ha creado el proyecto hay que eliminar todo lo se crea por defecto y no har谩 falta. Estas son las cosas a modificar:

  • Quitar del m茅todo viewDidLoad de la clase GameViewController todo lo que va despu茅s de la l铆nea:
skView.ignoresSiblingOrder = true
  • Eliminar lo que contiene el m茅todo touchesBegan en la clase GameScene
  •  Por 煤ltimo por una parte borrar el archivo GameScene.sks ya que sirve para crear una escena gr谩ficamente y no lo usaremos. Y por otra si se quiere la imagen Spaceship que no la usaremos. 
Una vez hecho esto tenemos nuestra plantilla lista para comenzar.

3.2 Transiciones entre escenas.

En esta parte vamos a crear una escena para el men煤 y a帽adiremos un bot贸n para pasar a la escena de juego.

Para empezar creamos una nueva subclase de SKScene a la que llamaremos MenuScene.

Fig. 4. Creamos la clase MenuScene
Una vez creada vamos a ir a la clase GameViewController y vamos hacer que esta presente la escena del men煤. Para ello en el m茅todo viewDidLoad a帽adimos al final el siguiente c贸digo:

         let scene = MenuScene(size: skView.bounds.size)
        
         /* Set the scale mode to scale to fit the window */
         scene.scaleMode = .AspectFill
        

         skView.presentScene(scene)



 Con esto el m茅todo quedar铆a como en la Fig. 5:

Fig. 5. M茅todo ViewDidLoad
Con estos simples pasos hemos creado una escena y hemos hecho que el controlador la presente inicialmente. Hasta ahora si ejecutamos no mostrar谩 nada ya que la escena del men煤 esta vac铆a por ahora.

Vamos a empezar a crear nuestro sencillo men煤. El men煤 contar谩 con un t铆tulo y un bot贸n centrar para iniciar el juego, de play.


  • Para el t铆tulo usaremos un SKLabelNode
  • Para el bot贸n usaremos un SKSpriteNode. Pensareis que podr铆amos usar un UIButton y llev谩is raz贸n pero incluirlos aumenta la complejidad. ¡Os animo a probar con ellos!


La creaci贸n de todos los elementos iniciales se hace en el m茅todo didMoveToView el cual se ejecuta una vez la escena es presentada.  Lo primero ser谩 cambiar el color de fondo de la escena por ejemplo a un naranja. Para ello a帽adimos:

        self.backgroundColor = UIColor.orangeColor()        


Ahora s铆 vamos a empezar creando el t铆tulo. Para la creaci贸n se objetos en pantalla mi recomendaci贸n es hacerlo todo proporcional al tama帽o de la vista que se tiene, ahora lo ir茅is entendiendo. Para ello declaramos las siguientes variables que se corresponde al ancho, alto de la pantalla y sus mitades.


        var frame = self.frame;
        var _W:CGFloat = frame.size.width;
        var _H:CGFloat = frame.size.height;
        var _w:CGFloat = frame.size.width * 0.5;

        var _h:CGFloat = frame.size.height * 0.5;




Haciendo uso de estas variables creamos y situamos el t铆tulo:

        let titleLabel = SKLabelNode(fontNamed: "Chalkduster")
        titleLabel.text = "Test";
        titleLabel.fontColor = UIColor.whiteColor()
        titleLabel.fontSize = 60.0
        titleLabel.position = CGPointMake(_w, _H * 0.9 - titleLabel.frame.size.height * 0.5);

        self.addChild(titleLabel);


Ahora para el bot贸n podr铆amos usar otro SKLabelNode pero vamos a crear un SKSpriteNode con una imagen en este caso para que quede mucho mejor.



En este caso no voy a entrar en tema de tama帽os y con ello resoluci贸n y escala seg煤n el dispositivo pero hay que tenerlo en cuenta.  Una vez aclarado esto a帽adimos la imagen a Images.xcassets y a帽adimos lo siguiente para crear nuestro bot贸n:

        let playButton = SKSpriteNode(imageNamed: "play");
        playButton.position = CGPointMake(_w, _h);

        playButton.name = "PlayButton"
        self.addChild(playButton)


Si ejecutamos ahora mismo obtendremos algo similar a la Fig. 6, pero hasta ahora si pulsamos sobre el bot贸n no tenemos ning煤n acci贸n.

Fig. 6. Muestra del Men煤 

Para detectar los toques sobre la pantalla sobreescribiremos el m茅todo touchesBegan sencillamente ya que solo queremos detectar un simple toque. En este haciendo uso del nombre que le hemos asignado al bot贸n podremos detectar los toques sobre 茅l.  En la Fig. 7 se ve como quedar铆a el m茅todo. 


Fig. 7. M茅todo TouchesBegan en escena Men煤

En este m茅todo sencillamente se obtienen el nodo sobre el que se pulsa y se comprueba si es el bot贸n. En caso de que s铆 se crea una transici贸n y la nueva escena y se le dice a la visa que lleve a cabo su presentaci贸n. 

Si ejecutamos el proyecto veremos como se puede pasar a la escena de juego donde aparecer谩 el texto Hello World sino lo hemos borrado antes.

3.2 Trabajar con SKNode: Crear y A帽adir a la Escena


En el apartado anterior ya hemos visto como usar dos de los SKNode, el primero de ellos un SKLabelNode y para el bot贸n un SKSpriteNode al que le hemos puesto una foto.  En este apartado vamos a trabajar un poco m谩s subclases de SKNode. Debido a que no resulta un poco pesado buscar im谩genes en vez de usar SKSpriteNode vamos a usar SKShapeNode para crear figuras en especial c铆rculos de colores. A estas figuras le a帽adiremos algunas animaciones y en el siguiente apartado le a帽adiremos f铆sicas. 

Vamos a crear dos bolas, una de color azul y otra de color rojo, y las pondremos centradas en la pantalla. Y le a帽adiremos una animaci贸n diferente a cada una cuando pulsemos sobre ellas. Para ello, se a帽ade el c贸digo de la Fig. 8 en el m茅todo didMoveToView de la escena juego. 

Fig. 8. A帽adimos 2 bolas a la escena

Atenci贸n al nombre que le hemos puesto a cada bola ya que lo usaremos para aplicar una animaci贸n a cada una de ellas. Por ejemplo a la azul vamos a hacer que aumente su tama帽o al doble y vuelva a su estado normal. Y para la roja haremos que desaparezca y vuelva a aparecer. Para ello usaremos la clase SKAction la cual nos permite mediante el m茅todo Sequence a帽adir varias SKAction secuencialmente. En la Fig. 9. vemos como se ha hecho en unas pocas l铆neas. 

Fig. 9. A帽adir animaciones a las bolas cuando pulsamos sobre ellas

Hasta ahora deber铆amos tener algo similar a la Fig. 10, en la cual tenemos dos bolas y si pulsamos sobre alguna de ellas se ejecuta la animaci贸n correspondiente. 

Fig. 10 Escena Juego con las bolas y las animaciones 

Con esto damos por terminada esta secci贸n, vamos a la siguiente que es la m谩s divertida, !jugar con las f铆sicas!

3.3 Jugar con las F铆sicas

En esta 煤ltima secci贸n queremos a帽adir f铆sicas a las bolas para que se muevan por la pantalla. Antes de ellos vamos a crear los l铆mites de la pantalla para que no se escapen. Para los bordes vamos a crear un SKSpriteNode denominado Playground al cu谩l le vamos a a帽adir f铆sicas de tipo borde. Lo m谩s complicado de entender son las m谩scaras pero si prestamos atenci贸n le asignamos como categor铆a la 1, y como m谩scara de colisi贸n tiene el m谩ximo es decir todo chocar谩 con 茅l. En cuanto a la m谩scara de contacto es 0 por lo que no habr谩. Lo mejor para comprender es toquetear y ver el comportamiento. 

Fig. 11. Creamos el Playground
Una vez creados los bordes o l铆mites a帽adimos el c贸digo de la Fig. 12 cada parte a su correspondiente bola. Si lo analizamos estamos haciendo que las bolas choquen con los bordes pero no entre s铆. 


Fig. 12. A帽adir f铆sicas a las bolas
La bola azul tiene la categor铆a 2 y la roja la 4 (tienen que ser potencias de dos), y como colisi贸n solo tiene la categor铆a de los bordes que es 1. De este modo se tiene el comportamiento que quer铆amos. Para apreciar que esta todo correcto a帽adir esta l铆nea cuando hacemos las animaciones para que las bolas reciban una fuerza y cambien su trayectoria y se crucen:

node.physicsBody?.applyForce(CGVectorMake(500,500))

Tambi茅n podeis a帽adir esta l铆nea en el controlador para que se muestren las f铆sicas lo que es muy c贸modo mientras se desarrolla un juego.

 skView.showsPhysics = true

FIN

Espero que os haya gustado el tutorial. Me hubiera gustado explicar tantas cosas pero son demasiadas para abarcarlas todas. Yo creo que con esta breve introducci贸n y ejemplos es suficiente para iniciarse y que la curiosidad haga el resto. 

Para cualquier duda o sugerencia que quer谩is preguntar ponerlo en los comentarios. 

Enlace directo del proyecto completo  SpriteKitTest
Enlace del proyecto en GitHub: SpriteKitTest 








martes, 12 de mayo de 2015

Android 5.0 Lollipop Novedades

Ya ha llegado la nueva versi贸n de Android denominada Lollipop 5.0. En esta entrada vamos a resumir las principales novedades que Android Lollipop introduce sin detallar las incre铆bles nuevas API que se han a帽adido disponibles para los desarrolladores.

MATERIAL DESIGN 

Se trata de una nueva filosof铆a de dise帽o para la visualizaci贸n, renderizado e interactividad para todas las plataformas.  Persigue el dise帽o basado en materiales, buscando los m谩s naturales. Adem谩s para mejorar la interactividad llamado la atenci贸n del usuario juega con los contrastes tanto en colores como contornos. 

Google ha puesto a la disposici贸n de los dise帽adores una gran cantidad de informaci贸n y toda la documentaci贸n para  crear aplicaciones muy atractivas a la vez que se aumenta el rendimiento y fluidez. 


Si ten茅is curiosidad, quereis iniciaros o simplemente mejorar vuestras aplicaciones entra aqu铆


Multimedia y Sonido

Esta parte en mi opini贸n es m谩s llamativa a nivel de usuario ya que casi todos los usuarios hacen un mayor uso del dispositivo para la reproducci贸n de video o audio as铆 como la c谩mara. Las principales novedades son:

  • Menor latencia de audio de entrada para una experiencia en tiempo real mejor
  • Audio multicanal hasta 7.1
  • Soporte para audio USB
  • OpenGL ES 3.1
  • Fotograf铆a: m谩xima resoluci贸n con 30fps, soporte para formato RAW, y diferentes ajustes.
  • Tecnolog铆a de video art, con soporte para perfil HEVC que permite hasta UHD 4K


Android TV 


Android se presenta como el primero que intenta hacer una 煤nico del gran ecosistema. Ya que no solo permitir铆a la conexi贸n con Android Wear sino que tambi茅n es la base de Android TV.  Por ejemplo podremos:
  • Tener una interfaz adaptada para la gran pantalla
  • Pensado para una mayor visualizaci贸n con menor navegaci贸n
  • B煤squeda por voz
  • Posiblidad de hacer uso de gamepads
  • Posiblidad de hacer cast con las aplicaciones de entretenimiento

Notificaciones inteligentes

La idea principal es sencillamente que solo se nos debe interrumpir cuando realmente sea necesario.  Para ello se han a帽adido:
  • Poder responder y ver mensajes directamente desde la pantalla de bloqueo
  • Un sistema de prioridades de notificaciones
  • Una mejor gesti贸n de las notificaciones. 

En mi opini贸n lo mejor es que las llamadas entrantes no interrumpir谩n lo que estemos haciendo en un momento dado. En la imagen superior se ve lo que quiero decir. 

M谩s autonom铆a


Android Lollipop ha optimizado el uso de la bater铆a haciendo su vida un poquito m谩s larga. Para hacernos una idea se amplia hasta 90 minutos la duraci贸n de una misma bater铆a. 

Adem谩s ahora ofrece una visualizaci贸n de la estimaci贸n de los tiempo de bater铆a es decir cuanto queda para que se acabe o se cargue. 




Seguridad: Factory reset en caso de robo


Android Lollipop incluye la encriptaci贸n autom谩tica activada para proteger los datos en caso de p茅rdida o robo. Pero no todo queda aqu铆 ya que adem谩s incluye las siguientes caracter铆sticas:

  • SELinux: protecci贸n contra malware y vulnerabilidades.
  • Android Smart Lock: protecci贸n gracias al emparejamiento con otro dispositivo como el coche o wearable.
  • Google Protecci贸n Factor Reset: respetar de f谩brica el dispositivo en caso de p茅rdida o robo. 

Modo multiusuario

Permite la gesti贸n de m煤ltiples usuarios en los tel茅fonos. Se dispondr谩 de un usuario invitado el cual tiene acceso pero no al contenido del resto de usuarios. Es parecido a como esta implementado en sistemas operativos de escritorio. Adem谩s se puede bloquear un contenido mediante un clave. 


Compatibilidad con accesorios BLE


Se ha intentado mejorar la conectividad con los m煤ltiples dispositivos, sobre todo para evitar interrupciones en las conexiones. 

La principal novedad es el es nuevo Bluetooth de baja energ铆a (BLE) el cual optimiza el consumo de potencia para dispositivos como los relojes inteligentes, auriculares o manos libres.
 


Paso de informaci贸n entre dispositivos Android


Aunque no es una novedad en s铆 es realmente interesante y c贸modo ya que podremos tener nuestras apps al migrarnos a un nuevo dispositivo gracias a la cuenta de Google. 

Conclusi贸n

Hay actualizaciones que cambian cosas, pero hay otras como est谩 que innovan. Y adem谩s que llevan la experiencia de usuario hasta un alto grado de personalizaci贸n, comodidad y sencillez haciendo lo sentir parte del ecosistema. 



martes, 21 de abril de 2015

Lector de C贸digo de Barras y QR


1. Introducci贸n

Con la entrada de Swift y iOS 8 son muchas las novedades que han introducido en framework como MapKit, CoreLocation, PassKit o AVFoundation. 

En este tutorial quiero mostraros como realizar un lector de c贸digos de barras y c贸digos QR haciendo uso de la librer铆a AVFoundation todo ello haciendo uso de Swift. 


2.¿Qu茅 es un c贸digo de barras? ¿y un c贸digo de QR?

Aunque muchos de nosotros lo sepamos y veamos a diario siempre es bueno profundizar en algo que vamos a usar. Por ello vamos a hablar de los mecanismos y caracter铆sticas escondidas de estos c贸digos. 

Empecemos por los c贸digos de barras. Son c贸digos basado en la representaci贸n mediante l铆neas paralelas de distinto grosor y espaciado de modo que en conjunto contienen una determinada informaci贸n. Es decir las barras y los espacios representan peque帽as cadenas de caracteres. De este modo son muy usados para recocer r谩pidamente un art铆culo de forma 煤nica, global y no ambigua.

Existen multitud de tipos como ha ido evolucionando a lo largo del tiempo desde la primera patente en 1952. Gracias a los c贸digos de barras se ha podido agilizar el etiquetado de precios, el control del stock de mercanc铆as, ofrecer estad铆sticas comerciales y  automatizar el registro y seguimiento de productos. Todo ello a un bajo coste, con una probabilidad de error muy baja y ofreciendo flexibilidad y rapidez.


Fig. 1 Ejemplo de c贸digo de barras


Con respecto a los c贸digos QR estos son como una evoluci贸n de los simples c贸digos de barras. Se pueden definir como un c贸digo de barras bidimensional. Exactamente son una forma de guardar informaci贸n en un matriz de puntos. Se caracterizan por tener unos cuadrados en las esquinas para detectar la posici贸n del c贸digo al lector. Su nombre QR viene de "Quick Response", es decir su objetivo es leer su contenido a alta velocidad.

Fig. 2 Ejemplo de c贸digo QR


Para m谩s informaci贸n ver:

En el siguiente gr谩fico os muestro algunos ejemplos. Aunque algunos parecen similares son c贸digos y est谩ndares diferentes.





 Por curiosidad os dejo una p谩gina web donde pod茅is crear vuestro propio c贸digo. En mi caso cree uno QR con la cadena "HolaMundo" como informaci贸n codificada.

Fig. 3 C贸digo QR: HolaMundo

Enlace: GeneradorC贸digos


3. Leer C贸digos usando AVFoundation

La librer铆a gracias a funcionalidad implementa en la clase AVCaptureMetaDataOutput permite la detecci贸n distintos tipos de c贸digos. La siguiente lista muestra todos los disponibles en la versi贸n 8 de iOS:


      • AVMetadataObjectTypeUPCECode
      • AVMetadataObjectTypeCode39Code
      • AVMetadataObjectTypeCode39Mod43Code
      • AVMetadataObjectTypeEAN13Code
      • AVMetadataObjectTypeEAN8Code
      • AVMetadataObjectTypeCode93Code
      • AVMetadataObjectTypeCode128Code
      • AVMetadataObjectTypePDF417Code
      • AVMetadataObjectTypeQRCode
      • AVMetadataObjectTypeAztecCode
      • AVMetadataObjectTypeInterleaved2of5Code
      • AVMetadataObjectTypeITF14Code
      • AVMetadataObjectTypeDataMatrixCode


Esta funcionalidad de detecci贸n se produce en tiempo real mediante la c谩mara del dispositivo, a trav茅s del stream o fotogramas que esta genera.

Para implementar nuestro escaner se necesario crear una sesi贸n (AVCaptureSession) e implementar un m茅todo de su delegado. Este proceso se puede complicar en funci贸n de lo que busquemos que realice nuestro esc谩ner. En el ejemplo explicaremos lo esencial para un uso adecuado. El ejemplo consistir谩 en crear un ScannerViewController es decir un controlador de vista que implemente el lector de c贸digo de barras permitiendo una funcionalidad y comunicaci贸n mediante delegaci贸n.

A continuaci贸n explicaremos las principales clases de las que haremos uso:


3.1 AVCaptureSession

Se trata de uno de los objetos claves el cual ayuda a manejar el flujo de datos desde  la etapa de captura a trav茅s de el dispositivo de entrada como una c谩mara o micr贸fono a la salida como puede ser un archivo de audio o video.

3.2 AVCaptureDevice

Representa al dispositivo f铆sico de captura y las propiedades asociadas a este. Este objeto se usa para configurar las propiedades subyacente al hardware. El dispositivo de captura provee la entrada de datos a AVCaptureSession. Se puede tener mucha flexibilidad cambiando las propiedades de entrada como el enfoque o exposici贸n. 

3.3 AVCaptureInputDevice

Es muy util para captura de datos de dispositivos de entrada. 

3.4 AVCaptureMetadataOutput

Es la clase encargada de interceptar objetos de metadatos de parte de la sesi贸n y envi谩rselos al delegado. Se puede usar procesar espec铆ficos tipos de metadatos incluido los datos de entrada. 

3.5 AVCaptureVideoPreviewLayer

Es una especial CGLayer que ayuda a mostrar datos capturar desde dispositivos de entrada.




4. Clase: ScannerViewController

En este apartado vamos a crear nuestra clase para la lectura de c贸digos de barras y QR. Explicaremos el c贸digo relacionado con respecto al lector de c贸digos en s铆 ya que es lo m谩s importante. El resto como voy a dejar la clase para descargarla no hay ning煤n problema, a煤n as铆 hay unos detalles que comentar茅.

Lo primero es ver las propiedades de la clase. La primera de ella es la referida al delegado que explicaremos m谩s adelante. Las siguientes son todas las relacionadas con la captura. Y por 煤ltimo a帽adimos algunas de control y el c贸digo le铆do en s铆.

    var delegate: ScannerViewControllerDelegate?
    
    var device: AVCaptureDevice?
    var input: AVCaptureDeviceInput?
    var output: AVCaptureMetadataOutput?
    var session: AVCaptureSession?
    var preview: AVCaptureVideoPreviewLayer?
    
    var codeDetected: Bool = false
    var code:String?

    var canBeDisplayed = true

A continuaci贸n vamos a analizar la funci贸n para la puesta a punto de la c谩mara por partes. La primera de ella que tenemos abajo es comprobar si el dispositivo cuenta con la c谩mara. Por ejemplo el emulador no tiene y por lo tanto no podemos probar el lector en 茅l.

        self.device = AVCaptureDevice.
                      defaultDeviceWithMediaType(AVMediaTypeVideo)
        if self.device == nil {
            println("No video camera on this device!")
            //self.dismissViewControllerAnimated(true, completion: nil)
            self.canBeDisplayed = false
            return

        }

En el siguiente paso configuramos el resto de instancias. Lo primero es crear la sesi贸n en caso de que no lo este. A continuaci贸n creamos y a帽adimos la instancia de AVCaptureDeviceInput referida a esa sesi贸n.

El siguiente paso es configurar AVCaptureMetadataOutput conectando a la sesi贸n creada e indicando los tipos de c贸digos permitidos as铆 como indicando su delegado que ser谩 este propio controlador. Por 煤ltimo creamos la capa que mostrara los datos para que ocupe toda la vista. Una vez esta todo correctamente configurados podemos lanzar la sesi贸n con "startRunning()".

        if let s = self.session{
            return
            
        }else{
            self.session = AVCaptureSession()
            
            if let s = self.session{
                
                self.input = AVCaptureDeviceInput.
                             deviceInputWithDevice(self.device, error: nil)
                             as? AVCaptureDeviceInput
                
                if s.canAddInput(self.input) {
                    s.addInput(self.input)
                }
                
                self.output = AVCaptureMetadataOutput()
                self.output?.setMetadataObjectsDelegate(self
                             queue: dispatch_get_main_queue())
                if s.canAddOutput(self.output) {
                    s.addOutput(self.output)
                }
                self.output?.metadataObjectTypes = self.output?.availableMetadataObjectTypes
                
                
                self.preview = AVCaptureVideoPreviewLayer(session: s)
                self.preview?.videoGravity = AVLayerVideoGravityResizeAspectFill
                self.preview?.frame = self.view.frame
                self.view.layer.insertSublayer(self.preview, atIndex: 0)
                
                s.startRunning()
            }

        }



Con esto tenemos implementado nuestro m茅todo "setupCamera()". A continuaci贸n es necesario implementar el m茅todo del protocolo AVCaptureMetadaOutputDelegate. Para ello lo primero es a帽adirlo en la cabecera.  Este m茅todo se llama cada vez que se ha detectada un c贸digo.

// MARK:  AVCaptureMetadataOutputObjectsDelegate
    func captureOutput(captureOutput: AVCaptureOutput!, 
                       didOutputMetadataObjects metadataObjects: [AnyObject]!, 
                       fromConnection connection: AVCaptureConnection!) {
        
        if !self.codeDetected{
            
            for data in metadataObjects {
                let metaData = data as! AVMetadataObject
                let transformed = 
                    self.preview?.transformedMetadataObjectForMetadataObject(metaData) 
                    as? AVMetadataMachineReadableCodeObject
                
                if let unwraped = transformed {
                    let code: String = unwraped.stringValue
                    println("CodeBar: " + code)
                    if !(code == ""){
                        self.codeDetected = true
                        self.code = code
                        //self.delegate?.codeDetected(code)
                        
                        //self.dismissViewControllerAnimated(true, completion: nil)
                        self.showAlertCodeDetected(code)
                    }
                }
            }
            
        }

    }

Lo siguiente a mostrar de la clase son el propio protocolo delegado que se crea para el controlador, es decir el protocolo que deber谩n implementar las clases que hagan uso de nuestro esc谩ner. Y por otro lado funciones y detalles correspondientes a detalles de visualizaci贸n como pueden ser alertas.

Lo primero es definir el protocolo fuera de la clase relacionado con la propiedad delegate de la clase que al principio se comenta:

     protocol ScannerViewControllerDelegate {
    
        func codeDetected(code: String)
    

     }

Las siguientes funciones son simples funciones para mostrar alertas:

    func showAlertError(){
        
        var alertView = UIAlertView(
            title:"Atention",
            message:"Scanner can't be displayed",
            delegate:self,
            cancelButtonTitle:"OK")
        alertView.tag = 1
        
        alertView.show()
    }
    
    func showAlertCodeDetected(code: String){
        
        var alertView = UIAlertView(
            title:"Code Detected",
            message:"The code is: " + code,
            delegate:self,
            cancelButtonTitle:"Accept",
            otherButtonTitles: "Cancel")
        
        alertView.tag = 0
        
        alertView.show()

    }

Y referidas a estas alertas tambi茅n se implementa su protocolo denominado UIAlertViewDelegate:

    // MARK:  UIAlertViewDelegate
    
    func alertView(alertView: UIAlertView, clickedButtonAtIndex buttonIndex: Int) {
        
        if(alertView.tag == 0){
            
            if buttonIndex == 0{
                self.delegate?.codeDetected(self.code!)
                self.dismissViewControllerAnimated(true, completion: nil)
            }else if buttonIndex == 1{
                
                self.codeDetected = false
            }
            
            
        }else if(alertView.tag == 1){
        
            self.dismissViewControllerAnimated(true, completion: nil)
        }
    }


Por 煤ltimo a帽ado un bot贸n "Cancelar" a la vista para que en caso de no querer detectar ning煤n c贸digo se pueda pulsar y quitar el esc谩ner. Ese c贸digo se puede ver en la propia clase ya que no incumbe al tema del tutorial.

En la siguiente imagen se ve un ejemplo donde se detecta un c贸digo de barras. Cuando se detecta muestra una alerta y si aceptamos se llama al m茅todo "codeDetected" del protocolo ScannerViewControllerDelegate que estar谩 implementado en la clase que hace uso del esc谩ner recibiendo el c贸digo.



Aqu铆 dejo los enlaces tanto de descarga directa como de GitHub.

Enlace descarga directa: ScannerViewController
Enlace GitHub: ScannerViewController