🍁
Swift: macOS 13以降でのLaunch At Loginの実装
macOS 13からServiceManagementが強化されSMAppServiceが追加されたことで、ようやくヘルパーアプリに頼らずにログイン項目にアプリを登録できるようになりました。🎉(ヘルパーではなくアプリ本体がログイン項目に登録され、ログイン時に起動するようにできます。)しかも、実装方法もかなりシンプルでわかりやすいAPIとなっております。
実装例
import SwiftUI
import ServiceManagement
class ContentViewState: ObservableObject {
    @Published var launchAtLogin: Bool
    init() {
        launchAtLogin = SMAppService.mainApp.status == .enabled
    }
    func toggleLaunchAtLogin(_ isOn: Bool) {
        do {
            if isOn {
                try SMAppService.mainApp.register()
            } else {
                try SMAppService.mainApp.unregister()
            }
        } catch {
            Swift.print(error.localizedDescription)
        }
        launchAtLogin = SMAppService.mainApp.status == .enabled
    }
}
struct ContentView: View {
    @StateObject var state = ContentViewState()
    var body: some View {
        VStack {
            Toggle(isOn: Binding<Bool>(
                get: { state.launchAtLogin },
                set: { state.toggleLaunchAtLogin($0) }
            )) {
                Text(verbatim: "launch at login")
            }
        }
    }
}
ポイント
- 
SMAppService.mainApp.statusで現状ログイン項目に入っているのかどうかが判断できます。
- 
SMAppService.mainApp.register()でログイン項目に登録できます。(tryがついていますがXcodeでRunした時はnot permittedとなるようです。動作確認するにはリリースしないといけない?謎です。)
- 
SMAppService.mainApp.unregister()でログイン項目から登録解除できます。環境設定から手動で登録解除しているのに、さらにその状態からunregister()を叩くとErrorがthrowされます。
- ユーザーが状態を切り替えようとした際に失敗しうるAPIなので、UI側はプロパティとToggleを直接Bindingするのではなく、Binding<Bool>(get:set:)のsetでAPIのレスポンスに合わせてプロパティの値を更新するようにします。
参考



Discussion
macOS 12までのLaunch At Loginの実装(SwiftUI編)