如何在 Xamarin Forms 中使用推送通知
How to use Push Notifications in Xamarin Forms
我有一个使用 Xamarin.Forms 目标 IOS、Android 和 WP 8 的应用程序。
我的应用程序需要推送通知功能。
我看过 pushsharp
演示,看起来很有希望。但是我看到的所有代码都是针对每个平台单独完成的。
我希望它在 Xamarin.Forms 项目中完成,在 App.cs 的某处,这样我就不需要重复注册设备的代码,也不需要处理推送通知的方式被处理。
如有任何帮助,我们将不胜感激。欢迎使用示例代码或教程参考。
Edit :我根据 Idot 的 . Here is the 实现了它作为我的答案。
这在纯 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
xamarin 支持和表单建议我使用以下插件。
This plugin works well
https://github.com/rdelrosario/xamarin-plugins/tree/master/PushNotification
一旦我开始工作就会更新答案。
更新:
我收到了适用于 iOS 和 Android 的推送通知。
我用了Google Cloud Messaging Client, an excellent component for Android, and didn't have to write much of the code as mentioned in 。
我的 iOS 实现与 类似,不需要太多代码。
为了从服务器推送通知,我使用了 PushSharp 的 nuget 包。
我没有在 WP 中实现,因为我的项目不需要它。
如果您要实施推送通知,这篇 Xamarin Help on Push Notifications 值得一读。
更新(2018 年 6 月)- 在 iOS 和 Android 上使用以下 FCM 插件,ti 支持 Xamarin.Forms - FirebasePushNotificationPlugin
我前几天刚实现了推送通知,我会在这里分享我的解决方案(基于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
中添加以下方法:
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) 实施 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
最近这里有一篇博客 post 关于使用 Azure 移动服务在 Xamarin Forms 上实现推送通知(以及每个单独的平台,因为没有基于 Forms 的实现)。
在 Xamarin Forms 中,您还可以使用像 Donky 这样的通知 SDK(在欧洲相当于美国的 Urban Airship);您可以在一天内轻松制作一个可扩展的通知项目,我已经两次使用此 SDK 在 35 分钟内构建了 WhatsApp 克隆 shell。参见 http://docs.mobiledonky.com
您可以查看开箱即用的 Appboy 组件。 https://components.xamarin.com/view/appboy-sdk-bindings
正如其他人所说,如果没有一些特定于平台的组件,您将无法通用。
我有一个使用 Xamarin.Forms 目标 IOS、Android 和 WP 8 的应用程序。
我的应用程序需要推送通知功能。
我看过 pushsharp
演示,看起来很有希望。但是我看到的所有代码都是针对每个平台单独完成的。
我希望它在 Xamarin.Forms 项目中完成,在 App.cs 的某处,这样我就不需要重复注册设备的代码,也不需要处理推送通知的方式被处理。
如有任何帮助,我们将不胜感激。欢迎使用示例代码或教程参考。
Edit :我根据 Idot 的
这在纯 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
xamarin 支持和表单建议我使用以下插件。
This plugin works well
https://github.com/rdelrosario/xamarin-plugins/tree/master/PushNotification
一旦我开始工作就会更新答案。
更新:
我收到了适用于 iOS 和 Android 的推送通知。
我用了Google Cloud Messaging Client, an excellent component for Android, and didn't have to write much of the code as mentioned in
我的 iOS 实现与
为了从服务器推送通知,我使用了 PushSharp 的 nuget 包。
我没有在 WP 中实现,因为我的项目不需要它。
如果您要实施推送通知,这篇 Xamarin Help on Push Notifications 值得一读。
更新(2018 年 6 月)- 在 iOS 和 Android 上使用以下 FCM 插件,ti 支持 Xamarin.Forms - FirebasePushNotificationPlugin
我前几天刚实现了推送通知,我会在这里分享我的解决方案(基于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
中添加以下方法:
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) 实施 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
最近这里有一篇博客 post 关于使用 Azure 移动服务在 Xamarin Forms 上实现推送通知(以及每个单独的平台,因为没有基于 Forms 的实现)。
在 Xamarin Forms 中,您还可以使用像 Donky 这样的通知 SDK(在欧洲相当于美国的 Urban Airship);您可以在一天内轻松制作一个可扩展的通知项目,我已经两次使用此 SDK 在 35 分钟内构建了 WhatsApp 克隆 shell。参见 http://docs.mobiledonky.com
您可以查看开箱即用的 Appboy 组件。 https://components.xamarin.com/view/appboy-sdk-bindings
正如其他人所说,如果没有一些特定于平台的组件,您将无法通用。