Como usar notificações Push nos formulários Xamarin

Sou uma aplicação que usa Xamarin.Formulários a apontar para IOS, Android e WP 8.

Preciso de enviar notificações na minha aplicação.

Vi as demos dos pushsharp e parece promissor. Mas todos os códigos que vi foram feitos separadamente para cada plataforma.

Gostava que fosse feito no Xamarin.Forms project, algures na aplicação.cs para que eu não precise repetir o código para registrar o dispositivo, e lidar com a forma como as notificações push devem ser processadas.

Qualquer a ajuda seria muito apreciada. Os códigos de exemplo ou referências tutoriais são bem-vindos.

Edit : implementei-o com base na resposta do Idot . Aqui está o relação para a minha resposta.

Author: Rohit Vipin Mathews, 2015-03-13

6 answers

Acabei de implementar a notificação push há alguns dias, e vou partilhar a minha solução aqui (com base em PushSharp)

Guia passo a passo:

1) no seu projecto partilhado, crie uma Interface chamada IPushNotificationRegister

public interface IPushNotificationRegister
{
    void ExtractTokenAndRegister();
}

Esta interface é usada para obter o item de envio e, em seguida, enviá-lo para o servidor. Este símbolo é único por dispositivo.

2) no seu projecto partilhado, deve invocar ExtractTokenAndRegister (usando o seu COI favorito, chamei-o logo a seguir sessao).

Implementação Android:

3) Adicionar receptores para ouvir eventos recebidos pelo serviço 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[] { "@PACKAGE_NAME@" })]
    [IntentFilter(new string[] { "com.google.android.c2dm.intent.REGISTRATION" }, Categories = new string[] { "@PACKAGE_NAME@" })]
    [IntentFilter(new string[] { "com.google.android.gcm.intent.RETRY" }, Categories = new string[] { "@PACKAGE_NAME@" })]
    [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);
        }
    }
}

Adicionar um serviço de intenção para processar a notificação

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<ILogger>();
            _notificationService = Resolver.Resolve<IPushNotificationService>();
            _pushNotificationRegister = Resolver.Resolve<IPushNotificationRegister>();
        }

        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 a Interface 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);
        }


    }
}

Implementação do IOS:

4) no seu AppDelegate, Adicione o seguinte método:

A)

public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
    var deviceTokenString = deviceToken.ToString().Replace("<","").Replace(">", "").Replace(" ", "");
    var notificationService = Resolver.Resolve<IPushNotificationService>();
    var pushNotificationRegister = Resolver.Resolve<IPushNotificationRegister>();

    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 | UIRemoteNotificationType.Badge | UIRemoteNotificationType.Sound;
            UIApplication.SharedApplication.RegisterForRemoteNotificationTypes(notificationTypes);
        }
    }
}
Quanto ao WP, não o implementei. Se precisar do Código do lado do servidor usando PushSharp, avise-me. Pode verificar as amostras de clientes que baseei a minha solução aqui.
 47
Author: IdoT, 2018-03-24 22:17:39

Foi-me sugerido usar o seguinte plugin pelo suporte e formulários xamarin.

Este plugin funciona bem

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

Actualizarei a resposta assim que a puser a funcionar.

Actualizar :

tenho notificações push a trabalhar para o iOS e para o Android.

Eu usei O Google Cloud Messaging Client , Um componente excelente para Android, e não tinha que escrever grande parte do código como mencionado em esta resposta.

A minha implementação no iOS era semelhante a Este , não era necessário muito código.

E para empurrar as notificações do servidor, usei o pacote nuget de PushSharp.

Eu não implementei no WP, porque isso não era necessário no meu projecto.

Esta ajuda Xamarin nas notificações Push vale a pena ler se você vai implementar notificações Push.

Update (junho de 2018) - Use o seguinte plugin para o FCM no iOS e no Android, o ti suporta o Xamarin.Formulários - FirebasePushNotificationPlugin

 15
Author: Rohit Vipin Mathews, 2018-06-29 17:00:39

Em Xamarin Formas você também pode usar uma notificações SDK como Donky (que é o equivalente Europeu ao Americano Urbana Aeronave); você pode fazer facilmente escalável as notificações do projeto em um único dia, eu tenho o dobro construído WhatsApp clone conchas em menos de 35 minutos de cada vez usando este SDK. Ver http://docs.mobiledonky.com

 2
Author: Xamtastic, 2015-11-30 16:14:34

Isto não é possível fazer em Xamarina pura.Forms but is relatively trivial to implement a solution which they can be handled in the App.cs (embora isso exija implementações específicas de plataforma).

Dê uma olhada na implementação IXForms dentro do Xamarin.Formulario.Projecto Labs onde as notificações são canalizadas de volta para o projecto Forms:

Https://github.com/XLabs/Xamarin-Forms-Labs

E mais especificamente:

Https://github.com/XLabs/Xamarin-Forms-Labs/tree/master/src/Platform/XLabs.Platform/Mvvm

 1
Author: JordanMazurke, 2015-03-18 15:50:21

Há um post no blog recentemente sobre a implementação de Notificações Push nos formulários Xamarin (bem, cada plataforma individual porque não há implementação baseada em formulários), usando os Serviços Móveis Azure.

Http://www.xamarinhelp.com/push-notifications/

 1
Author: Adam Pedley, 2015-04-18 03:34:53
Podes ver o componente Appboy que tem apoio para isto fora da caixa. https://components.xamarin.com/view/appboy-sdk-bindings Como outros já disseram, não se pode fazer genericamente sem alguns componentes específicos da plataforma.
 1
Author: Brian Wheeler, 2016-04-21 11:46:40