Xamarin.Forms
Acceso a funciones nativas con DependencyService
Buscar..
Observaciones
Si no desea que su código se rompa cuando no se encuentra ninguna implementación, primero verifique que DependencyService
tiene una implementación disponible.
Puede hacerlo mediante una simple comprobación si no es null
.
var speaker = DependencyService.Get<ITextToSpeech>();
if (speaker != null)
{
speaker.Speak("Ready for action!");
}
o, si su IDE es compatible con C # 6, con el operador condicional nulo:
var speaker = DependencyService.Get<ITextToSpeech>();
speaker?.Speak("Ready for action!");
Si no hace esto y no se encuentra ninguna implementación en tiempo de ejecución, su código generará una excepción.
Implementando texto a voz
Un buen ejemplo de una característica que solicita código específico de plataforma es cuando desea implementar texto a voz (tts). Este ejemplo asume que está trabajando con código compartido en una biblioteca PCL.
Una vista general esquemática de nuestra solución se vería como la imagen de abajo.
En nuestro código compartido definimos una interfaz que está registrada con DependencyService
. Aquí es donde haremos nuestros llamamientos. Definir una interfaz como la de abajo.
public interface ITextToSpeech
{
void Speak (string text);
}
Ahora, en cada plataforma específica, necesitamos crear una implementación de esta interfaz. Vamos a empezar con la implementación de iOS.
Implementación de iOS
using AVFoundation;
public class TextToSpeechImplementation : ITextToSpeech
{
public TextToSpeechImplementation () {}
public void Speak (string text)
{
var speechSynthesizer = new AVSpeechSynthesizer ();
var speechUtterance = new AVSpeechUtterance (text) {
Rate = AVSpeechUtterance.MaximumSpeechRate/4,
Voice = AVSpeechSynthesisVoice.FromLanguage ("en-US"),
Volume = 0.5f,
PitchMultiplier = 1.0f
};
speechSynthesizer.SpeakUtterance (speechUtterance);
}
}
En el ejemplo de código anterior, observa que hay un código específico para iOS. Me gusta tipos como AVSpeechSynthesizer
. Estos no funcionarían en código compartido.
Para registrar esta implementación con el Servicio de DependencyService
Xamarin, agregue este atributo encima de la declaración de espacio de nombres.
using AVFoundation;
using DependencyServiceSample.iOS;//enables registration outside of namespace
[assembly: Xamarin.Forms.Dependency (typeof (TextToSpeechImplementation))]
namespace DependencyServiceSample.iOS {
public class TextToSpeechImplementation : ITextToSpeech
//... Rest of code
Ahora, cuando realiza una llamada como esta en su código compartido, se inyecta la implementación correcta para la plataforma en la que está ejecutando su aplicación.
DependencyService.Get<ITextToSpeech>()
. Más sobre esto más adelante.
Implementación de Android
La implementación de Android de este código se vería debajo.
using Android.Speech.Tts;
using Xamarin.Forms;
using System.Collections.Generic;
using DependencyServiceSample.Droid;
public class TextToSpeechImplementation : Java.Lang.Object, ITextToSpeech, TextToSpeech.IOnInitListener
{
TextToSpeech speaker;
string toSpeak;
public TextToSpeechImplementation () {}
public void Speak (string text)
{
var ctx = Forms.Context; // useful for many Android SDK features
toSpeak = text;
if (speaker == null) {
speaker = new TextToSpeech (ctx, this);
} else {
var p = new Dictionary<string,string> ();
speaker.Speak (toSpeak, QueueMode.Flush, p);
}
}
#region IOnInitListener implementation
public void OnInit (OperationResult status)
{
if (status.Equals (OperationResult.Success)) {
var p = new Dictionary<string,string> ();
speaker.Speak (toSpeak, QueueMode.Flush, p);
}
}
#endregion
}
Nuevamente, no olvide registrarlo en DependencyService
.
using Android.Speech.Tts;
using Xamarin.Forms;
using System.Collections.Generic;
using DependencyServiceSample.Droid;
[assembly: Xamarin.Forms.Dependency (typeof (TextToSpeechImplementation))]
namespace DependencyServiceSample.Droid{
//... Rest of code
Implementación de Windows Phone
Finalmente, para Windows Phone se puede usar este código.
public class TextToSpeechImplementation : ITextToSpeech
{
public TextToSpeechImplementation() {}
public async void Speak(string text)
{
MediaElement mediaElement = new MediaElement();
var synth = new Windows.Media.SpeechSynthesis.SpeechSynthesizer();
SpeechSynthesisStream stream = await synth.SynthesizeTextToStreamAsync("Hello World");
mediaElement.SetSource(stream, stream.ContentType);
mediaElement.Play();
await synth.SynthesizeTextToStreamAsync(text);
}
}
Y una vez más no te olvides de registrarlo.
using Windows.Media.SpeechSynthesis;
using Windows.UI.Xaml.Controls;
using DependencyServiceSample.WinPhone;//enables registration outside of namespace
[assembly: Xamarin.Forms.Dependency (typeof (TextToSpeechImplementation))]
namespace DependencyServiceSample.WinPhone{
//... Rest of code
Implementando en Código Compartido
¡Ahora todo está listo para que funcione! Finalmente, en su código compartido ahora puede llamar a esta función utilizando la interfaz. En tiempo de ejecución, se inyectará la implementación que corresponda a la plataforma actual en la que se está ejecutando.
En este código, verá una página que podría estar en un proyecto de Xamarin Forms. Crea un botón que invoca el método Speak()
usando el servicio DependencyService
.
public MainPage ()
{
var speak = new Button {
Text = "Hello, Forms !",
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.CenterAndExpand,
};
speak.Clicked += (sender, e) => {
DependencyService.Get<ITextToSpeech>().Speak("Hello from Xamarin Forms");
};
Content = speak;
}
El resultado será que cuando se ejecute la aplicación y se haga clic en el botón, se pronunciará el texto proporcionado.
Todo esto sin tener que hacer cosas difíciles como sugerencias del compilador y demás. Ahora tiene una forma uniforme de acceder a la funcionalidad específica de la plataforma a través del código independiente de la plataforma.
Obtención de los números de versión del SO de la aplicación y del dispositivo - Android e iOS - PCL
El siguiente ejemplo recopilará el número de versión del SO del dispositivo y la versión de la aplicación (que se define en las propiedades de cada proyecto) que se ingresa en Nombre de versión en Android y Versión en iOS.
Primero haz una interfaz en tu proyecto PCL:
public interface INativeHelper {
/// <summary>
/// On iOS, gets the <c>CFBundleVersion</c> number and on Android, gets the <c>PackageInfo</c>'s <c>VersionName</c>, both of which are specified in their respective project properties.
/// </summary>
/// <returns><c>string</c>, containing the build number.</returns>
string GetAppVersion();
/// <summary>
/// On iOS, gets the <c>UIDevice.CurrentDevice.SystemVersion</c> number and on Android, gets the <c>Build.VERSION.Release</c>.
/// </summary>
/// <returns><c>string</c>, containing the OS version number.</returns>
string GetOsVersion();
}
Ahora implementamos la interfaz en los proyectos de Android e iOS.
Androide:
[assembly: Dependency(typeof(NativeHelper_Android))]
namespace YourNamespace.Droid{
public class NativeHelper_Android : INativeHelper {
/// <summary>
/// See interface summary.
/// </summary>
public string GetAppVersion() {
Context context = Forms.Context;
return context.PackageManager.GetPackageInfo(context.PackageName, 0).VersionName;
}
/// <summary>
/// See interface summary.
/// </summary>
public string GetOsVersion() { return Build.VERSION.Release; }
}
}
iOS:
[assembly: Dependency(typeof(NativeHelper_iOS))]
namespace YourNamespace.iOS {
public class NativeHelper_iOS : INativeHelper {
/// <summary>
/// See interface summary.
/// </summary>
public string GetAppVersion() { return Foundation.NSBundle.MainBundle.InfoDictionary[new Foundation.NSString("CFBundleVersion")].ToString(); }
/// <summary>
/// See interface summary.
/// </summary>
public string GetOsVersion() { return UIDevice.CurrentDevice.SystemVersion; }
}
}
Ahora para usar el código en un método:
public string GetOsAndAppVersion {
INativeHelper helper = DependencyService.Get<INativeHelper>();
if(helper != null) {
string osVersion = helper.GetOsVersion();
string appVersion = helper.GetBuildNumber()
}
}