Launch at login for macOS apps, through SMAppService. A fork of LaunchAtLogin-Modern with the same API that never makes the main thread wait on the login items daemon.
Every read of SMAppService.mainApp.status is a synchronous call to that daemon, which checks the app's code signature each time. LaunchAtLogin-Modern's toggle reads it from its binding, and SwiftUI reads a binding many times while it builds, lays out and shows a window, so a settings window with the toggle in it opened noticeably slower.
- The status is read once and kept, then read again off the main thread after every change, and when the app becomes active: right away while a view shows it (
LaunchAtLogin.Toggleor any view observingLaunchAtLogin.observable), otherwise the next time a view asks for it - Reading
isEnabledorstatusoff the main thread, where waiting costs no frames, reads it again when the kept status is more than a second old - Setting
isEnabledshows the new value at once, and registers or unregisters off the main thread statusgives the wholeSMAppService.Status, andrefresh()reads it again- When the user turned the login item off in System Settings, turning it back on with the toggle opens System Settings on Login Items, since only they can allow it there. Setting
isEnabledfrom code never opens it
.package(url: "https://github.com/FuzzyIdeas/LaunchAtLogin", from: "1.0.0")import LaunchAtLogin
struct SettingsView: View {
var body: some View {
LaunchAtLogin.Toggle()
}
}
LaunchAtLogin.isEnabled = trueLaunchAtLogin.Toggle("Start at login") and LaunchAtLogin.Toggle { Text("Start at login") } set another label.
A view with its own control binds to LaunchAtLogin.observable, which redraws it when the status changes:
@ObservedObject private var launchAtLogin = LaunchAtLogin.observable
MyToggle("Start at login", isOn: $launchAtLogin.isEnabled)A change that fails is logged under the app's bundle identifier, category LaunchAtLogin.
MIT, see LICENSE.