Widget timeline
Build a widget that shows a timeline of time entries.
Syntax:
TimelineProviderprotocol to define the timeline provider
Example
Demo.swift
ContentView.swift
App.swift
import WidgetKit
import SwiftUI
struct TimeEntry: TimelineEntry { let date: Date }
struct TimeProvider: TimelineProvider {
func placeholder(in context: Context) -> TimeEntry { .init(date: Date()) }
func getSnapshot(in context: Context, completion: @escaping (TimeEntry) -> Void) { completion(.init(date: Date())) }
func getTimeline(in context: Context, completion: @escaping (Timeline<TimeEntry>) -> Void) {
let entries = stride(from: 0, through: 60*30, by: 60).map { offset in
TimeEntry(date: Date().addingTimeInterval(Double(offset)))
}
completion(Timeline(entries: entries, policy: .atEnd))
}
}
struct TimeWidgetView: View {
var entry: TimeEntry
var body: some View { Text(entry.date, style: .time).font(.headline) }
}
@main
struct TimeWidget: Widget {
var body: some WidgetConfiguration {
StaticConfiguration(kind: "TimeWidget", provider: TimeProvider()) { e in TimeWidgetView(entry: e) }
}
}
The example above shows a simple widget timeline with a placeholder, snapshot, and timeline provider.
Share extension skeleton
Build a share extension that allows users to share content with your app.
Syntax:
ShareExtensionSkeletonstruct to define the share extension skeleton
Example
Demo.swift
ContentView.swift
App.swift
import SwiftUI
struct ShareExtensionSkeleton: View {
@State private var sharedText = ""
var body: some View {
VStack(spacing: 12) {
Text("Incoming content")
TextEditor(text: $sharedText).frame(minHeight: 120).border(.secondary)
HStack { Spacer(); Button("Post") { /* handle share */ } }
}
.padding()
}
}
The example above shows a simple share extension skeleton with a text editor and a post button.
App Groups (Sharing Data with Widget)
Enable App Groups for both the app and the widget extension, and use a shared suite to exchange small data.
Syntax: UserDefaults(suiteName: "group.id"), write with set(_:forKey:), read with integer(forKey:).
Checklist
- Add capability App Groups to App target and Widget target
- Create a group identifier, e.g.
group.com.example.notes
App (write count)
Widget (read count)
import Foundation
func updateSharedNotesCount(_ count: Int) {
let defaults = UserDefaults(suiteName: "group.com.example.notes")
defaults?.set(count, forKey: "notesCount")
}
This example shares a notes count via App Groups: the app writes the value and the widget reads it to display.
Widgets
Create a Widget Extension target in Xcode, then design timelines/views using WidgetKit and SwiftUI.
Syntax: implement TimelineProvider, define a Widget, and return a StaticConfiguration(kind:provider:content:).
Example
MyWidget.swift
import WidgetKit
import SwiftUI
struct Provider: TimelineProvider {
func placeholder(in context: Context) -> SimpleEntry { .init(date: Date()) }
func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) { completion(.init(date: Date())) }
func getTimeline(in context: Context, completion: @escaping (Timeline<SimpleEntry>) -> ()) {
completion(Timeline(entries: [.init(date: Date())], policy: .atEnd))
}
}
struct SimpleEntry: TimelineEntry { let date: Date }
struct MyWidgetEntryView: View {
var entry: SimpleEntry
var body: some View { Text(entry.date, style: .time) }
}
@main
struct MyWidget: Widget {
var body: some WidgetConfiguration {
StaticConfiguration(kind: "MyWidget", provider: Provider()) { entry in
MyWidgetEntryView(entry: entry)
}
}
}
}
The example above shows a simple widget with a timeline provider and a static configuration.
Deep Links from Widgets
Open your app to a specific screen when the widget is tapped by providing a URL.
Syntax: implement Link and onOpenURL.
Example
Widget link (View)
App (onOpenURL)
import SwiftUI
struct NotesCountView: View {
var body: some View {
Link(destination: URL(string: "myapp://notes")!) {
Text("Notes: \(entry.count)")
}
}
}
The example above shows a simple widget with a link to a specific screen and an app that handles the URL.
Refresh & Timeline Policy
Choose a refresh strategy and trigger reloads when data changes.
Syntax: implement TimelineProvider and WidgetCenter.
Example
Timeline policy
Trigger reload from App
import WidgetKit
// Update at a future date
completion(Timeline(entries: entries, policy: .after(Date().addingTimeInterval(1800))))
// Or end when entries are exhausted
// completion(Timeline(entries: entries, policy: .atEnd))
The example above shows a simple widget with a timeline provider and a static configuration.
Supported Families
Advertise which sizes your widget supports.
Syntax: implement WidgetConfiguration and supportedFamilies.
Example
Families.swift
import WidgetKit
@main
struct NotesCountWidget: Widget {
var body: some WidgetConfiguration {
StaticConfiguration(kind: "NotesCount", provider: NotesProvider()) { entry in
NotesCountView(entry: entry)
}
.supportedFamilies([.systemSmall, .systemMedium])
}
}
The example above shows a simple widget with a timeline provider and a static configuration.
Leave a Reply