I have an app using Xamarin.Forms targeting IOS, Android and WP 8.
I need push notification feature in my app.
I have seen the pushsharp
demos and it seems promising. But all the codes I have seen are done separately for each platform.
I would like it to be done in the Xamarin.Forms project, somewhere in the App.cs so that I don't need to repeat the code for registering device, and handle how push notifications should be processed.
Any help would be greatly appreciated. Sample codes or tutorial references are welcome.
Edit : I implemented it based on Idot's answer. Here is the link for my answer.
Firebase Cloud Messaging (FCM), formerly called Google Cloud Messaging (GCM), is a free cloud service from Google that allows app developers to send notifications and messages to users across a variety of platforms, including Android, iOS and web applications.
What is Push Notification. Push notifications let your application notify a user of new messages or events even when the user is not actively using your application.
I just implemented push notification a few days ago, and I'll share my solution here (based on PushSharp)
Step by step guide:
1) In your shared project, create an Interface called IPushNotificationRegister
public interface IPushNotificationRegister { void ExtractTokenAndRegister(); }
This interface is used for fetching the push token and then send it to the server. this Token is unique per device.
2) In Your shared project, you should invoke ExtractTokenAndRegister
(using your favorite IOC, I called it right after login).
Android Implementation:
3) Add Receivers for listening to events received by Google GCM service:
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); } } }
c) Add Intent service to process the notification
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) Implement the 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); } } }
iOS implementation:
4) In your AppDelegate
, add the following method:
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) Implement 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); } } }
Regarding WP, I didn't implement it.
If you need the code on the server side using PushSharp, let me know.
You can check the client samples I've based my solution here
I have been suggested to use the following plugin by xamarin support and forms.
This plugin works well
https://github.com/rdelrosario/xamarin-plugins/tree/master/PushNotification
Will update the answer once I get it to work.
UPDATE :
I got push notifications working for both iOS and Android.
I used Google Cloud Messaging Client, an excellent component for Android, and didn't have to write much of the code as mentioned in this answer.
My iOS implementation was similar to this, not much code required.
And for Pushing the notifications from the Server I used nuget package of PushSharp.
I didn't implement in WP, as that was not required in my project.
This Xamarin Help on Push Notifications is worth reading if you are going to implement Push Notifications.
Update (June 2018) - Use the following plugin for FCM on iOS and Android, ti supports Xamarin.Forms - FirebasePushNotificationPlugin
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With