1. Widget Extension理论知识
1.1 widget是一个独立的target,需要一套完整的证书 描述文件等
1.2 widget与主程序的信息交互,一方面:AppGroups 一方面:可尝试通过服务端
1.3 widget支持的展示,iPhone负一屏,桌面,锁屏,三个地方进行添加。另:锁屏与其他两处有所不同。
1.4 widget支持系统,自iOS 14+起,到iOS 16+可在锁屏添加,再到iOS 17+可直接通过小组件进行交互而不跳转主程序
2. Widget Extension具体实现, 基于iOS 17+
2.1 创建一个基础的Widget Extension
2.1.1 xCode打开项目,File -> New -> target -> Widget Extension
2.1.2 弹出的窗口栏,不要勾选 include Configuration App Intent 与 include Live Activity
2.1.3 run your widget
3. Widget Extension代码结构
一个基础的widget组成部分:输出Widgetbundle,结构体Widget,时间线TimelineProvider, 数据TimelineEntry,视图View
3.1 输出Widgetbundle, 输出结构体Widget
3.2 结构体Widget, 整合TimelineProvider, TimelineEntry, View
3.3 时间线TimelineProvider,widget的刷新机制
3.4 数据TimelineEntry,存储信息的结构体
3.4 视图View,展示的UI
import SwiftUI
import WidgetKit
// 输出WidgetBundle
@main
struct TestWidgetBundle: WidgetBundle {
var body: some Widget {
//这里输出widget实体
TestWidget()
}
}
//结构体Widget
struct TestWidget: Widget {
let kind: String = "widget.com"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: Provider()) { entry in
//这里放widget视图
if #available(iOS 17.0, *) {
TestWidgetView(entry: entry)
.containerBackground(.fill.tertiary, for: .widget)
} else {
TestWidgetView(entry: entry)
.padding()
.background()
}
}
.configurationDisplayName("widget")
.description("This is an widget")
.supportedFamilies([.systemSmall,.systemMedium,.systemLarge,.accessoryInline,.accessoryCircular,.accessoryRectangular]) //支持的样式,后三种iOS 16+
}
}
//时间线TimelineProvider
struct Provider: TimelineProvider {
typealias Entry = SimpleEntry
//等待数据加载,占位视图
func placeholder(in context: Context) -> Entry {
Entry(date: Date())
}
//小组件库中,展示用的视图,可以理解为商品橱窗里面的展示品
func getSnapshot(in context: Context, completion: @escaping (Entry) -> Void) {
completion(Entry(date: Date()))
}
//加载成功,真正用于交互展示的视图
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> Void) {
let entry = Entry(date: Date())
let timeline = Timeline(entries: [entry], policy: .never)
completion(timeline)
}
}
//数据TimelineEntry
struct SimpleEntry: TimelineEntry {
let date: Date
//... 其余数据
}
//视图View
struct TestWidgetView : View {
var entry: Provider.Entry
var body: some View {
VStack {
HStack {
Text("widget:")
Text(entry.date, style: .time)
}
HStack {
Text("press me 1").padding(5).background(Color.teal)
Text("press me 2").padding(5).background(Color.teal)
Text("press me 3").padding(5).background(Color.teal)
}
.padding(.vertical, 20)
}
}
}
上面代码,直接复制进widget target看看小组件是否能跑起来