Seif Selmi
Seif Selmi

Reputation: 77

Xamarin.iOS handle push notification when app is not closed

I managed to handle push notification if the app is in the background using the method didReceiveRemoteNotification. Is there a way to handle the push notification if the app is in the foreground and not closed ? Thanks

Upvotes: 3

Views: 4695

Answers (4)

longstevel
longstevel

Reputation: 1

I got both foreground and background notifications in Xamarin iOS by the sample app.delegte.cs code shown below.

   using Foundation;
   using System;
   using System.Diagnostics;
   using System.Linq;
   using UIKit;
   using UserNotifications;
   using WindowsAzure.Messaging;
   using Firebase.Core;
   using Firebase.CloudMessaging;
   using System.Runtime.CompilerServices;
   using ObjCRuntime;

   namespace NotificationHubSample.iOS

{ [Register("AppDelegate")]

   public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
    private SBNotificationHub Hub { get; set; }
    

    public override bool FinishedLaunching(UIApplication app, NSDictionary options)
    {
        global::Xamarin.Forms.Forms.Init();
        LoadApplication(new App());

        

        base.FinishedLaunching(app, options);

        Firebase.Core.App.Configure();

        RegisterForRemoteNotifications();

        UIApplication.SharedApplication.SetMinimumBackgroundFetchInterval(UIApplication.BackgroundFetchIntervalMinimum);


        return true;
    }

    void RegisterForRemoteNotifications()
    {
        // register for remote notifications based on system version
        if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
        {
            
            

            UNUserNotificationCenter.Current.RequestAuthorization(UNAuthorizationOptions.Alert |
                UNAuthorizationOptions.Sound |
                UNAuthorizationOptions.Sound,
                (granted, error) =>
                {
                    if (granted)
                        InvokeOnMainThread(UIApplication.SharedApplication.RegisterForRemoteNotifications);
                });
        }
        else if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
        {
            var pushSettings = UIUserNotificationSettings.GetSettingsForTypes(
            UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound,
            new NSSet());

            UIApplication.SharedApplication.RegisterUserNotificationSettings(pushSettings);
            UIApplication.SharedApplication.RegisterForRemoteNotifications();
        }
        else
        {
            UIRemoteNotificationType notificationTypes = UIRemoteNotificationType.Alert | UIRemoteNotificationType.Badge | UIRemoteNotificationType.Sound;
            UIApplication.SharedApplication.RegisterForRemoteNotificationTypes(notificationTypes);
        }
        UIApplication.SharedApplication.RegisterForRemoteNotifications();
    }

    public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
    {
        Hub = new SBNotificationHub(AppConstants.ListenConnectionString, AppConstants.NotificationHubName);

        // update registration with Azure Notification Hub
        Hub.UnregisterAll(deviceToken, (error) =>
        {
            if (error != null)
            {
                Debug.WriteLine($"Unable to call unregister {error}");
                return;
            }

            var tags = new NSSet(AppConstants.SubscriptionTags.ToArray());
            Hub.RegisterNative(deviceToken, tags, (errorCallback) =>
            {
                if (errorCallback != null)
                {
                    Debug.WriteLine($"RegisterNativeAsync error: {errorCallback}");
                }
            });

            var templateExpiration = DateTime.Now.AddDays(120).ToString(System.Globalization.CultureInfo.CreateSpecificCulture("en-US"));
            Hub.RegisterTemplate(deviceToken, "defaultTemplate", AppConstants.APNTemplateBody, templateExpiration, tags, (errorCallback) =>
            {
                if (errorCallback != null)
                {
                    if (errorCallback != null)
                    {
                        Debug.WriteLine($"RegisterTemplateAsync error: {errorCallback}");
                    }
                }
            });
        });

        // Firebase ios Registration
        Messaging.SharedInstance.ApnsToken = deviceToken;
        
       }
   // Process the notification when the app is open.
   
public override void ReceivedRemoteNotification(UIApplication application, NSDictionary userInfo)
    {
        ProcessNotification(userInfo, false);
        

    }   // End of the ReceiveRemoteNotification method

    

    // Process the notification when the app is closed.
    public override void DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo, Action<UIBackgroundFetchResult> completionHandler)
    {
        ProcessNotification(userInfo, false);            
        
    }


    void ProcessNotification(NSDictionary options, bool fromFinishedLaunching)
    {
        // make sure we have a payload
        if (options != null && options.ContainsKey(new NSString("aps")))
        {
            // get the APS dictionary and extract message payload. Message JSON will be converted
            // into a NSDictionary so more complex payloads may require more processing
            NSDictionary aps = options.ObjectForKey(new NSString("aps")) as NSDictionary;
            
            string payload = string.Empty;
            NSString payloadKey = new NSString("alert");
            
            if (aps.ContainsKey(payloadKey))
            {
                payload = aps[payloadKey].ToString();
            }

          
            
            if (!string.IsNullOrWhiteSpace(payload))
            {
                (App.Current.MainPage as MainPage)?.AddMessage(payload);
            }

        }
        else
        {
            Debug.WriteLine($"Received request to process notification but there was no payload.");
        } 
     } // End of the ProcessNotification method





}

}

Upvotes: 0

CodeSi
CodeSi

Reputation: 421

To handle the push notification event regardless the app run in foreground or background. Following these steps to get DidReceiveRemoteNotification be called always

1) Override DidReceiveRemoteNotification method in AppDelegate.cs

public override void DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo, Action<UIBackgroundFetchResult> completionHandler)

2) Add Required background modes - remote-notification(value) to info.plist

3) Set content-available in payload to 1

{
"aps" : {
    "alert" : {
        "title" : "Game Request",
        "body" : "Bob wants to play poker"
    },
    "badge" : 5,
    "content-available" : 1
}

}

Upvotes: 1

Ax1le
Ax1le

Reputation: 6643

Have you implemented UserNotification? If you deploy your project on iOS 10+ you can try to subscribe the notification in the FinishedLaunching(UIApplication application, NSDictionary launchOptions) like:

if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
{
    var authOptions = UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound;
    UNUserNotificationCenter.Current.RequestAuthorization(authOptions, (granted, error) => {
        Console.WriteLine(granted);
    });
    UNUserNotificationCenter.Current.Delegate = new MyNotificationCenterDelegate();
}

Then when the notification comes and the application is in the foreground, the WillPresentNotification() will fire, this handle event returns which action will this app response when notification comes. At last you can get the userInfo in the DidReceiveNotificationResponse() event:

public class MyNotificationCenterDelegate : UNUserNotificationCenterDelegate
{
    public override void DidReceiveNotificationResponse(UNUserNotificationCenter center, UNNotificationResponse response, Action completionHandler)
    {
        completionHandler();
    }

    public override void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification, Action<UNNotificationPresentationOptions> completionHandler)
    {
        completionHandler(UNNotificationPresentationOptions.Sound | UNNotificationPresentationOptions.Alert);

    }       
}

But if you don't want to implement UserNotification or you just push a silent remote notification with the key content-available true, the didReceiveRemoteNotification() will also be fired even though the app is in foreground.

Upvotes: 3

MilanG
MilanG

Reputation: 2604

The override method ReceivedRemoteNotification or DidReceiveRemoteNotification in the AppDelegate, will get fired when you receive the push notification when you are in foreground.

In this method you can check if your app is in Active state or not and based on it, you can handle your notifications.

if (UIApplication.SharedApplication.ApplicationState == UIApplicationState.Active) 
{
    //You app is in Foreground state.
    //Process the Pushnotification data, or show alert.
}

Apple's doc.

Implement the application(:didReceiveRemoteNotification:fetchCompletionHandler:) method instead of this one whenever possible. If your delegate implements both methods, the app object calls the application(:didReceiveRemoteNotification:fetchCompletionHandler:) method.

So, if you have both methods (ReceivedRemoteNotification & DidReceiveRemoteNotification) implemented in your AppDelegate, then DidReceiveRemoteNotification method will get called.

Upvotes: 0

Related Questions