I have multiple Widget
s for my iOS/iPadOS/watchOS app. I have one widget with supported family .systemLarge
.
struct MyWidget: Widget {
var body: some WidgetConfiguration {
StaticConfiguration(...)
.xxx // some modifiers
.supportedFamilies([.systemLarge])
}
}
I want this widget to be supported on new stand-by location so I need to support family .systemSmall
as well (I want to reuse body
). But since I don't want this .systemSmall
widget in home screen's gallery I need to use .disfavoredLocations([.homeScreen], for: [.systemSmall])
as well.
Unfortunetely, I'm supporting iOS 15 and 16 as well so I need to wrap this modifier somehow into #available(iOS 17.0, *)
. But... this can't be done since there is no type-erased WidgetConfiguration
.
Then I was thinking about something like this with the help of WidgetBundle
:
@available(iOS 17.0, *)
struct MyWidgetIOS17: Widget {
var body: some WidgetConfiguration {
var widget = MyWidget()
return widget.body.disfavoredLocations([.homeScreen], for: [.systemSmall])
}
}
@main
struct Widgets: WidgetBundle {
var body: some Widget {
if #available(iOS 17.0, *) {
MyWidgetIOS17()
} else {
MyWidget()
}
}
}
But... while
if #available(iOS 17.0, *) {
MyWidgetIOS17()
}
works,
if #available(iOS 17.0, *) {
MyWidgetIOS17()
} else {
MyWidget()
}
does not.
Does anybody know how to use disfavoredLocations
below iOS 17 while still reusing the Widget
s body?
I solved this issue with an extension on WidgetConfiguration
which uses disfavoredLocations
just for iOS 17+
enum WidgetDisfavoredLocation {
case homeScreen
case lockScreen
case standBy
case iPhoneWidgetsOnMac
}
extension WidgetConfiguration {
func backDeployedDisfavoredLocations(
_ locations: [WidgetDisfavoredLocation],
for families: [WidgetFamily]
) -> some WidgetConfiguration {
if #available(iOS 17.0, *) {
return disfavoredLocations(
locations.map { location in
switch location {
case .homeScreen:
return .homeScreen
case .lockScreen:
return .lockScreen
case .standBy:
return .standBy
case .iPhoneWidgetsOnMac:
return .iPhoneWidgetsOnMac
}
},
for: families
)
} else {
return self
}
}
}