How to run main application from LoginItem on macOS Big Sur

Viewed 194

I want to release an update for my macOS app. I have a login item that starts the app automatically. I was using this code in the helper application:

if !alreadyRunning
{
    DistributedNotificationCenter.default().addObserver(self, selector: #selector(AppDelegate.terminate), name: NSNotification.Name("killme"), object: mainIdentifier)
            
    let path = Bundle.main.bundlePath as NSString
    var components = path.pathComponents
    components.removeLast()
    components.removeLast()
    components.removeLast()
    components.append("MacOS")
    components.append("MyAppName")
            
    let newPath = NSString.path(withComponents: components)
            
    NSWorkspace.shared.launchApplication(newPath)
}
else
{
    self.terminate()
}

which has been working for three years. However with macOS Big Sur the launchApplication function is now deprecated and it says that I should use the openApplication function instead.

I changed the lower part of my app to this:

let url = URL(fileURLWithPath: newPath)
let configuration = NSWorkspace.OpenConfiguration()
configuration.promptsUserIfNeeded = true
configuration.allowsRunningApplicationSubstitution = true
            
NSWorkspace.shared.openApplication(at: url, configuration: configuration, completionHandler: nil)

In fact, I have tried all of the flags that are available on the Configuration. There are a couple of different errors that are thrown. Either it says that the launcher application is not permitted to launch my main app or something about the helper app not being able to run terminal commands.

A simple workaround is to just ignore the deprecation warning, which I would like to avoid. How can my LoginItem app run my main application on Big Sur?

1 Answers

openApplication expects an URL to the MyAppName.app folder instead of the binary.

Try removeLast() one more time to remove "Contents" and don't add "MacOS" or "MyAppName".

let path = Bundle.main.bundlePath as NSString
var components = path.pathComponents
components.removeLast()
components.removeLast()
components.removeLast()
components.removeLast()

let newPath = NSString.path(withComponents: components)
let url = URL(fileURLWithPath: newPath)
let configuration = NSWorkspace.OpenConfiguration()
            
NSWorkspace.shared.openApplication(at: url, configuration: configuration, completionHandler: nil)
Related