Archive for the ‘air’ Category

Flash Player 10.1 en Android 2.2 y Android Apps en AIR

Jueves, Mayo 20th, 2010

Todos lo sabían, pero sigue siendo una gran noticia. Android tendrá instalado por defecto Flash Player 10.1 y podrá reproducir, tal como funciona en un desktop, todos los sitios y aplicaciones hechas en Flash o Flex. Nada del bullshit de Steve Jobs. Flash corre perfecto en dispositivos móviles touch, no es un "drenador" de batería y no requiere recodear toda la web. Simplemente funciona.

Apps nativas hechas en Flash en el market de Android

En el sandbox muestran también varias apps nativas de Androids que se instalan desde el market, pero que fueron construidas con Flash y compiladas con AIR. Tal como funcionaba el compilador para iPhone, un developer puede crear una app en Flash y ponerla en el market de Android, la Ovi Store de Nokia o el Market de Blackberry.

Para el usuario, ambas experiencias son nativas y transparentes. Para los desarrolladores, la vida es más fácil.

Enviar comentario

Adobe abandona iPhone en Flash, se enfoca en Android

Miércoles, Abril 21st, 2010

Mike Chambers, manager de Flash Platform en Adobe, anunció hoy en su blog que Adobe dejará de invertir en herramientas para desarrollo orientado al iPhone de Apple. No es una sorpresa, pero es la posición oficial de Adobe frente a Apple y su prohibición de apps hechas en Flash dentro de la App Store.

Android, el futuro para Adobe

Además, anuncian que Android será la plataforma móvil donde se dirigirán sus esfuerzos. Hablando del Motorola Droid, el Nexus One y la tabla Android con NVIDIA Tegra, futura competidora del iPad.

Hablan de otros sistemas operativos móviles, pero el enfoque clave del artículo es en Andoid.

Adobe reitera lo cerrado de Apple, se compromete con "open"

Recuerdan además que Apple no sólo ha restringido el desarrollo de apps para iPhone con herramientas de terceros, sino también el uso de otras redes de publicidad (como AdSense) diferentes a las propias de Apple, así como su ilógico sistema de rechazo de apps por contenido.

Cierra el artículo Mike asegurando que "las plataformas abiertas le ganarán al final a aquellas cerradas y controladas que Apple quiere crear", recordando que Adobe AIR y Flash Player 10.1 permitirá crear apps nativas para Android, Palm, Windows Phone 7, Symbian y Blackberry.

Lo que me deja esperando que ponga su dinero donde sus palabras están. Que abran el Flash Player como open source, igual que Flex. Ya es hora.

Enviar comentario

Enviar y recibir datos UDP con Adobe AIR 2.0

Miércoles, Marzo 3rd, 2010

En este tip, aprenderemos a enviar información a través de UDP (Universal Datagram Protocol) que es una nueva característica de Adobe AIR 2.0 que nos permitirá enviar y recibir datos, que al ser UDP no garantiza la recepción o entrega, ya que sus cabeceras no llevan el control de datos haciendo ligero los envíos. Al ser así, se puede usar esta nueva característica para aplicaciones con baja latencia y donde la perdida de datos sea indiferente. Por ejemplo puedes utilizar esto con aplicaciones en tiempo real o juegos multiplayer, ejemplos o utilidades pueden haber miles, depende mucho del análisis que hagas.

Para este ejemplo, como ya saben, necesitan tener Flash Builder o eclipse con el SDK de AIR 2.0. De la misma forma puedes ver los anteriores tips que escribí para que te sientas familiarizado con Adobe AIR.

Usaremos la clase DatagramSocket y para eso crearemos una instancia de esta clase. Asimismo, tendremos una variable con la dirección IP que usaremos para la conexión. En este ejemplo usaré la dirección local de mi computador, puedes poner IP de máquinas en tu red y usar el ejemplo en más de un computador.

Código :

private var $__datagramSocket:DatagramSocket;
private var $__IP:String = "127.0.0.1";

Cuando la aplicación se inicie crearemos el constructor de la clase DatagramSocket, agregando un escuchador que permita detectar cuando un mensaje fue recibido:

Código :

$__datagramSocket = new DatagramSocket();
$__datagramSocket.addEventListener( DatagramSocketDataEvent.DATA, dataReceived, false, 0, true );

Adicional a esto el método bind() nos permite establecer la conexión entre el puerto que usaremos y la dirección IP que servirá para dicha conexión. El método receive() es quien nos permite iniciar la escucha de los datos enviados.

Código :

$__datagramSocket.bind( 55555, $__IP );
$__datagramSocket.receive();

El método que usaremos para escuchar cuando los datos lleguen es dataReceived:

Código :

private function dataReceived( event:DatagramSocketDataEvent ):void{
   campo.text = campo.text + "nOtro dice: " + event.data.toString();
}

Para este tip, crearemos un ejemplo básico de chat enviando texto y mostrando la información de otro usuario. Para eso crearemos la siguiente interfaz:

Código :

<s:Label text="Chat:" width="200"  fontWeight="bold"/>
<s:TextArea width="200" height="200" id="campo" text="...INICIA CHAT..." 
         verticalAlign="bottom" editable="false"/>
<s:Label text="Enviar:" width="200"  fontWeight="bold"/>
<s:TextInput id="txtInput" width="200"
          click="{txtInput.text = ''}"
          keyDown="send(event)"
          text="Escribe aqu’ y presiona enter" />

Como ven en el código, al presionar una tecla llamará al método send, nosotros validaremos que sea con ENTER:

Código :

private function send( e:KeyboardEvent = null ):void
{
   if( e.keyCode == Keyboard.ENTER ){
      var data:ByteArray = new ByteArray();
      data.writeUTFBytes(txtInput.text);

      $__datagramSocket.send( data, 0, 0, $__IP, 55554);

      campo.text = campo.text + "nTu dices: " + txtInput.text;
      txtInput.text = "";
   }
}

Es necesario aclarar que los puertos donde se conectarán deben estar libres y no siendo utilizados incluso por varias de esta misma app, además de tener permisos de seguridad. Aquí te dejo el código completo de la app que hice, es sólo un demo pero creo que sirve como base para que puedas crear cosas impresionantes.

Código :

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
                  xmlns:s="library://ns.adobe.com/flex/spark"
                  xmlns:mx="library://ns.adobe.com/flex/mx"
                  creationComplete="init()"
                   width="236" height="300">
   <s:layout>
      <s:VerticalLayout horizontalAlign="center" paddingTop="10"/>
   </s:layout>

   
   <fx:Script>
      <![CDATA[
         
         private var $__datagramSocket:DatagramSocket;
         private var $__IP:String = "127.0.0.1";
         
         private function init():void{
            
            $__datagramSocket = new DatagramSocket();
            $__datagramSocket.addEventListener( DatagramSocketDataEvent.DATA, dataReceived, false, 0, true );
            $__datagramSocket.bind( 55555, $__IP );
            $__datagramSocket.receive();
         }
         
         private function dataReceived( event:DatagramSocketDataEvent ):void{
            campo.text = campo.text + "nOtro dice: " + event.data.toString();
         }
         
         private function send( e:KeyboardEvent = null ):void
         {
            if( e.keyCode == Keyboard.ENTER ){
               var data:ByteArray = new ByteArray();
               data.writeUTFBytes(txtInput.text);
               
               $__datagramSocket.send( data, 0, 0, $__IP, 55554);
               
               campo.text = campo.text + "nTu dices: " + txtInput.text;
               txtInput.text = "";
            }
         }
         
      ]]>
   </fx:Script>
   
   <s:Label text="Chat:" width="200"  fontWeight="bold"/>
   <s:TextArea width="200" height="200" id="campo" text="...INICIA CHAT..." 
            verticalAlign="bottom" editable="false"/>
   <s:Label text="Enviar:" width="200"  fontWeight="bold"/>
   <s:TextInput id="txtInput" width="200"
             click="{txtInput.text = ''}"
             keyDown="send(event)"
             text="Escribe aqu’ y presiona enter" />
   
</s:WindowedApplication>

Puedes descargar el demo aquí

Enviar comentario

Acceder a dispositivos de almacenamiento en AIR 2.0

Viernes, Febrero 26th, 2010

Este es uno de los tips de Adobe AIR 2.0 que más me agradó preparar, porque en realidad tenía la necesidad, en un proyecto, de acceder a dispositivos de almacenamientos para leer, editar y grabar información. La clase StorageVolume nos permite leer todos los archivos existentes en nuestro dispositivo de almacenamiento, reconociendo los permisos de los archivos, si son de sistema o no, etc. Por otro lado podemos crear y eliminar directorios, así como también archivos: moviendo, copiando, etc. Recuerda que debes tener Adobe AIR 2.0 configurado en tu Flash Builder o Eclipse

Entonces para este tip, haremos una básica aplicación que permita reconocer cuando se insertó o removió un dispositivo de almacenamiento. Empezaremos creando la interfaz:

Código :

<s:Label id="msg" width="100%" y="20" text="inserta un USB drive" 
          verticalAlign="top" textAlign="center"
          color="#110E91" fontWeight="bold"/>
<mx:Box id="boxContent" width="90%" height="126" x="20"  y="40"/>

Ahora crearemos nuestros listener que estén pendientes de cuando el dispositivo sea agregado o retirado, para eso usaremos una función que será ejecutada al iniciar la aplicación:

Código :

private function init():void{
   StorageVolumeInfo.storageVolumeInfo.addEventListener(StorageVolumeChangeEvent.STORAGE_VOLUME_MOUNT, mount, false, 0, true);
   StorageVolumeInfo.storageVolumeInfo.addEventListener(StorageVolumeChangeEvent.STORAGE_VOLUME_UNMOUNT, unMount, false, 0, true);
}

Y escribimos ahora las funciones que nos avisará en el campo de texto:

Código :

private function mount(e:StorageVolumeChangeEvent):void{
   var myDrive:StorageVolume = e.storageVolume;
   msg.text = "Se conectó: "+ myDrive.name + "  Size: "+Math.round( (myDrive.rootDirectory.spaceAvailable /1073741824) *100)/100 +" Gb";
}
         
private function unMount(e:StorageVolumeChangeEvent):void{
   msg.text = "Se removió: "+ e.rootDirectory.nativePath;
}

Si conectamos un dispositivo:

Si retiramos el dispositivo:

Vemos que nuestro evento StorageVolumeChangeEvent nos avisa cuando un dispositivo fue agregado o removido, este a su vez, nos envía información importante como por ejemplo el nombre, el espacio disponible, que tipo es ("FAT", "NTFS", "HFS" o "UFS"), etc. Pero lo más importante es poder acceder a los archivos que contiene.

Reconocer los archivos

En realidad hasta aquí es el tip de acceso a dispositivos de almacenamiento, pero decidí ampliarlo un poco más reconociendo los archivos que contiene, para eso usaremos la propiedad rootDirectory y recorreremos el dispositivo usando el método getDirectoryListing().

Usaré una función que nos haga el trabajo de reconocer los directorios (carpetas) y archivos para poder guardarlos en un arreglo y usarlo después:

Código :

private var $__arrFile:Array = new Array();

private function readDrive( files:File ):void{
   var arr:Array = files.getDirectoryListing();
   for each (var f:File in arr){
      if (f.isHidden == false){
         if (f.isDirectory){
            trace("Directorio", f.name);
         }else{
            trace("archivo", f.name );
            $__arrFile.push(f);
         }
      }
   }
}

Listo!!!, tenemos guardado en el arreglo todos los archivos que podemos acceder.

¿Y ahora?

Ya tenemos los archivos del dispositivo y podemos basarnos en el anterior tip que hice de Abrir archivos con Adobe AIR 2.0, creando una lista y abriendo con la aplicación por defecto cada file.

Nos valdremos de un componente creado en Flex para poder colocar el nombre del archivo y su id del array. Lo llamaremos MyBox.mxml.

Código :

<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
       xmlns:s="library://ns.adobe.com/flex/spark"
       xmlns:mx="library://ns.adobe.com/flex/mx"
       creationComplete="init()"
       width="200" height="20">
   <s:Label x="10" y="5" width="180" height="15"
          id="campo" buttonMode="true"/>
   
   <fx:Script>
      <![CDATA[
         public var idBox:int;
         
         private function init():void{
            this.addEventListener(MouseEvent.MOUSE_OVER, mouseEvent, false, 0, true);
            this.addEventListener(MouseEvent.MOUSE_OUT, mouseEvent, false, 0, true);
         }
         
         public function setLabel(myText:String):void{
            if(myText.length>=20)
               myText = myText.substr(0,15)+"..."+myText.substr(myText.length-4,4);
            campo.text = myText
         }
         
         private function mouseEvent(e:MouseEvent):void{
            if(e.type == MouseEvent.MOUSE_OVER)
               this.alpha = 0.2;
            else
               this.alpha = 1;
         }
      ]]>
   </fx:Script>
   
</s:Group>

Volvemos a nuestra aplicación y creamos una función que utilice el componente MyBox y haga la lista:

Código :

private function createList():void{
   for (var i:int = 0; i< $__arrFile.length; i++) {
      var box:MyBox = new MyBox();
      box.setLabel( $__arrFile[i].name );
      box.y = 30*i;
      box.idBox = i;
      box.addEventListener(MouseEvent.CLICK, go, false, 0, true);
      boxContent.addElement(box);
   }
}

He creado un listener de Mouse que llama al evento go, que abrirá el archivo con su aplicación por defecto:

Código :

private function go(e:MouseEvent):void{
   var tmp:File = ($__arrFile[e.currentTarget.idBox] as File);
   tmp.openWithDefaultApplication();
}

Y con eso tenemos ya nuestra aplicación funcionando, reconociendo los archivos de tu dispositivo de almacenamiento y al dar click abrir el archivo.

Ingresamos un dispositivo:

Hacemos click a un elemento de la lista, por ejemplo al SWF:

Eso es todo, quería hacer los thumb pero creo que ya salía un poco del tip, pero haré otro con eso :P Aquí les dejo el código completo:

Código :

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
                  xmlns:s="library://ns.adobe.com/flex/spark"
                  xmlns:mx="library://ns.adobe.com/flex/mx"
                  creationComplete="init()"
                  width="300" height="200">

   <fx:Script>
      <![CDATA[
         
         private var $__arrFile:Array = new Array();
         
         private function init():void{
            StorageVolumeInfo.storageVolumeInfo.addEventListener(StorageVolumeChangeEvent.STORAGE_VOLUME_MOUNT, mount, false, 0, true);
            StorageVolumeInfo.storageVolumeInfo.addEventListener(StorageVolumeChangeEvent.STORAGE_VOLUME_UNMOUNT, unMount, false, 0, true);
         }
      
         private function mount(e:StorageVolumeChangeEvent):void{
            var myDrive:StorageVolume = e.storageVolume;
            msg.text = "Se conectó: "+ myDrive.name + "  Size: "+Math.round( (myDrive.rootDirectory.spaceAvailable /1073741824) *100)/100 +" Gb";
            readDrive( myDrive.rootDirectory );
         }
         
         private function unMount(e:StorageVolumeChangeEvent):void{
            msg.text = "Se removió: "+ e.rootDirectory.nativePath;
         }
         
         private function readDrive( files:File ):void{
            var arr:Array = files.getDirectoryListing();
            for each (var f:File in arr){
               if (f.isHidden == false){
                  if (f.isDirectory){
                     trace("Directorio", f.name);
                  }else{
                     trace("archivo", f.name );
                     $__arrFile.push(f);
                  }
               }
            }
            createList();
         }
         
         private function createList():void{
            for (var i:int = 0; i< $__arrFile.length; i++) {
               var box:MyBox = new MyBox();
               box.setLabel( $__arrFile[i].name );
               box.y = 30*i;
               box.idBox = i;
               box.addEventListener(MouseEvent.CLICK, go, false, 0, true);
               boxContent.addElement(box);
            }
         }
         
         private function go(e:MouseEvent):void{
            var tmp:File = ($__arrFile[e.currentTarget.idBox] as File);
            tmp.openWithDefaultApplication();
         }
      ]]>
   </fx:Script>
   
   <s:Label id="msg" width="100%" y="20" text="inserta un USB drive" 
          verticalAlign="top" textAlign="center"
          color="#110E91" fontWeight="bold"/>
   <mx:Box id="boxContent" width="90%" height="126" x="20"  y="40"/>
   
</s:WindowedApplication>

Pueden descargar la aplicación aquí.

Enviar comentario

Control de errores globales en Adobe AIR 2.0

Miércoles, Febrero 24th, 2010

En muchas ocasiones cuando trabajamos con aplicaciones pueden aparecer errores no controlados o inesperados, que muchas veces podemos controlar, pero otras fueron realmente imprevistos. Para eso la nueva versión de Adobe AIR implementa un controlador de errores globales (usando AIR 2.0 y FlashPlayer 10.1), con lo cual NO QUIERE DECIR que, nosotros, los desarrolladores no prestemos importancia al control de errores, sino que será una previsión en caso de no entender porque existió un error desconocido. Por ejemplo, podemos usar la clase UncaughtErrorEvent para detectar un error imprevisto y este ser enviado vía email o al servidor para que nosotros lo solucionemos.

Para empezar, como en los demás tips que escribí, usaremos Flash Builder y el SDK de AIR 2.0.

Primero crearemos la interfaz, un botón que obligue al error y un textArea que nos muestre los mensajes:

Código :

<s:Button id="btn" label="Disparar Error"
           click="viewError(event)"
           horizontalCenter="0" top="10"/>
<s:TextArea  id="txtResp"
           horizontalCenter="0" top="40" width="80%" height="160"
           verticalAlign="top" textAlign="left" color="#FF0000"/>

Ahora utilizaremos la clase UncaughtErrorEvent que nos permite controlar los errores globales.

Código :

loaderInfo.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR, captureError );

Cabe resaltar que podemos controlar errores del propio main de la aplicación, así como otros generados desde swf externos utilizando:

  • LoaderInfo.uncaughtErrorEvents
  • Loader.uncaughtErrorEvents

Estos deben ser escuchados desde el SWF principal ;)

Siguiendo con el ejemplo, nuestro botón llamará a una función que nos genere el error:

Código :

private function viewError(e:Event):void{
   var foo:String = null;
   trace(foo.length);
}

Este error será escuchado por el evento UncaughtErrorEvent y ejecutará nuestra función captureError:

Código :

private function captureError(e:UncaughtErrorEvent):void{
   txtResp.text = "CaptureError";
   if (e.error is Error){
      var error:Error = e.error as Error;
      txtResp.text +=   "nnError ID: " + error.errorID +
                        "nnError Name: " + error.name +
                        "nnError Message:n" + error.message
   }else{
      var errorEvent:ErrorEvent = e.error as ErrorEvent;
      txtResp.text += "n" + errorEvent.errorID
   }
}

Es una gran ventaja el uso de esta clase, ya que nos permite no sólo poder conocer, vía email por ejemplo, de algún error inesperado, sino que podemos decidir si la aplicación puede o no continuar, ya que muchas veces estos errores impiden el flujo normal de la aplicación.

El código completo está aquí:

Código :

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
                  xmlns:s="library://ns.adobe.com/flex/spark"
                  xmlns:mx="library://ns.adobe.com/flex/mx"
                  applicationComplete="init()"
                  width="200" height="230">
   
   <fx:Script>
      <![CDATA[
      
         private function init():void{
            loaderInfo.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR, captureError );
         }
         
         private function captureError(e:UncaughtErrorEvent):void{
            txtResp.text = "CaptureError";
            if (e.error is Error){
               var error:Error = e.error as Error;
               txtResp.text +=   "nnError ID: " + error.errorID +
                           "nnError Name: " + error.name +
                           "nnError Message:n" + error.message
            }else{
               var errorEvent:ErrorEvent = e.error as ErrorEvent;
               txtResp.text += "n" + errorEvent.errorID
            }
         }
         
         private function viewError(e:Event):void{
            var foo:String = null;
            trace(foo.length);
         }
         
      ]]>
   </fx:Script>
   
   
   <s:Button id="btn" label="Disparar Error"
           click="viewError(event)"
           horizontalCenter="0" top="10"/>
   <s:TextArea  id="txtResp"
           horizontalCenter="0" top="40" width="80%" height="160"
           verticalAlign="top" textAlign="left" color="#FF0000"/>
   
</s:WindowedApplication>

Puedes descargar aquí el ejemplo.

Enviar comentario

Accede a las DNS desde Adobe AIR 2

Martes, Febrero 23rd, 2010

Entre las novedades de Adobe AIR 2.0 está la posibilidad de obtener el registros de recursos DNS (Domain Name System) gracias a su nueva API DNSResolver, que cuando obtiene los datos solicitados nos dispara un evento DNSResolverEvent. Incluso ahora puedes obtener información de un host IPv4 (32-bits) y IPv6 (64-bits). Aunque existen varios tipos de registros DNS, Adobe AIR implementa sólo 5:

  • ARecord: Clase que devuelve información de 32-bits de la dirección IPv4.
  • AAAARecord: Clase que devuelve información de 64-bits de la dirección IPv6.
  • MXRecord: Clase que proporciona información acerca de un nombre de dominio apuntando a una lista de intercambio de correo (MX).
  • PTRRecord: Se le conoce como "registro inverso", funciona a la inversa del registro A, traduce IP a dominio.
  • SRVRecord: Permite indicar los servicios que ofrece el dominio.

Como ya explicamos en el tip anterior, debemos usar Flash Builder(FB) o eclipse (con el SDK de flex), sumado a esto tenemos que tener el SDK de AIR 2.0.

Entonces, crearemos una instancia de la clase DNSResolver y un listener que nos permita detectar cuando la información llegue a nuestra aplicación, asimismo usaremos un evento ErrorEvent que nos avise en caso ocurra algún problema.

Código :

private var $__dns:DNSResolver;
         
private function init():void{
   $__dns = new DNSResolver();
   $__dns.addEventListener(DNSResolverEvent.LOOKUP, look, false, 0, true);
   $__dns.addEventListener(ErrorEvent.ERROR, error, false, 0, true);
}

Para poder hacer funcionar el DNSResolver usamos:

Código :

$__dns.lookup( "www.google.com" , ARecord );

Eso nos dará como respuesta la ip, por lo menos a la que yo accedo: 74.125.159.106. Dicha información es capturada desde nuestro método look

Código :

private function look (e:DNSResolverEvent):void{
   var records:Array = new Array();
   records = e.resourceRecords;
   //
   txtResp.text = records[0].address;
}

Con esto ya puedes acceder a la IP del dominio que desees, como el resto de respuestas DNS son casi iguales, las implementé en el código y creo que no es necesario explicar, ya que es muy parecido.

Código :

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
                  xmlns:s="library://ns.adobe.com/flex/spark"
                  xmlns:mx="library://ns.adobe.com/flex/mx"
                  creationComplete="init()"
                  width="300" height="290">
   <s:layout>
      <s:VerticalLayout/>
   </s:layout>
   
   
   <fx:Script>
      <![CDATA[
         import flash.net.dns.AAAARecord;
         import flash.net.dns.ARecord;
         import flash.net.dns.DNSResolver;
         import flash.net.dns.MXRecord;
         import flash.net.dns.PTRRecord;
         import flash.net.dns.SRVRecord;
         
         private var $__dns:DNSResolver;
         
         private function init():void{
            $__dns = new DNSResolver();
            $__dns.addEventListener(DNSResolverEvent.LOOKUP, look, false, 0, true);
            $__dns.addEventListener(ErrorEvent.ERROR, error, false, 0, true);
         }
         
         private function look (e:DNSResolverEvent):void{
            var records:Array = new Array();
            records = e.resourceRecords;
            //
            if (records[0] is ARecord)
               txtResp.text = "Addr: " + records[0].address;
            
            else if (records[0] is PTRRecord)
               txtResp.text = "PTR: " + records[0].ptrdName;
            
            else if (records[0] is MXRecord){
               txtResp.text = "Exchange: " + records[0].exchange;
               txtResp.text += "nPreference: " +records[0].preference;
            }
            else if (records[0] is SRVRecord)
            {
               var priority:String = "Priority: " + records[0].priority;
               var weight:String = "Weight: " + records[0].weight;
               var port:String = "Port: " + records[0].port;
               var target:String = "Target: " + records[0].target;
               
               txtResp.text += priority + "n" + weight + "n" + port + "n" + target;
            }
         }
         
         private function error(e:ErrorEvent):void{
            txtResp.text = "ERROR: "+e;
         }
         
         private function go():void{
            var type:String = cbType.selectedItem.label;
            switch(type)
            {
               case "ARecord":
                  $__dns.lookup(campo.text, ARecord);
                  break;
               case "AAAARecord":
                  $__dns.lookup(campo.text, AAAARecord);
                  break;      
               case "MXRecord":
                  $__dns.lookup(campo.text, MXRecord);
                  break;
               case "PTRRecord":
                  $__dns.lookup(campo.text, PTRRecord);
                  break;
               case "SRVRecord":
                  $__dns.lookup(campo.text, SRVRecord);
                  break;
            }
         }
         
      ]]>
   </fx:Script>
   
   <mx:HBox horizontalCenter="0"  paddingTop="10" width="300" horizontalAlign="center">   
      <s:Label text="Consultar:" paddingTop="5"/>
      <s:TextInput id="campo" width="200"/>
   </mx:HBox>
   
   <mx:HBox paddingLeft="10" width="300" horizontalAlign="center">
      <mx:ComboBox editable="false" id="cbType">
         <fx:Array>
            <fx:Object label="ARecord" />
            <fx:Object label="AAAARecord" />
            <fx:Object label="MXRecord" />
            <fx:Object label="PTRRecord" />
            <fx:Object label="SRVRecord" />
         </fx:Array>
      </mx:ComboBox>
      <s:Button id="btn" click="go()" label="Ver información"/>
      
   </mx:HBox>
   
   <mx:Box paddingLeft="10" width="300" horizontalAlign="center">
      <s:TextArea id="txtResp" width="90%" height="200" />
   </mx:Box>
   
</s:WindowedApplication>

Puedes descargar la aplicación aquí.

Enviar comentario

Abrir archivos desde Adobe AIR 2.0

Lunes, Febrero 22nd, 2010

-
Cuando Adobe decidió escuchar a los principales desarrolladores o agencias sobre que les gustaría implementar en la nueva versión de Adobe AIR, muchos de ellos querían abrir archivos externos logrando con esto un gran abanico de posibilidades. Con la nueva versión de Adobe AIR 2.0 se puede seleccionar un archivo y abrirlo con su aplicación por defecto, si este archivo no tiene asignado una aplicación con cual poder abrir, mostrará un error. Por otro lado, no puedes acceder a este archivo para manipularlo ya que te saldrá un mensaje de Seguridad (por lo menos no con File, lo veremos en otro tip).

Como ya explicamos en el tip anterior, debemos usar Flash Builder(FB) o eclipse (con el SDK de flex), sumado a esto tenemos que tener el SDK de AIR 2.0.

Vamos a crear un boton en FB para que nos dispare una función:

Código :

<s:Button id="btn" label="Open File" click="openNewFile()" />

La función nos abrirá el browser para poder seleccionar el archivo que deseamos:

Código :

private var $__file:File;
         
private function openNewFile():void{
   $__file = new File();
   $__file.addEventListener(Event.SELECT, fileSelected, false, 0, true);
   $__file.browseForOpen("Buscar archivo a abrir!!");
   //con esto también podemos poner un título a la ventana que abrirá
}

Nuestro evento Event.SELECT será ejecutado cuando ya tengamos aceptado el archivo que seleccionamos.

Código :

private function fileSelected(e:Event):void{
   try {
      //aquí la magia
      $__file.openWithDefaultApplication();
   } catch(error:Error) {
      trace("Problemas con el archivo a abrir");
   }
}

Y listo, con esto podemos probar y ver que logramos abrir un .PSD en Photoshop o un .DOC en Word, siempre y cuando estas apicaciones sean "por defecto".

Aquí el código completo

Código :

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
                  xmlns:s="library://ns.adobe.com/flex/spark"
                  xmlns:mx="library://ns.adobe.com/flex/mx" width="356" height="183">
   
   <fx:Script>
      <![CDATA[
         
         private var $__file:File;
         
         private function openNewFile():void{
            $__file = new File();
            $__file.addEventListener(Event.SELECT, fileSelected, false, 0, true);
            $__file.browseForOpen("Buscar archivo a abrir!!");
         }
         
         private function fileSelected(e:Event):void{
            try {
               $__file.openWithDefaultApplication();
            } catch(error:Error) {
               trace("Problemas con el archivo a abrir");
            }
         }
         
      ]]>
   </fx:Script>
   
   
   <s:Button id="btn" label="Open File" click="openNewFile()" horizontalCenter="0" verticalCenter="0"/>
   
   
</s:WindowedApplication>

Descarga la aplicación aquí

Enviar comentario

Multitouch con Adobe AIR 2, Flash Lite 4 y Flash Player 10.1

Lunes, Febrero 22nd, 2010

-
Con las novedades del Flash Player 10.1, Flash Lite 4 y AIR 2.0 existe una que a los usuarios de iphone o macbook les debe ser muy familiar, el multitouch. En este tip enseñaremos como utilizar la clase TransformGestureEvent que nos permite zoom y rotar elementos. Para eso necesitamos Flash Builder con el SDK de AIR 2.0 que ya pueden descargar del sitio Adobe Labs. Cuando Flash CS5 sea liberado, también podrán usarlo para sus aplicaciones.

Una vez configurado el SDK de AIR 2.0, creamos un proyecto FLEX del tipo Desktop (Adobe AIR) y lo primero que haremos es cargar una imagen que usaremos de ejemplo:

Código :

var l:Loader = new Loader();
l.load(new URLRequest("logo.png"));
l.x = l.y = -100;
$__img1 = new Image();
$__img1.addChild(l);
this.addElement($__img1);
$__img1.x = $__img1.y = 200;

Con eso agregamos un elemento a nuestro stage de la aplicación, y ahora pasamos a agregar un evento para que detecte la rotación, usaremos el evento TransformGestureEvent del tipo GESTURE_ROTATE

Código :

this.addEventListener(TransformGestureEvent.GESTURE_ROTATE, _rotation, false, 0, true);

Este evento se dispará cuando se detecte los dos dedos sobre el stage y hagas el movimiento de rotación

Código :

private function _rotation(e:TransformGestureEvent):void{
$__img1.rotation += e.rotation;
}

Ahora, si queremos usar el zoom o escalar los elementos abriendo o cerrando los dedos sobre el stage usamos GESTURE_ZOOM del evento TransformGestureEvent.

Código :

this.addEventListener(TransformGestureEvent.GESTURE_ZOOM, _zoom, false, 0, true);

Y creamos su función:

Código :

private function _zoom(e:TransformGestureEvent):void
{
   if (e.scaleX > 1)
   {
      $__img1.scaleX += e.scaleX / 100;
      $__img1.scaleY += e.scaleY / 100;
   }
   else
   {
      $__img1.scaleX -= e.scaleX / 100;
      $__img1.scaleY -= e.scaleY / 100;
   }
}

Aquí es necesario un IF porque siempre está detectando que el zoom actual es 1 cada vez que interactuas, entonces si juntas los dedos al momento de querer hacer ZoomIN, irá de 1.0, 0.9, 0.8 así sucesivamente.

La aplicación final quedaría así:

Código :

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
                  xmlns:s="library://ns.adobe.com/flex/spark"
                  xmlns:mx="library://ns.adobe.com/flex/mx"
                  creationComplete="init()"
                  width="320"
                  height="400">

   <fx:Script>
      <![CDATA[
         import mx.controls.Image;
         private var $__img1:Image;

         //
         private function init():void
         {
            var l:Loader=new Loader();
            l.load(new URLRequest("logo.png"));
            l.x=l.y=-100;
            $__img1=new Image();
            $__img1.addChild(l);
            this.addElement($__img1);
            $__img1.x=$__img1.y=200;
            //
            $__img1.addEventListener(MouseEvent.MOUSE_DOWN, activeMove, false, 0, true);
            $__img1.addEventListener(MouseEvent.MOUSE_UP, activeMove, false, 0, true);
            this.addEventListener(TransformGestureEvent.GESTURE_ROTATE, _rotation, false, 0, true);
            this.addEventListener(TransformGestureEvent.GESTURE_ZOOM, _zoom, false, 0, true);
         }

         private function _rotation(e:TransformGestureEvent):void
         {
            $__img1.rotation+=e.rotation;
         }

         private function _zoom(e:TransformGestureEvent):void
         {
            if (e.scaleX > 1)
            {
               $__img1.scaleX+=e.scaleX / 100;
               $__img1.scaleY+=e.scaleY / 100;
            }
            else
            {
               $__img1.scaleX-=e.scaleX / 100;
               $__img1.scaleY-=e.scaleY / 100;
            }
         }

         private function activeMove(e:MouseEvent):void
         {
            if (e.type == MouseEvent.MOUSE_DOWN)
               $__img1.startDrag();
            else if (e.type == MouseEvent.MOUSE_UP)
               $__img1.stopDrag();
            else
               throw new Error("upsss!!!");
         }
      ]]>
   </fx:Script>
</s:WindowedApplication>

Puedes descargar el ejemplo aquí, necesitas tener el runtime de AIR 2

Enviar comentario

Wired crea aplicación para iPads y tablets en Adobe AIR

Jueves, Febrero 18th, 2010

-
Los últimos cinco años, el negocio del contenido impreso se ha ido al mismo lugar donde quedó el telégrafo o Windows Vista. La inversión en publicidad en medios impresos baja constantemente, los periódicos dejan de circular y las revistas mueren o convierten su negocio a una estrategia 100% en linea. Muchos terminan ganando menos, compitiendo con blogs, copypasteadores o innovadores de la industria web. Y hay razones y culpables.

Otros, como Wired, rompen todo esquema y lanzan algo realmente interesante.

¿Recuerdan que Adobe anunció Flash Player 10.1 completo y Adobe AIR para dispositivos móviles? Aprovechando este anuncio, Wired ha creado una nueva experiencia multimedia para leer sus revistas. Con AIR se podrá exportar este producto a Windows, Linux y Mac. En el caso móvil, será posible exportarlo también a tablets basadas en Android. Al final, con el compilador para iPhone de Flash CS5 y el mismo código, lo pondrán en la App Store y podrá ser usado en el iPad.


Una estrategia completa en todas las plataformas usando AIR, InDesign, algo de HTML5 (parece) y Flash.

¿Funcionará? No tengo idea, sigue siendo contenido de pago, pero definitivamente es una experiencia superior y única a lo que ofrece la web. Quizás funcione, quizás no salve a la industria, pero seguro la innovación apoyará a mejorar la industria impresa y empujarla al futuro. ¿Qué opinan ustedes?

Enviar comentario

El futuro de Flash

Jueves, Febrero 11th, 2010

Desde que el iPad fue anunciado, sin Flash, mucha gente ha estado especulando su caída. Se suma el experimento de Youtube con HTML 5 y el tag <video>. Tal fue el hype generado por la supuesta muerte, que dedicamos un capítulo de MejorandoLaWeb al tema.

El mundo de Flash está cambiando. La computación está cambiando. La web está cambiando. Pero Flash no morirá y si Adobe toma las decisiones correctas, incluso puede convertirse en el líder de campos que no esperamos. Este año será decidido todo.

Flash, HTML 5, Javascript y el video

HTML 5 tiene cosas impresionantes. Drag and Drop de archivos al navegador, animaciones vectoriales en SVG, un tag para embeber video, otro tag para audio, acceso a disco y geolocalización por múltiples métodos (GPS, IP, manual, etc). Esto ha dado pie a que muchos digan que "Flash es innecesario".

Molly Holzschlag es una de las personas que más sabe de estándares en el mundo y compiló una lista de capacidades de HTML 5 y los navegadores que las implementan. No es mala la implementación, pero usarla en producción es triste.

El video es un problema "emocional". Algunos quieren OGG como formato, otros H.264 y otros algo completamente diferente. Ahora mismo, el tag <video> tiene la misma versatilidad de las epocas del Real Player.

Cosas que hace Flash que no puede hacer HTML5 o JS ni hay planes para que pueda

  • Streaming: UStream, Tinychat, Livestream, incluso Youtube live, inviables con "estándares".
  • Animación vectorial compleja: SVG? CSS3? Jajajaja. Si tu crees que hacer animaciones con esas tecnologías es más fácil, igual que Flash y gasta menos CPU, no has comparado a nivel técnico. La realidad es que actualmente, sólo Flash lo permite como debe ser. El resto de animaciones en SVG, CSS3 o JS gastan demasiada CPU y no hay un software del nivel de Flash para crearlas.
  • Edición y manipulación de audio: AS3 es capaz de mezclar audio en tiempo real. Nadie más puede hacerlo al nivel de AS3.
  • Edición bit por bit de mapas de bits: Aviary, Picnik y Photoshop Online hechos en Flash y Flex lo demuestran. ¿En HTML5 o JS? Ninguno realmente usable.
  • 100% de compatibilidad a través de todas las plataformas: Si dices que es posible escribir un sólo código HTML5/CSS/JS que funcione en todos los navegadores ahora mismo, no has hecho nada profesional. En SWF es normal

Flash no es sólo el player. Flash CS5 es un entorno integrado con la capacidad de diseñar, dibujar, animar, incluir video, audio, editar todos estos componentes, agregar interactividad y programación de alta complejidad, compilar para desktops, móviles o iPhones. Ninguna herramienta del lado "estándar abierto" ofrece ese nivel de integración ahora mismo. No Dreamweaver, no Visual Studio 2010, no Aptana, ni siquiera una combinación de varias.

Flash, teléfonos móviles, Apple

El mundo móvil es diferente. El iPhone cambió el mundo y estableció una fuerte tendencia a las tiendas de aplicaciones, la integración de HTML 5 actualizado en el teléfono e ignorar a Flash. Android y otros siguieron el mismo camino.

Este mes en el Mobile World Congress, Adobe presentará el Flash Player 10.1 para todos los teléfonos móviles (excepto iPhone), un compilador especial para crear apps de iPhone con SWF desde Flash CS5 y el secreto a gritos, una forma unificada de desarrollar apps "pseudo-nativas" para Android, WebOS, Blackberry y Symbian, con un mismo código.

Flash ya era usado por el 90% de la humanidad conectada antes de Youtube. Las animaciones y los juegos en linea lograron posicionar a Flash en el principio. No hay razón para pensar que no pasará a nivel móvil. Ninguna empresa tiene un entorno tan avanzado para el desarrollo de juegos móviles como Adobe con Flash. Y pasará en todas las plataformas de teléfonos actuales (En tu Nokia 1100 puede que no)

¿Y Flex? ¿Y Adobe AIR?

Flex es líder en desarrollo de RIAs. No se nota mucho su presencia en la web, pero está en muchas intranets y empresas. Aun no tengo claro si Flex Mobile hará un impacto tan fuerte como Flash/AIR Mobile, pero su presencia como la mejor y más veloz herramienta para aplicaciones web se mantendrá, a pesar de que HTML 5 y jQuery UI son amenazas muy reales y fuertes.

Adobe AIR tiene que evolucionar. El uso de archivos .air y "badge installers" es simplemente estúpido. No está mal que los ofrezcan, pero también incluyan la opción de crear instaladores por SO. Si el rumor de AIR Mobile es cierto y cometen una cagada como la de los .air, Flash no será el sueño que esperábamos. Esperemos que Adobe tome la decisión correcta.

Flash "estándar", Flash Open Source

Flash es estándar en el mismo sentido que los .doc y .docx lo son. Es una realidad. No es algo malo de por sí, pero muchos no se sienten cómodos. Flash tiene abiertas las especificaciones del formato SWF, pero prohíben crear "players" alternativos con esas specs ¿Por qué? Según ellos, para proteger la segmentación del mercado y mantener un sólo player. Yo solía creer en esto.

Ya no lo creo más. La pésima forma en la que Adobe ha manejado las plataformas móviles (i-Mode -> Flash Lite con AS0.5 -> muerte de Flash Lite -> vacío -> ¿10.1?) , sumado a la lección de Android que se puede tener una distro oficial open source sin perder el control me lo deja claro. Adobe debería, sin duda, liberar el código del Player y permitir que la comunidad "ayude". Si Adobe no puede implementar bien Flash en Linux y Mac, la comunidad sí podrá. ¿El miedo es que Microsoft los mate como mató a Java con una maquina virtual especial? Adobe ya está grande y debe poder superar esto. Con su penetración, pueden mantener el control de un player abierto.

Si no, quizás y el 2022, cuando HTML 5 será un estándar cerrado y aprobado, será realmente el declive de Flash.

NOTA: Si "odias Flash", por favor cita razones técnicas para odiarlo.
Si crees que estoy equivocado y Flash morirá, di tus razones técnicas o políticas por la que lo crees.
Si no tienes razones y es sólo porque "no te gusta", reflexiona.
Lee los comentarios, han aportado mucho al tema.

Enviar comentario