iOS 14 中设备之间的小部件行为不一致

Inconsistent Widget Behaviour Between Devices in iOS 14

我最近为我的应用程序启动了一个 iOS 14 小部件。在测试中,一切似乎都很好,但在发布时我的行为不一致。在某些设备上,小部件加载为黑色,在其他设备上,它仅加载占位符内容,而在某些设备上,它按预期工作。表现出的行为,无论好坏,在添加小部件屏幕中和添加到主屏幕时都是一致的。在我的小部件不起作用的设备上,其他小部件可以工作。

Widget 中的内容仅在应用程序中发生更改时才会更改,因此我在调用 sceneWillResignActive 时在 SceneDelegate 中调用 WidgetCenter.shared.reloadAllTimelines()。预期的行为是当用户将应用程序设置为后台时,小部件将更新。在显示黑色或占位符内容的设备上,此 Widget Center 更新不起作用,在它起作用的设备上,更新功能按预期工作。

这是我的小部件的代码:

struct ThisWeekProvider: TimelineProvider {
    func placeholder(in context: Context) -> ThisWeekEntry {
        return ThisWeekEntry(date: Date(), thisWeekJSON: getDefaultTimeSummaryJSON())
    }

    func getSnapshot(in context: Context, completion: @escaping (ThisWeekEntry) -> ()) {

        var thisWeekData = TimeSummaryJSON()
        if context.isPreview {
            thisWeekData = getThisWeekData()
        } else {
            thisWeekData = getThisWeekData()
        }

        let entry = ThisWeekEntry(date: Date(), thisWeekJSON: thisWeekData)
        completion(entry)
    }

    func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
        let entries: [ThisWeekEntry] = [ThisWeekEntry(date: Date(), thisWeekJSON: getThisWeekData())]

        let timeline = Timeline(entries: entries, policy: .after(entries[0].thisWeekJSON.endDate))
        completion(timeline)
    }
}

struct ThisWeekEntry: TimelineEntry {
    let date: Date
    let thisWeekJSON: TimeSummaryJSON
}

struct ThisWeekWidgetEntryView : View {
    var entry: ThisWeekProvider.Entry
    var body: some View {

        // Generate View
        // Use data from 'entry' to fill widget

}

struct ThisWeekWidget: Widget {
    let kind: String = K.thisWeekWidget

    var body: some WidgetConfiguration {
        StaticConfiguration(kind: kind, provider: ThisWeekProvider()) { entry in
            ThisWeekWidgetEntryView(entry: entry)
        }
        .configurationDisplayName("this_week_widget".localized())
        .description("this_week_description".localized())
        .supportedFamilies([.systemSmall])
    }
}

自定义数据类型'TimeSummaryJSON'如下:

struct TimeSummaryJSON: Codable {
    
    var labourIncome: String = "[=12=].00"
    var equipmentIncome: String = "[=12=].00"
    var days: String = "0"
    var hours: String = "0"
    
    var endDate: Date = Date()
    var settingsFirstDayOfWeek: String = K.monday
    var localeFirstDayOfWeek: Bool = false
    
}

获取数据'getThisWeekData()'的自定义函数如下:

private func getThisWeekData() -> TimeSummaryJSON {
    if let encodedData = UserDefaults(suiteName: AppGroup.shared.rawValue)!.object(forKey: K.thisWeek) as? Data {
        if let thisWeekJSON = try? JSONDecoder().decode(TimeSummaryJSON.self, from: encodedData) {
            return checkExpiryForCurrentWeek(thisWeekJSON)
        } else {
            print("Decoding Error - Return Default This Week")
            return getDefaultTimeSummaryJSON()
        }
    } else {
        print("No Shared Data - Return Default This Week")
        return getDefaultTimeSummaryJSON()
    }
}

保存和检索数据的过程是这样的:

  1. SceneDelegate 调用 sceneWillResignActive
  2. 数据从本地领域数据库中提取,计算并保存到 TimeSummaryJSON
  3. TimeSummaryJSON 已编码并保存到共享 AppGroup
  4. WidgetCenter.shared 呼叫 reloadAllTimelines()
  5. Widget 解码来自 AppGroup
  6. 的 JSON 数据
  7. 如果 JSON 解码成功,则当前用户数据显示在小部件中,如果 JSON 解码失败,则发送默认的 TimeSummaryJSON

我已经相当广泛地查看了我的代码并阅读了无数论坛,看来我做的一切都是正确的。我错过了什么吗?谁能建议为什么设备之间的行为不一致?我真的很好,真的卡住了,我不确定接下来要尝试什么。

如有任何帮助,我们将不胜感激。

谢谢!

感谢 reddit 上的一些帮助,我终于找到了问题的根源。问题是我使用的图像分辨率太大,大文件大小超出了小部件的 30MB 内存限制。

帮助我的 reddit 用户是这样说的:

'黑色或经过编辑的小部件表示在加载过程中您达到了 30 MB 的内存限制。 此外,如果您一次重新加载多个小部件,您似乎更有可能达到内存预算。'

'Forgot to mention that black/redacted widget can also happen if the widget crashes (not necessary due to memory budget). So maybe you have some threading problems or are force unwrapping something that is nil.'

这是 link 的完整讨论: https://www.reddit.com/r/iOSProgramming/comments/mmo5lf/inconsistent_widget_behaviour_between_devices_in/