Xamarin Forms: Push notification is not receiving to ios device

SreeeeSreeee INMember ✭✭✭✭✭
edited June 25 in Xamarin.Forms

I have done the following things:

  1. Created a project in FCM console and added ios project into it.
  2. Downloaded the GoogleService-Info.plist and added it to the xamarin forms ios project directory and set the build action as Bundlesource.
  3. On Info.plist enabled remote notification background mode.
  4. Added FirebaseAppDelegateProxyEnabled in the app’s Info.plist file and set it to No.
  5. Created a provisioning profile and distribution certificate and installed it into the keychain access. Also, mapped these certificates in the project options.
  6. Uploaded .p12 certificate in FCM console.
  7. Added codes for handling push notification in AppDelegate.cs.

My Code:

    [Register("AppDelegate")]
    public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
    {
        public override bool FinishedLaunching(UIApplication app, NSDictionary options)
        {
            global::Xamarin.Forms.Forms.Init();
            LoadApplication(new App("",""));
            RequestPushPermissionsAsync();
            _launchoptions = options;
            return base.FinishedLaunching(app, options);
        }
        NSDictionary _launchoptions;
        public override void OnActivated(UIApplication uiApplication)
        {
            base.OnActivated(uiApplication);
            if (_launchoptions != null && _launchoptions.ContainsKey(UIApplication.LaunchOptionsRemoteNotificationKey))
            {
                var notfication = _launchoptions[UIApplication.LaunchOptionsRemoteNotificationKey] as NSDictionary;
                PresentNotification(notfication);
            }
            _launchoptions = null;
        }

        async Task RequestPushPermissionsAsync()
        {
            var requestResult = await UNUserNotificationCenter.Current.RequestAuthorizationAsync(
                 UNAuthorizationOptions.Alert
                | UNAuthorizationOptions.Badge
                | UNAuthorizationOptions.Sound);

            bool approved = requestResult.Item1;
            NSError error = requestResult.Item2;
            if (error == null)
            {
                if (!approved)
                {
                    Console.Write("Permission to receive notification was not granted");
                    return;
                }

                var currentSettings = await UNUserNotificationCenter.Current.GetNotificationSettingsAsync();
                if (currentSettings.AuthorizationStatus != UNAuthorizationStatus.Authorized)
                {
                    Console.WriteLine("Permissions were requested in the past but have been revoked (-Settings  app)");
                    return;
                }
                UIApplication.SharedApplication.RegisterForRemoteNotifications();
            }
            else
            {
                Console.Write($"Error requesting permissions: {error}.");
            }
        }

        public async override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
        {
            if (deviceToken == null)
            {
                return;
            }
            Console.WriteLine($"Token received: {deviceToken}");
            await SendRegistrationTokenToMainPRoject(deviceToken);
        }

        async Task SendRegistrationTokenToMainPRoject(NSData deviceToken)
        {
            MessagingCenter.Send<object, string>(this, "fcmtoken", deviceToken.ToString());
        }

        public override void FailedToRegisterForRemoteNotifications(UIApplication application, NSError error)
        {
            Console.WriteLine($"Failed to register for remote notifications: {error.Description}");
        }

        public override void DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo,
            Action<UIBackgroundFetchResult> completionHandler)
        {
            PresentNotification(userInfo);
            completionHandler(UIBackgroundFetchResult.NoData);
            try
            {
                UIApplication.SharedApplication.ApplicationIconBadgeNumber = 0;
                NSDictionary aps = userInfo.ObjectForKey(new NSString("aps")) as NSDictionary;
                var message = (aps[new NSString("webContentList")] as NSString).ToString();
                LoadApplication(new App("", message));
            }
            catch (Exception ex)
            {
                //LogInfo.ReportErrorInfo(ex.Message, ex.StackTrace, "AppDelegate-DidReceiveRemoteNotification");
            }
        }

        void PresentNotification(NSDictionary userInfo)
        {
            NSDictionary aps = userInfo.ObjectForKey(new NSString("aps")) as NSDictionary;

            var msg = string.Empty;

            if (aps.ContainsKey(new NSString("alert")))
            {
                msg = (aps[new NSString("alert")] as NSString).ToString();
            }
            if (string.IsNullOrEmpty(msg))
            {
                msg = "(unable to parse)";
            }
            MessagingCenter.Send<object, string>(this, App.NotificationReceivedKey, msg);
        }
    }

I am not using any NuGet packages in ios part. When running the project into a device, the FCM token generating part is working and I can see the fcm token on the VS console. I tried to send a test notification to a device from postman but getting InvalidRegistration error.

Postman Response

{
    "multicast_id": 8754155136812875313,
    "success": 0,
    "failure": 1,
    "canonical_ids": 0,
    "results": [
        {
            "error": "InvalidRegistration"
        }
    ]
}

Postman Body

 {
    "to" : "d20ad003 7473bfba 85dffc33 1534decf b4b886f1 c738878f fd7f2c60 d9dabc36",
 "collapse_key" : "type_a",
 "data" : {
     "body" : "Body of Your Notification in Data",
     "title": "Title of Your Notification in Title",
     "key_1" : "Value for key_1",
     "key_2" : "Value for key_2"
 },
 "notification" : {
     "body" : "Body of Your Notification",
     "title": "Title of Your Notification",
     "sound": "default",
     "content_available" : true
 }
}

I have completed the android part implementation and notifications are receiving when push from the postman. But getting InvalidRegistration error on postman and not receiving any notification in my ios device.

Anyone suggest a solution for this issue.

Thanks in advance.

Best Answer

  • FaizalSaidaliFaizalSaidali US ✭✭✭
    Accepted Answer

    @Sreeee , I have reviewed and can resolve this issue.

    1. Install the plugin Xamarin.Firebase.iOS.CloudMessaging in iOS project
    2. AppDelegate class needs to inherit from IUNUserNotificationCenterDelegate and IMessagingDelegate interfaces
    3. Include the Firebase.Core.App.Configure (); in FinishedLaunching method before registering remote notification
    4. Then you can add the registering remote notification code (You can get the code from given link)
    5. You need to set user notification delegate and messaging shared instant delegate (UNUserNotificationCenter.Current.Delegate = this; // For iOS 10 display notification (sent via APNS) and Messaging.SharedInstance.Delegate = this;)
    6. Include DidReceiveRegistrationToken and DidReceiveMessage methods with corresponding attributes

    Please refer this AppDelegate class for more clarity https://github.com/xamarin/GoogleApisForiOSComponents/blob/master/Firebase.CloudMessaging/samples/CloudMessagingSample/CloudMessagingSample/AppDelegate.cs

Answers

  • FaizalSaidaliFaizalSaidali USMember ✭✭✭

    Hi @Sreeee , I am not sure, this is your issue. But I noticed it in your RegisteredForRemoteNotifications method. I think your mistake happens when the NSData value converting to string in direct method.

    public override void RegisteredForRemoteNotifications (UIApplication application, NSData deviceToken)
    {
        // Get current device token
        var DeviceToken = deviceToken.Description;
        if (!string.IsNullOrWhiteSpace(DeviceToken)) {
            DeviceToken = DeviceToken.Trim('<').Trim('>');
        }
    
        // Get previous device token
        var oldDeviceToken = NSUserDefaults.StandardUserDefaults.StringForKey("PushDeviceToken");
    
        // Has the token changed?
        if (string.IsNullOrEmpty(oldDeviceToken) || !oldDeviceToken.Equals(DeviceToken))
        {
            //TODO: Put your own logic here to notify your server that the device token has changed/been created!
        }
    
        // Save new device token
        NSUserDefaults.StandardUserDefaults.SetString(DeviceToken, "PushDeviceToken");
    }
    

    Reference: https://docs.microsoft.com/en-us/xamarin/ios/platform/user-notifications/deprecated/remote-notifications-in-ios

  • SreeeeSreeee INMember ✭✭✭✭✭

    @FaizalSaidali I tried your code but getting the same value for deviceToken and DeviceToken. Using Console.WriteLine I check both token values but both are same.

  • SreeeeSreeee INMember ✭✭✭✭✭

    @FaizalSaidali Did you see any other mistake in my implementation?

  • FaizalSaidaliFaizalSaidali USMember ✭✭✭

    @Sreeee I think, you can make a JIRA for me to assign this task :smiley:
    I noticed one open issue in that reference(I have posted before). Please take a look on that.

  • SreeeeSreeee INMember ✭✭✭✭✭
    edited June 25

    @FaizalSaidali Can you tell me a conclusion about the possibility of the error?

    Is my issue is related to the certificates or FCM project creation or in the codes in AppDelegate.cs?

    The FCM token is always generating when installing the app. I follow this youtube video for this implementation and the complete source code is here. The AppDelegate.cs file of the source code.

  • FaizalSaidaliFaizalSaidali USMember ✭✭✭
    edited June 25

    @Sreeee , Make sure the registration with APNS is handled in the FinishedLaunching method, like below,

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

    As per my understanding, you got the token from the given event. (I didn't use it)
    Firebase.InstanceID.InstanceId.Notifications.ObserveTokenRefresh(async (sender, e) => {};

    Reference: https://firebase.google.com/docs/cloud-messaging/ios/client

  • SreeeeSreeee INMember ✭✭✭✭✭

    @FaizalSaidali I added APNS registration codes in FinishedLaunching method, but no luck. :'(

  • SreeeeSreeee INMember ✭✭✭✭✭

    @FaizalSaidali If I give you a sample project, can you have a look?

  • LucasZhangLucasZhang Member, Xamarin Team Xamurai

    Does the notification can been received on Android ?

  • SreeeeSreeee INMember ✭✭✭✭✭
  • LucasZhangLucasZhang Member, Xamarin Team Xamurai
    edited June 25

    Did you test it on a real device or simulator? And did you get some error log in output?

  • SreeeeSreeee INMember ✭✭✭✭✭

    @LucasZhang I am testing on real iPhone device. There are no errors showing in output.

  • FaizalSaidaliFaizalSaidali USMember ✭✭✭

    @Sreeee > @Sreeee said:

    @FaizalSaidali If I give you a sample project, can you have a look?

    @Sreeee Sure. If you con give me a sample, that would be better for me to check

  • FaizalSaidaliFaizalSaidali USMember ✭✭✭

    @Sreeee , Before that, can you follow these given steps
    1. Add these interfaces (IUNUserNotificationCenterDelegate and IMessagingDelegate) in to AppDelegate.
    public partial class AppDelegate : FormsApplicationDelegate, IUNUserNotificationCenterDelegate, IMessagingDelegate
    2. UNUserNotificationCenter.Current.Delegate = this; // For iOS 10 display notification (sent via APNS)
    3. Messaging.SharedInstance.Delegate = this; // For iOS 10 data message (sent via FCM)

  • SreeeeSreeee INMember ✭✭✭✭✭

    @FaizalSaidali

    IMessagingDelegate interface is not found.

    Getting the following error when adding IMessagingDelegate.

    Error CS0246: The type or namespace name 'IMessagingDelegate' could not be found (are you missing a using directive or an assembly reference?) (CS0246)

  • SreeeeSreeee INMember ✭✭✭✭✭

    Hi @FaizalSaidali and @LucasZhang

    I have created a sample project and a postman collection and added it to my google folder.

    Postman collection contains 2 REST APIs, one for Android device and the other one for ios device

    If you import the postman collection and run the Android REST API, I will receive the notification, because I have added my device FCM token on it. But when running the ios REST API in postman will return InvalidRegistration error in postman.

    Can you please go through the sample project and please give me a solution?

  • FaizalSaidaliFaizalSaidali USMember ✭✭✭

    @Sreeee , Will you able to install the Nuget package as Xamarin.Firebase.iOS.CloudMessaging in your iOS project

  • SreeeeSreeee INMember ✭✭✭✭✭

    @FaizalSaidali Currently I am not using Xamarin.Firebase.iOS.CloudMessaging in IOS project. Is that needed for push notification?

  • FaizalSaidaliFaizalSaidali USMember ✭✭✭
    edited June 26

    @Sreeee , I have checked in my one project. In that have these packages
    Please take a look on this: https://github.com/xamarin/GoogleApisForiOSComponents/blob/master/Firebase.CloudMessaging/component/GettingStarted.md

  • SreeeeSreeee INMember ✭✭✭✭✭
    edited June 26

    @FaizalSaidali I added the Xamarin.Firebase.iOS.CloudMessaging to ios project, but getting lot of errors.

    Screenshot

    Now I uninstall the Xamarin.Firebase.iOS.CloudMessaging package and I removed firebase related lines from ios.csproj and solved the issue. If I add that package again the same errors are coming.

  • FaizalSaidaliFaizalSaidali USMember ✭✭✭

    Try these too

  • SreeeeSreeee INMember ✭✭✭✭✭

    @FaizalSaidali How we are using these packages in the project?

  • FaizalSaidaliFaizalSaidali USMember ✭✭✭

    @Sreeee , I think, these packages are attaching with Xamarin.Firebase.iOS.CloudMessaging. So you don't want to install separately.
    Can you take a look on the given url, it may helps you to integrate it properly.
    https://github.com/xamarin/GoogleApisForiOSComponents/tree/master/Firebase.CloudMessaging/samples/CloudMessagingSample/CloudMessagingSample

    I'm sorry, I can't able to check your attachment yet. If you didn't getting any solution, I will work around it.

  • SreeeeSreeee INMember ✭✭✭✭✭

    @FaizalSaidali Ok I will go through the links and update you.

  • SreeeeSreeee INMember ✭✭✭✭✭

    @FaizalSaidali Did you get time to check the sample project. Still, I am struggling with this issue.

  • FaizalSaidaliFaizalSaidali USMember ✭✭✭

    @Sreeee , Sorry, I didn't check that. I thought that was fixed. Anyway I will add this in my today's schedule.
    I need to know, what kind of issue you have facing now after adding the package and what is the current status?

  • SreeeeSreeee INMember ✭✭✭✭✭

    @FaizalSaidali Thank you very much for your time.

    Currently, there are no errors(initially have some errors) when adding Xamarin.Firebase.iOS.CloudMessaging package.

    When running the project on a real iPhone device I can see the devicetoken on the log. But when trying to push notification from the postman, showing InvalidRegistration error. I have added the sample project and a sample postman collection to the google drive.

    Postman collection contains 2 REST APIs, one for Android device and the other one for ios device

    If you import the postman collection and run the Android REST API, I will receive the notification, because I have added my device FCM token on it. But when running the ios REST API in postman will return InvalidRegistration error in postman.

  • FaizalSaidaliFaizalSaidali USMember ✭✭✭
    Accepted Answer

    @Sreeee , I have reviewed and can resolve this issue.

    1. Install the plugin Xamarin.Firebase.iOS.CloudMessaging in iOS project
    2. AppDelegate class needs to inherit from IUNUserNotificationCenterDelegate and IMessagingDelegate interfaces
    3. Include the Firebase.Core.App.Configure (); in FinishedLaunching method before registering remote notification
    4. Then you can add the registering remote notification code (You can get the code from given link)
    5. You need to set user notification delegate and messaging shared instant delegate (UNUserNotificationCenter.Current.Delegate = this; // For iOS 10 display notification (sent via APNS) and Messaging.SharedInstance.Delegate = this;)
    6. Include DidReceiveRegistrationToken and DidReceiveMessage methods with corresponding attributes

    Please refer this AppDelegate class for more clarity https://github.com/xamarin/GoogleApisForiOSComponents/blob/master/Firebase.CloudMessaging/samples/CloudMessagingSample/CloudMessagingSample/AppDelegate.cs

Sign In or Register to comment.