Notificaciones locales de :::no-loc(Xamarin.Forms):::Local notifications in :::no-loc(Xamarin.Forms):::

Descargar ejemplo Descargar el ejemploDownload Sample Download the sample

Las notificaciones locales son alertas que envían las aplicaciones instaladas en un dispositivo móvil.Local notifications are alerts sent by applications installed on a mobile device. Se suelen usar a menudo en características como las siguientes:Local notifications are often used for features such as:

  • Eventos de calendarioCalendar events
  • RecordatoriosReminders
  • Desencadenadores basados en la ubicaciónLocation-based triggers

Cada plataforma controla la creación, la visualización y el consumo de notificaciones locales de manera diferente.Each platform handles the creation, display, and consumption of local notifications differently. En este artículo se explica cómo crear una abstracción multiplataforma para enviar y recibir notificaciones locales con :::no-loc(Xamarin.Forms):::.This article explains how to create a cross-platform abstraction to send and receive local notifications with :::no-loc(Xamarin.Forms):::.

Aplicación de notificaciones locales en iOS y AndroidLocal notifications application on iOS and Android

Creación de una interfaz multiplataformaCreate a cross-platform interface

La aplicación de :::no-loc(Xamarin.Forms)::: debe crear y consumir notificaciones sin preocuparse por las implementaciones subyacentes de la plataforma.The :::no-loc(Xamarin.Forms)::: application should create and consume notifications without concern for the underlying platform implementations. La siguiente interfaz de INotificationManager se implementa en la biblioteca de código compartido y define una API multiplataforma que la aplicación puede usar para interactuar con las notificaciones:The following INotificationManager interface is implemented in the shared code library, and defines a cross-platform API that the application can use to interact with notifications:

public interface INotificationManager
{
    event EventHandler NotificationReceived;

    void Initialize();

    int ScheduleNotification(string title, string message);

    void ReceiveNotification(string title, string message);
}

Esta interfaz se implementará en cada proyecto de plataforma.This interface will be implemented in each platform project. El evento NotificationReceived permite que la aplicación controle las notificaciones entrantes.The NotificationReceived event allows the application to handle incoming notifications. El método Initialize debe ejecutar alguna lógica de plataforma nativa necesaria para preparar el sistema de notificación.The Initialize method should perform any native platform logic needed to prepare the notification system. El método ScheduleNotification debe enviar una notificación.The ScheduleNotification method should send a notification. La plataforma subyacente debe llamar al método ReceiveNotification cuando se reciba un mensaje.The ReceiveNotification method should be called by the underlying platform when a message is received.

Uso de la interfaz en :::no-loc(Xamarin.Forms):::Consume the interface in :::no-loc(Xamarin.Forms):::

Una vez creada una interfaz, se puede usar en el proyecto compartido de :::no-loc(Xamarin.Forms)::: aunque aún no se hayan creado las implementaciones de la plataforma.Once an interface has been created, it can be consumed in the shared :::no-loc(Xamarin.Forms)::: project even though platform implementations haven't been created yet. La aplicación de ejemplo contiene un elemento ContentPage denominado MainPage.xaml con el siguiente contenido:The sample application contains a ContentPage called MainPage.xaml with the following content:

<StackLayout Margin="0,35,0,0"
             x:Name="stackLayout">
    <Label Text="Click the button to create a local notification."
           TextColor="Red"
           HorizontalOptions="Center"
           VerticalOptions="Start" />
    <Button Text="Create Notification"
            HorizontalOptions="Center"
            VerticalOptions="Start"
            Clicked="OnScheduleClick"/>
</StackLayout>

El diseño contiene un elemento Label con instrucciones para el usuario y un elemento Button que debe programar una notificación cuando se pulse.The layout contains a Label element with instructions for the user and a Button that should schedule a notification when tapped.

El código subyacente de la clase MainPage controla el envío y la recepción de notificaciones:The MainPage class code-behind handles the sending and receiving of notifications:

public partial class MainPage : ContentPage
{
    INotificationManager notificationManager;
    int notificationNumber = 0;

    public MainPage()
    {
        InitializeComponent();

        notificationManager = DependencyService.Get<INotificationManager>();
        notificationManager.NotificationReceived += (sender, eventArgs) =>
        {
            var evtData = (NotificationEventArgs)eventArgs;
            ShowNotification(evtData.Title, evtData.Message);
        };
    }

    void OnScheduleClick(object sender, EventArgs e)
    {
        notificationNumber++;
        string title = $"Local Notification #{notificationNumber}";
        string message = $"You have now received {notificationNumber} notifications!";
        notificationManager.ScheduleNotification(title, message);
    }

    void ShowNotification(string title, string message)
    {
        Device.BeginInvokeOnMainThread(() =>
        {
            var msg = new Label()
            {
                Text = $"Notification Received:\nTitle: {title}\nMessage: {message}"
            };
            stackLayout.Children.Add(msg);
        });
    }
}

El constructor de clase MainPage usa el elemento DependencyService de :::no-loc(Xamarin.Forms)::: para recuperar una instancia específica de la plataforma de INotificationManager.The MainPage class constructor uses the :::no-loc(Xamarin.Forms)::: DependencyService to retrieve a platform-specific instance of the INotificationManager. El método OnScheduleClicked usa la instancia de INotificationManager para programar una nueva notificación.The OnScheduleClicked method uses the INotificationManager instance to schedule a new notification. Se llama al método ShowNotification desde el controlador de eventos asociado al evento NotificationReceived y se inserta un nuevo elemento Label en la página cuando se invoca el evento.The ShowNotification method is called from the event handler attached to the NotificationReceived event, and will insert a new Label into the page when the event is invoked.

El controlador de eventos NotificationReceived convierte sus argumentos de evento en NotificationEventArgs.The NotificationReceived event handler casts its event arguments to NotificationEventArgs. Este tipo se define en el proyecto compartido de :::no-loc(Xamarin.Forms)::::This type is defined in the shared :::no-loc(Xamarin.Forms)::: project:

public class NotificationEventArgs : EventArgs
{
    public string Title { get; set; }
    public string Message { get; set; }
}

Para obtener más información sobre DependencyService de :::no-loc(Xamarin.Forms):::, vea DependencyService de :::no-loc(Xamarin.Forms):::.For more information about the :::no-loc(Xamarin.Forms)::: DependencyService, see :::no-loc(Xamarin.Forms)::: DependencyService.

Creación de la implementación de la interfaz de AndroidCreate the Android interface implementation

Para que la aplicación de :::no-loc(Xamarin.Forms)::: envíe y reciba notificaciones en Android, esta debe proporcionar una implementación de la interfaz INotificationManager.For the :::no-loc(Xamarin.Forms)::: application to send and receive notifications on Android, the application must provide an implementation of the INotificationManager interface.

Creación de la clase AndroidNotificationManagerCreate the AndroidNotificationManager class

La clase AndroidNotificationManager implementa la interfaz INotificationManager:The AndroidNotificationManager class implements the INotificationManager interface:

using Android.Support.V4.App;
using :::no-loc(Xamarin.Forms):::;
using AndroidApp = Android.App.Application;

[assembly: Dependency(typeof(LocalNotifications.Droid.AndroidNotificationManager))]
namespace LocalNotifications.Droid
{
    public class AndroidNotificationManager : INotificationManager
    {
        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);

            var notification = builder.Build();
            manager.Notify(messageId, notification);

            return messageId;
        }

        public void ReceiveNotification(string title, string message)
        {
            var args = new NotificationEventArgs()
            {
                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;
        }
    }
}

El atributo assembly situado encima del espacio de nombres registra la implementación de la interfaz de INotificationManager con DependencyService.The assembly attribute above the namespace registers the INotificationManager interface implementation with the DependencyService.

Android permite que las aplicaciones definan varios canales para las notificaciones.Android allows applications to define multiple channels for notifications. El método Initialize crea un canal básico que usa la aplicación de ejemplo para enviar notificaciones.The Initialize method creates a basic channel the sample application uses to send notifications. El método ScheduleNotification define la lógica específica de la plataforma necesaria para crear y enviar una notificación.The ScheduleNotification method defines the platform-specific logic required to create and send a notification. Por último, el sistema operativo Android llama al método ReceiveNotification cuando se recibe un mensaje e invoca el controlador de eventos.Finally, the ReceiveNotification method is called by the Android OS when a message is received, and invokes the event handler.

Nota

La clase Application se define en los espacios de nombres :::no-loc(Xamarin.Forms)::: y Android.App, por lo que el alias AndroidApp se define en las instrucciones using para diferenciar los dos.The Application class is defined in both the :::no-loc(Xamarin.Forms)::: and Android.App namespaces so the AndroidApp alias is defined in the using statements to differentiate the two.

Administración de las notificaciones entrantes en AndroidHandle incoming notifications on Android

La clase MainActivity debe detectar las notificaciones entrantes y notificar la instancia de AndroidNotificationManager.The MainActivity class must detect incoming notifications and notify the AndroidNotificationManager instance. El atributo Activity de la clase MainActivity debe especificar un valor LaunchMode de LaunchMode.SingleTop:The Activity attribute on the MainActivity class should specify a LaunchMode value of LaunchMode.SingleTop:

[Activity(
        //...
        LaunchMode = LaunchMode.SingleTop]
    public class MainActivity : global:::::no-loc(Xamarin.Forms):::.Platform.Android.FormsAppCompatActivity
    {
        // ...
    }

El modo SingleTop impide que se inicien varias instancias de un elemento Activity mientras la aplicación está en primer plano.The SingleTop mode prevents multiple instances of an Activity from being started while the application is in the foreground. Es posible que este valor de LaunchMode no sea adecuado para las aplicaciones que inician varias actividades en escenarios de notificación más complejos.This LaunchMode may not be appropriate for applications that launch multiple activities in more complex notification scenarios. Para más información sobre los valores de enumeración de LaunchMode, consulte la actividad LaunchMode de Android.For more information about LaunchMode enumeration values, see Android Activity LaunchMode.

En la clase MainActivity se modifica para recibir notificaciones entrantes:In the MainActivity class is modified to receive incoming notifications:

protected override void OnCreate(Bundle savedInstanceState)
{
    // ...

    global:::::no-loc(Xamarin.Forms):::.Forms.Init(this, savedInstanceState);
    LoadApplication(new App());
    CreateNotificationFromIntent(Intent);
}

protected override void OnNewIntent(Intent intent)
{
    CreateNotificationFromIntent(intent);
}

void CreateNotificationFromIntent(Intent intent)
{
    if (intent?.Extras != null)
    {
        string title = intent.Extras.GetString(AndroidNotificationManager.TitleKey);
        string message = intent.Extras.GetString(AndroidNotificationManager.MessageKey);
        DependencyService.Get<INotificationManager>().ReceiveNotification(title, message);
    }
}

El método CreateNotificationFromIntent extrae los datos de notificación del argumento intent y los proporciona a AndroidNotificationManager mediante el método ReceiveNotification.The CreateNotificationFromIntent method extracts notification data from the intent argument and provides it to the AndroidNotificationManager using the ReceiveNotification method. Se llama al método CreateNotificationFromIntent desde el método OnCreate y el método OnNewIntent:The CreateNotificationFromIntent method is called from both the OnCreate method and the OnNewIntent method:

  • Cuando la aplicación se inicia mediante los datos de notificación, los datos de Intent se pasan al método OnCreate.When the application is started by notification data, the Intent data will be passed to the OnCreate method.
  • Si la aplicación ya está en primer plano, los datos de Intent se pasan al método OnNewIntent.If the application is already in the foreground, the Intent data will be passed to the OnNewIntent method.

Android ofrece muchas opciones avanzadas para las notificaciones.Android offers many advanced options for notifications. Para más información, consulte Notificaciones en Xamarin.Android .For more information, see Notifications in Xamarin.Android.

Creación de la implementación de la interfaz de iOSCreate the iOS interface implementation

Para que la aplicación de :::no-loc(Xamarin.Forms)::: envíe y reciba notificaciones en iOS, esta debe proporcionar una implementación de INotificationManager.For the :::no-loc(Xamarin.Forms)::: application to send and receive notifications on iOS, the application must provide an implementation of the INotificationManager.

Creación de la clase iOSNotificationManagerCreate the iOSNotificationManager class

La clase iOSNotificationManager implementa la interfaz INotificationManager:The iOSNotificationManager class implements the INotificationManager interface:

[assembly: Dependency(typeof(LocalNotifications.iOS.iOSNotificationManager))]
namespace LocalNotifications.iOS
{
    public class iOSNotificationManager : INotificationManager
    {
        int messageId = -1;

        bool hasNotificationsPermission;

        public event EventHandler NotificationReceived;

        public void Initialize()
        {
            // request the permission to use local notifications
            UNUserNotificationCenter.Current.RequestAuthorization(UNAuthorizationOptions.Alert, (approved, err) =>
            {
                hasNotificationsPermission = approved;
            });
        }

        public int ScheduleNotification(string title, string message)
        {
            // EARLY OUT: app doesn't have permissions
            if(!hasNotificationsPermission)
            {
                return -1;
            }

            messageId++;

            var content = new UNMutableNotificationContent()
            {
                Title = title,
                Subtitle = "",
                Body = message,
                Badge = 1
            };

            // Local notifications can be time or location based
            // Create a time-based trigger, interval is in seconds and must be greater than 0
            var trigger = UNTimeIntervalNotificationTrigger.CreateTrigger(0.25, false);

            var request = UNNotificationRequest.FromIdentifier(messageId.ToString(), content, trigger);
            UNUserNotificationCenter.Current.AddNotificationRequest(request, (err) =>
            {
                if (err != null)
                {
                    throw new Exception($"Failed to schedule notification: {err}");
                }
            });

            return messageId;
        }

        public void ReceiveNotification(string title, string message)
        {
            var args = new NotificationEventArgs()
            {
                Title = title,
                Message = message
            };
            NotificationReceived?.Invoke(null, args);
        }
    }
}

El atributo assembly situado encima del espacio de nombres registra la implementación de la interfaz de INotificationManager con DependencyService.The assembly attribute above the namespace registers the INotificationManager interface implementation with the DependencyService.

En iOS, debe solicitar permiso para usar notificaciones antes de intentar programar una notificación.On iOS, you must request permission to use notifications before attempting to schedule a notification. El método Initialize solicita autorización para usar notificaciones locales.The Initialize method requests authorization to use local notifications. El método ScheduleNotification define la lógica necesaria para crear y enviar una notificación.The ScheduleNotification method defines the logic required to create and send a notification. Por último, iOS llamará al método ReceiveNotification cuando se reciba un mensaje e invocará el controlador de eventos.Finally, the ReceiveNotification method will be called by iOS when a message is received, and invokes the event handler.

Control de las notificaciones entrantes en iOSHandle incoming notifications on iOS

En iOS, debe crear un delegado que cree subclases UNUserNotificationCenterDelegate para administrar los mensajes entrantes.On iOS, you must create a delegate that subclasses UNUserNotificationCenterDelegate to handle incoming messages. La aplicación de ejemplo define una clase iOSNotificationReceiver:The sample application defines an iOSNotificationReceiver class:

public class iOSNotificationReceiver : UNUserNotificationCenterDelegate
{
    public override void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification, Action<UNNotificationPresentationOptions> completionHandler)
    {
        DependencyService.Get<INotificationManager>().ReceiveNotification(notification.Request.Content.Title, notification.Request.Content.Body);

        // alerts are always shown for demonstration but this can be set to "None"
        // to avoid showing alerts if the app is in the foreground
        completionHandler(UNNotificationPresentationOptions.Alert);
    }
}

Esta clase usa DependencyService para obtener una instancia de la clase iOSNotificationManager y proporciona datos de notificación entrantes al método ReceiveNotification.This class uses the DependencyService to get an instance of the iOSNotificationManager class and provides incoming notification data to the ReceiveNotification method.

La clase AppDelegate debe especificar el delegado personalizado durante el inicio de la aplicación.The AppDelegate class must specify the custom delegate during application startup. La clase AppDelegate debe especificar un objeto iOSNotificationReceiver como delegado UNUserNotificationCenter durante el inicio de la aplicación.The AppDelegate class must specify an iOSNotificationReceiver object as the UNUserNotificationCenter delegate during application startup. Esto sucede en el método FinishedLaunching:This occurs in the FinishedLaunching method:

public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
    global:::::no-loc(Xamarin.Forms):::.Forms.Init();

    UNUserNotificationCenter.Current.Delegate = new iOSNotificationReceiver();

    LoadApplication(new App());
    return base.FinishedLaunching(app, options);
}

iOS ofrece muchas opciones avanzadas para las notificaciones.iOS offers many advanced options for notifications. Para más información, consulte Notificaciones en Xamarin.iOS.For more information, see Notifications in Xamarin.iOS.

Probar la aplicaciónTest the application

Una vez que los proyectos de plataforma contienen una implementación registrada de la interfaz INotificationManager, la aplicación se puede probar en ambas plataformas.Once the platform projects contain a registered implementation of the INotificationManager interface, the application can be tested on both platforms. Ejecute la aplicación y haga clic en el botón Schedule Notification (Programar notificación) para crear una notificación.Run the application and click the Schedule Notification button to create a notification.

En Android, la notificación aparecerá en el área de notificación.On Android, the notification will appear in the notification area. Cuando se pulsa en la notificación, la aplicación la recibe y muestra un mensaje debajo del botón Schedule Notification (Programar notificación):When the notification is tapped, the application receives the notification and displays a message below the Schedule Notification button:

Notificaciones locales en Android

En iOS, la aplicación recibe automáticamente las notificaciones entrantes sin necesidad de la intervención del usuario.On iOS, incoming notifications are automatically received by the application without requiring user input. La aplicación recibe la notificación y muestra un mensaje debajo del botón Schedule Notification (Programar notificación):The application receives the notification and displays a message below the Schedule Notification button:

Notificaciones locales en iOS