Handling Notifications in Xamarin Forms Android

I am using the library https://github.com/aritchie/notifications and I can create and schedule notifications correctly.

I want to handle them on Android so that depending on the notification - it will navigate to a specific page when the user clicks on it.

I found that the event below fires when I click on notification (in my android project)

 protected override void OnNewIntent(Intent intent)
    {

    }

      

However, I cannot find any information in the intent from my notification to create a navigation to a specific page.

Any advice would be appreciated.

Hooray!

Edit # 1 (adding additional code for the related issue):

If I close the notification and close the application before receiving the notification - I get an error when the application crashed. If I get a notification and close the app - I can load the app from the OK notification.

I have a dependency service that uses the following methods.

public void Remind(DateTime dateTime, string msgtype, string usermedid)
    {
        DateTime now = DateTime.Now;
        var diffinseconds = (dateTime - now).TotalSeconds;
        Intent alarmIntent = new Intent(Forms.Context, typeof(AlarmBroadcastReceiver));
        alarmIntent.PutExtra("notificationtype", msgtype);
        alarmIntent.PutExtra("id", id);


        PendingIntent pendingIntent = PendingIntent.GetBroadcast(Forms.Context, 0, alarmIntent, PendingIntentFlags.UpdateCurrent);
        AlarmManager alarmManager = (AlarmManager)Forms.Context.GetSystemService(Context.AlarmService);

        //TODO: For demo set after 5 seconds.
        alarmManager.Set(AlarmType.ElapsedRealtime, SystemClock.ElapsedRealtime() + diffinseconds * 1000, pendingIntent);

    }

    [BroadcastReceiver(Enabled = true)]
    [IntentFilter(new string[]{"android.intent.action.BOOT_COMPLETED"}, Priority = (int) IntentFilterPriority.LowPriority)]
    public class AlarmBroadcastReceiver : BroadcastReceiver
    {
        public override void OnReceive(Context context, Intent intent)
        {
            string notificationtype = intent.GetStringExtra("notificationtype");

            PowerManager.WakeLock sWakeLock;
            var pm = PowerManager.FromContext(context);
            sWakeLock = pm.NewWakeLock(WakeLockFlags.Partial, "GCM Broadcast Reciever Tag");
            sWakeLock.Acquire();

            intent = new Intent(Forms.Context, typeof(MainActivity));
            intent.PutExtra("notificationtype", notificationtype);
            intent.AddFlags(ActivityFlags.IncludeStoppedPackages);



            // Instantiate the builder and set notification elements, including pending intent:
            NotificationCompat.Builder builder = new NotificationCompat.Builder(Forms.Context)
                .SetDefaults((int)NotificationDefaults.Sound | (int)NotificationDefaults.Vibrate)
                .SetAutoCancel(true)
                .SetContentIntent(PendingIntent.GetActivity(Forms.Context, 0, intent, 0)).SetContentTitle("Sample Notification")
                .SetContentText("Hello World! This is my first action notification!")
                .SetTicker("New Notification")

                .SetSmallIcon(Resource.Drawable.icon);


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

            notification.Flags = NotificationFlags.AutoCancel;

            // Get the notification manager:
            //NotificationManager notificationManager = Forms.Context.GetSystemService(Context.NotificationService) as NotificationManager;
            var manager = NotificationManagerCompat.From(context);

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

            sWakeLock.Release();



        }
    }

      

How do I keep my broadcast receiver waiting for the application to close?

+1


source to share


1 answer


Ok so it took me a while to figure it out. OnNewIntent

called when the app is in the background and a notification is clicked. It is also called every time the application is minimized and returned up ... so to tell the difference between the two events you need to check the passed in Intent

for what additional data inside it. Additional data would be obtained from Intent

what you made when you first ran the notification.

Also set the parameter MainActivity

LaunchMode

to LaunchMode.SingleTop

so that your app doesn't restart every time you click on the notification.

[Activity(LaunchMode = LaunchMode.SingleTop, ....)]
public class MainActivity : FormsApplicationActivity {

    ....

    /// <summary>
    /// Called when the app is in the background and a notification is clicked on (also called each time the app is minimized and the brought back up), a new <c>Intent</c> is created
    ///     and sent out, since we use <c>LaunchMode</c> set to <c>SingleTop</c> this method is called instead of the app being restarted.
    /// </summary>
    /// <param name="intent">The <c>Intent</c> that was set when the call was made. If started from a notification click, extra <c>string</c> values can be extracted.</param>
    protected override void OnNewIntent(Intent intent) {

        if(intent.HasExtra("Some special key you made up")) { //Here is where you check for special notification intent extras
            //Do something brilliant now that you know a notification was clicked on
        }
        base.OnNewIntent(intent);
    }

      

To see how you can add data to Intent

, you can check out the Xamarin Sport app , but not too narrow in everything else they do, as I always try. Just focus on the part PutExtra

.

Edit # 1:

If your application is completely closed, you need to pull the data from Intent

passed to OnCreate

and pass it to your class App

or do something else with it:



protected override async void OnCreate(Android.OS.Bundle bundle) {

    base.OnCreate(bundle);

    Forms.Init(this, bundle);

    string parameterValue = Intent.GetStringExtra("Some special key you made up"); //This would come in from the Push Notification being clicked on

    Console.WriteLine("\nIn MainActivity.OnCreate() - Param Intent Extras: {0}\n", parameterValue);

    //MessagingCenter.Send("nothing", ConstantKeys.NewNotification); //Do something special with the notification data

    LoadApplication(parameterValue != null ? new App(parameterValue) : new App()); //Do something special with the notification data
}

      

Edit # 2:

Some changes that I would recommend to your method OnReceive

based on my current code (some might not be needed, but that's exactly what I'm doing):

  • Name your broadcast receiver
  • Add silly Xamarin constructors
  • Constant property used instead of string for IntentFilter
  • Remove priority of IntentFilter
  • Check null sense (may not be needed)
  • Use Application.Context instead of Forms.Context (I am using Forms.Context in other parts of my application, so not sure about this, but can't hurt)
  • Do not overwrite passed to Intent
  • Create launch intent instead of normal
  • Add IncludeStoppedPackages flag before pulling additional functions
  • Check completed event for loading
  • Use Notification.Builder instead of NotificationCompat.Builder (although you may need to change this)
  • Add the following flags to the pendingintent: PendingIntentFlags.UpdateCurrent | PendingIntentFlags.OneShot - Use NotificationManager (unless you have a specific reason for commenting it)
[assembly: UsesPermission(Android.Manifest.Permission.Vibrate)]  
[assembly: UsesPermission(Android.Manifest.Permission.WakeLock)]                //Optional, keeps the processor from sleeping when a message is received
[assembly: UsesPermission(Android.Manifest.Permission.ReceiveBootCompleted)]                        //Allows our app to be opened and to process notifications even when the app is closed

namespace Your.App.Namespace {

[BroadcastReceiver(Enabled = true, Label = "GCM Alarm Notifications Broadcast Receiver")]
[IntentFilter(new []{ Intent.ActionBootCompleted })]
public class AlarmBroadcastReceiver : BroadcastReceiver {
    #region Constructors

    // ReSharper disable UnusedMember.Global
    public AlarmBroadcastReceiver() { }

    public AlarmBroadcastReceiver(IntPtr handle, JniHandleOwnership transfer) : base(handle, transfer) { }
    // ReSharper restore UnusedMember.Global

    #endregion

    public void Remind(DateTime dateTime, string msgtype, string usermedid) {
        DateTime now = DateTime.Now;
        var diffinseconds = (dateTime - now).TotalSeconds;

        Intent alarmIntent = new Intent(Application.Context, typeof(AlarmBroadcastReceiver));
        alarmIntent.PutExtra("notificationtype", msgtype);
        alarmIntent.PutExtra("id", id);

        PendingIntent pendingIntent = PendingIntent.GetBroadcast(Application.Context, 0, alarmIntent, PendingIntentFlags.UpdateCurrent);
        AlarmManager alarmManager = (AlarmManager)Application.Context.GetSystemService(Context.AlarmService);

        //TODO: For demo set after 5 seconds.
        alarmManager.Set(AlarmType.ElapsedRealtime, SystemClock.ElapsedRealtime() + diffinseconds * 1000, pendingIntent);
    }

    public override void OnReceive(Context context, Intent intent) {
        #region Null Check

        if(intent == null) {
            Console.WriteLine("\nIn AlarmBroadcastReceiver.OnReceive() - Intent is null\n");
            return;
        }

        #endregion

        intent.AddFlags(ActivityFlags.IncludeStoppedPackages);

        string action = intent.Action;
        Console.WriteLine("\nIn AlarmBroadcastReceiver.OnReceive() - Action: {0}\n", action);

        #region Boot Completed Check

        if(action.Equals("android.intent.action.BOOT_COMPLETED")) {

            PowerManager pm = PowerManager.FromContext(context);
            PowerManager.WakeLock sWakeLock = pm.NewWakeLock(WakeLockFlags.Partial, "GCM Broadcast Receiver Tag");
            sWakeLock.Acquire();

            Console.WriteLine("\nIn AlarmBroadcastReceiver.OnReceive() - Process Shared Preferences Notifications\n");

            #region Process Saved Scheduled Notifications

            //Get list of saved scheduled notifications that did not fire off before the device was turned off (I store them in SharedPreferences and delete them after they are fired off)

            //Go through the list and reschedule them

            #endregion

            sWakeLock.Release();
            return;
        }

        #endregion

        string notificationtype = intent.GetStringExtra("notificationtype");

        Intent startupIntent = Application.Context.PackageManager.GetLaunchIntentForPackage(Application.Context.PackageName);
        startupIntent.PutExtra("notificationtype", notificationtype);

        // Instantiate the builder and set notification elements, including pending intent:
        Notification.Builder builder = new Notification.Builder(Application.Context)
            .SetDefaults((int)NotificationDefaults.Sound | (int)NotificationDefaults.Vibrate)
            .SetAutoCancel(true)
            .SetContentIntent(PendingIntent.GetActivity(Application.Context, 0, intent, PendingIntentFlags.UpdateCurrent | PendingIntentFlags.OneShot))
            .SetContentTitle("Sample Notification")
            .SetContentText("Hello World! This is my first action notification!")
            .SetTicker("New Notification")
            .SetSmallIcon(Resource.Drawable.icon);

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

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

        // Publish the notification:
        int notificationId = ??;//This should be a real unique number, otherwise it can cause problems if there are ever multiple scheduled notifications
        notificationManager.Notify(notificationId, notification);
    }
}
}

      

+3


source







All Articles