Sarvesh
Sarvesh

Reputation: 401

How to reload timeline of iOS 14 widget from notification response?

I'm making a home screen widget for iOS 14 using the new WidgetKit and I want my widget timeline to refresh when the user responds to a notification.

This is what my code looks like currently:

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        
    if response.actionIdentifier == "actionIdentifier" {        
        print("notification response received")
        WidgetCenter.shared.reloadAllTimelines()
    }

    completionHandler()
}

But my widget is not updated when the user responds to the notification. The print statement gets printed, so I know my app is receiving the response. The widget also gets refreshed when I call reloadAllTimeLines() anywhere else in my app, so I'm sure my widget extension is implemented correctly. But it's not updating in the above scenario.

Is this a bug or am I doing something wrong? Or is there another way to reload a widget timeline after the user responds to a notification.

Upvotes: 18

Views: 13540

Answers (3)

Jordan H
Jordan H

Reputation: 55785

tldr; Reloading your widgets while the app is in the background does seem to work, however, it may not update immediately.

I encountered this recently and added logging to determine what's going on. If curious I did this by adding NSLog everywhere relevant, replicating the issue, collecting a sysdiagnose, and examining the system_logs. I tested this scenario which seems to be the most extreme: trigger the notification action from my Apple Watch with the iPhone locked, in low power mode, with the app not open in the background, and 3 widgets added to the Home Screen.

What I found is the app was launched, the notification action was processed, and reloadAllTimelines() was triggered as expected. But getTimelines in the widget was not called - not until about 24 minutes later! So it will update eventually. And note this was not due to my timeline reload policy - I have that set to only refresh once a day at midnight.

iOS is surely trying to be smart about when it'll process reload requests to preserve battery life etc.

Upvotes: 4

Sarvesh
Sarvesh

Reputation: 401

This seems to be fixed in iOS 14 beta 2. The widget now correctly updates when refreshAllTimelines() is called from the notification response.

Upvotes: 12

Piyush Chopra
Piyush Chopra

Reputation: 49

Try calling that under Dispatch Main, or try calling it with a delay of, to test, say 2 seconds.

I am calling the same on SwiftUI's List as

let listArray = ["Item1", "Item2", "Item3"]
List(listArray) { listObject in
    Button(action: {
        WidgetCenter.shared.reloadAllTimelines()
    }) {
        HStack {
            Text(listObject)
                .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .leading)
                .padding()
        }
    }
}

And it's working like charm.

Upvotes: 4

Related Questions