0

I am using xamarin forms for my app. I need to send local notification based on SQLite table for ios. I am using the following code:

AppDelegate.cs:

using System;
using Foundation;
using UIKit;
using Xamarin.Forms;
using Firebase.Database;
using Firebase.CloudMessaging;
using UserNotifications;
using Microsoft.AppCenter.Crashes;
using Plugin.Permissions;
using Plugin.Permissions.Abstractions;
using CoreTelephony;
using Firebase.Auth;
using System.Threading.Tasks;
using System.Collections.Generic;

namespace MyApp.iOS
{
    [Register("AppDelegate")]
    public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate, IUNUserNotificationCenterDelegate, IMessagingDelegate
    {

        public override bool FinishedLaunching(UIApplication app, NSDictionary options)
        {

            global::Xamarin.Forms.Forms.Init();

            AppDomain.CurrentDomain.UnhandledException += CurrentDomainOnUnhandledException;
            Firebase.Core.App.Configure();
            Database.DefaultInstance.PersistenceEnabled = true;
            LoadApplication(new MyApp.App());
            RegisterForRemoteNotifications();



            Messaging.SharedInstance.Delegate = this;
            if (UNUserNotificationCenter.Current != null)
            {
                UNUserNotificationCenter.Current.Delegate = new UserNotificationCenterDelegate();
            }
            if (UNUserNotificationCenter.Current != null)
            {
                UNUserNotificationCenter.Current.Delegate = new UserNotificationCenterDelegate();
            }
            Xamarin.FormsMaps.Init();
            UIApplication.SharedApplication.IdleTimerDisabled = true;
            UIApplication.SharedApplication.SetMinimumBackgroundFetchInterval(UIApplication.BackgroundFetchIntervalMinimum);
            return base.FinishedLaunching(app, options);
        }



        public override bool ShouldRestoreApplicationState(UIApplication application, NSCoder coder)
        {
            return true;
        }

        private async System.Threading.Tasks.Task AcessPermissionsAsync()
        {
            try
            {

                await CrossPermissions.Current.RequestPermissionsAsync(Permission.Camera); 
            }
           catch(Exception ex)
            {
                Crashes.TrackError(ex);
            }


       }

            private void RegisterForRemoteNotifications()
        {
            if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
            {
                UNUserNotificationCenter.Current.RemoveAllPendingNotificationRequests(); // To remove all pending notifications which are not delivered yet but scheduled.
                UNUserNotificationCenter.Current.RemoveAllDeliveredNotifications(); // To remove all delivered notifications
            }
            else
            {
                UIApplication.SharedApplication.CancelAllLocalNotifications();
            }
            // Register your app for remote notifications.
            if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
            { 
                // For iOS 10 display notification (sent via APNS)
                UNUserNotificationCenter.Current.Delegate = this;

                var authOptions = UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound;
                UNUserNotificationCenter.Current.RequestAuthorization(authOptions, async (granted, error) =>
                {
                    Console.WriteLine(granted);
                    await System.Threading.Tasks.Task.Delay(500);
                    await AcessPermissionsAsync();
                });
            }
            else
            {
                // iOS 9 or before
                var allNotificationTypes = UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound;
                var settings = UIUserNotificationSettings.GetSettingsForTypes(allNotificationTypes, null);
                UIApplication.SharedApplication.RegisterUserNotificationSettings(settings);
            }

            UIApplication.SharedApplication.RegisterForRemoteNotifications();
        }




        public override void DidEnterBackground(UIApplication uiApplication)
        {
            Messaging.SharedInstance.ShouldEstablishDirectChannel = false;
        }
        public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
        {
            Messaging.SharedInstance.ApnsToken = deviceToken;
        }

        [Export("messaging:didReceiveRegistrationToken:")]
        public void DidReceiveRegistrationToken(Messaging messaging, string fcmToken)
        {
            Xamarin.Forms.Application.Current.Properties["Fcmtocken"] = Messaging.SharedInstance.FcmToken ?? "";
            Xamarin.Forms.Application.Current.SavePropertiesAsync();
            System.Diagnostics.Debug.WriteLine($"######Token######  :  {fcmToken}");
            DeviceId.FCMTocken = fcmToken;
            // TODO: If necessary send token to application server.
            // Note: This callback is fired at each app startup and whenever a new token is generated.
        }

        public override void ReceivedRemoteNotification(UIApplication application, NSDictionary userInfo)
        {
            // If you are receiving a notification message while your app is in the background,
            // this callback will not be fired till the user taps on the notification launching the application.
            // TODO: Handle data of notification

            // With swizzling disabled you must let Messaging know about the message, for Analytics


            // Print full message.
            Console.WriteLine(userInfo);
        }

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

                Console.WriteLine(userInfo);

                completionHandler(UIBackgroundFetchResult.NewData);
            }
            catch(Exception ex)
            {
                Crashes.TrackError(ex);
            }
        }  
        public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations(UIApplication application, UIWindow forWindow)
        {
            switch (Device.Idiom)
            {
                case TargetIdiom.Phone:
                    return UIInterfaceOrientationMask.Portrait;
                case TargetIdiom.Tablet:
                    return UIInterfaceOrientationMask.Landscape;
                default:
                    return UIInterfaceOrientationMask.Portrait;
            }
        }

        private void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs unhandledExceptionEventArgs)
        {
            var newExc = new Exception("CurrentDomainOnUnhandledException", unhandledExceptionEventArgs.ExceptionObject as Exception);
            ExceptionFileWriter.ToLogUnhandledException(newExc);
        }
        public void DidRefreshRegistrationToken(Messaging messaging, string fcmToken)
        {
            Xamarin.Forms.Application.Current.Properties["Fcmtocken"] = Messaging.SharedInstance.FcmToken ?? "";
            Xamarin.Forms.Application.Current.SavePropertiesAsync();
            System.Diagnostics.Debug.WriteLine($"######Token######  :  {fcmToken}");
            DeviceId.FCMTocken = fcmToken;
        }

        public override void PerformFetch(UIApplication application, Action<UIBackgroundFetchResult> completionHandler)
        {
            try
            {
                var baseService = new DatabaseServices<object, object>();
                baseService.NotificationAssetTrip();
            }
            catch(Exception ex)
            {
                Logs.LogCreate("PerformFetch:Exception: " + ex.Message.ToString());
            }
            completionHandler(UIBackgroundFetchResult.NewData);
        }
    }
}

UserNotificationCenterDelegate.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Foundation;
using iAd;
using ObjCRuntime;
using UIKit;
using UserNotifications;

namespace MyApp.iOS
{
    public class UserNotificationCenterDelegate : UNUserNotificationCenterDelegate
    {
        private DBService dataBase;
        #region Constructors
        public UserNotificationCenterDelegate()
        {
            UNUserNotificationCenter.Current.Delegate = this;
        }
        #endregion

        #region Override Methods
        public override void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification, Action<UNNotificationPresentationOptions> completionHandler)
        {
            completionHandler.DynamicInvoke(UNNotificationPresentationOptions.Alert);
        }
        #endregion
    }
}

App.xaml.cs:

private void SendNotificationTripAsset(int tripid)
 {
 //Forexample i have table with columns like title,subtitle,message means, i give like this
                            var content = new UserNotifications.UNMutableNotificationContent()
                            {
                                Title = title,
                                Subtitle = subtitle,
                                Body = message,
                                Badge = 1
                            };

                            var request = UserNotifications.UNNotificationRequest.FromIdentifier(list.TripID.ToString(), content, null);
                            UserNotifications.UNUserNotificationCenter.Current.AddNotificationRequest(request, (err) =>
                            {
                                if (err != null)
                                {
                                   throw new Exception($"Failed to schedule notification: {err}");
                                }
                            });
 }

But the notification is not trigged after app is killed(terminated). Can anyone please help me to resolve this issue.

Manthiram
  • 149
  • 2
  • 13
  • Possible duplicate of [iOS Push Notification When app is killed](https://stackoverflow.com/questions/51302525/ios-push-notification-when-app-is-killed) – Akash Kava Nov 21 '19 at 14:48

1 Answers1

1

To send a local notification when app is killed, you have to specify the time when should the local notification been sent. In your code, when you create the request, set a proper NNotificationTrigger :

NNotificationTrigger trigger = UNTimeIntervalNotificationTrigger.CreateTrigger(3, false);

var request = UserNotifications.UNNotificationRequest.FromIdentifier(list.TripID.ToString(), content, trigger );

That means this notification will be fired after 3 seconds. You can change the time to whatever you want.

Code will not execute when your app is killed, so if you don't know the specific time to fire the notification or it fires randomly, you should use a remote notification.

nevermore
  • 15,432
  • 1
  • 12
  • 30