Replace: you need to merely add the LaunchAtLogin library to your venture. It’s going to deal with the whole lot and it has another cool utility options.
Venture setup
Let’s begin this tutorial by creating a brand new Xcode venture with a macOS app template. Identify it for instance MainApplication, use storyboards and naturally choose Swift because the default language, we do not want exams for this venture in any respect.
Now that we’ve the primary software goal, there’s this good little perform out there known as SMLoginItemSetEnabled
. With that perform you’ll be able to register an software bundle identifier to auto begin when the person logs in, however you cannot register your individual app identifier. Sounds loopy, huh? 😜
You’ll be able to register a bundle identifier embedded into your essential software to get auto-launched by the system. To do that you’ll have to create a brand new launcher software which will probably be launched later by your essential software.
You additionally should code signal your software together with your Developer ID, in any other case it will not begin after you log in to macOS. Sandboxing is a vital a part of the method, so just remember to observe each instruction fastidiously.
Targets & configurations
Create a brand new goal inside your present venture. Identify this new goal for instance LauncherApplication. Allow sandbox and code signing for each targets (essential and launcher apps) below the Signing & Capabilities tab. For the LauncherApplication goal within the construct settings set skip set up to sure.
For the launcher app add a brand new entry to the Information.plist file: Software is background solely with the worth: sure. This may set your software as a background app, we do not really want person interface for a launcher device, proper?
Add a brand new copy file construct part to your essential software goal to repeat your launcher software into the bundle. The vacation spot must be wrapper and the subpath must be Contents/Library/LoginItems
.
Hyperlink the ServiceManagement.framework
to your essential software and double examine that the launcher app is embedded into your essential software.
From the LauncherApplication
‘s storyboard file delete your window and your view controller, additionally you’ll be able to take away the ViewController.swift
file from this goal. It is a background app in spite of everything, so we do not want these silly issues to put round.
Creating the launcher programmatically
Someplace in your essential software it’s a must to register your launcher software’s identifier. When your essential software begins it’s a must to kill the launcher software if it is nonetheless operating. You are able to do this by sending a notification to that particular app with the NSDistributedNotificationCenter
class.
import Cocoa
import ServiceManagement
extension Notification.Identify {
static let killLauncher = Notification.Identify("killLauncher")
}
@NSApplicationMain
class AppDelegate: NSObject {}
extension AppDelegate: NSApplicationDelegate {
func applicationDidFinishLaunching(_ aNotification: Notification) {
let launcherAppId = "com.tiborbodecs.LauncherApplication"
let runningApps = NSWorkspace.shared.runningApplications
let isRunning = !runningApps.filter {
$0.bundleIdentifier == launcherAppId
}.isEmpty
SMLoginItemSetEnabled(launcherAppId as CFString, true)
if isRunning {
DistributedNotificationCenter.default().publish(
title: .killLauncher,
object: Bundle.essential.bundleIdentifier!
)
}
}
}
Within the launcher software it’s a must to begin your essential software if it is not operating already. That is it. You must also subscribe for the notifications from the primary app to terminate if the launcher is just not wanted anymore.
import Cocoa
extension Notification.Identify {
static let killLauncher = Notification.Identify("killLauncher")
}
@NSApplicationMain
class AppDelegate: NSObject {
@objc func terminate() {
NSApp.terminate(nil)
}
}
extension AppDelegate: NSApplicationDelegate {
func applicationDidFinishLaunching(_ aNotification: Notification) {
let mainAppIdentifier = "com.tiborbodecs.MainApplication"
let runningApps = NSWorkspace.shared.runningApplications
let isRunning = !runningApps.filter {
$0.bundleIdentifier == mainAppIdentifier
}.isEmpty
if !isRunning {
DistributedNotificationCenter.default().addObserver(
self,
selector: #selector(self.terminate),
title: .killLauncher,
object: mainAppIdentifier
)
let path = Bundle.essential.bundlePath as NSString
var elements = path.pathComponents
elements.removeLast()
elements.removeLast()
elements.removeLast()
elements.append("MacOS")
elements.append("MainApplication")
let newPath = NSString.path(withComponents: elements)
NSWorkspace.shared.launchApplication(newPath)
}
else {
self.terminate()
}
}
}
That is it, we’re able to launch. Export your essential software and right here is a very powerful factor: code signal it together with your Developer ID. Begin it, shut it, sign off and again into the system. Hopefully your essential software will probably be operating once more.