Reputation: 111
Update: I have tried setting the policy on the timeline to .atEnd
, since there is only one entry. This has not made a difference. I have tried both in the RSS Parser file, and in the AppDelegate to run the WidgetCenter reloadAllTimeLines
method, and it too does nothing. This is driving me nuts, and I'm about to have to use a developer support ticket to get this figured out.
I am slowly getting my app ready for some iOS 14 features, but keep coming across bug after bug, or (MORE LIKELY) not doing things correctly on my end. I'm trying every thing in my power to get the widget to update but it will not. The widget itself is simple; it shows the title and some text of the most recent entry from an RSS feed. I built an XMLParser, and this code gets run for the timeline:
struct Provider: TimelineProvider {
@State private var rssItems:[RSSItem]?
let feedParser = FeedParser()
func placeholder(in context: Context) -> SimpleEntry {
SimpleEntry(date: Date(), title:"News", description: "News article here", link: "Http://link", pubDate: "The day it posted")
}
func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) {
let entry = SimpleEntry(date: Date(), title:"News", description: "News Article Here", link: "Http://link", pubDate: "The day it posted")
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<SimpleEntry>) -> ()) {
WidgetCenter.shared.reloadAllTimelines()
var entries: [SimpleEntry] = []
feedParser.parseFeed(url: "https://fritchcoc.wordpress.com/feed") {(rssItems) in
self.rssItems = rssItems
let currentDate = Date()
let string1 = "Latest News: \n\n"
let string2 = rssItems[0].title
var appendString1 = string1+string2
let entry = SimpleEntry(date: currentDate, title:appendString1, description: rssItems[0].description, link: rssItems[0].link, pubDate: rssItems[0].pubDate)
entries.append(entry)
let refreshDate = Calendar.current.date(byAdding: .minute, value: 2, to: Date())!
let timeline = Timeline(entries: entries, policy: .after(refreshDate))
completion(timeline)
}
}
}
When you first install the widget, it correctly shows the latest news item. However, I added some more entries to the RSS feed to test it, and it never updates to show these changes, only whatever is new at the time of install. I install on a 2nd device, and on the 2nd device, it DOES show the new ones that I added for testing, so I know that it is working properly on the parser end, and on the RSS itself.
Upvotes: 14
Views: 18085
Reputation: 363
Try using the .onChange function in one of your View-Files. If there is any change to your SimpleEntry array, you can call WidgetCenter.shared.reloadAllTimelines().
It could look like:
.onChange(of: simpleEntryArray.count) { change in
// some code to save your changes
WidgetCenter.shared.reloadAllTimelines()
}
Upvotes: 0
Reputation: 89
Discovered the issue with the iOS 14 widget not refreshing in my app was caused by the default cache policy of the URLRequest. By default, the cache was being used rather than requesting new data from the server. The JSON was loading from the cached data. After adding this cachePolicy parameter to the URLRequest "cachePolicy: URLRequest.CachePolicy.reloadIgnoringLocalCacheData", the widget started to update correctly and displayed the correct up-to-date data from the server.
var urlRequest = URLRequest(url: url, cachePolicy: URLRequest.CachePolicy.reloadIgnoringLocalCacheData)
Upvotes: 0
Reputation: 299
WidgetCenter.shared.reloadTimelines(ofKind: "Widgets")
won't work if you don't check background fetch in background mode capabilities
it took me a week to find it!
Upvotes: 4
Reputation: 11
https://developer.apple.com/forums/thread/653265?answerId=619739022#619739022
Updating every minute is far too aggressive. Widgets have a limited number of updates and if you were to try to update every minute, you'll quickly run out of updates. While debugging with Xcode these limits are not imposed, but if you're running your app outside of Xcode you'd see the behavior you're describing where your widget would stop updating.
What happens if you update every 15 minutes? If that doesn't work, please file a Feedback Assistant report with the details of what you're doing and the results you see.
Upvotes: 1
Reputation: 436
iOS is handling timeline execution, and it will not show it right away. I have checked your code and everything seems ok. I am building a similar app, and everything is working. I have almost the same code. I have API hit test, and it seems that it refreshes widget every 10-20 minutes. At least in my case.
I would put it as .atEnd
timeline policy.
Each configured widget receives a limited number of refreshes every day. Several factors affect how many refreshes a widget receives, such as whether the containing app is running in the foreground or background, how frequently the widget is shown onscreen, and what types of activities the containing app engages in.
WidgetKit does not impose this limit when debugging your widget in Xcode. To verify that your widget behaves correctly, test your app and widget’s behavior outside of Xcode’s debugger.Source
Did you try to debug it? What your result?
Can you try testing some API that has hit test so you can check how many times API got hit?
EDIT: If you want to update your widget as soon as the news article is added then you will need to implement notifications that will force refresh of the widget.
EDIT2: I have found that sometimes my widget wouldn't refresh after initial refresh and removing and adding widget to the screen fixed that problem. I think that this is problem occur only when developing/debugging.
EDIT3: Remove WidgetCenter.shared.reloadAllTimelines()
from the getTimeline()
. Build project and run it. Check console log, you should print something on every request. It should trigger in the next few minutes.
Upvotes: 8