0

I'm writing an app that displays a list of PDF files in a NSTableView that the user should be able to double-click to open in the default application (Preview, Adobe Reader, ...).

I've tried using NSWorkspace.shared.openFile and NSWorkspace.shared.open(_: withAppBundleIdentifier: options: additionalEventParamDescriptor: launchIdentifiers:), but none of them work.

I can't use the new func open(URL, configuration: NSWorkspace.OpenConfiguration, completionHandler: ((NSRunningApplication?, Error?) -> Void)?) as this is targeted at pre-Catalina computers.

Here are the two code snippets:

1.

@objc func doubleClickOnResultRow() {
    let clickedRow = resultsTableView.selectedRow

    if ( clickedRow > -1 ) {
        let myURL = foundItems[clickedRow] as URL
        if (!NSWorkspace.shared.openFile(myURL.path)) {
            print("Unable to open : ", myURL.path)
        }
    }
}

This first one does nothing, and I get a "Unable to open : url/to/my/file.pdf" in the console.

2.

@objc func doubleClickOnResultRow() {
    let clickedRow = resultsTableView.selectedRow

    if ( clickedRow > -1 ) {
        let myURL = foundItems[clickedRow] as URL
        NSWorkspace.shared.open([myURL], withAppBundleIdentifier: "com.apple.Preview", options: NSWorkspace.LaunchOptions.withErrorPresentation, additionalEventParamDescriptor: nil, launchIdentifiers: nil)
    }
}

With this one, however, when I double-click on a file, I get a error window with the Finder icon that says :

"The application “My app” does not have permission to open “myfile.pdf.” Here is the screenshot:

Finder error

I don't understand what I'm doing wrong. Eventually I could build a lightweight PDF viewer inside my app, but I would really like to avoid it if possible.

EDIT 03/31/2020, 16:10

I've tried a third way, by calling the shell command "open" with this (found here):

func shell(_ command: String) -> String {
        let task = Process()
        task.launchPath = "/bin/bash"
        task.arguments = ["-c", command]

        let pipe = Pipe()
        task.standardOutput = pipe
        task.launch()

        let data = pipe.fileHandleForReading.readDataToEndOfFile()
        let output: String = NSString(data: data, encoding: String.Encoding.utf8.rawValue)! as String

        return output
}

and then

let command = "open \""+myURL.path+"\""
print(shell(command))

and I get

LSOpenURLsWithRole() failed with error -54 for the file path/to/my/file.pdf.
  • Read about [App Sandboxing](https://developer.apple.com/documentation/security/app_sandbox?language=objc). – trojanfoe Mar 31 '20 at 14:06

1 Answers1

1

You have to construct the URL to file using init(fileURLWithPath:) of URL not the usual init?(string:)

let url = URL(fileURLWithPath: "/path/to/file.pdf") 

Then you can open it with default application using NSWorkspace.open instance method

NSWorkspace.shared.open(url)
MjZac
  • 3,303
  • 1
  • 20
  • 27