IOS Widget(5):小组件刷新机制

邹齐智
2023-12-01

该图显示了WidgetKit请求时间线,提供程序生成时间线以及WidgetKit在2小时后请求新时间线的图

Timeline刷新机制代码实现(新增组件时,系统默认就实现了)

func getTimeline(for configuration: TimeTypeConfigurationIntent, in context: Context, completion: @escaping (Timeline) -> ()) {
var entries: [SimpleEntry] = []

// Generate a timeline consisting of five entries an hour apart, starting from the current date.
let currentDate = Date()
for hourOffset in 0 ..< 5 {
    // 下面这个代码表示,在当前日期上加上 hourOffset 个小时得到一个新的日期
    // .hour可以换成 .second .minute .day 等
    let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
    let entry = SimpleEntry(date: entryDate, configuration: configuration)
    entries.append(entry)
}

// 调用回调方法把生成好的时间线数据传递给系统
// policy 表示刷新策略
// .atEnd 表示,所有的时间线条目完成之后重新刷新一次,表现就是这个getTimeline方法被回调一次
// .after(date: Date) 表示,多久时间结束后再刷新一次
// .never表示时间轴走完就不刷了
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)

}
备注:
  网上大部分资料都写着Timeline时间轴相隔5分钟,即每次创建5分钟内的刷新条目,但是小组件预算每日40到70次刷新,假设按70次算,总时间70 * 5 = 350分钟,大约6个小时就把次数用完了。所以大部分情况5分钟的间隔确实可以满足了,但是难免还是有用户把这个限制次数用完了。保险起见,尽量把时间间隔扩大,如果内存消耗不大,可以把间隔控制在60分钟,时间轴上每个条目间隔1分钟。这样几乎不会把系统给小组件的预算刷新次数给用完。

正是因为IOS系统对小组件有刷新次数有限制和内存方面的限制(官网没有找到,但是看到网友们说是30M左右的限制,自己使用过程中也发现了占用内存过多导致进程被挂起,小组件就展示不出来了),所以没控制好刷新策略的话,可能经常会出现小组件界面展示不出来,或者过了一段时间之后,小组件直接不刷新了。

刷新策略建议
每次刷新时,时间轴准备好15-60分钟的刷新数据,最少是5分钟
时间轴每个刷新条目时间间隔尽可能大,时钟内组件间隔可以设置为1分钟
条目数量不宜过多,越少越好,时钟组件最多60左右
不要在5分钟内创建300个条目来做时钟按秒刷新,大概率会失败
时钟刷新策略(只有小时分钟,没有秒)
static func prepareEntriesEveryMinute(_ completion: @escaping (Timeline) -> ()) {
// 第一次刷新时间:延迟2秒刷
let firstDate = Provider.getFirstEntryDate()
// 第二次刷新时间:第一个整分钟时刷
let firstMinuteDate = Provider.getFirstMinuteEntryDate()

var entries: [WidgetEntry] = []
entries.append(WidgetEntry(date: firstDate))
entries.append(WidgetEntry(date: firstMinuteDate))

// 后面以第一个整点分钟开始,每次加一分钟刷
for minuteOffset in 1 ..< 60 {
    guard let entryDate = Calendar.current.date(byAdding: .minute, value: minuteOffset, to: firstMinuteDate) else {
        continue
    }
    entries.append(WidgetEntry(date: entryDate))
}
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)

}

static func getFirstEntryDate() -> Date {
let offsetSecond: TimeInterval = TimeInterval(2)
var currentDate = Date()
currentDate += offsetSecond
return currentDate
}

// 获取第一个分钟时间点所处的时间点
static func getFirstMinuteEntryDate() -> Date {
var currentDate = Date()
let passSecond = Calendar.current.component(.second, from: currentDate)
let offsetSecond: TimeInterval = TimeInterval(60 - passSecond)
currentDate += offsetSecond
return currentDate
}
主动请求重新刷新
如果在App中修改了小组件的数据,可以通过如下的方式主动触发WidgetKit刷新小组件。

// 指定刷新哪个组件
WidgetCenter.shared.reloadTimelines(ofKind: “com.mygame.character-detail”)
// 刷新全部组件
WidgetCenter.shared.reloadAllTimelines()
]USB Microphone https://www.soft-voice.com/
Wooden Speakers https://www.zeshuiplatform.com/
亚马逊测评 www.yisuping.cn
深圳网站建设www.sz886.com

 类似资料: