Widgets & App Extensions

Widget timeline

Build a widget that shows a timeline of time entries.

Syntax:

  • TimelineProvider protocol 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:

  • ShareExtensionSkeleton struct 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: &#91;.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(&#91;.systemSmall, .systemMedium])
} }

The example above shows a simple widget with a timeline provider and a static configuration.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *