1

I want to add background fetch for my app, when the silent remote notification arrives (with content-available : 1 ), so when it arrives, I trigger a background update locally, check for new data and if so generate a local push notification for the user. However, it works perfectly only when the app is in the background, not suspended or not running state. In those states I get it to fetch some data, but local notification is not fired (it's created as seen in console of the device), any ideas how can I solve that?

Here's my code for generating push (it works as expected)

func generatePushNotification(with title: String, body: String, badge: Int = 1){
        let content = UNMutableNotificationContent()
        content.badge = badge as NSNumber
        content.title = title
        content.body = body
        content.sound = UNNotificationSound.default
        let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1,
                                                        repeats: false)
        let notification = UNNotificationRequest(identifier: "pushLocal", content: content, trigger: trigger)
        UNUserNotificationCenter.current().add(notification) { (error) in
            if error != nil {
                NSLog((error?.localizedDescription)!)
            }
        }
    }

Here's my code for notificationFetch

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        networkManager.getScheduleForGroup(group) { (resp, error) in
            self.generatePushNotification(with: "Back", body: "ground")
            completionHandler(.newData)

        }
        completionHandler(.noData)

    }

Here's the console output:

dasd    CANCELED: com.apple.pushLaunch.**:297454 <private>!

SpringBoard    Saving notification 802A-AE8C: 0 [ hasAlertContent: 0, shouldPresentAlert: 1 ]

SpringBoard  Delivered user visible push notification 802A-AE8C

SpringBoard  Load 0 pending notification dictionaries

SpringBoard  Adding notification 802A-AE8C to destinations 0 [ hasAlertContent: 0, shouldPresentAlert: 1 hasSound: 0 shouldPlaySound: 1 ]
  • silent remote notifications does mean push notifications not local notifications. – Ankit Jayaswal Apr 10 '19 at 10:23
  • @AnkitJayaswal what do you mean? – Nikita Krasnov Apr 10 '19 at 10:27
  • Silent Notifications are for push notifications with `content-available` key, but it is not available with Local Notification. For more detail - https://stackoverflow.com/questions/44944383/is-it-possible-to-send-silent-local-notification-on-ios – Ankit Jayaswal Apr 10 '19 at 10:30
  • @AnkitJayaswal I don't want a silent Local Notification, instead I want it to be with sound. Silent is my remote notification. – Nikita Krasnov Apr 10 '19 at 10:36
  • It is not a good way to use background fetch with remote notifications because application comes in background for few seconds in it. Try to set the UIApplicationBackgroundFetchIntervalMinimum based on your length of task and interval of remote notification. – Abilash Bansal Apr 10 '19 at 10:38
  • 1
    You shouldn't call `completionHandler(.noData)` outside the closure. This indicates to ios that you had no data and will result in your app being suspended again before your network operation completes – Paulw11 Apr 10 '19 at 10:41
  • @AbilashBansal that was one of the ideas, but in this case a cannot guarantee, that the fetch will be performed (IOS decides when to do it). – Nikita Krasnov Apr 10 '19 at 10:46
  • @Paulw11 good point, missed that, however that doesn't solve the problem – Nikita Krasnov Apr 10 '19 at 10:49
  • @NikitaKrasnov How long it takes your task to perform? You can do it directly without background fetch. you can perform it on receiving remote notification directly. If it takes less than 30 seconds then it probably perform your task before going to suspend state . – Abilash Bansal Apr 10 '19 at 10:53
  • You won't get anything happening when your app is not running as it isn't running, so the delegate method can't be called. – Paulw11 Apr 10 '19 at 11:06

2 Answers2

2
let content = UNMutableNotificationContent()
content.title = title
content.body = body
content.sound = UNNotificationSound.default()

var dateComponents = Calendar.current.dateComponents([.hour, .minute, .second], from: Date())

let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false)

let request = UNNotificationRequest(identifier: identifier, content: content, trigger: trigger)

UNUserNotificationCenter.current().add(request, withCompletionHandler: { (error) in
    if let error = error{
        print(error)
    }
})
UNUserNotificationCenter.current().delegate = self

Use this

AtulParmar
  • 4,358
  • 1
  • 24
  • 45
  • That doesn't help – Nikita Krasnov Apr 10 '19 at 11:53
  • let notification = UILocalNotification() notification.fireDate = NSDate(timeIntervalSinceNow: 1) as Date notification.alertBody = body notification.alertAction = title notification.soundName = UILocalNotificationDefaultSoundName UIApplication.shared.scheduleLocalNotification(notification) USE this – Darshan Singh Khangarot Apr 11 '19 at 14:28
0

//AppDelegate

UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
        UNUserNotificationCenter.current().requestAuthorization(
            options: authOptions,
            completionHandler: {_, _ in })


application.registerUserNotificationSettings(UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil))

//In ViewController

 let content = UNMutableNotificationContent()
        content.title = “Notification Title”
        content.body = “Notification Body”
        content.sound = UNNotificationSound.default()
        content.badge = 1

        let date = Date()

        let localDate = date.toLocalTime()

        var triggerDaily = Calendar.current.dateComponents([.hour,.minute,.second,], from: localDate)
        triggerDaily.hour = 22
        triggerDaily.minute = 00
        triggerDaily.second = 00

        let trigger = UNCalendarNotificationTrigger(dateMatching: triggerDaily, repeats: true)

        let identifier = "Local Notification"
        let request = UNNotificationRequest(identifier: identifier, content: content, trigger: trigger)

        UNUserNotificationCenter.current().add(request) { (error) in
            if let error = error {
                print("Error \(error.localizedDescription)")
            }
        }

//Add Extension to convert time

extension Date { 

  func convertToGlobalTime() -> Date {
     let currentTimezone = TimeZone.current
     let interval = -TimeInterval(currentTimezone.secondsFromGMT(for: self))
     return Date(timeInterval: interval, since: self)
 }

 func convertToLocalTime() -> Date {
     let currentTimezone = TimeZone.current
     let interval = TimeInterval(currentTimezone(for: self))
     return Date(timeInterval: interval, since: self)
 }

}
abhinikam
  • 1
  • 1