Fabien Conus
Fabien Conus

Reputation: 11

Swift on MacOS: cannot open a file from my app

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.

Upvotes: 1

Views: 1768

Answers (2)

BinaryBang
BinaryBang

Reputation: 83

enter image description here

According to LSOpenURLsWithRole() failed with error -54 for the file path/to/my/file.pdf.
This is because your app does not have the permission to access other file.
You should do the following things to resolve.
1,find the entitlements file.
2,set the "App Sandbox" key to NO.
3,then you can open the file successfully.

Upvotes: 1

MjZac
MjZac

Reputation: 3526

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)

Upvotes: 3

Related Questions