Watch Complications

RSS for tag

Display timely and relevant information about your app on the Apple Watch face using Complications.

Posts under Watch Complications tag

30 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

AccessoryInline complication reports full color rendering mode, but displays in monochrome
I'm in process of reimplementing my app in SwiftUI and WidgetKit. So far so good, I really like that I can finally use SwiftUI views for widgets. However, I'm having issues with AccessoryInline widget on Utility watch face. My old UtilitarianLarge complication displays in full color, but AccessoryInline widget displays only in gray - it's not even widgetAccentable on Utility watch face. I receive widgetRenderingMode from the Environment, and it shows fullColor. However, no matter how I try to apply color to the image or text, both stay gray. This widget family is not documented well (as many of things in WatchOS), and Google/ChatGPT/Bing produced zero usable results. It looks like it's a bug in WIdgetKit. If it's supposed to be displayed in Accented mode only, it should report as such in widgetRenderingMode (and support WidgetAccentable). Otherwise it should display in full color, just like the old complication.
1
1
624
Jan ’24
transferCurrentComplicationUserInfo(_:) works like transferUserInfo(_:)
Hey there, I'm implementing Watch Complications in an existing project, and I'm having the problem that transferCurrentComplicationUserInfo(_:) works exactly as transferUserInfo(_:) is described in the documentation, but not as it should. That is, when the WatchApp is opened, func session(_ session: WCSession, didReceiveUserInfo userInfo: [String: Any] = [:]) receives the data sent by transferCurrentComplicationUserInfo(_:). If not, the data is queued until the Watch App is opened again. In other words, transferCurrentComplicationUserInfo(_:) never wakes up the ExtensionDelegate when the Watch App is not running. Has anyone experienced the same thing and know how to fix it? More details: Testing on iPhone 11 (iOS 17.1.2) and Apple Watch SE (WatchOS 10.2) I made sure that the quota of 50 is not exhausted when I test. The WatchApp is still dual-target (I want to avoid having to migrate to single-target and SwiftUI lifecycle) Watch App code: class ExtensionDelegate: NSObject, WKExtensionDelegate, WCSessionDelegate { let session = WCSession.default override init() { super.init() if WCSession.isSupported() { session.delegate = self session.activate() } } func session(_ session: WCSession, didReceiveUserInfo userInfo: [String: Any] = [:]) { WatchWidgetSessionHandler.shared.processComplicationUserInfo(userInfo) } } IOS App code: class WatchAppDataManager: NSObject, WCSessionDelegate { override init() { super.init() let session = WCSession.default session.delegate = self session.activate() } func sendDataToWidget(for kinds: [WatchWidgetKind]) async { guard WCSession.default.activationState == .activated, WCSession.default.isComplicationEnabled else { return } let widgetsData = dataProvider.getData(for: kinds) if !widgetsData.isEmpty { WCSession.default.transferCurrentComplicationUserInfo(widgetsData) } } }
2
0
908
Mar ’24
Apple watch series 9 (OS 10.3) not showing up in xcode 15.1 under devices list.
When connecting my iphone (14pro with iOS 17.2.1) with a paired apple watch (series 9 with OS 10.3), it is not showing up on the devices/simulators list in xcode 15.1. Beyond unpairing/repairing the watch, restarting either iphone or watch, connecting/disconnecting the iphone from the computer or deleting xcode and re-installing xcode, any other suggestions? Under the WatchApp field it shows "no eligible device connected", however, under the console the Apple Watch does appear. I have tried just about everything and can't get the watch to appear in Xcode. I am running all this on a MacBook Pro with Sonoma. Thanks for any assistance!
0
0
907
Dec ’23
WidgetKit works in Simulator but not on device
I can't get the simplest Widget to work. I simply want to present the app's icon. It does what it's supposed to do in the simulator but on the actual device it only says "Please adopt containerBackground API" at the place where the Widget would have shown otherwise. I found out that I am supposed to add .containerBackground(Color.clear, for: .widget) for no reason at all to make this work. However, when I do that, I just get a gray circle where the app icon was supposed to show. The png files should be fine because again on the simulator it works so I have no idea what I am doing wrong. If someone can tell me what I'm doing wrong or if someone can share their Widget class that would be awesome - I literally only want to show my app's icon on the Watch face but I already fail at that, no idea why they made WidgetKit impossible to work with. import SwiftUI import WidgetKit struct IconEntry: TimelineEntry { let date = Date() let icon: Image } struct IconProvider: TimelineProvider { func placeholder(in context: Context) -> IconEntry { return IconEntry(icon: getImageForContext(context, color: false)) } func getSnapshot(in context: Context, completion: @escaping (IconEntry) -> ()) { let entry = IconEntry(icon: getImageForContext(context, color: false)) completion(entry) } func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) { let entry = IconEntry(icon: getImageForContext(context, color: false)) let timeline = Timeline(entries: [entry], policy: .never) completion(timeline) } } struct IconWidget: Widget { let kind: String = "IconWidget" var body: some WidgetConfiguration { StaticConfiguration(kind: kind, provider: IconProvider()) { entry in IconView() .containerBackground(Color.clear, for: .widget) } .supportedFamilies([.accessoryCircular, .accessoryCorner, .accessoryRectangular]) .description(Text("Show the app's icon on a watch face.")) } } struct InlineWidget: Widget { var body: some WidgetConfiguration { StaticConfiguration(kind: "Inline", provider: IconProvider()) { entry in Text("App Title") .containerBackground(Color.clear, for: .widget) } .configurationDisplayName("App Title") .description("Description") .supportedFamilies([.accessoryInline]) } } func getImageForContext(_ context: TimelineProviderContext, color: Bool) -> Image { var fileNameToUse = "iconColor.png" if(!color) { fileNameToUse = "iconAlpha.png" } let displaySize = context.displaySize if(displaySize.width == 0 || displaySize.height == 0) { return Image(uiImage: .init()) } let uiImage = UIImage(imageLiteralResourceName: fileNameToUse).resizeImage(width: displaySize.width, height: displaySize.height) let image = Image(uiImage: uiImage) return image } struct IconView: View { @Environment(\.widgetRenderingMode) var widgetRenderingMode var body: some View { imageFor(widgetRenderingMode) .resizable() .onAppear { print("ICON VIEW \(widgetRenderingMode == .fullColor ? "COLOR" : "ALPHA")") } .containerBackground(Color.clear, for: .widget) } } private func imageFor(_ widgetRenderingMode: WidgetRenderingMode) -> Image { switch widgetRenderingMode { case .fullColor: return Image(uiImage: UIImage(imageLiteralResourceName: "iconColor.png")) default: return Image(uiImage: UIImage(imageLiteralResourceName: "iconAlpha.png")) } } @main struct IconBundle: WidgetBundle { @WidgetBundleBuilder var body: some Widget { IconWidget() InlineWidget() } } extension UIImage { func resizeImage(width: CGFloat, height: CGFloat) -> UIImage { let edgeLength = min(width, height) let newSize = CGSize(width: edgeLength, height: edgeLength) UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0) self.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)) if let resizedImage = UIGraphicsGetImageFromCurrentImageContext() { UIGraphicsEndImageContext() return resizedImage } else { return UIImage() } } }
2
0
1.1k
Dec ’23
How to support foregroundColor (deprecated) and foregroundStyle in watchOS 9/10?
In my Watch app on watchOS 9 I was using .foregroundColor(myColour) to colour the text in a widgetLabel on a corner complication like this: let myColour: Color = functionThatReturnsAColorObjectConstructedLike Color.init(...) // green .widgetLabel { Text(myText) .foregroundColor(myColour) } It worked fine; the widget label was green. Now, in watchOS 10, I see that foregroundColor() is being deprecated in favour of foregroundStyle(), and I can use .foregroundStyle(.green), and - importantly - foregroundStyle() is only available on watchOS 10 and newer. myColour is calculated depending on some other info, so I can't just write .green, and when I use .foregroundStyle(myColour) the widget label comes out as white every time, even if I set myColour = .green. I think I have to use some sort of extension to pick the right combination, something like: extension View { func foregroundType(colour: Colour, style: any ShapeStyle) -> some THING? { if #available(watchOS 10.0, *) { return foregroundStyle(style) } else { return foregroundColor(colour) } } } // Usage let myStyle: any ShapeStyle = SOMETHING? ... .widgetLabel { Text(myText) .foregroundType(colour: myColour, style: myStyle) It doesn't work. I just can't figure out what should be returned, nor how to return it. Any ideas?
2
2
2.4k
Jun ’24
WidgetKit complications won't update
We are migrating ClockKit complications to WidgetKit in our watch app (watchOS 9+). The migration went smoothly, UI part works just fine. However, we've hit the wall with widgets not updating when requested by the watch app. I believe we are missing something very simple and fundamental, but couldn't find what exactly so far. Advice and tips would be very welcome! 🙇‍♂️ Our implementation details: Whenever data is changed in the main app, the updated data is submitted to the watch app via WatchConnectivity framework using WCSession.default.transferCurrentComplicationUserInfo(_:). According to documentation, this method should be used to transfer complication-related data, since it will wake the watch app even if it is in the background or not opened at all. Watch app receives updated data and stores it in UserDefaults shared with Watch Widget Extension hosting WidgetKit complications via App Group. Watch app then request widget timeline reload via WidgetCenter.shared.reloadAllTimelines(). According to documentation, it reloads the timelines for all configured widgets belonging to the containing app, so it seems the appropriate way to reload WidgetKit complications. Widget Timeline Provider class in Watch Widget Extension reads updated data from shared UserDefaults and uses it to provide the updated snapshot for widget views to render. We believe our implementation logic is correct, but it doesn't work, for some reason. Widgets sometimes update when the watch app is opened, but not always. The most definitive way to force widgets to update is to switch to a different watch face, which confirms that the Widget Timeline Provider has access to properly updated data. P.S. We are aware of the daily reload budget imposed on widgets, so we use widgets reload trigger sparingly. Anyway, according to documentation, reload budget is not effective when in DEBUG mode, but widgets won't reload even in DEBUG mode. Thank you!
18
9
5.4k
Jul ’24
Migrating to WidgetKit, issues with editing Watch Faces on iPhone
Anyone who has successfully migrated to using WidgetKit for their Apple Watch complications, your help would be greatly appreciated! I've migrated to WidgetKit for my Watch app. On the Apple Watch Face Editor, the new Widget names and options appear correctly. However, on the iPhone Apple Watch app, it offers both WidgetKit and old ClockKit complications... this should not be. I also have found rendering issues where Watch Faces on the main My Watch tab have blank gaps for WidgetKit complications, when selecting the Watch Face they then render (see photos) I've put in a feedback FB12460375 Have tried a full clear and reinstall of my app on both devices, no change. This issue occurs on WatchOS 9.5.2 / iOS 16.5.1 and WatchOS 10 Beta 2 / iOS 17 Beta 2 Any other ideas?
7
0
1.7k
Sep ’24
ClockKit Complications not working with Xcode 14 single-target watchOS app
I’ve created a single-target watchOS app in Xcode 14, but I can’t seem to get ClockKit complications working. I’ve added a CLKComplicationDataSource class to my watch target, and in the Info pane for my target I have set the CLKComplicationPrincipalClass key to MODULE-NAME.ComplicationController I haven’t yet added Complication placeholder images to my Assets.xcassets, but as far as I am aware, that shouldn’t be a problem while I am still testing. However, when I run it on a watchOS simulator, the complications never show up on the watch complications list when adding a complication. All of the tutorials I can find for ClockKit complications reference older two-target WatchKit apps. Do the newer single target apps no longer support ClockKit? If so, how can I make a two-target WatchKit app with Xcode 14? Unfortunately I cannot use WidgetKit for my complications because I need to support watchOS 7 at least, and WidgetKit only supports watchOS 9+ Thanks for your help
3
1
1.9k
Aug ’24
CLKComplicationWidgetMigrator not working
I'm trying to migrate from Complication with CLKComplication to WidgetKit. I have implemented the required methods in https://developer.apple.com/documentation/widgetkit/converting-a-clockkit-app, but the migration is not working. There is no evidence that the method for migration is also called. It was the same with Xcode 14.0.1 and Xcode 14.1RC. class ComplicationController: NSObject, CLKComplicationDataSource, CLKComplicationWidgetMigrator { ...     @available(watchOS 9.0, *)     var widgetMigrator: CLKComplicationWidgetMigrator {         return self     }     @available(watchOS 9.0, *)     func widgetConfiguration(from complicationDescriptor: CLKComplicationDescriptor) async -> CLKComplicationWidgetMigrationConfiguration? {         return CLKComplicationStaticWidgetMigrationConfiguration(kind: "MyWidget", extensionBundleIdentifier: "com.example.myapp.mywatchkitapp.mywidget")     } } What's wrong? Has anyone been able to migrate?
7
1
1.9k
Oct ’24
Partial fix for widgets & complications not showing correctly
I recently raised this post explaining how I couldn't seem to get watchOS 9 complications to work, and I've figured out a partial fix. The original post details the issues with complications - and some are still valid - but this fix applies to both my complications and Home Screen / Lock Screen widgets. I was following the various WWDC 2020/2022 videos and the Emoji Rangers sample code, adding bits here and there, and assuming they were completely valid. Sadly, this bit of code in the widget's dynamic intents IntentTimelineProvider getTimeline really just banjaxed everything: // Create entries for one day, 15 minutes apart let currentDate = Date() for minuteOffset in stride(from: 0, to: 60 * 60 * 24, by: 15) { let entryDate = Calendar.current.date(byAdding: .minute, value: minuteOffset, to: currentDate)! entries.append(EventEntry(date: entryDate, event: event)) } If I remove that, and generate a different timeline with specific dates and times (for example: now, in 10 mins, in 2 hours, in a day, etc.) the complications appear correctly, as do Home Screen and Lock Screen widgets. The outstanding issues with complications are: The previews all use the same data, but getSnapshot() is supposed to return the data specific to that event from the configuration, i.e. if let theId = configuration.event?.identifier. "Christmas" is correct, but "Gallery Opening" is using Christmas's data. Once I've selected the event I want to use in a complication the edit screen shows it as totally blank, not even a placeholder: I hope this little fix works for you guys. And, if you know how to fix the above issues, let me know. (iOS 16.1 beta 1, Xcode 14.1 beta 1)
1
1
2.3k
Apr ’24