How to add swift availability check to Environment values?

I want to use the new .isLuminanceReduced Environment value while still retaining backwards compatibility with watchOS 7.

How can I add an availability check and provide a fallback in the case of running on < watchOS 8?

You may need to add @available on the struct using the new Environment value, and choose it using if #available.

Something like this:

struct MyView_watchOS7OrLower: View {
    var body: some View {
        Circle()
            .fill(Color.blue)
    }
}

@available(watchOSApplicationExtension 8.0, *)
struct MyView_watchOS8OrHigher: View {
    @Environment(\.isLuminanceReduced) var isLuminanceReduced

    var body: some View {
        if isLuminanceReduced {
            Circle()
                .stroke(Color.gray, lineWidth: 10)
        } else {
            Circle()
                .fill(Color.white)
        }
    }
}

@ViewBuilder
func MyView() -> some View {
    if #available(watchOS 8.0, *) {
        MyView_watchOS8OrHigher()
    } else {
        MyView_watchOS7OrLower()
    }
}

The answer I found to this is not really satisfying, but it works fine with SwiftUI. Every time the variable isLuminanceReduced changes, the ExtensionDelegate also changes the app state and calls applicationWillResignActive().

So to keep backwards compatible I introduced a singleton class that just holds a Bool isOn:

class LuminanceReducedCompat: ObservableObject {

    @Published var isOn: Bool = false

    public static let shared = LuminanceReducedCompat()

    private var notifcationObservers = [Any]()

    private init() {}

}

Now you can change the isOn variable in the applicationWillResignActive(). On your SwiftUI views you can add a that object now as an observed object.

@ObservedObject var luminanceReducedCompat = LuminanceReducedCompat.shared

I know that's not really nice, but the best I found until now. I don't want to maintain 2 views that show the same. I though about using a custom Environment Value that reflects the official watchOS 8 value, but I am not sure how to push this into the view stack correctly and update it.

I thought I found a workable solution but it's no good. It only works in the fallback case and it breaks the feature for watchOS8:

struct IsLuminanceReduced: EnvironmentKey {
    static var defaultValue: Bool = false
}

@available(watchOS, obsoleted: 8.0)
extension EnvironmentValues {
    var isLuminanceReduced: Bool {
        get { self[IsLuminanceReduced.self] }
        set { self[IsLuminanceReduced.self] = newValue }
    }
}

If I could figure out how to tell Swift "with watchOS8, * IGNORE this…"

Maybe you can pick up this fumble and carry it across the line?

How to add swift availability check to Environment values?
 
 
Q