I use an XMLParser for my app written in Swift, and am trying to get a Widget set up for iOS 14 in which it will show the most recent article on the RSS. I see the placeholder just fine when I add it, but it stays empty with just a line where text should be and never seems to get the information from 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>) -> ()) { var entries: [SimpleEntry] = [] feedParser.parseFeed(url: "http://fritchcoc.wordpress.com/feed") {(rssItems) in self.rssItems = rssItems let currentDate = Date() let entry = SimpleEntry(date: currentDate, title:rssItems[0].title, description: rssItems[0].description, link: rssItems[0].link, pubDate: rssItems[0].pubDate) entries.append(entry) } let timeline = Timeline(entries: entries, policy: .atEnd) completion(timeline) } } struct SimpleEntry: TimelineEntry { let date: Date let title: String let description: String let link: String let pubDate: String } struct FritchNewsEntryView : View { var entry: SimpleEntry var body: some View { VStack(alignment: .leading, spacing: 4) { Text(entry.title) }.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .leading) .padding() .background(LinearGradient(gradient: Gradient(colors: [.orange, .yellow]), startPoint: .top, endPoint: .bottom)) } } @main struct FritchNews: Widget { let kind: String = "FritchNews" var body: some WidgetConfiguration { StaticConfiguration(kind: kind, provider: Provider()) { entry in FritchNewsEntryView(entry: entry) } .configurationDisplayName("My Widget") .description("This is an example widget.") } }
解决
Apple does not allow HTTP connections by default, the easiest solution is to change the URL to https://fritchcoc.wordpress.com/feed
If you want to allow HTTP connections in your app (or widget) you can add exceptions (to one domain or all) in the Info.plist for the target, see NSAppTransportSecurity at Apple Docs
Edit:
After a better look and finding for the implementation of FeedParser online, I noticed that parseFeed() is asynchronous.
Thus the completion is called with an empty array, it should be called after the parsing is done:
struct Provider: TimelineProvider { ... func getTimeline(in context: Context, completion: @escaping (Timeline<SimpleEntry>) -> ()) { var entries: [SimpleEntry] = [] feedParser.parseFeed(url: "http://fritchcoc.wordpress.com/feed") {(rssItems) in self.rssItems = rssItems let currentDate = Date() let entry = SimpleEntry(date: currentDate, title:rssItems[0].title, description: rssItems[0].description, link: rssItems[0].link, pubDate: rssItems[0].pubDate) entries.append(entry) let timeline = Timeline(entries: entries, policy: .atEnd) completion(timeline) } } }