Inicio > Delphi, FMX, Tethering, VCL, XE6 > Tethering; Operaciones básicas…

Tethering; Operaciones básicas…

miércoles, 23 de abril de 2014 Dejar un comentario Ir a comentarios
Share Button

images Una de las características más atractivas de la nueva versión de RAD Studio, y sobre la que seguro continuaremos hablando, pues están previstas ampliaciones y mejoras para las próximas versiones, es el AppThthering. Antes de continuar con el artículo, os dejo unos links por si queréis revisar documentación sobre esta característica. Si ya lo habéis revisado, pues podéis continuar con la introducción.

Lo primero a revisar es la DocWiki de Embarcadero. Con esta información ya podemos iniciar. No es que sea muy extensa, pero está la suficiente y básica del funcionamiento.

También podéis revisar la entrada anterior que publiqué en el blog, en la que os mostré algunas preguntas y respuestas que aparecieron en la presentación de embarcadero sobre características del nuevo RAD Studio. Hay un bloque dedicado a AppTethtering bastante clarificador.

Añadir un par de videos que se pueden encontrar en el canal de embarcadero:

Por último, os remito a algunas entradas de los blogs de embarcadero, como la de Sarina DuPond titulada “Extend your Windows apps to mobile with Tethering in XE6”,  o esta publicada en Fixed by Code titulada “Fun with Delphi XE6 App tethering and barcodes”.

 

INTRODUCCIÓN

Si a estas alturas no ha quedado claro (con todo lo anterior) qué es y para qué se usa el Tethering, sólo queda citar el siguiente párrafo (traducido):

Usando Tethering sus aplicaciones pueden fácilmente:

  • Descubrir otras aplicaciones que estén usando Tethering y ejecutándose en el mismo dispositivo o de otros dispositivos que estén conectados a la red (interna).
  • Ejecutar acciones de forma remota. Una aplicación puede “publicar” acciones, de forma que las otras aplicaciones puedan invocarlas/llamarlas de forma remota.
  • Compartir datos entre aplicaciones. El Tethering permite intercambiar tipos de Datos estándar y streams.

El tethering no depende de un protocolo específico de transporte de datos, de forma que se pueden implementar nuevos protocolos utilizando la API de tethering. La RTL proporciona soporte para conexiones ethernet que se ejecutan en la misma red local (LAN), incluso si se están ejecutando en el mismo dispositivo.

Hay que decir que el tethering, aunque puede ser muy útil en determinados escenarios, tiene un funcionamiento bastante básico desde el punto de vista del programador. Toda la gestión la realizamos utilizando 2 componentes (iguales para todas las aplicaciones que lo utilizan).

TTetheringManager

Este componente es el que está más enfocado a las conexiones entre dispositivos.

TTetheringAppProfile

Es el componente que está más enfocado al intercambio de Datos. Es el que se utiliza para “publicar” acciones que posteriormente se van a compartir entre aplicaciones o para enviar y recibir recursos.

 

OPERACIONES BÁSICAS

Vamos a hacer un recorrido por las operaciones básicas que podemos realizar entre aplicaciones.

 

EXPLORACIÓN

Lo primero que podemos hacer cuando arrancamos una aplicación en la que estamos trabajando con Tethering es explorar la red en busca de aplicaciones a las que nos podamos conectar.
Hay 2 formas de conectarse a otras aplicaciones; Veremos que hay un modo “automático” y un modo “manual”. Dejaré el “modo automático” para más adelante y ahora vamos a centrarnos en el manual.

Lo primero que podemos hacer al arrancar la aplicación es “explorar” la red en busca de aplicaciones con las que nos podamos “emparejar”; Para ello el componente de TTetheringManager cuenta con el método DiscoverManagers, al que le pasamos un parámetro opcional de Timeout.

0
1
// Buscar otras aplicaciones
ttManager.DiscoverManagers(3000);

 

En la imagen siguiente podemos ver 2 aplicaciones, cada una en la parte superior con su “Identificador”. Una vez realizamos la búsqueda, podemos recorrer la propiedad RemoteManagers para acceder a las aplicaciones que hemos encontrado. En la imagen inferior, podemos ver el resultado de la búsqueda.

Imagen1216

Si ejecutamos varias aplicaciones (instancia FMX) y volvemos a realizar la búsqueda, veremos que el resultado es el esperado (cada aplicación al iniciar genera como identificador un nuevo GUID), de forma que el resultado es el siguiente:

Imagen1217

Al finalizar la búsqueda “salta”  el evento OnEndManagersDiscovery, que podemos capturar para saber cuando podemos continuar.

 

EMPAREJAR APLICACIONES

Si continuamos trabajando con la búsqueda “manual”, una vez tenemos el resultado de la búsqueda, si nos interesa podremos realizar el “pair” (como Delphi le llama) o emparejamiento de aplicaciones.
Para ello utilizamos el método PairManager de TTetheringManager, con una llamada tan simple como esta:

0
1
2
3
4
5
var
mInfo:TTetheringManagerInfo;
begin
  // Emparejar el seleccionado   
  mInfo := ttManager.RemoteManagers[mmAplicaciones.ItemIndex];   
  ttManager.PairManager(mInfo);

Utilizamos la lista obtenida y disponible en RemoteManager para la llamada.

Si todo funciona correctamente, en la aplicación que ha realizado la llamada “saltará” un evento OnPairedToRemote (con la información del Manager al que nos hemos conectado como parámetro) y en la aplicación a la que nos hemos conectado “saltará” el evento OnPairedFromLocal con la información igualmente del manager como parámetro.

Si se intenta realizar más de una vez este “emparejamiento” veremos que los eventos no vuelven a saltar, mientras ambas aplicaciones sigan conectadas.

 

EMPAREJAMIENTO AUTOMÁTICO

Como hemos visto, el emparejamiento “manual” es bastante sencillo. En el caso del automático, aun lo es más, pues basta con hacer una llamada al método AutoConnect en nuestra aplicación. Con ello, se hace una búsqueda de aplicaciones disponibles y se intenta el emparejamiento de forma automática.

UTILIZANDO CONEXION CON PASSWORD

Al realizar las conexiones (emparejamientos) tenemos la posibilidad de añadir algo de seguridad utilizando un password. El en componente TTetheringManager podemos rellenar la propiedad de Password.

Cuando una aplicación intenta realizar el emparejamiento con otra (con otro componente  TTetheringManager), “protegido” con un password, “salta” el evento OnRequestManagerPassword en la aplicación que intenta hacerla conexión. Utilizando este evento podemos rellenar “in situ” el password (o solicitarlo al usuario) que necesita el emparejamiento.

0
1
2
3
4
5
procedure TFormMain.ttManagerRequestManagerPassword(const Sender: TObject;
  const RemoteIdentifier: string; var Password: string);
begin
  _Log('OnRequestManagerPassword; ' + RemoteIdentifier);
  Password := 'EmbarcaderoXE6';
end;

COMPARTIR DATOS CON RECURSOS

Hay varias formas de compartir datos entre aplicaciones. La primera que vamos a ver (y que me ha resultado muy intuitiva) es la que utiliza Recursos compartidos (públicos).

La idea es la siguiente; Desde una aplicación publicamos un recurso con un nombre único y desde cualquiera de las aplicaciones que tenemos “emparejada” a ella, podemos solicitar directamente el valor de ese recurso a partir del nombre único que hemos definido anteriormente.

Imagen1219

Imagen1218

En la aplicación que publica el recurso (SharedRes1), podemos modificar su valor accediendo a los recursos “locales” que hemos publicado:

0
1
  // Modificar el valor de nuestro recurso compartido
  ttaProfiler.Resources.FindByName('SharedRes1').Value := ‘nuevo valor’;

Y desde las aplicaciones conectadas podemos acceder a los recursos compartidos, primero accediendo al “RemoteProfile” y luego directamente al recurso (a partir del nombre único) o también podemos acceder a la lista que los contiene todos y recorrerla.

Para ello desde el TTetheringManager tenemos la propiedad RemoteProfiles, para acceder a los “RemoteProfiles”. Una vez que ye tenemos el “RemoteProfile” podemos acceder a un recurso de forma individual (GetRemoteResourceValue) o a la lista completa de los publicados (GetRemoteProfileResources).

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var
  rRes:TRemoteResource;
  pInfo:TTetheringProfileInfo;
begin
 
  // Primero accedemos al perfil remoto
  pInfo := ttManager.RemoteProfiles[0];
  // Luego accedemos al Recurso a partir del nombre único.
  rRes := ttaProfile.GetRemoteResourceValue(pInfo, 'SharedRes1');
 
  // Otra opción sería recorrer la lista de recursos
  _Log('Recursos remotos: ' + IntToStr(ttaProfile.GetRemoteProfileResources(pInfo).Count));
  // Accedemos (en este caso) al primero
  rRes := ttaProfile.GetRemoteProfileResources(pInfo)[0];
 
  // Valores del recurso
  _Log('   Name: ' + rRes.Name);
  _Log('   Hint: ' + rRes.Hint);
  _Log('   Value: ' + rRes.Value.AsString);
 
  // Finalmente accedemos al valor
  edtRes.Text := rRes.Value.AsString;

 

Por último, queda una opción interesante que es la de “Suscribirse a los cambios de un recurso”. De forma, que los cambios que se producen en ese recurso, se reciben de forma automática por todos aquellos que se hayan suscrito.

Para ello, al igual que antes, basta con utilizar el “RemoteProfile” y el nombre único que hemos asignado a nuestro recurso. Un código tan simple como este:

0
1
2
3
// Para obtener el “RemoteProfile” y el “RecursoRemoto” se hace igual que hemos
// en el código anterior…
// Nos subscribimos para futuros cambios
ttaProfile.SubscribeToRemoteItem(pInfo, rRes);

Os adjunto un video sencillo donde se ve funcionando…

 

NOTA: Hay en la parte central un pequeño desfase entre el sonido y las acciones, pero no afectan a la compresión del video (creo –es muy pequeña-). Cosas de ser novato en esto de las presentaciones…  ;-)

 

ENVIANDO DATOS A RECURSOS TEMPORALES

Hemos visto cómo intercambiar datos entre aplicaciones utilizando “Shared resources” (recursos compartidos), aunque también podemos hacerlo utilizando lo que se llaman “recursos temporales”.  En este caso una aplicación envía directamente datos a otro (sin ninguna definición previa) y la segunda los recibe en un “recurso temporal”.

Para ello basta con que la aplicación utilice el método SendString o SendStream sobre uno de “profiles” de las aplicaciones a las que está conectada. Bastaría con un código como el siguiente:

0
1
2
3
4
5
6
var
  mInfo:TTetheringProfileInfo;
begin
  // Acceder al primer Profile de los conectados
  mInfo := ttManager.RemoteProfiles[0];
  // Enviar una cadena
  ttaProfiler.SendString(mInfo, 'Enviando cadena...', edtSend.Text {cadena a enviar});

La aplicación a la que realizamos el envío, recibe un primer evento OnAcceptResource, en el que tenemos datos del recurso y la posibilidad (mediante el parámetro Accept) de aceptar el envío o no. La cabecera del evento es la siguiente:

0
1
2
procedure TFormMain.ttaProfileAcceptResource(const Sender: TObject;
  const AProfileId: string; const AResource: TCustomRemoteItem;
  var AcceptResource: Boolean);

Una vez que aceptamos el recurso, nos llega un segundo evento; OnResourceReceived en el que por parámetro tenemos acceso al recurso que se nos ha enviado.

 

EJECUTANDO ACCIONES

Por último, vamos a ver cómo ejecutar acciones en aplicaciones a las que estamos “emparejados”.  De forma similar a como se hace en los recursos podemos ejecutar acciones “remotas” de dos formas.

Para la primera utilizamos una llamada directa a las acciones que se publican en otra aplicación y para la segunda veremos como hacerlo “mapeando” una acción en local con una en Remoto.

En cualquier caso lo primero que debemos hacer es crear una acción en nuestra aplicación y “publicarla” para que pueda ser llamada desde otras aplicaciones a las que nos hemos “emparejado”. Para ello creamos una Action utilizando un TActionList como lo hacemos siempre. Una vez la tenemos, en nuestro AppProfile creamos una “Action local” que enlaza con la que queremos publicar. Con esto ya tenemos nuestra acción lista para ser ejecuta “en remoto” (por una aplicación “emparejada” con la esta).

EJECUTAR UNA ACCIÓN REMOTA DIRECTAMENTE

La forma más directa de ejecutar una acción que tiene publicada una de las aplicaciones con las que nos hemos emparejado es utilizar el método GetRemoteProfileActions, desde el AppProfile de nuestra aplicación. Co ello podremos acceder a las acciones publicadas en otra aplicación.

Código de ejemplo:

0
1
2
3
4
5
6
7
8
9
var
  ra:TRemoteAction;
begin
 
  // Accedemos a la acción publicada en la aplicación
  ra := ttaProfile.GetRemoteProfileActions(ttManager.RemoteProfiles[0]).Items[0];
  // Si hemos podido encontrarla, la ejecutamos…
  if Assigned(ra) then begin
    ra.Execute;
  end;

Así de simple y así de potente.

Hay que tener en cuenta que en estos ejemplos, yo estoy accediendo directamente a los elementos de la lista utilizando el índice [0]; En una aplicación real, habría que implementar algunas precauciones en función de los elementos creados o recorrer las listas (si hubiera más de un elemento) para acceder exactamente al elemento deseado. Es este caso lo hemos hecho así para simplificar.

EJECUTAR UNA ACIÓN REMOTA USANDO UNA LOCAL.

La alternativa para ejecutar una acción remota es crear una local y “mapear” en cierta manera ambas. De esta forma, cuando ejecutas la “acción local” en programa ejecuta la acción remota de la aplicación a la que está conectado.

Para ello debemos marcar la acción local como tipo “Mirror”; Es lo único necesario (y diferente) para ejecutar una acción de una aplicación “emparejada” a ejecutar una local.

En la imagen siguiente podemos ver,  un TActionList con una TAction definida con el nombre ActionCerrar (1). Hasta aquí como siempre.

Luego nuestro componente ttaProfile en la propiedad Actions, posee una TActionLocal llamada ActionCerrar (2) y que se enlaza con la acción estándar definida antes (3).

Por último podemos ver como esta TActionLocal tiene la propiedad Kind a Mirror, que es lo que marca que al ejecutarla, se ejecute la Acción remota de otra aplicación.

Imagen1225

Aunque en la explicación parece complejo, una vez que se hace es bastante sencillo, tal y como se ve en el vídeo anterior.

AÑADIDO: me había dejado por publicar el código de las aplicaciones.

<Link al código fuente>

Hasta aquí la entrada. Espero que os sea útil. Como siempre los comentarios, críticas, sugerencias,…  será bien recibidas.

Un saludo.

Share Button
Categories: Delphi, FMX, Tethering, VCL, XE6 Tags: , ,
  1. casimiro
    martes, 29 de abril de 2014 a las 12:35 | #1

    Muy interesante.

  2. Neftalí
    martes, 29 de abril de 2014 a las 15:45 | #2

    @casimiro
    Gracias Antonio.

  3. Jose Angel
    viernes, 9 de mayo de 2014 a las 12:35 | #3

    Y yo seguía preguntándome que era eso del Tethering y tenemos aquí un How to for dummies.

    Muchas gracias.

  4. lunes, 9 de junio de 2014 a las 22:57 | #4

    super bien explicado!!!
    gracias :)

  5. dec
    lunes, 20 de octubre de 2014 a las 12:50 | #5

    ¡Aquí otro dummy agradecido! Gracias Germán, vamos ahora al otro artículo:

    http://neftali.clubdelphi.com/?p=3647

    :)

  6. Angel
    miércoles, 11 de febrero de 2015 a las 20:51 | #6

    Hola
    Buen tutorial!.
    Tengo una pregunta: haz usado estos componentes de tethering en un form modal? Me refiero a un form que no sea el principal y que no tenga AutoCreate, es decir un TForm que uno crea, hace ShowModal y luego Free.
    La pregunta viene a que quedan resource leaks relacionados con los 2 componentes de tethering y no se como solucionarlos… Estoy probando con XE7 y uso la conexcion automática (uso AutoConnect) al estilo de los ejemoplos de Embarcadero!!
    Saludos y gracias

  7. Neftalí
    jueves, 12 de febrero de 2015 a las 10:46 | #7

    @Angel
    El form que he utilizado no era modal, pero a priori eso no debe tener nada que ver con la liberación de recursos. El Free del componente es el mismo método independientemente de quien lo llame (sea un form que se visualiza en modal o no).
    Es más, podrías crear y destruir un componente sin necesidad de formulario.

    Un saludo.

  8. miércoles, 18 de febrero de 2015 a las 17:43 | #8

    Hola, quisiera preguntarle si es razonable utilizar Tethering para pasar datos de un celular a una aplicacion delphi. Mi proyecto es recibir mensajes enviados desde celulares que no tienen plan de datos para reportar si se reviso el contador, enviar el valor de un contador, envia un mensaje de texto que incluye el numero de contador y el valor en el contador, el mensaje se recibe y se lee con delphi la cola de mensajes recibido(encontre un ejemplo en la web) ahora requiero enviarlo al computador , o suguiere usar otra tecnica para pasar datos de un telefono al sistema

  9. Neftalí
    jueves, 19 de febrero de 2015 a las 10:21 | #9

    @Carlos A Ramirez
    Hola Carlos.
    Si en teléfono y el computador están en la misma red wifi (o accesibles por bluetooth) sí que es posible.´
    En cuando a razonable, lo único que debes tener en cuenta (y hacer algunas pruebas) es que si la cantidad de datos es muy grande, tal vez tengas que probar la velocidad para ver si es adecuada a tu proyecto.

  10. viernes, 1 de septiembre de 2017 a las 19:12 | #10

    Estoy probando con un escritorio y un supuesto móvil. El escritorio genera un contador de 1 a 100 y el móvil lo recibe perfectamente. Pero si pongo dos móviles la velocidad de recepción baja una burrada. Se ocurre algo?

  11. viernes, 1 de septiembre de 2017 a las 19:13 | #11

    La conexión es manual y solo comparto un recurso en el escritorio que es el numero

  12. jueves, 7 de septiembre de 2017 a las 13:34 | #12

    @Manolo
    Hace tiempo que no hago pruebas, pero no debería pasar.
    Prueba cobn la opción que se describe en: “ENVIANDO DATOS A RECURSOS TEMPORALES” a ver si el problema persiste.

    Un saludo.

  1. Sin trackbacks aún.
What is 21 + 4 ?
Please leave these two fields as-is:
IMPORTANTE! Para continuar, debes contestar la pregunta anterior (para evitar SPAM) :-)