import WidgetKit
import SwiftUI
struct SimpleEntry: TimelineEntry {
let date: Date
let count: Int
let message: String
}
struct Provider: TimelineProvider {
func placeholder(in context: Context) -> SimpleEntry {
SimpleEntry(date: Date(), count: 0, message: "Placeholder")
}
func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> Void) {
let entry = SimpleEntry(date: Date(), count: 42, message: "Snapshot")
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<SimpleEntry>) -> Void) {
var entries: [SimpleEntry] = []
let currentDate = Date()
// Generate timeline entries for next 5 hours
for hourOffset in 0..<5 {
let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
let entry = SimpleEntry(
date: entryDate,
count: hourOffset * 10,
message: "Update \(hourOffset)"
)
entries.append(entry)
}
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
}
}
struct SimpleWidgetEntryView: View {
var entry: Provider.Entry
@Environment(\.widgetFamily) var family
var body: some View {
switch family {
case .systemSmall:
SmallWidgetView(entry: entry)
case .systemMedium:
MediumWidgetView(entry: entry)
case .systemLarge:
LargeWidgetView(entry: entry)
default:
SmallWidgetView(entry: entry)
}
}
}
struct SmallWidgetView: View {
let entry: SimpleEntry
var body: some View {
VStack {
Text(entry.message)
.font(.headline)
Text("\(entry.count)")
.font(.largeTitle)
.fontWeight(.bold)
}
.padding()
}
}
struct MediumWidgetView: View {
let entry: SimpleEntry
var body: some View {
HStack {
VStack(alignment: .leading) {
Text(entry.message)
.font(.headline)
Text(entry.date, style: .time)
.font(.caption)
}
Spacer()
Text("\(entry.count)")
.font(.system(size: 40, weight: .bold))
}
.padding()
}
}
struct LargeWidgetView: View {
let entry: SimpleEntry
var body: some View {
VStack(alignment: .leading, spacing: 16) {
Text(entry.message)
.font(.title)
.fontWeight(.bold)
Text("Count: \(entry.count)")
.font(.title2)
Text(entry.date, style: .time)
.font(.caption)
.foregroundColor(.secondary)
Spacer()
}
.padding()
}
}
@main
struct SimpleWidget: Widget {
let kind: String = "SimpleWidget"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: Provider()) { entry in
SimpleWidgetEntryView(entry: entry)
}
.configurationDisplayName("My Widget")
.description("This displays useful information.")
.supportedFamilies([.systemSmall, .systemMedium, .systemLarge])
}
}
import Foundation
class SharedDataManager {
static let shared = SharedDataManager()
private let appGroupID = "group.com.myapp.shared"
private var userDefaults: UserDefaults? {
UserDefaults(suiteName: appGroupID)
}
func saveWidgetData(_ data: WidgetData) {
if let encoded = try? JSONEncoder().encode(data) {
userDefaults?.set(encoded, forKey: "widgetData")
}
}
func getWidgetData() -> WidgetData? {
guard let data = userDefaults?.data(forKey: "widgetData") else { return nil }
return try? JSONDecoder().decode(WidgetData.self, from: data)
}
func getSharedContainerURL() -> URL? {
FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupID)
}
}
struct WidgetData: Codable {
let count: Int
let message: String
let lastUpdated: Date
}
App extensions expand app functionality into other parts of iOS. Today widgets display glanceable information using WidgetKit with SwiftUI views and timeline providers. Share extensions let users share content to your app from other apps—I process shared items with NSExtensionContext and NSItemProvider. Widget timelines define when to update content with TimelineEntry and TimelineProvider. For widgets, I use @main with Widget protocol and provide configurations. App groups enable data sharing between the main app and extensions via shared containers. Notification content extensions customize notification UI. Action extensions process selected content. Each extension runs in its own process with memory constraints.