iOS14 widget 刷新

一、小组件推荐的刷新间隔是15分钟

调试的时候,想1分钟刷新一下 widget的状态,基本可以成功,但是上线后大概率不会按照设计的时机更新。下面是苹果员工的回答:
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.

------WidgetKit won't request a new timeline at the end

实践
  • 我在项目中使用的每隔 5分钟刷新 也是可以的
  • Text 可以设置 DateStyle 属性,比如设置为 .timer 就是类似计时器那样子的每一秒走一次。系统会根据相对时间估算来 timer 的时间
主动刷新
//刷新所有 widget
WidgetCenter.shared.reloadAllTimelines

//或者

//刷新某一个widget.  xxxx 是该widget的 identifier
WidgetCenter.shared.reloadTimelines(ofKind: "xxxx")

宿主App的数据有更新时,可以主动刷新 widget UI。具体怎么做呢?对于宿主App是 OC 写的项目,需要下面两步:

  1. 建立桥接文件
  • 一般在新建 swift 文件时 Xcode 会自动弹出是否建立 bridge 文件的弹框,选择创建。
  • 也可以自己新建一个 Header file 文件,然后指定 Targets-> Swift Compiler -> Object-C Bridging Header -> Header文件
  1. 建立swift文件
    WidgetCenterswift 的类,这里我们新建一个 swift 文件作为我们的刷新工具类, 里面代码如下:
// 导入 widget kit 库
import WidgetKit
//声明 14以上的系统才可用此 api
@available(iOS 14.0, *)
//定义 oc 方法
@objcMembers final class WidgetKitHelper : NSObject {
    class func reloadAllWidgets() {
       // arm64架构真机以及模拟器可以使用
        #if arch(arm64) || arch(i386) || arch(x86_64)
            WidgetCenter.shared.reloadAllTimelines()
        #endif
    }
}

刷新时,直接调用

[WidgetKitHelper reloadAllWidgets]

数据共享

我们刷新 widget 是因为有数据更新了所以要刷新 UI。那 widget 如何取出宿主App 的数据进行刷新呢?也需要两步:

  1. 建立 App Group
    参考 sharing userdefaults between main app and widget
    App Group 定义一个唯一标识比如:group.com.yourcompany.xxx
    同时,开发者证书的 Capabilities 这一项也要把 App Group 勾选上

  2. widget 中取出数据

UserDefaults(suiteName: "group.com.yourcompany.xxx").object(forKey: "xxxxxx")

二、TimelineProvider

定时刷新小组件时,在 TimelineProvider 中提供一系列的数据以及刷新周期。比如例子中提到的 小龙参加战斗 1小时 掉血 25%,那么添加5个刷新日期和数据:

struct CharacterDetailProvider: TimelineProvider {
    func getTimeline(in context: Context, completion: @escaping (Timeline) -> Void) {
        var date = Date()
        var healthLevel = 0.25
        var entries: [CharacterDetailEntry] = []

        while healthLevel <= 1 {
            // Add the current health level for a given date.
            entries.append(CharacterDetailEntry(date: date, healthLevel: healthLevel))

            // Health recovers at 25 percent per hour, with a maximum of 100 percent.
            healthLevel = min(1, healthLevel + 0.25)

            // Move the date forward by 1 hour.
            date = Calendar.current.date(byAdding: .hour, value: 1, to: date)!
        }

        // Create the timeline and call the completion handler.
        let timeline = Timeline(entries: entries, policy: .atEnd)
        completion(timeline)
    }
}

具体的例子和 刷新策略 可以参考: https://developer.apple.comdocumentation/widgetkit/timelineprovider
https://developer.apple.com/documentation/widgetkit/keeping-a-widget-up-to-date

你可能感兴趣的:(iOS14 widget 刷新)