Seguimos aprendiendo y profundizando nuestros conocimientos en desarrollo móvil con Xamarin.Forms, este fin de semana se ha revisando y desarrollo algunos ejercicios prácticos acerca de las notificaciones locales haciendo uso de algunas funcionalidades de reloj del dispositivo móvil y la clase DependencyService que es un localizador de servicios que habilita las aplicaciones desde Xamarin.Forms con el fin de invocar la funcionalidad nativa de la plataforma desde código compartido.
Considerando que las notificaciones locales son alertas enviadas por aplicaciones instaladas en nuestros dispositivo móvil y menudo se usan para funciones como:
👦 Recordatorios.
📅 Eventos del calendario.
📌 Ubicaciones basado en geolocalización
DependencyService
Es el servicio de dependencia que permite acceder a funcionalidades nativas de cada plataforma con el fin de resolver la implementación de una capa interfaz sencilla. En el siguiente diagrama, se muestra cómo se invoca la funcionalidad nativa de la plataforma en una aplicación de Xamarin.Forms:
Diagrama referencial de https://docs.microsoft.com |
Para poder profundizar el concepto acerca de DependencyService sugiero revisar el siguiente link:
Lo interesante de todo esto es que Xamarin.Forms también nos facilita el uso de Plugins, para realizar este tipo de funcionalidad sin tener que codificar en cada plataforma, los más usados son:
👍 Xam.Plugin.Badge
👍 Plugin.Notifications
Más adelante iremos revisando y creando ejemplos prácticos con ambos plugins, por ahora implementaremos el ejemplo práctico apoyándonos con DependencyService y de este modo ir potenciando nuestra curva de aprendizaje en Xamarin.Forms; empecemos.
Requisitos:
Microsoft Visual Studio Community 2019.
Xamarin.Froms - XAML.
DependencyService.
Para lo cual iniciamos creando nuestro proyecto de nombre LocalNotifications de tipo Aplicación Móvil (Xamarin.Forms), seleccionamos la plantilla En Blanco y marcamos para las Plataformas de Android y iOS.
Luego agregaremos un elemento de tipo interfaz de nombre INotification.cs y una clase con el nombre de Notification.cs en el proyecto principal LocalNotifications. Finalmente agregamos clase AndroidNotification en el proyecto LocalNotifications.Android.
Diseño de Interfaz:
Entry x:Name="_entryMessage": Será el encargado de determinar el texto o mensaje a notificar.
TimePicker x:Name="_timeExecute": Encargado de definir la hora para ejecutar la notificación local.
Switch x:Name="_switchActive": Define si se envía o no la notificación de acuerdo a lo ingresado y según la hora definido; es decir en caso este inactivo se ejecuta la notificación de acuerdo a la HORA definido, caso contrario a pesar de estar en la HORA definido y NO este activo, la notificación no se ejecutará.
Los demás elementos son de tipo Label que son etiquetas estáticas como completo de nuestra interfaz de diseño con XAML.
Para este ejemplo práctico todas las pruebas se viene realizando en un equipo móvil físico con Sistema Operativo Android, aclarando que esto no restringe el uso de emuladores y recordar que sólo se viene implementado por ahora los proyectos para la plataforma de Android.
XAML completo del archivo SignUpLogin.xaml
<?xml
version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="LocalNotifications.MainPage"
Title="Notifications"
Padding="10">
<StackLayout Margin="0,35,0,0"
x:Name="stackLayout">
<Label Text="Crear
notificación"
TextColor="#424949"
HorizontalOptions="Center"
VerticalOptions="Start"
FontSize="Large"/>
<Entry x:Name="_entryMessage"
Placeholder="Ingresa
en mensaje o texto a notificar..."
FontSize="16"/>
<StackLayout HorizontalOptions="FillAndExpand" Orientation="Horizontal">
<Label Text="Determinar
Hora"
TextColor="#424949"
HorizontalOptions="StartAndExpand"
FontSize="16"
VerticalOptions="Center"/>
<TimePicker x:Name="_timeExecute"
Time="12:00:00"
Format="t"
PropertyChanged="OnTimePickerPropertyChanged" />
</StackLayout>
<StackLayout HorizontalOptions="FillAndExpand" Orientation="Horizontal">
<Label Text="Activar
Notificación"
TextColor="#424949"
HorizontalOptions="StartAndExpand"
FontSize="16"
VerticalOptions="Center"/>
<Switch x:Name="_switchActive"
HorizontalOptions="EndAndExpand"
Toggled="OnSwitchToggled" />
</StackLayout>
</StackLayout>
</ContentPage>
Implementar el CodeBehind:
En la interfaz INotification.cs ya creada en el proyecto LocalNotifications e ingresamos las siguiente instrucción:
using System;
namespace LocalNotifications
{
public interface INotification
{
/// <summary>
/// Delegado nulo que servira para retorna el valor de la notificación
a nuestro intefaz del XAML MainPage
/// </summary>
event EventHandler NotificationReceived;
/// <summary>
/// Método para inicializar la creación del canal de notificación en
base a la versión del SDK
/// </summary>
void Initialize();
/// <summary>
/// Método para definir el horario de ejecución a notificar
/// </summary>
/// <param name="title"></param>
/// <param name="message"></param>
/// <returns></returns>
int ScheduleNotification(string title, string
message);
/// <summary>
/// Método para mostrar la notificación en la interfaz creada
/// </summary>
/// <param name="title"></param>
/// <param name="message"></param>
void ReceiveNotification(string title, string
message);
}
}
Luego creamos los siguiente atributos de tipo publico de nuestra clases o entidad Notification.cs ubicado en el proyecto LocalNotifications:
using System;
namespace LocalNotifications
{
public class Notification : EventArgs
{
public string Title { get; set; }
public string Message
{ get; set; }
}
}
Para finalizar el desarrollo en las 3 clases creadas, se implementará la interfaz de cada método creado en la clase AndroidNotification del proyecto LocalNotifications.Android:
using System;
using Android.App;
using Android.Content;
using Android.Graphics;
using Android.OS;
using Android.Support.V4.App;
using Xamarin.Forms;
using AndroidApp = Android.App.Application;
[assembly: Dependency(typeof(LocalNotifications.Droid.AndroidNotification))]
namespace LocalNotifications.Droid
{
public class AndroidNotification : INotification
{
const string
channelId = "default";
const string
channelName = "Default";
const string
channelDescription = "The default channel for
notifications.";
const int
pendingIntentId = 0;
public const string TitleKey = "title";
public const string MessageKey = "message";
bool channelInitialized = false;
int messageId = -1;
NotificationManager manager;
public event
EventHandler NotificationReceived;
public void
Initialize()
{
CreateNotificationChannel();
}
public int
ScheduleNotification(string title, string message)
{
if (!channelInitialized)
{
CreateNotificationChannel();
}
messageId++;
Intent intent = new Intent(AndroidApp.Context, typeof(MainActivity));
intent.PutExtra(TitleKey, title);
intent.PutExtra(MessageKey, message);
PendingIntent pendingIntent =
PendingIntent.GetActivity(AndroidApp.Context, pendingIntentId, intent,
PendingIntentFlags.OneShot);
NotificationCompat.Builder builder
= new
NotificationCompat.Builder(AndroidApp.Context, channelId)
.SetContentIntent(pendingIntent)
.SetContentTitle(title)
.SetContentText(message)
.SetLargeIcon(BitmapFactory.DecodeResource(AndroidApp.Context.Resources,
Resource.Drawable.xamagonBlue))
.SetSmallIcon(Resource.Drawable.xamagonBlue)
.SetDefaults((int)NotificationDefaults.Sound | (int)NotificationDefaults.Vibrate);
Android.App.Notification
notification = builder.Build();
manager.Notify(messageId,
notification);
return messageId;
}
public void
ReceiveNotification(string title, string message)
{
var args = new
Notification()
{
Title = title,
Message = message,
};
NotificationReceived?.Invoke(null, args);
}
void CreateNotificationChannel()
{
manager = (NotificationManager)AndroidApp.Context.GetSystemService(AndroidApp.NotificationService);
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
{
var channelNameJava = new Java.Lang.String(channelName);
var channel = new
NotificationChannel(channelId, channelNameJava, NotificationImportance.Default)
{
Description =
channelDescription
};
manager.CreateNotificationChannel(channel);
}
channelInitialized = true;
}
}
}
Recordemos además que debemos inicializar la aplicación y el DependencyService desde el CodeBehind del archivo App.xaml.cs del proyecto LocalNotifications:
public App()
{
InitializeComponent();
DependencyService.Get<INotification>().Initialize();
MainPage = new MainPage();
}
Ahora se implementará las siguientes instrucciones en el CodeBehind del archivo MainPage.xaml.cs y de este modo dar funcionalidad a todo lo desarrollado:
El método OnTimerNotification es quien realmente se encarga de realizar la notificación, es decir es la interfaz que se encarga de inicializar la ejecución de la notificación de acuerdo a la hora definido y además es el encargado de secuenciar todo el canal de ejecución en base al método CreateNotificationChannel, recuerda que para ello debe determina la invocación o implementación de DependencyService al carga el MainPage.xaml.cs.
Los demás métodos o instrucciones cuenta con las explicación en cabecera de cada uno de ellos (sección <summary>).
using System;
using System.ComponentModel;
using Xamarin.Forms;
namespace LocalNotifications
{
public partial class MainPage : ContentPage
{
INotification notification;
int notifNumber = 0;
DateTime _triggerTime;
public MainPage()
{
InitializeComponent();
//Inicializa la
referencia a la interfaz para poder ejecutar la notificación
notification =
DependencyService.Get<INotification>();
//Se encarga de
recuperar los datos de la notificación para mostrar en pantalla
notification.NotificationReceived
+= (sender, eventArgs) =>
{
var evtData = (Notification)eventArgs;
ShowNotification(evtData.Title,
evtData.Message);
};
//Se encarga de
iniciar la ejecucón de la notificación según el horario definido
Device.StartTimer(TimeSpan.FromSeconds(1), OnTimerNotification);
}
#region notification
/// <summary>
/// Metodo para la ejecucón de la notificación
/// </summary>
/// <returns></returns>
bool OnTimerNotification()
{
if (_switchActive.IsToggled && DateTime.Now >=
_triggerTime)
{
_switchActive.IsToggled = false;//Se desactiva
con el fin de poder crear otra notificación
notifNumber++;
string title = $"Notificación N° {notifNumber}";
string message = _entryMessage.Text
notification.ScheduleNotification(title,
message); //Interfaz que se encarga de inicializar la ejecución de
la notificación de acuerdo a la hora definido y secuenciar todo el canal de
ejecución
}
return true;
}
/// <summary>
/// Recuperar los datos de la notificación ejecutada
/// </summary>
/// <param name="title"></param>
/// <param name="message"></param>
void ShowNotification(string title, string message)
{
Device.BeginInvokeOnMainThread(() =>
{
var msg = new Label()
{
Text = $"Notificación recibida:\nTitle: {title}\nMessage: {message}"
};
stackLayout.Children.Add(msg);
});
}
#endregion
#region timeExecute
/// <summary>
/// Método encargado de capturar el tiempo del elemento TimePicker
x:Name="_timeExecute"
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
void OnTimePickerPropertyChanged(object sender, PropertyChangedEventArgs args)
{
if (args.PropertyName == "Time")
{
SetTriggerTime();
}
}
/// <summary>
/// Captura el valor de la propiedad Toggled del elemento Switch
x:Name="_switchActive" de acuerdo a la HORA de ejecución DEFINIDO
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
void OnSwitchToggled(object sender, ToggledEventArgs args)
{
SetTriggerTime();
}
/// <summary>
/// Método que DETERMINA o DEFINE el tiempo de ejecución en base a la
PROPIEDAD OnTimePickerPropertyChanged del elemento TimePicker
x:Name="_timeExecute"
/// </summary>
void SetTriggerTime()
{
if (_switchActive.IsToggled)
{
_triggerTime = DateTime.Today +
_timeExecute.Time;
if (_triggerTime < DateTime.Now)
{
_triggerTime +=
TimeSpan.FromDays(1);
}
}
}
#endregion
}
}
Resultado:
Comparto el vídeo 📹 acerca de lo desarrollado de acuerdo a la descripción de este post publicado, las pruebas fueron validados en plataforma 📱 para Android.
Descarga la fuente de:
En proceso de carga... |
Gratitud a Dios nuevamente😊y gracias a todos ustedes por la acogida de este nuevo post, éxitos y bendiciones 🙏 y un gran abrazo a todos, y cuidarse como siempre ✌...!!!
0 Comentarios