WidgetKit

RSS for tag

Show relevant, glanceable content from your app on iOS and iPadOS Home Screen and Lock Screen, macOS Desktop, Apple Watch Smart Stack and Complications, and in StandBy mode on iPhone.

Posts under WidgetKit tag

200 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

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
1.6k
3w
Reloading data and rescheduling local notifications, based on AppIntent interaction in iOS 17 Widgets and Live Activities
Hi everyone, I have two questions regarding some issues with the new iOS 17 interactive widgets and live activities. Question 1: How can I update other Widgets and/or Live Activities, based on an AppIntent interaction in either one? I have several widgets that is displaying the same information, but in different sizes (Small, Medium, Large and Lockscreen). Most of our users are using many of them together on their Lockscreen and Home Screen. When they are interacting with the AppIntent button in either the Widget og LiveActivity it does not update and vice-versa. Based on the documentation it's pretty clear that interacting with a Widget it will update the timeline for that specific widget after the .perform() in the AppIntent is returned. Unfortunately, I also need to update the LiveActivity and the other TimeLines for the rest of the widgets. I have tried to use the WidgetCenter.shared.reloadAllTimelines() but it seems like it does not update the LiveActivity or the LockScreen widgets correctly. Question 2: How can I update and reschedule the local notifications based on the interaction in the Widget and Live Activity? The app sends a local notification whenever an activity starts or stops (e.g like a pomodoro timer with intervals). Let's assume the user have setup a 30 minute activity in the app, but now decides to pause the activity from either the widget or live activity. I then want to remove the scheduled local notification that was supposed to be fired in 30 minutes. I haven't been able to read from the documentation if this is possible, but would like to know if there is any way this can be performed. Looking forward to hear if anyone have encountered the same challenges :)
1
0
641
Nov ’23
WatchOS IntentTimelineProvider recommendations
Hi! I have an Apple Watch app that provide widgets (circular, corners and InLine) to my users. I use the IntentTimelineProvider.recommendations method to provide the preconfigured widgets but only 16 first seems to be displayed. Is there an implicit limit of 16 items or I am doing something wrong? https://developer.apple.com/documentation/widgetkit/intenttimelineprovider/recommendations()-5ltr5
0
0
313
Sep ’23
CLLocationManager: getting kCLErrorDenied in widget
I am having some problem with accessing the CLLLocationManager location from my widget. It works fine with Xcode 15 running on a iOS17 simulator. But running it on a iOS17 device gives me an error in the delegate: To access the location manager, I have this class: class WidgetLocationManager: NSObject, CLLocationManagerDelegate { var locationManager: CLLocationManager? private var handler: ((CLLocation?) -> Void)? override init() { super.init() DispatchQueue.main.async { print("WidgetLocationManager: init") self.locationManager = CLLocationManager() if self.locationManager!.authorizationStatus == .notDetermined { print("WidgetLocationManager: init - auth status is Undetermined") } else { print("WidgetLocationManager: init - auth status = \(self.locationManager!.authorizationStatus)") } } } func fetchLocation(handler: @escaping (CLLocation?) -> Void) { self.handler = handler self.locationManager = CLLocationManager() self.locationManager!.delegate = self self.locationManager!.requestLocation() } func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { if let lastLocation = locations.last { if (CLLocationCoordinate2DIsValid(lastLocation.coordinate) == true && abs(lastLocation.timestamp.timeIntervalSinceNow) < 60 && lastLocation.horizontalAccuracy < 200.0 && lastLocation.horizontalAccuracy > 0.0) { self.handler!(locations.last!) } } } func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { print("WidgetLocationManager: locationManager didFailWithError = \(error)") self.handler!(nil) } } When run on device, I get an error: WidgetLocationManager: locationManager didFailWithError = Error Domain=kCLErrorDomain Code=1 "(null)" Code = 1 in CLError is kCLErrorDenied ("Access to location or ranging has been denied by the user") This is despite getting the following output in the init method: WidgetLocationManager: init - auth status = CLAuthorizationStatus(rawValue: 4) The weird thing is that it works fine in the simulator. On device, I've tried deleting and reinstalling the app a couple of times, restarting the device, making sure the privacy setting is correct etc. Also, on the iOS17 device, when I am in the "Add Widget" page, the location manager runs fine in the preview screen, and shows the 'current location' to the user. But as soon as I add the widget to the home screen, it starts giving me this problem where the location can't be found, and I have to display an error message in the widget. I have the following keys in the Info.plist for the widget: NSLocationAlwaysAndWhenInUseUsageDescription NSLocationWhenInUseUsageDescription NSWidgetWantsLocation The app target also has the following keys in the Info.plist: NSLocationWhenInUseUsageDescription NSLocationAlwaysAndWhenInUseUsageDescription Any idea for what I can try to fix this problem? Thanks.
2
0
940
Sep ’23
Privacy sensitive label is not redacted when watchOS 10 is locked
I am not sure if is it watchOS 10 regression, but running my widget on Apple Watch I can see Label which is supposed to be rendered redacted when Apple Watch is not on my wrist. I use the .privacySensitive() modifier by it seems not to do anything. I can use the isLuminanceReduced environment in combination with .redacted(reason: .placeholder) which works when the wrist is not raised. But there's no environment AFAIK to know when the watch is locked. BTW .redacted(reason: .privacy) don't do anything either, I have to use .placeholder. Is anyone else having issues with privacy on Apple Watch when using the .accessoryRectangular widget family? Talking about regular widget, not the Smart Stack.
2
1
512
Nov ’23
ios17 widget display area problem
I am having trouble displaying widgets on iOS17. In iOS16, it can be displayed in the full size of the widget, but in iOS17, it is displayed in an area 16 dots smaller in all direction than the original size. I would like to have the same display on iOS17 as on iOS16, is there a better way? struct widgetSmall : View { var body: some View { ZStack() { Rectangle() .foregroundColor(Color.yellow) VStack() { HStack() { Text("Upper-left") Spacer() } Spacer() HStack() { Spacer() Text("Lower-right") } } } } }
1
0
679
Sep ’23
original widget white screen after app upgrade via TestFlight
I've been working on an app that has lock screen and home screen widgets supports. Now we are rewriting the whole app -- and in a brand new workspace -- but only porting the existing widget to the new workspace with minimum tweaking. We've made sure all the app bundle ID & app group ID are matching between the old and new, for the app, widget and intents (can't use app intents as that's still beta for our 16.0 requirement). Now we are start testing in TestFlight builds we are seeing the home screen widgets that was installed in the original app turns blank/white when the new app is installed. It still handle tapping to the app but nothing visual; configuration pane is "unable to load". When my coworker installed the production app back onto the device the data in User Defaults is loaded, so we know data is not lost. There's almost nothing online talking about widget upgrades but one article, that basically says it cannot be done -- and suggested a workaround to deprecate the production widget. :/ Anyone has experience on major app upgrade affecting widget upgrade? if yes did you have a solution to handle it that you can share? Thanks!
0
0
471
Sep ’23
Trouble with new XCode 15 Preview Macro for Widgets
I'm trying to get rid of the auto-padding added recently by iOS 17, and I found out that you can use the WidgetConfigurations properly with the new Preview Macro, but I'm having trouble getting it to work, and some help would be much appreciated. Here's my code: struct ChartEntry: TimelineEntry { let date: Date let configuration: ConfigurationIntent ... static func getSampleEntry() -> ChartEntry { let sample = ChartEntry(date: Date(), configuration: WidgetUtils.getSampleConfiguration()) return sample } } struct PreviewTimelineProvider: TimelineProvider { typealias Entry = ChartEntry func placeholder(in context: Context) -> ChartEntry { ChartEntry.getSampleEntry() } func getSnapshot(in context: Context, completion: @escaping (ChartEntry) -> Void) { completion(ChartEntry.getSampleEntry()) } func getTimeline(in context: Context, completion: @escaping (Timeline<ChartEntry>) -> Void) { var entries: [ChartEntry] = [] let currentDate = Date() for hourOffset in 0 ..< 5 { let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)! let entry = ChartEntry(date: entryDate, configuration: WidgetUtils.getSampleConfiguration()) entries.append(entry) } let timeline = Timeline(entries: entries, policy: .atEnd) completion(timeline) } } struct DailyHoursOfSunshine: Identifiable { let id = UUID() var date: Date var hoursOfSunshine: Double init(date: Date, hoursOfSunshine: Double) { self.date = date self.hoursOfSunshine = hoursOfSunshine } } var data = [ DailyHoursOfSunshine(date: Date(), hoursOfSunshine: 0), // Sunday DailyHoursOfSunshine(date: Date().addingTimeInterval(86400), hoursOfSunshine: 60), // Monday DailyHoursOfSunshine(date: Date().addingTimeInterval(2 * 86400), hoursOfSunshine: 50), // Tuesday DailyHoursOfSunshine(date: Date().addingTimeInterval(3 * 86400), hoursOfSunshine: 72), // Wednesday DailyHoursOfSunshine(date: Date().addingTimeInterval(4 * 86400), hoursOfSunshine: 88), // Thursday DailyHoursOfSunshine(date: Date().addingTimeInterval(5 * 86400), hoursOfSunshine: 70), // Friday DailyHoursOfSunshine(date: Date().addingTimeInterval(6 * 86400), hoursOfSunshine: 120) // Saturday ] struct ChartSmallView: View { var entry: ChartEntry var body: some View { VStack { Spacer() VStack(alignment: .leading, spacing: 0) { Chart(data) { AreaMark( x: .value("Week", $0.date), y: .value("Hours of Sunshine", $0.hoursOfSunshine) ) .alignsMarkStylesWithPlotArea() } .foregroundStyle( .linearGradient ( colors: [.blue, .clear], startPoint: .top, endPoint: .bottom ) ) .chartXAxis(.hidden) .chartYAxis(.hidden) .chartLegend(.hidden) .padding([.horizontal], 3) } Spacer() } .frame(maxWidth: .infinity) } } #Preview("Small", as: .systemSmall) { ChartWidget() } timelineProvider: { PreviewTimelineProvider() } NOTE: There's nothing much on my ChartWidget struct, just the configuration to disable the margins and declare the preferred size and calling the ChartSmallView struct, I just didn't copy it here because it is in another file and I'm a little busy to go out excluding sensible information. I would actually prefer to call just ChartSmallView on my preview, but then I wouldn't have access to the configuration that disables the awful contextualized margins. The code compiles just fine, but when the preview tries to build it, the following error happens: == PREVIEW UPDATE ERROR: CompileDylibError: Failed to build ChartSmallView.swift Compiling failed: cannot convert value of type 'PreviewTimelineProvider' to closure result type 'any View' @__swiftmacro_63MyWidgetExtension_PreviewReplacement_ChartSmallView_133_77BD2C8074131F1FDF53BC08606762A7Ll0F0fMf_.swift ------------------------------ @available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, xrOS 1.0, *) struct $s63MyWidgetExtension_PreviewReplacement_ChartSmallView_133_77BD2C8074131F1FDF53BC08606762A7Ll0F0fMf_15PreviewRegistryfMu_: DeveloperToolsSupport.PreviewRegistry { static let fileID: String = "MyWidgetExtension_PreviewReplacement_ChartSmallView_1/ChartSmallView.1.preview-thunk.swift" static let line: Int = 125 static let column: Int = 1 static func makePreview() throws -> DeveloperToolsSupport.Preview { DeveloperToolsSupport.Preview("Small", as: .systemSmall) { ChartWidget() } timelineProvider: { PreviewTimelineProvider() } } } ------------------------------ /.../MyWidgetExtension.build/Objects-normal/x86_64/ChartSmallView.1.preview-thunk.swift:137:13: error: cannot convert value of type 'PreviewTimelineProvider' to closure result type 'any View' PreviewTimelineProvider() ^~~~~~~~~~~~~~~~~~~~~~~~~ as! any View I have also attempted to use the Preview Macro in the following way: #Preview("Small", as: .systemSmall) { ChartWidget() } timeline: { ChartEntry.getSampleEntry() } But achieved the same result. If anyone has any idea of what I'm doing wrong, I would appreciate the help. I couldn't find much material online to help me here
2
0
1.4k
Sep ’23
Dynamic Island Height
I just want to know what is maximum height of dynamic island(expanded). When I just go through the documentation, it is showing 160pt. Here is url: https://developer.apple.com/design/human-interface-guidelines/live-activities#Specifications But as I observed, some of applications have more than 160pt height of dynamic island (expanded). If this is possible, how we can increase height of dynamic island. Even if we go through figma library, it is also showing more height https://www.figma.com/file/YVWH9fn64y36***6jYdks5/Dynamic-Island-iPhone-14-(Community)?node-id=0%3A1&mode=dev
0
0
967
Sep ’23
Interactive widgets in Standby without unlocking phone
I'm currently implementing interactive widgets for my app. The widget calls an intent that is also used by Shortcuts and this interaction seems to work with no issues. Now I'm looking to get that running in Standby and on the lockscreen with the phone locked. I figured static var authenticationPolicy: IntentAuthenticationPolicy = .alwaysAllowed would do the trick, but the phone still asks to be unlocked before running the intent. Is there any way to get this working? I've seen some examples for widgets that can be run with the phone locked, but they all seem to be audio intents that play some audio. Example of the intent code:
0
0
401
Sep ’23
IOS 17 UserDefaults doesnt work as intented sharing data beetween app and widgetkit
Hi, I have an app that contains widgetkit elements. I have appgroup and everything used work fine before ios 17 and xcode 15 I was using suitname pattern like group.MY_TEAM_ID.com.xxxx.xxxxx and there was no problem with it. now xcode 15 complains like Using kCFPreferencesAnyUser with a container is only allowed for System Containers, detaching from cfprefsd. when I change suitname group.com.xxxx.xxxxx or any other suitname. I see data saved to userdefaults but reading data from widget site returns nil all the time.
2
1
797
Sep ’23
When the default value is 0 in widget configuration, the integer stepper setting behavior makes no sense
I have created a widget that has two configurable options, one is a boolean, and it works well, and the other one is an integer that makes problems. This is my current parameter's configuration: Whenever I create this widget, “plus days” is not set to 0, but to -2. Or any value I put in the minimum field. If the default value is different from 0, everything works well. I also tried to use Field instead of Stepper, but then both minimum and maximum values are ignored, regardless of what values I put in there. I also noticed that setting a value in here to 0 removes tags from the XML, so I tried to keep them with value 0, but it also didn't do the trick. Is it a bug or desired behavior? And is there a workaround for this?
0
0
175
Sep ’23
iOS 17 App Intent Widget → How do i make a filler when their is no information in the intent data?
Hi! I'm working on a widget using the new app intent & widgetkit features. Until now everything works, but I can't figure out how to give for example a line of text or a dummy data when the intent data is empty. For example in the Widgetsmith app, you can put pictures on your homescreen using widgets. But from the moment that you delete the picture in the app, the widget changes to a text screen where they have placed information about changing the widget to another option. Can you help me? My code so far: // // TimersIntentWidget.swift // // Created by Mees Akveld on 25/09/2023. // import Foundation import AppIntents import WidgetKit import SwiftUI @available(iOS 17, *) struct PresetIntentWidget: AppIntentTimelineProvider { func timeline(for configuration: selectPresetIntent, in context: Context) async -> Timeline<PresetEntry> { let entry = PresetEntry(date: Date(), presetModel: configuration.preset) let timeline = Timeline(entries: [entry], policy: .never) return timeline } func snapshot(for configuration: selectPresetIntent, in context: Context) async -> PresetEntry { PresetEntry(date: Date(), presetModel: configuration.preset) } func placeholder(in context: Context) -> PresetEntry { PresetEntry(date: Date(), presetModel: WidgetPreset.allPresets[0]) } } @available(iOS 17, *) struct PresetEntry: TimelineEntry { let date: Date let presetModel: WidgetPreset } @available(iOS 17, *) struct PresetWidgetView: View { let entry: PresetEntry private func isColorTheme() -> Int { let defaults = UserDefaults(suiteName: "group.MeesAkveld.ShareDefaults") let colorTheme = defaults?.integer(forKey: "ColorTheme") ?? 1 if colorTheme == 0 { return 1 } else { return colorTheme } } var body: some View { GeometryReader { geometry in ZStack { Image("bannerT\(isColorTheme())_Small") .resizable() .aspectRatio(contentMode: .fill) .scaleEffect(1.11) HStack { Rectangle() .cornerRadius(20) .frame(width: geometry.size.width - 20, height: geometry.size.height - 20, alignment: .center) .foregroundStyle(customBlue2Func()) Spacer() } .padding(.leading, 10) HStack { VStack(alignment: .leading, spacing: 10) { Image(systemName: entry.presetModel.icon != "" ? entry.presetModel.icon : "timer") .font(.system(size: 30)) .multilineTextAlignment(.center) .frame(width: 18) .offset(x: 10) VStack(alignment: .leading){ Text(entry.presetModel.title != "" ? entry.presetModel.title : "") .bold() Text(timeToText(hours: entry.presetModel.hours, minutes: entry.presetModel.minutes, seconds: entry.presetModel.seconds)) } .lineLimit(entry.presetModel.id == "noPresets" ? 2 : 1) } .foregroundColor(customBlueFunc()) Spacer() } .padding(25) } .widgetURL(URL(string:"preset:///\(entry.presetModel.id)")) } } } @available(iOS 17, *) struct PresetWidgetConfiguration: Widget { var body: some WidgetConfiguration { AppIntentConfiguration( kind: "presetWidgetIntent", intent: selectPresetIntent.self, provider: PresetIntentWidget() ) { entry in PresetWidgetView(entry: entry) } .configurationDisplayName("Presets") .description("View and activate a preset of your choosing from your homescreen.") .contentMarginsDisabled() .supportedFamilies([.systemSmall]) } } @available(iOS 17, *) struct PresetIntentWidget_Previews: PreviewProvider { static var previews: some View { PresetWidgetView(entry: PresetEntry(date: Date(), presetModel: WidgetPreset(id: "", title: "Title", icon: "", hours: 1, minutes: 1, seconds: 1, showEditView: false))) } } @available(iOS 17, *) struct WidgetPreset: AppEntity, Decodable { var id: String var title: String var icon: String var hours: Int var minutes: Int var seconds: Int var showEditView: Bool static var typeDisplayRepresentation: TypeDisplayRepresentation = "Preset" static var defaultQuery = WidgetPresetQuery() var displayRepresentation: DisplayRepresentation { DisplayRepresentation(title: "\(title)", subtitle: "\(timeToText(hours: hours, minutes: minutes, seconds: seconds))") } static var allPresets: [WidgetPreset]{ get { let defaults = UserDefaults(suiteName: "group.MeesAkveld.ShareDefaults") let presetsData = defaults!.data(forKey: "presets") if let data = presetsData, let loadedPresets = try? JSONDecoder().decode([WidgetPreset].self, from: data) { return loadedPresets } else { return [] } } } } @available(iOS 17, *) struct WidgetPresetQuery: EntityQuery { func entities(for identifiers: [WidgetPreset.ID]) async throws -> [WidgetPreset] { WidgetPreset.allPresets.filter { identifiers.contains($0.id) } } func suggestedEntities() async throws -> [WidgetPreset] { WidgetPreset.allPresets } func defaultResult() async -> WidgetPreset? { WidgetPreset.allPresets.first } } @available(iOS 17, *) struct selectPresetIntent: WidgetConfigurationIntent { static var title: LocalizedStringResource = "Preset" static var description: IntentDescription = IntentDescription("Select a preset") @Parameter(title: "Selected preset:") var preset: WidgetPreset }
0
1
861
Sep ’23
iOS17: Widget support for SwiftUI and MapKit
Hi there, we're in the process of refactoring some portions of our widgets to add some new capabilities like interactivity. In the mean time, we're wondering if there is any support for native MapKit within Widget on iOS17. We tried a simple test, but seems that MapKit is still not available on Widgets. Is this correct? Am I missing something? Many thanks for your answer!
1
0
652
Oct ’23