Saltar al contenido

Cómo usar notificaciones push en formularios Xamarin

Luego de mucho trabajar pudimos hallar el resultado de esta contratiempo que muchos lectores de nuestra web presentan. Si tienes algún detalle que aportar no dudes en aportar tu comentario.

Solución:

Acabo de implementar la notificación push hace unos días y compartiré mi solución aquí (basada en PushSharp)

Guía paso por paso:

1) En su proyecto compartido, cree una interfaz llamada IPushNotificationRegister

public interface IPushNotificationRegister

    void ExtractTokenAndRegister();

Esta interfaz se utiliza para obtener el token de inserción y luego enviarlo al servidor. este Token es único por dispositivo.

2) En su proyecto compartido, debe invocar ExtractTokenAndRegister (usando su IOC favorito, lo llamé justo después de iniciar sesión).

Implementación de Android:

3) Agregue receptores para escuchar los eventos recibidos por el servicio Google GCM:

a)

[BroadcastReceiver]
[IntentFilter(new[]  Intent.ActionBootCompleted )]
public class GCMBootReceiver : BroadcastReceiver

    public override void OnReceive(Context context, Intent intent)
    
        MyIntentService.RunIntentInService(context, intent);
        SetResult(Result.Ok, null, null);
    

B)

[assembly: Permission(Name = "@[email protected]_MESSAGE")]
[assembly: UsesPermission(Name = "android.permission.WAKE_LOCK")]
[assembly: UsesPermission(Name = "@[email protected]_MESSAGE")]
[assembly: UsesPermission(Name = "com.google.android.c2dm.permission.RECEIVE")]
[assembly: UsesPermission(Name = "android.permission.GET_ACCOUNTS")]
[assembly: UsesPermission(Name = "android.permission.INTERNET")]

namespace Consumer.Mobile.Droid.PushNotification

    [BroadcastReceiver(Permission = "com.google.android.c2dm.permission.SEND")]
    [IntentFilter(new string[]  "com.google.android.c2dm.intent.RECEIVE" , Categories = new string[]  "@[email protected]" )]
    [IntentFilter(new string[]  "com.google.android.c2dm.intent.REGISTRATION" , Categories = new string[]  "@[email protected]" )]
    [IntentFilter(new string[]  "com.google.android.gcm.intent.RETRY" , Categories = new string[]  "@[email protected]" )]
    [IntentFilter (new[] Intent.ActionBootCompleted , Categories = new[] Intent.CategoryDefault )]
    public class GCMBroadcastReceiver : BroadcastReceiver
    
        public override void OnReceive(Context context, Intent intent)
        
            MyIntentService.RunIntentInService(context, intent);
            SetResult(Result.Ok, null, null);
        
    

c) Agregar servicio Intent para procesar la notificación

using Android.App;
using Android.Content;
using Android.Graphics;
using Android.Media;
using Android.OS;
using Android.Support.V4.App;
using Consumer.Mobile.Infra;
using Consumer.Mobile.Services.PushNotification;
using Java.Lang;
using XLabs.Ioc;
using TaskStackBuilder = Android.Support.V4.App.TaskStackBuilder;

namespace Consumer.Mobile.Droid.PushNotification

    [Service]
    public class MyIntentService : IntentService
    
        private readonly ILogger _logger;
        private readonly IPushNotificationService _notificationService;
        private readonly IPushNotificationRegister _pushNotificationRegister;

        public MyIntentService()
        
            _logger = Resolver.Resolve();
            _notificationService = Resolver.Resolve();
            _pushNotificationRegister = Resolver.Resolve();
        

        static PowerManager.WakeLock _sWakeLock;
        static readonly object Lock = new object();


        public static void RunIntentInService(Context context, Intent intent)
        
            lock (Lock)
            
                if (_sWakeLock == null)
                
                    // This is called from BroadcastReceiver, there is no init.
                    var pm = PowerManager.FromContext(context);
                    _sWakeLock = pm.NewWakeLock(
                    WakeLockFlags.Partial, "My WakeLock Tag");
                
            

            _sWakeLock.Acquire();
            intent.SetClass(context, typeof(MyIntentService));
            context.StartService(intent);
        

        protected override void OnHandleIntent(Intent intent)
        
            try
            
                Context context = this.ApplicationContext;
                string action = intent.Action;

                if (action.Equals("com.google.android.c2dm.intent.REGISTRATION"))
                
                    HandleRegistration(context, intent);
                
                else if (action.Equals("com.google.android.c2dm.intent.RECEIVE"))
                
                    HandleMessage(context, intent);
                
            
            finally
            
                lock (Lock)
                
                    //Sanity check for null as this is a public method
                    if (_sWakeLock != null)
                        _sWakeLock.Release();
                
            
        

        private void HandleMessage(Context context, Intent intent)
        

            Intent resultIntent = new Intent(this, typeof(MainActivity));


            TaskStackBuilder stackBuilder = TaskStackBuilder.Create(this);

            var c = Class.FromType(typeof(MainActivity));
            stackBuilder.AddParentStack(c);
            stackBuilder.AddNextIntent(resultIntent);

            string alert = intent.GetStringExtra("Alert");
            int number = intent.GetIntExtra("Badge", 0);

            var imageUrl = intent.GetStringExtra("ImageUrl");
            var title = intent.GetStringExtra("Title");

            Bitmap bitmap = GetBitmap(imageUrl);

            PendingIntent resultPendingIntent = stackBuilder.GetPendingIntent(0, (int)PendingIntentFlags.UpdateCurrent);

            NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
                .SetAutoCancel(true) // dismiss the notification from the notification area when the user clicks on it
                .SetContentIntent(resultPendingIntent) // start up this activity when the user clicks the intent.
                .SetContentTitle(title) // Set the title
                .SetNumber(number) // Display the count in the Content Info
                .SetSmallIcon(Resource.Drawable.Icon) // This is the icon to display
                .SetLargeIcon(bitmap)
                .SetSound(RingtoneManager.GetDefaultUri(RingtoneType.Notification))
                .SetContentText(alert); // the message to display.

            // Build the notification:
            Notification notification = builder.Build();

            // Get the notification manager:
            NotificationManager notificationManager =
                GetSystemService(Context.NotificationService) as NotificationManager;

            // Publish the notification:
            const int notificationId = 0;
            notificationManager.Notify(notificationId, notification);
        

        private void HandleRegistration(Context context, Intent intent)
        
            var token = intent.GetStringExtra("registration_id");
            _logger.Info(this.Class.SimpleName, "Received Token : " + token);

            if (_pushNotificationRegister.ShouldSendToken(token))
            
                var uid = Android.Provider.Settings.Secure.GetString(MainActivity.Context.ContentResolver, Android.Provider.Settings.Secure.AndroidId);
                _notificationService.AddPushToken(token, DeviceUtils.GetDeviceType(), uid);
            
        


        private Bitmap GetBitmap(string url)
        

            try
            
                System.Net.WebRequest request =
                    System.Net.WebRequest.Create(url);
                System.Net.WebResponse response = request.GetResponse();
                System.IO.Stream responseStream =
                    response.GetResponseStream();
                return BitmapFactory.DecodeStream(responseStream);


            
            catch (System.Net.WebException)
            
                return null;
            

        

    

d) Implementar la interfaz IPushNotificationRegister:

using Android.App;
using Android.Content;
using Consumer.Mobile.Services;
using Consumer.Mobile.Services.PushNotification;
[assembly: Permission(Name = "@[email protected]_MESSAGE")]
[assembly: UsesPermission(Name = "@[email protected]_MESSAGE")]

// Gives the app permission to register and receive messages.
[assembly: UsesPermission(Name = "com.google.android.c2dm.permission.RECEIVE")]

// Needed to keep the processor from sleeping when a message arrives
[assembly: UsesPermission(Name = "android.permission.WAKE_LOCK")]
[assembly: UsesPermission(Name = "android.permission.RECEIVE_BOOT_COMPLETED")]
namespace Consumer.Mobile.Droid.PushNotification

    public class PushNotificationRegister : IPushNotificationRegister
              
        public override void ExtractTokenAndRegister()
        
            string senders = AndroidConfig.GCMSenderId;
            Intent intent = new Intent("com.google.android.c2dm.intent.REGISTER");
            intent.SetPackage("com.google.android.gsf");
            intent.PutExtra("app", PendingIntent.GetBroadcast(MainActivity.Context, 0, new Intent(), 0));
            intent.PutExtra("sender", senders);
            MainActivity.Context.StartService(intent);
        


    

Implementación de iOS:

4) En tu AppDelegate, agregue el siguiente método:

a)

public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)

    var deviceTokenString = deviceToken.ToString().Replace("<","").Replace(">", "").Replace(" ", "");
    var notificationService = Resolver.Resolve();
    var pushNotificationRegister = Resolver.Resolve();

    if (pushNotificationRegister.ShouldSendToken(deviceTokenString))
    
        var uid = UIDevice.CurrentDevice.IdentifierForVendor.AsString();
        notificationService.AddPushToken(deviceTokenString, DeviceUtils.GetDeviceType(), uid);
    

b) Implementar IPushNotificationRegister :

using Consumer.Mobile.Services;
using Consumer.Mobile.Services.PushNotification;
using UIKit;

namespace Consumer.Mobile.iOS.PushNotification

    public class iOSPushNotificationRegister : IPushNotificationRegister
    
        public override void ExtractTokenAndRegister()
        
            const UIRemoteNotificationType notificationTypes = UIRemoteNotificationType.Alert 
    

Con respecto a WP, no lo implementé.

Si necesita el código en el lado del servidor usando PushSharp, hágamelo saber.

Puede consultar las muestras de clientes en las que he basado mi solución aquí

El soporte y los formularios de xamarin me han sugerido que use el siguiente complemento.

Este complemento funciona bien

https://github.com/rdelrosario/xamarin-plugins/tree/master/PushNotification

Actualizaré la respuesta una vez que lo haga funcionar.

ACTUALIZAR :

Recibí notificaciones push que funcionan tanto para iOS como para Android.

Usé Google Cloud Messaging Client, un excelente componente para Android, y no tuve que escribir gran parte del código como se menciona en esta respuesta.

Mi implementación de iOS fue similar a esto, no se requiere mucho código.

Y para enviar las notificaciones desde el servidor utilicé el paquete nuget de PushSharp.

No implementé en WP, ya que no era necesario en mi proyecto.

Vale la pena leer esta Ayuda de Xamarin sobre notificaciones push si va a implementar notificaciones push.

Actualización (junio de 2018): use el siguiente complemento para FCM en iOS y Android, ti es compatible con Xamarin.Forms – FirebasePushNotificationPlugin

En Xamarin Forms también puede usar un SDK de notificaciones como Donky (que es el equivalente europeo del American Urban Airship); puede crear fácilmente un proyecto de notificaciones escalables en un solo día, he construido dos veces shells de clonación de WhatsApp en menos de 35 minutos cada vez con este SDK. Ver http://docs.mobiledonky.com

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *