NSTask : Couldn't posix_spawn: error 13 when launching app
Asked Answered
O

2

6

I have a sub-app in my main Swift app. I made it so it's copied automatically in the Resources folder of the main app when building it. That way, I want to be able to launch an instance of the sub-app from the main app.

The thing is, I'm having an error that is hard to debug/find answers about.

Here is my code :

    let args = ["--args", "-admin_url", site.url, "-login", site.login, "-pass", site.password]
    let helperPath = (NSBundle.mainBundle().pathForResource("App Helper", ofType: "app"))!
    let task = NSTask.init()
    task.launchPath = helperPath
    task.arguments = args
    task.launch()

And the error :

[56490:7218926] Couldn't posix_spawn: error 13

I have no idea where to look, what to search for. I don't know what I'm doing wrong. I'm wondering if the issue is related to the sub-app itself. That sub-app is empty for now. I set Application is Agent to YES. And in MainMenu.xib, I set the Visible at launch option to no. That sub-app needs to do some work in the background and doesn't need any UI at all.

Thanks !

Olva answered 30/6, 2016 at 20:23 Comment(1)
Error 13 is an error for Permission Denied. What is your helperPath? If it is not /usr/bin, you will get this error.Telephone
R
2

Don't use NSTask for this, use NSWorkspace:

let helperAppURL = NSBundle.mainBundle().URLForResource("App Helper",
                                      withExtension:"app")!

_ = try? NSWorkspace.sharedWorkspace().openURL(helperAppURL,
       options:[.Default],
   configuration:[NSWorkspaceLaunchConfigurationArguments :
            ["--args", "-admin_url", site.url, "-login",
             site.login, "-pass", site.password]])

In the above code, for brevity, I ignored the result of the openURL() command, but in reality it can return an instance of NSRunningApplication which represents the task.

To keep track of the instances of your helper app you launch, you could keep references to this NSRunningApplication in an appropriate kind of collection class, and when the time comes, call its terminate() method.

Rev answered 30/6, 2016 at 22:33 Comment(4)
This works properly, thank you. But I'm not sure it's compatible with what I need to do. I need to be able to launch several instances of the app helper (this is ok I believe), and terminate a given one programmatically. Task does have a terminate() method. Can I do something equivalent with openURL() ?Olva
Yes, you should be able to do something similar with openURL(_:options:configuration:). Updating answer...Rev
NSWorkspace has problems with Catalina and aboveDulcle
appsloveworld.com/swift/100/65/… Using process is preferableDulcle
Y
2

the launch() function is deprecated, using run()

func shell(_ command: String) -> String {
  let task = Process()
  task.launchPath = "/usr/bin/"
  task.arguments = ["-c", command]
  
  let pipe = Pipe()
  task.standardOutput = pipe
  
  if #available(macOS 10.13, *) {
    try? task.run()
  } else {
    task.launch()
  }
  
  let data = pipe.fileHandleForReading.readDataToEndOfFile()
  let output: String = NSString(data: data, encoding: String.Encoding.utf8.rawValue)! as String
  
  return output
}

or using swift-commands

import Commands

Commands.Bash.run("say hello")
Yukoyukon answered 5/8, 2021 at 6:27 Comment(1)
Interesting, this fixed the issue for me but I didn't get any deprecation warnings.Insurrection

© 2022 - 2024 — McMap. All rights reserved.