I've created a Snippet for my iOS app which I want to be able to run from the LockScreen via a Shortcuts widget.
All works fine except when I run the shortcut and the App Snippet appears, it doesn't always render the SwiftUI view in the same way.
Sometimes the width boundaries are respected and sometimes not.
I've tested this on iOS 26.1 and iOS 26.2 beta 3
I think this is a bug but it would be great if anyone could see what I might be doing wrong if it's not.
Incase it is a bug I've filed a feedback (FB21076429) and I've created a stripped down sample project showing the issue and added screenshots showing the issue.
Basic code to reproduce issue:
// Intent.swift
// SnippetBug
import AppIntents
import Foundation
import SwiftUI
struct SnippetEntryIntent: AppIntent {
static let title: LocalizedStringResource = "Open Snippet"
static let description = IntentDescription("Shows a snippet.")
// Don’t open the app – stay in the snippet surface.
static let openAppWhenRun: Bool = false
func perform() async throws -> some ShowsSnippetIntent {
.result(snippetIntent: TestSnippetIntent())
}
}
struct TestSnippetIntent: SnippetIntent {
static let title: LocalizedStringResource = "Snippet Intent"
static let description = IntentDescription("Action from snippet.")
@MainActor
func perform() async throws -> some IntentResult & ShowsSnippetView {
.result(view: SnippetView(model: SnippetModel.shared))
}
}
@MainActor
final class SnippetModel {
static let shared = SnippetModel()
private init() {
}
}
struct SnippetView: View {
let model: SnippetModel
var body: some View {
HStack {
Text("Test Snippet with information")
Spacer()
Image(systemName: "heart")
}.font(.headline)
}
}
struct Shortcuts: AppShortcutsProvider {
static var appShortcuts: [AppShortcut] {
AppShortcut(
intent: SnippetEntryIntent(),
phrases: [
"Snippet for \(.applicationName)",
"Test Snippet \(.applicationName)"
],
shortTitle: "Snippet",
systemImageName: "barcode"
)
}
}
You also need these lines in your main App entry point:
import AppIntents
@main
struct SnippetBugApp: App {
init() {
let model = SnippetModel.shared
AppDependencyManager.shared.add(dependency: model)
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
This is correct
This is incorrect
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I'm having problems with my released app with iOS & WatchOS 26 support.
I've added AppIntentConfiguration support in the WatchOS app such that users can configure the complication. My complications also support multiple families and so I have slightly different configuration options available if its in the .accessoryRectangular slot or the .accessoryCircular one.
This works fine on Apple Watch when editing the Watch face. Here you can then select the configuration options fine and they are correct for the different variants.
However on iOS when configuring in the Apple Watch app on iPhone, the different complication size is ignored and the same configuration options are offered meaning they are wrong for one of them.
I created a sample project, here is the app intent code:
struct TestWidgetConfigurationIntent: AppIntent, WidgetConfigurationIntent {
static var title: LocalizedStringResource = "New Widgets with Configuration"
static var description = IntentDescription("Lots of stuff.")
static var isDiscoverable: Bool { return false}
init() {}
func perform() async throws -> some IntentResult {
return .result()
}
@Parameter(title: "Enable More Detail", default: true)
var moreDetail: Bool
@Parameter(title: "Enable Other Parameter", default: true)
var otherParameter: Bool
static var parameterSummary: some ParameterSummary {
When(widgetFamily: .equalTo, .accessoryRectangular) {
Summary("Test Info") {
\.$moreDetail
\.$otherParameter
}
} otherwise : {
Summary("Test Info") {
\.$moreDetail
}
}
}
}
In WatchOS you get the correct configuration options:
In iOS you do not, you get the same configuration option regardless of which family size you select:
This could be a bug so I've filed feedback FB20328319. Otherwise if anyone has insights, it would be very appreciated. This is all tested on the current iOS 26.0 and WatchOS 26.0 versions. Thanks!
Topic:
App & System Services
SubTopic:
Widgets & Live Activities
Tags:
WatchKit
watchOS
WidgetKit
App Intents
Are there any HealthKit related changes to be aware of in the new update that enables SPO2 / Blood Oxygen Saturation measurements on certain Apple Watch models within the US?
I’m aware of processing happening on the phone…. But beyond that:
Does this mean values are then saved to Apple Health?
Do these models still take background SPO2 measurements in the same way as other models do?
Are these values then visible in third party iOS apps as normal through HealthKit?
Do these values sync back to the paired Apple Watch HealthKit store for third party apps to access on the Watch?
For reference I have an iOS and WatchOS app that, amongst other features, provides the ability to see your SPO2 values in the Watch app, complications and in the iOS app.
Topic:
App & System Services
SubTopic:
Health & Fitness
Tags:
WatchKit
Health and Fitness
watchOS
HealthKit
New in iOS 26 and WatchOS 26 is a Sleep Score calculation for users based on Duration, Bedtime and Interruptions.
Unfortunately I can't find any APIs for developers to tap into this metric. Yes, in theory it's all created off the same Sleep Analysis data already available with HealthKit but that makes it very hard to recreate in our apps. If the numbers don't match up exactly, users will understandably complain.
Can anyone confirm that this is the case and I've not missed a Sleep Score API? I'll then file feedback.
Hopefully this doesn't go the way of Heart Rate Zones where the Apple Watch iPhone app has generated them for years and provided no way for third party apps to access these values (yes many feedbacks provided previously).
New features in WatchOS 26 with configurable widgets make it more important than ever that apps adopt IntentConfiguration options where applicable.
I develop an app with an Apple Watch complication/widget on many many user's Watch faces around the world. I've completed updating my code to support WidgetKit and remove ClockKit.
However, I face huge issues adding support for users to configure their widget/complications.
If I update a widget to go from StaticConfiguration to IntentConfiguration, even when keeping the "kind" string the same, the widget disappears from the Watch face.
This is an unacceptable user experience meaning I can't proceed with the migration. The problem is users will expect me to offer configuration in the Watch face soon for their widget/complication. Currently this process is done in a sub-optimal way in the app itself.
A similar issue exists on iOS where the widget will just "freeze" indefinitely is migrated.
This issue still occurs on the iOS 26 and WatchOS 26 betas.
So how to move this forward.
This has been discussed previously here: https://developer.apple.com/forums/thread/661247
I've mentioned it at WidgetKit labs
I've filed feedback last year: FB13880020
I've filed feedback this year: FB18180368
It seems really important this gets fixed for developers to adopt these new features, is there any other migration route I'm missing or a workaround that would mitigate this seemingly big problem.
I'm having a problem with Xcode 26 where a symbol bug is causing my app to crash at launch if they are running iOS 17.X
This has to do with a HealthKit API that was introduced in iOS 18.1 HKQuantityType(.appleSleepingBreathingDisturbances), I use availability clauses to ensure I only support it in that version. This all worked fine with Xcode 16.4 but breaks in Xcode 26.
This means ALL my users running iOS 17 will get at launch crashes if this isn't resolved in the Xcode GM seed.
I'll post the code here in case I'm doing anything wrong. This, the HealthKit capability, the "HealthKit Privacy - Health Share Usage Description" and "Privacy - Health Update Usage Description", and device/simulator on iOS 17.X are all you need to reproduce the issue.
I've made a feedback too as I'm 95% sure it's a bug: FB19727966
import SwiftUI
import HealthKit
struct ContentView: View {
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Hello, world!")
}
.padding()
.task {
print(await requestPermission())
}
}
}
#Preview {
ContentView()
}
func requestPermission() async -> Bool {
if #available(iOS 18.0, *) {
let healthTypes = [HKQuantityType(.appleSleepingBreathingDisturbances)]
var readTypes = healthTypes.map({$0})
let write: Set<HKSampleType> = []
let res: ()? = try? await HKHealthStore().requestAuthorization(toShare: write, read: Set(readTypes))
guard res != nil else {
print("requestPermission returned nil")
return false
}
return true
}
else { return false}
}
I'm trying to create two widgets, widget A and B.
Currently A and B are very similar so they share the same Intent and Intent Timeline Provider.
I use the Intent Configuration interface to set a parameter, in this example lets say its the background tint.
On one of the widgets, widget A, I want to also set another String enum parameter (for a timescale), but I don't want this option to be there for widget B as it's not relevant.
I'm aware of some of the options for configuring the ParameterSummary, but none that let me pass in or inject the "kind" string (or widget ID) of the widget that's being modified.
I'll try to provide some code for examples.
My Widget Definition (targeting >= iOS 17)
struct WidgetA: Widget {
// I'd like to access this parameter within the intent
let kind: String = "WidgetA"
var body: some WidgetConfiguration {
AppIntentConfiguration(kind: kind, intent: WidgetIntent.self, provider: IntentTimelineProvider()) { entry in
WidgetView(data: entry)
}
.configurationDisplayName("Widget A")
.description("A widget.")
.supportedFamilies([.systemMedium, .systemLarge])
}
}
struct WidgetB: Widget {
let kind: String = "WidgetB"
var body: some WidgetConfiguration {
AppIntentConfiguration(kind: kind, intent: WidgetIntent.self, provider: IntentTimelineProvider()) { entry in
WidgetView(data: entry)
}
.configurationDisplayName("Widget B")
.description("B widget.")
.supportedFamilies([.systemMedium, .systemLarge])
}
}
struct IntentTimelineProvider: AppIntentTimelineProvider {
typealias Entry = WidgetIntentTimelineEntry
typealias Intent = WidgetIntent
........
}
struct WidgetIntent: AppIntent, WidgetConfigurationIntent {
// This intent allows configuration of the widget background
// This intent also allows for the widget to display interactive buttons for changing the Trend Type
static var title: LocalizedStringResource = "Widget Configuration"
static var description = IntentDescription("Description.")
static var isDiscoverable: Bool { return false}
init() {}
init(trend:String) {
self.trend = trend
}
// Used for implementing interactive Widget
func perform() async throws -> some IntentResult {
print("WidgetIntent perform \(trend)")
#if os(iOS)
WidgetState.setState(type: trend)
#endif
return .result()
}
@Parameter(title: "Trend Type", default: "Trend")
var trend:String
// I only want to show this parameter for Widget A and not Widget B
@Parameter(title: "Trend Timescale", default: .week)
var timescale: TimescaleTypeAppEnum?
@Parameter(title: "Background Tint", default: BackgroundTintTypeAppEnum.none)
var backgroundTint: BackgroundTintTypeAppEnum?
static var parameterSummary: some ParameterSummary {
// Summary("Test Info") {
// \.$timescale
// \.$backgroundTint
// }
// An example of a configurable widget parameter summary, but not based of kind/ID string
When(\.$backgroundTint, .equalTo, BackgroundTintTypeAppEnum.none) {
Summary("Test Info") {
\.$timescale
\.$backgroundTint
}
} otherwise : {
Summary("Test Info") {
\.$backgroundTint
}
}
}
}
enum TimescaleTypeAppEnum: String, AppEnum {
case week
case fortnight
static var typeDisplayRepresentation = TypeDisplayRepresentation(name: "Trend Timescale")
static var caseDisplayRepresentations: [Self: DisplayRepresentation] = [
.week: "Past Week",
.fortnight: "Past Fortnight"
]
}
enum BackgroundTintTypeAppEnum: String, AppEnum {
case blue
case none
static var typeDisplayRepresentation = TypeDisplayRepresentation(name: "Background Tint")
static var caseDisplayRepresentations: [Self: DisplayRepresentation] = [
.none: "None (Default)",
.blue: "Blue"
]
}
I know I could achieve what I'm after by having a separate Intent and separate IntentTimelineProvider for each widget. But this all seems unnessecary for just a simple optional parameter based on what widget its configuring.... unless I'm missing the point about Intents, Widgets or something!
I've done a fair bit of other searching but can't find an answer to this overall scenario.
Many thanks for any help.
I'm looking to maximise my Watch app's widget to be as up to date as possible.
If we imagined the app was a simple step counter, and we wanted to display the users count as up to date as possible. We can conclude:
We don't care about widget timelines beyond the current entry as we can't predict the future!
We need to refresh the count as often as possible
The refresh should be very quick with a straightforward HealthKit query, no networking or heavy work needed.
We will assume the user has the complication/widget on their active Watch face.
With the standard WidgetKit APIs we can expire the timeline after 15 minutes and in my experimentation a Watch app can usually update its widget timeline at that frequency if it's on the Watch face.
I'm experimenting with two methods to try and improve refreshes further
A user's step count might not have recently changed when the timeline update is called. I was therefore looking into the HealthKit enableBackgroundDelivery API (which requires the HealthKit Background Delivery entitlement to be enabled) to get updates limited to once an hour from a HKObserverQuery, I can then call the WidgetCenter.shared.reloadAllTimelines() from there.
WatchOS also support the BGAppRefreshTaskRequest(identifier:"") and .backgroundTask(.appRefresh) APIs. I can request updates once every 15 minutes here too and then call the WidgetCenter.shared.reloadAllTimelines().
With option 1, this update opportunity is great as it will specifically update when there's new steps so even once an hour this would be helpful (A real shame to be limited to once an hour even if this used up WidgetKit standard reload budgets: FB13879817, FB11677132, FB10016177). But I can't determine if this update takes away one of the standard timeline expiration updates that already run 4 times an hour? Could I observe additional Health types to get additional updates? Do I need the Background Modes Capability as well as the HealthKit Background Delivery for this in Xcode or just the HealthKit one?
With option 2, I can't find a suitable option in the (short) list of supported background modes in Xcode. Does not selecting any mean my app will get 0 refreshes from this route and so should not be implemented in my use case?
Topic:
App & System Services
SubTopic:
Widgets & Live Activities
Tags:
WatchKit
HealthKit
WidgetKit
Background Tasks
In WatchOS 26 you can now configure Apple Watch Widgets that use AppIntents instead of having a preconfigured option via AppIntentRecommendation.
This is demonstrated in the Weather Details Widget. In that, the Intent has been set up such that the options have icons for each parameter.
How can I update my Intent code to offer this?
struct DataPointsWidgetIntent: AppIntent, WidgetConfigurationIntent {
static var title: LocalizedStringResource = "Data Points Widget Configuration"
static var description = IntentDescription("Configure the individual data point display for Widgets.")
static var isDiscoverable: Bool { return false}
init() {}
func perform() async throws -> some IntentResult {
print("DataPointsWidgetIntent perform")
return .result()
}
@Parameter(title: "Show Individual Data Points", default: true)
var showDataPoints: Bool?
@Parameter(title: "Trend Timescale", default: .week)
var timescale: TimescaleTypeAppEnum?
static var parameterSummary: some ParameterSummary {
Summary("Test Info") {
\.$showDataPoints
\.$timescale
}
}
}
enum TimescaleTypeAppEnum: String, AppEnum {
case week
case fortnight
static var typeDisplayRepresentation = TypeDisplayRepresentation(name: "Trend Timescale")
static var caseDisplayRepresentations: [Self: DisplayRepresentation] = [
.week: "Past Week",
.fortnight: "Past Fortnight"
]
}
Topic:
App & System Services
SubTopic:
Widgets & Live Activities
Tags:
WidgetKit
Intents
WeatherKit
App Intents
I have a Health & Fitness widget that runs on iPhone and Apple Watch. As Health data access requires the device to be unlocked, the iPhone widget is already slightly limited in capability because of updates.
With widgets further expanding to places like CarPlay, I know I can use the .disfavouredLocations{} API to try and prevent it being offered there. This is crucial as the widget functionality would be basically non-existent as your device is locked during CarPlay use.
My problem is, on the Mac despite using the .disfavouredLocations{.iPhoneWidgetsOnMac} etc...., the widget can still be added in the "other unsupported section". And yet, in that section the Apple Fitness app widget is no where to be seen. Is there an API I am missing to completely remove a widget from the Mac widget gallery and hopefully CarPlay, Standby etc.... (all places where the device running the widget is usually locked -> No Health data)?
Or does the Apple Fitness app have a private API to block it from these places where its function is not wanted and this isn't available to other apps?
I'm trying to make a Swift Chart where 24 AreaMarks an hour apart on X axis over a day display a vertical gradient.
The gradient is vertical and is essentially [Color.opacity(0.1),Colour,Color.opacity(0.1]
The idea here is where the upper and lower points of each AreaMark are the same or close to each other in the Y axis, the chart essentially displays a line, where they are far apart you get a nice fading vertical gradient.
However, it seems that the .alignsMarkStylesWithPlotArea modifier is always set for AreaMarks even if manually applying it false.
Investigating further, I've learnt that with AreaMarks in a series, Swift Charts seems to only listen to the first foreground style set in. I've created some sample code to demonstrate this.
struct DemoChartView: View {
var body: some View {
Chart {
AreaMark(x: .value("Time", Date().addingTimeInterval(0)), yStart: .value("1", 40), yEnd: .value("2", 60))
.foregroundStyle(LinearGradient(colors: [.pink, .teal], startPoint: .top, endPoint: .bottom))
.alignsMarkStylesWithPlotArea(false)
AreaMark(x: .value("Time", Date().addingTimeInterval(3600)), yStart: .value("1", 44), yEnd: .value("2", 58))
.foregroundStyle(LinearGradient(colors: [.orange, .yellow], startPoint: .top, endPoint: .bottom))
.alignsMarkStylesWithPlotArea(false)
AreaMark(x: .value("Time", Date().addingTimeInterval(03600*2)), yStart: .value("1", 50), yEnd: .value("2", 90))
.foregroundStyle(LinearGradient(colors: [.green, .blue], startPoint: .top, endPoint: .bottom))
.alignsMarkStylesWithPlotArea(false)
}
}
}
Which produces this:
So here, all the different .foregroundStyle LinearGradients are being ignored AND the .alignsMarkStylesWithPlotArea(false) is also ignored - the amount of pink on the first mark is different to the second and third 🤷♂️
Has anyone encountered this. Are AreaMarks the correct choice or are they just not setup to create this type of data display. Thanks
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?
I ran into a problem recently with my production app and an update for iOS 18. In this example I was using a new API added to the RC candidate of iOS 18.0, using this API as an example, I couldn't find a satisfactory way to avoid crashing on iOS 18.1 where the API was not available. I had plenty of users running the iOS 18.1 Beta and ultimately it's my fault if a version of my app did work, and then didn't after an update....
This code causes a crash on iOS 18.1 beta as the .appleSleepingBreathingDisturbances API doesn't seem to have made it's way into the beta:
if #available(iOS 18.0, *), #available(watchOS 11, *) {
healthKitTypesToRead.insert(HKQuantityType.quantityType(forIdentifier: .appleSleepingBreathingDisturbances)!)
}
I tried this but it still crashed on 18.1:
if #available(iOS 18.0, *), #available(watchOS 11, *) {
if let newQuantity = HKQuantityType.quantityType(forIdentifier: .appleSleepingBreathingDisturbances) {
healthKitTypesToRead.insert(newQuantity)
}
}
In the end the only way I could resolve this was the following:
if #available(iOS 18.1, *){
// Do nothing
}
else if #available(iOS 18.0, *), #available(watchOS 11, *) {
if let newQuantity = HKQuantityType.quantityType(forIdentifier: .appleSleepingBreathingDisturbances) {
healthKitTypesToRead.insert(newQuantity)
}
}
This seems like a poor solution and I'll have to ensure I release a new version of the app once iOS 18.1 has the available API added to enable support for the feature.
How could I have checked availability for this API correctly without causing the app to crash? I'm asking this question more as a Swift language feature rather than issue with the specific API as I'm sure that will get resolved soon anyway.
Thanks
I’m having an issue with my published iPad app on the App Store where a selection of users (but not all) are finding they are unable to download my app on their iPad.
The app recently was updated to support only devices Running iOS/iPadOS 17 and also added iPad support as HealthKit is available there now.
The App Store listing correctly shows it as compatible but for some reasons user still see incompatibility messages.
This makes no sense as the app has been full built and tested on iPad and a lot of users are using it fine. All the iPads in question are running ipadOS 17 too. I can only assume this is a bug but I thought I’d post here in case maybe I had an Xcode build setting wrong or something.
Thank You
Topic:
App Store Distribution & Marketing
SubTopic:
App Store Connect
Tags:
App Store
iPadOS
Xcode
HealthKit
Is there any approach or sample code available to use these APIs:
.chartScrollableAxes(.horizontal)
.chartScrollPosition(x: ...)
.chartScrollPosition(initialX: ...)
.chartScrollTargetBehavior(...)
.chartXVisibleDomain(length: ...)
Plus a gesture recognised or Pinch or Magnification to create a Swift Chart with an X axis that can be zoomed in or out with a pinch gesture? And when zoomed in at any level above 0, the chart can then be scrolled left to right along the X axis.
I've had success using .chartScrollableAxes with .chartXSelection in parallel, so would also like to keep the ability to select X values too.