Better SwiftUI Settings Scene Access on macOS
SettingsAccess
Why
As of macOS 14 Sonoma:
-
Apple completely removed the ability to open the SwiftUI Settings scene using legacy
NSApp.sendAction()
method using theshowSettingsWindow:
(macOS 13) orshowPreferencesWindow:
(macOS 12 and earlier) selectors. The only available method of opening the Settings scene apart from the App menu → Settings menu item is to use the newSettingsLink
view. -
This presents two major restrictions:
SettingsLink
is a view that wraps a standard SwiftUIButton
. There is no way to detect when the user has clicked this button if additional code is desired to run in addition to the intrinsic behavior of opening the Settings scene. Due to how SwiftUI works, it is impossible to attach a simultaneous gesture to attempt to detect a button press.- There is no way to programmatically open the Settings scene.
-
These restrictons become problematic in many scenarios. Some examples that are currently impossible without SettingsAccess:
- You are building a window-based MenuBarExtra and want to have a button that opens Settings and also dismisses the window.
- You want to open the Settings scene in reponse to a user action in your application that requires the user manipulate a setting that may be invalid.
Solution
- SettingsAccess provides a custom button style that can be applied directly to
SettingsLink
in order to execute code before and/or after the button press action occurs. - SettingsAccess provides an environment method called
openSettings
that can be called anywhere in the view hierarchy to programmatically open the Settings scene.
In addition, SettingsAccess is backwards compatible from macOS 11 Big Sur and later. Calling openSettings()
will use the correct method to open the Settings scene for each operating system automatically.
Using the Package
Swift Package Manager (SPM)
Add SettingsAccess as a dependency using Swift Package Manager.
-
In an app project or framework, in Xcode:
Select the menu: File → Swift Packages → Add Package Dependency…
Enter this URL:
https://github.com/orchetect/SettingsAccess
-
In a Swift Package, add it to the Package.swift dependencies:
.package(url: "https://github.com/orchetect/SettingsAccess", from: "1.0.0")
Getting Started
-
Import the library.
import SettingsAccess
-
Attach the
openSettingsAccess
view modifier to the base view which needs access to theopenSettings
method.@main struct MyApp: App { var body: some Scene { WindowGroup { ContentView() .openSettingsAccess() } } }
-
In any subview where needed, add the environment method declaration. Then the Settings scene may be opened programmatically by calling this method.
struct ContentView: View { @Environment(\.openSettings) private var openSettings var body: some View { Button("Open Settings") { openSettings() } } }
Example Code
Try the Demo example project to see the library in action.
Requirements
Supports macOS 11.0+.
Author
Coded by a bunch of ? hamsters in a trenchcoat that calls itself @orchetect.
License
Licensed under the MIT license. See LICENSE for details.
Sponsoring
If you enjoy using SettingsAccess and want to contribute to open-source financially, GitHub sponsorship is much appreciated. Feedback and code contributions are also welcome.
Contributions
Contributions are welcome. Posting in Discussions first prior to new submitting PRs for features or modifications is encouraged.