【问题标题】:How to use Push Notifications in Xamarin Forms如何在 Xamarin 表单中使用推送通知
【发布时间】:2015-05-15 18:52:04
【问题描述】:

我有一个使用 Xamarin.Forms 面向 IOS、Android 和 WP 8 的应用程序。

我的应用需要推送通知功能。

我看过pushsharp 的演示,看起来很有希望。但是我看到的所有代码都是针对每个平台单独完成的。

我希望它在 Xamarin.Forms 项目中完成,在 App.cs 中的某个地方,这样我就不需要重复注册设备的代码,并处理应该如何处理推送通知。

任何帮助将不胜感激。欢迎使用示例代码或教程参考。

编辑:我基于 Idot 的answer 实现了它。这是我的回答 link

【问题讨论】:

  • Xamarin 官方论坛已经解决了这个问题,看看:forums.xamarin.com/discussion/20845/…
  • 它纯粹基于 azure,我正在寻找 pushsharp。它也不是关于 Xamarin 形式,而是针对每个平台的单独实现。但是感谢您为我找到了一些开始。
  • 在 Xamrin 中查看 HOL On Azure 推送通知:onedrive.live.com/…

标签: c# xamarin push-notification xamarin.forms pushsharp


【解决方案1】:

我前几天刚刚实现了推送通知,在这里分享一下我的解决方案(基于PushSharp

分步指南:

1) 在您的共享项目中,创建一个名为IPushNotificationRegister的接口

public interface IPushNotificationRegister
{
    void ExtractTokenAndRegister();
}

此接口用于获取推送令牌,然后将其发送到服务器。此令牌在每个设备上都是唯一的。

2) 在您的共享项目中,您应该调用ExtractTokenAndRegister(使用您最喜欢的 IOC,我在登录后立即调用它)。

Android 实现:

3) 添加接收器,用于监听 Google GCM 服务接收到的事件:

一)

[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 = "@PACKAGE_NAME@.permission.C2D_MESSAGE")]
[assembly: UsesPermission(Name = "android.permission.WAKE_LOCK")]
[assembly: UsesPermission(Name = "@PACKAGE_NAME@.permission.C2D_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);
        }
    }
}

c) 添加 Intent 服务来处理通知

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) 实现接口IPushNotificationRegister:

using Android.App;
using Android.Content;
using Consumer.Mobile.Services;
using Consumer.Mobile.Services.PushNotification;
[assembly: Permission(Name = "@PACKAGE_NAME@.permission.C2D_MESSAGE")]
[assembly: UsesPermission(Name = "@PACKAGE_NAME@.permission.C2D_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);
        }


    }
}

iOS 实现:

4) 在您的AppDelegate 中,添加以下方法:

一)

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) 实现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);
        }
    }
}

关于WP,我没有实现。

如果您需要使用 PushSharp 的服务器端代码,请告诉我。

您可以查看基于我的解决方案here的客户端示例

【讨论】:

  • 谢谢。我一定会看看的。不,我不需要服务器端代码。
  • 你在哪里处理IOS的DidReceiveRemoteNotification
  • 我没有,如果您想添加自定义行为以在应用程序运行时显示通知,您需要在 AppDelegate 类中处理它: public override void ReceivedRemoteNotification(UIApplication application, NSDictionary用户信息){}
  • 你有安卓的广播接收器,这就是我好奇的原因
  • 你说得对,我按照指南保留了 BootReceiver,如果您对在应用运行时处理通知不感兴趣,可以将其删除。
【解决方案2】:

xamarin 支持和表单建议我使用以下插件。

这个插件很好用

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

一旦我得到它的工作将更新答案。

更新:

我收到了适用于 iOS 和 Android 的推送通知。

我使用了Google Cloud Messaging Client,这是一个出色的Android 组件,并且不需要编写this answer 中提到的大量代码。

我的 iOS 实现类似于this,不需要太多代码。

为了从服务器推送通知,我使用了 PushSharp 的 nuget 包。

我没有在 WP 中实现,因为我的项目中不需要。

如果您要实现推送通知,这个Xamarin Help on Push Notifications 值得一读。

更新(2018 年 6 月) - 在 iOS 和 Android 上使用以下 FCM 插件,ti 支持 Xamarin.Forms - FirebasePushNotificationPlugin

【讨论】:

  • 此解决方案是否适用于 Android 5+?对于我所看到的 GCM 组件正在使它们崩溃,对吗?
  • 我没有发现任何问题,我会仔细检查并尽快回复。如果您遇到崩溃,请分享确切的错误消息。
  • 我真的在为相同的 Xamarin 文档而苦苦挣扎,我的听众没有被调用
  • 谢谢,这个插件支持 GCM 的主题,这样服务器就不需要获取注册 ID 和订阅主题的客户端应用程序。
  • @SHIVANGSANGHI - 您可以添加发件人 ID。
【解决方案3】:

在 Xamarin Forms 中,您还可以使用通知 SDK,例如 Donky(在欧洲相当于美国 Urban Airship);您可以在一天内轻松制作一个可扩展的通知项目,我使用此 SDK 在 35 分钟内两次构建了 WhatsApp 克隆 shell。见http://docs.mobiledonky.com

【讨论】:

    【解决方案4】:

    您可能会查看立即支持此功能的 Appboy 组件。 https://components.xamarin.com/view/appboy-sdk-bindings

    正如其他人所说,如果没有一些特定于平台的组件,一般情况下你就无法做到。

    【讨论】:

      【解决方案5】:

      这在纯 Xamarin.Forms 中是不可能做到的,但实现一个可以在 App.cs 中处理它们的解决方案相对简单(尽管这需要特定于平台的实现)。

      查看 Xamarin.Forms.Labs 项目中的 IXForms 实现,其中通知被引导回 Forms 项目:

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

      更具体地说:

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

      【讨论】:

        【解决方案6】:

        最近这里有一篇关于使用 Azure 移动服务在 Xamarin Forms(每个单独的平台,因为没有基于 Forms 的实现)上实现推送通知的博客文章。

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-09-22
          • 1970-01-01
          • 2018-03-01
          • 1970-01-01
          • 1970-01-01
          • 2018-10-06
          • 2017-07-04
          相关资源
          最近更新 更多