Implementing Apple Watch Widget Complications

I am trying to add Widget Complications to an existing Apple Watch app. I added the WatchOS widgets extension and followed instructions to create static, non-updating complications to merely launch the app from the watch home screen.

Here is my code in the widget extension:

import WidgetKit
import SwiftUI

struct Provider: TimelineProvider {
    
    func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> Void) {
    }
    
    func getTimeline(in context: Context, completion: @escaping (Timeline<SimpleEntry>) -> Void) {
    }
    
    func placeholder(in context: Context) -> SimpleEntry {
        SimpleEntry(date: Date())
    }
    
    func snapshot(in context: Context) async -> SimpleEntry {
        SimpleEntry(date: Date())
    }
}

struct SimpleEntry: TimelineEntry {
    let date: Date
}

struct TrapScores_WidgetsEntryView : View {
    
    @Environment(\.widgetFamily) var widgetFamily
    var entry: Provider.Entry
    
    var body: some View {
        
        switch widgetFamily {
        case .accessoryCorner:
            ComplicationCorner()
        case .accessoryCircular:
            ComplicationCircular()
        case .accessoryRectangular:
            Text("TrapScores")
        case .accessoryInline:
            Text("TrapScores")
        @unknown default:
            //mandatory as there are more widget families as in lockscreen widgets etc
            Text("AppIcon")
        }
    }
}

@main
struct TrapScores_Widgets: Widget {
    let kind: String = "TrapScores_Complications"
    
    var body: some WidgetConfiguration {
        StaticConfiguration(kind: kind, provider: Provider()) { entry in
            TrapScores_WidgetsEntryView(entry: entry)
                .containerBackground(.fill.secondary, for: .widget)
        }
        .configurationDisplayName("TrapScores")
        .description("This will launch TrapScores App")
        .supportedFamilies([.accessoryCorner, .accessoryCircular])
    }
}
    
    struct ComplicationCircular: View {
        var body: some View {
            Image("Graphic Circular")
                .widgetAccentable(true)
                .unredacted()
        }
    }
    struct ComplicationCorner: View {
        var body: some View {
            Image("Graphic Circular")
                .widgetAccentable(true)
                .unredacted()
        }
    }
    
    #Preview(as: .accessoryCircular) {
        TrapScores_Widgets()
    } timeline: {
        SimpleEntry(date: .now)
    }

The complications appear fine in the preview:

The complication can be added to the watch face, but no graphic comes with it and it is a blank circle:

Any suggestions on what I'm doing wrong?

Post not yet marked as solved Up vote post of WilburDD Down vote post of WilburDD
507 views
  • Did you find a solution to this?

Add a Comment

Replies

Nope. :-(

Your problem is this code:

    func getTimeline(in context: Context, completion: @escaping (Timeline<SimpleEntry>) -> Void) {
    }

All widgets run off of a timeline. It essentially tells the OS what particular widget to show when. You provided no Timeline in return, so the OS thinks you do not want to show anything. Something as simple as this:

    func getTimeline(in context: Context, completion: @escaping (Timeline<SimpleEntry>) -> Void) {
            let timeline = Timeline(entries: entries, policy: .never)
            completion(timeline)
    }

should be enough to get you going. This is pretty basic stuff for widgets. I would recommend doing Apple's Widgets Code-along from WWDC 20.