跳到主要内容

Widget Extension 开发

问题

如何开发 iOS Widget 桌面小组件?

答案

核心概念

  • TimelineProvider:提供时间线数据,告诉系统何时刷新
  • TimelineEntry:一个时间点的数据快照
  • View:SwiftUI 纯声明式 UI

基本实现

struct MyWidgetEntry: TimelineEntry {
let date: Date
let title: String
let value: String
}

struct MyWidgetProvider: TimelineProvider {
func placeholder(in context: Context) -> MyWidgetEntry {
MyWidgetEntry(date: .now, title: "Loading", value: "--")
}

func getSnapshot(in context: Context, completion: @escaping (MyWidgetEntry) -> Void) {
completion(MyWidgetEntry(date: .now, title: "步数", value: "8,234"))
}

func getTimeline(in context: Context, completion: @escaping (Timeline<MyWidgetEntry>) -> Void) {
// 每小时刷新一次
let entry = MyWidgetEntry(date: .now, title: "步数", value: "8,234")
let nextUpdate = Calendar.current.date(byAdding: .hour, value: 1, to: .now)!
let timeline = Timeline(entries: [entry], policy: .after(nextUpdate))
completion(timeline)
}
}

struct MyWidgetView: View {
let entry: MyWidgetEntry

var body: some View {
VStack {
Text(entry.title).font(.caption)
Text(entry.value).font(.title).bold()
}
}
}

注意事项

限制说明
无网络请求不能在 Widget 内发请求(用 Background Task / App Group 共享数据)
刷新频率系统控制,每天约 40-70 次
数据共享通过 App Group UserDefaults 或共享文件
交互iOS 17+ 支持 Button/Toggle(AppIntent

常见面试问题

Q1: Widget 和主 App 如何共享数据?

答案:通过 App Group。在 Capability 中添加 App Group,然后使用 UserDefaults(suiteName: "group.com.app") 或共享的 FileManager container 读写数据。主 App 写入数据后调用 WidgetCenter.shared.reloadAllTimelines() 通知 Widget 刷新。

相关链接