Tópicos Selectos de Xamarin Parte 1: Entendiendo Dependency Services
Xamarin.Forms es una plataforma increíble para crear aplicaciones móviles que funcionan en Android, iOS y Windows. De una manera ágil y dinámica, utilizamos un solo lenguaje para la funcionalidad (C#) y para el diseño (XAML, o también C#) de manera tal que el código de la lógica es compartido por los proyectos y los elementos visuales se mapean a elementos nativos y comportamientos propios de cada plataforma.
¿Podemos extender Xamarin.Forms en caso de ser necesario? Las necesidades de extensión incluyen:
- Modificar aspectos de la UI.
- Aprovechar a fondo las capacidades que nos ofrece cada plataforma.
- Crear nuevos controles o páginas.
La respuesta es sí, existen varias técnicas para lograrlo, y el día de hoy hablaremos de Dependency Service.
Justificación
Cada plataforma expone funcionalidad importante (y en ocasiones crítica) que no es directamente accesible desde el API de alto nivel en Forms. Por ejemplo:
- Acceso a la cámara
- Notificaciones locales
- Uso de sensores (GPS, batería, …)
- Etc.
Técnicas como Dependency Injection y Dependency Service llegan al rescate para extender la funcionalidad de nuestras apps móviles desarrolladas en Xamarin.Forms.
Definición
Dependency Service es una técnica que permite a las apps acceder a funcionalidad específica de plataforma desde el código compartido. De esta manera, los desarrolladores pueden crear apps que hagan todo lo que una app nativa puede hacer exponiendo un servicio que encuentra una implementación específica de una interfaz.
¿Cómo funciona?
Se requieren 4 componentes para utilizar Dependency Service:
- Interfaz. La funcionalidad requerida es definida a través de una interfaz en el proyecto de código compartido.
- Implementación por cada plataforma. Las clases que implementan la interfaz deben ser agregadas en cada proyecto de plataforma.
- Registro. Cada clase implementada debe ser registrada con Dependency Service a través de un atributo de metadatos. El registro permite a encontrar la clase a implementar y suministrarla en lugar de la interfaz en tiempo de ejecución.
- Llamada al Dependency Service. El código compartido necesita llamar explícitamente a Dependency Service para preguntar por implementaciones de la interfaz.
La mejor manera de entenderlo es con una práctica, así que manos a la obra.
Paso 1. Crea un nuevo proyecto de aplicación móvil Xamarin.Forms llamado DemoTTS.
Paso 2. Selecciona la plantilla de aplicación vacía y la estrategia de uso compartido .NET Standard.
Paso 3. Vamos a crear la interfaz. Para una buena organización de nuestra solución vamos a agregar una nueva carpeta en el proyecto DemoTTS (proyecto compartido) haciendo clic derecho en el nombre del proyecto.
Paso 4. El nombre de esta carpeta es Interfaces. Ahora da clic derecho sobre ella para agregar un nuevo elemento.
Paso 5. Este elemento es de tipo Interfaz y se llama ITextToSpeech.
Paso 6. El código de esta interfaz se muestra a continuación. Como puedes ver, define un método llamado Speak que acepta un parámetro de tipo string. Cada clase que implemente esta interfaz debe definir el código específico de plataforma para realizar la operación deseada.
Paso 7. Ahora vamos con la implementación del servicio de dependencias en cada plataforma. Comenzamos con Android. Abre el archivo MainActivity.cs (dentro del proyecto DemoTTS.Android) y agrega una instancia estática de MainActivity, asignándole el valor this antes del Forms.Init (dentro del método OnCreate). El código relevante se muestra encerrado en rojo en la siguiente imagen:
Paso 8. Agrega una nueva carpeta en el proyecto DemoTTS.Android haciendo clic derecho en el nombre del proyecto.
Paso 9. El nombre de esta carpeta es Clases. Ahora da clic derecho sobre ella para agregar una nueva clase.
Paso 10. El nombre de esta clase es TextToSpeechAndroid, y su código se muestra a continuacón. Si observas, la clase implementa la interfaz previamente definida (además de heredar de Object e implementar un IOnInitListener, los cuales son necesarios para sintetización de voz en una aplicación de Android). Con respecto a la interfaz ITextToSpeech, el método Speak es definido junto con su código específico de plataforma.
Observa también que el registro de esta clase TextToSpeechAndroid sucede con el atributo assembly: Dependency.
Paso 11. Ahora vamos con la implementación del servicio de dependencias en iOS. Haz clic derecho sobre el nombre del proyecto DemoTTS.iOS y agrega una nueva carpeta.
Paso 12. El nombre de esta carpeta es Clases. Ahora da clic derecho sobre ella para agregar una nueva clase.
Paso 13. Esta clase se llama TextToSpeechiOS y, al igual que en Android, implementa la interfaz ITextToSpeech (con el método Speak, por supuesto, que contiene código y objetos nativos a la plataforma de Apple para realizar la conversión de texto a voz). El código se muestra a continuación.
Observa también que el registro de esta clase TextToSpeechiOS se realiza con el atributo assembly: Dependency.
Paso 14. Ahora damos paso a la implementación del servicio de dependencias para el proyecto de UWP. Comienza dando clic derecho sobre el proyecto DemoTTS.UWP y agrega una nueva carpeta.
Paso 15. Esta carpeta se llama… ¡adivinaste! Clases y si das clic derecho, selecciona agregar una nueva clase…
Paso 16. La cual se llama TextToSpeechUWP y contiene el siguiente código específico de la plataforma de Windows 10 para sintetizar texto a voz. Observa también que el registro de esta clase TextToSpeechUWP ocurre con el atributo assembly: Dependency.
Paso 17. Como paso adicional, en el archivo App.xaml.cs del proyecto DemoTTS.UWP debes registrar la clase que acabas de crear con el código marcado en rojo en la siguiente imagen después del Forms.Init:
Paso 18. Otro paso requerido en la plataforma de Windows 10 es que se necesita solicitar el permiso del micrófono. Para ello da clic derecho en las Properties del proyecto DemoTTS.UWP:
Paso 19. Da clic en el Manifiesto del paquete (package manifest).
Paso 20. En la pestaña Capacidades (Capabilities) marca la casilla del Micrófono y guarda el archivo.
Ahora vamos a consumir el servicio de dependencias ya que tenemos todas las implementaciones de plataforma (NOTA: Si solo vas a probar el servicio en Android e iOS, no es necesario que agregues el código de UWP pero es recomendable cuando te dedicas profesionalmente a esto).
Paso 21. En primer lugar, vamos de regreso al proyecto DemoTTS (código compartido) y da clic derecho para agregar una nueva carpeta llamada Paginas.
Paso 22. Repite el proceso y agrega otra carpeta llamada Servicios. Ahora da clic derecho sobre esta nueva carpeta y agrega una clase.
Paso 23. Esta nueva clase se llama ServicioTTS y a través del método Get de DependencyService es que en tiempo de ejecución se determina cuál es la clase específica de plataforma que implementa ITextToSpeech, la cual obviamente correspondiente al sistema operativo del dispositivo donde está corriendo la aplicación móvil. Una vez determinada la instancia, se llama al método Speak. El código se muestra a continuación.
Paso 24. Ahora agrega un nuevo elemento en la carpeta Paginas.
Paso 25. Este elemento es de tipo Pagina de contenido (Content Page) y tiene por nombre PaginaTextoVoz.
El código XAML de esta página se muestra a continuación. Básicamente es un Label informativo, un Entry para el mensaje que queremos que el dispositivo diga y el Button para lanzar la acción.
El code-behind en C# se muestra a continuación. Solo necesitamos programar el manejador de evento Clicked del botón de la página con la llamada al método Speak del ServicioTTS recién creado.
Paso 26. Ya para concluir, abre el archivo App.xaml.cs del proyecto DemoTTS para modificar la página de inicio a PaginaTextoVoz:
Paso 27. Compila y ejecuta tu aplicación. El resultado es el siguiente:
Si analizas tu código, básicamente esto es lo que desarrollaste e implementaste:
¿Qué tal te pareció esta práctica? Espero que haya sido útil para tí y hayas aprendido lo básico de Dependency Service en Xamarin.Forms. En futuras entregas hablaré de los otros 3 temas mencionados al inicio: Custom Renderers, Effects y Styles para que estés al pendiente del blog 😉
¡Ah y por cierto! El código fuente de este proyecto está disponible en mi repositorio de GitHub .
No olvides compartir esta publicación con tus amigos o a quien pueda interesarle .
Si tienes alguna duda, sugerencia o comentario, házmelo saber.
¡Gracias por tu visita y hasta la próxima!
Luis