iOS 14 小部件不刷新

Posted

技术标签:

【中文标题】iOS 14 小部件不刷新【英文标题】:iOS 14 Widget Not Refreshing 【发布时间】:2021-01-10 23:20:51 【问题描述】:

更新:我已尝试将时间轴上的策略设置为 .atEnd,因为只有一个条目。这并没有什么不同。我在 RSS Parser 文件和 AppDelegate 中都尝试过运行 WidgetCenter reloadAllTimeLines 方法,但它也什么也没做。这让我发疯了,我将不得不使用开发人员支持票来解决这个问题。

我正在慢慢地让我的应用程序为一些 ios 14 功能做好准备,但不断遇到一个又一个错误,或者(更有可能)我没有正确地做事。我正在尽我所能来更新小部件,但它不会。小部件本身很简单;它显示来自 RSS 提要的最新条目的标题和一些文本。我构建了一个 XMLParser,这段代码在时间轴上运行:

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)

        
       
    

当您第一次安装小部件时,它会正确显示最新的新闻项目。但是,我在 RSS 提要中添加了更多条目以对其进行测试,并且它从不更新以显示这些更改,仅显示安装时的新内容。我安装在第二台设备上,在第二台设备上,它确实显示了我为测试添加的新设备,所以我知道它在解析器端和 RSS 本身上正常工作。

【问题讨论】:

对于未来的读者,这可能会有所帮助:How to refresh Widget data? 和 Setting the TimelineProvider refresh interval for Widget 【参考方案1】:

尝试在您的一个视图文件中使用 .onChange 函数。如果您的 SimpleEntry 数组有任何变化,您可以调用 WidgetCenter.shared.reloadAllTimelines()。

它可能看起来像:

.onChange(of: simpleEntryArray.count)  change in 
      // some code to save your changes
      WidgetCenter.shared.reloadAllTimelines()

【讨论】:

【参考方案2】:

发现 iOS 14 小部件在我的应用中未刷新的问题是由 URLRequest 的默认缓存策略引起的。默认情况下,使用缓存而不是从服务器请求新数据。 JSON 是从缓存的数据中加载的。将此 cachePolicy 参数添加到 URLRequest “cachePolicy: URLRequest.CachePolicy.reloadIgnoringLocalCacheData”后,小部件开始正确更新并显示来自服务器的正确最新数据。

var urlRequest = URLRequest(url: url, cachePolicy: URLRequest.CachePolicy.reloadIgnoringLocalCacheData)

【讨论】:

我应该把那个放在哪里?就像在它的主 swift 文件中或在 getTimeline 中一样? 将其与发出网络请求的代码一起放入主 swift 文件中。不在 getTimeline 内。它还可能取决于服务器端 API 的缓存策略,以确定此更改是否会产生任何影响。 在参考我的 OP 时,我看不出这可以去哪里。我正在使用 FeedParser,它不接受 URLRequest 缓存策略设置 假设您目前正在使用来自此处的 FeedParser:cocoapods.org/pods/FeedParser,您可以尝试使用 github.com/nmdias/FeedKit,它似乎已经取代了 FeedParser。然后更改FeedKit库中的代码,以非缓存读取模式加载数据。将 Feedkit/Sources/Feedkit/Parser/FeedParser.swift 的第 78 行从 data = try Data(contentsOf: sanitizedSchemeUrl) 更改为 data = try Data(contentsOf: sanitizedSchemeUrl, options: [.uncached]) 我不确定这是否会如果默认情况下它已经未缓存,则有所不同。 但是不知道如何在 FeedParser 中设置。【参考方案3】:
 WidgetCenter.shared.reloadTimelines(ofKind: "Widgets")

如果您不在后台模式功能中检查后台获取,则不会工作

我花了一个星期才找到它!

【讨论】:

对不起,我没有完全按照你在这里说的话 @user717452 我认为他的意思是在设置>常规中打开后台应用刷新【参考方案4】:

https://developer.apple.com/forums/thread/653265?answerId=619739022#619739022

每分钟更新一次太激进了。小部件的更新数量有限,如果您尝试每分钟更新一次,您将很快用完更新。在使用 Xcode 进行调试时,不会施加这些限制,但如果您在 Xcode 之外运行应用程序,您会看到您所描述的小部件停止更新的行为。 如果您每 15 分钟更新一次会发生什么?如果这不起作用,请提交反馈助理报告,其中包含您正在执行的操作的详细信息以及您看到的结果。

【讨论】:

【参考方案5】:

iOS 正在处理时间线执行,它不会立即显示。我检查了你的代码,一切似乎都很好。我正在构建一个类似的应用程序,一切正常。我有几乎相同的代码。我有 API 命中测试,它似乎每 10-20 分钟刷新一次小部件。至少在我的情况下。

我会将其称为.atEnd 时间线政策。

每个配置的小部件每天都会收到有限次数的刷新。有几个因素会影响小部件的刷新次数 接收,例如包含的应用程序是否正在运行 前景或背景,小部件在屏幕上显示的频率, 以及包含的应用参与哪些类型的活动。

在 Xcode 中调试小部件时,WidgetKit 不会施加此限制。要验证您的小部件是否正常运行,请测试您的应用并 小部件在 Xcode 调试器之外的行为。Source

你试过调试它吗?你的结果是什么?

您能否尝试测试一些已命中测试的 API,以便检查 API 被命中的次数?

编辑:如果您想在添加新闻文章后立即更新您的小部件,那么您将需要实现强制刷新小部件的通知。

EDIT2:我发现有时我的小部件在初始刷新后不会刷新,并且在屏幕上删除和添加小部件解决了这个问题。我认为这是仅在开发/调试时才会出现的问题。

EDIT3:从getTimeline() 中删除WidgetCenter.shared.reloadAllTimelines()。构建项目并运行它。检查控制台日志,您应该在每个请求上打印一些内容。它应该会在接下来的几分钟内触发。

【讨论】:

我已经这样做了,正如你所注意到的,它工作正常,但随后停止刷新。我在收到推送通知时调用了 reloadAllWidgets,当从应用程序委托中调用了 didLaunch 时。这些都没有奏效 我已经尝试在时间线上添加 1 个条目,然后执行 .atEnd。我尝试做一个条目并将其作为 .after 执行并将其设置为 5 分钟。这些都不起作用。我试过这样做.never,并在应用程序收到通知时调用 reloadAllWidgets。那里也没有。我在时间线中创建了 4 个不同的条目,每 5 分钟创建 5 个条目,然后将其设置为 .atEnd,仍然没有。 调试时,将其设置为目标,然后将其构建到设备中,您是否看到任何日志?只需等待几分钟并检查它们。我今天做了这样的应用程序,每次解锁设备或超过 10-20 分钟标记时,它似乎都在刷新。我只做网络请求。这是一个非常简单的应用程序。在请求和 getTimeline 函数中放置一些打印行,以便您知道它正在刷新。正如我所说,我在开发时遇到了问题,但删除并添加回主屏幕修复了它。从那以后它工作得很好。 在过去的 16 个小时里,我一直将它作为 TestFlight 测试版运行,并且没有一次刷新小部件,这是来自全新安装。 嗯,如果您没有看到来自 getTimeline 的任何输出,则有问题。您甚至没有看到getTimeline 方法的初始调用吗?您是否更改了目标以构建唯一的小部件?您是否尝试过从主屏幕中删除小部件并再次构建项目?如果是这样,我认为您应该考虑制作另一个空的小部件扩展,尝试在示例 getTimeline 实现中打印一些内容,然后慢慢开始添加原始实现中的所有内容。在这种情况下,您将观察到是什么破坏了小部件。

以上是关于iOS 14 小部件不刷新的主要内容,如果未能解决你的问题,请参考以下文章

询问位置权限时,iOS 14 小部件不显示 NSLocationWhenInUseUsageDescription

iOS 14 小部件的模糊背景

iOS 14 小部件中的动画

iOS小部件不令人耳目一新

如何本地化 iOS 14 小部件的名称 (CFBundleDisplayName)

iOS 14 小部件没有动态更改