Ah, you mistake me. I was asking because sandboxing makes this harder.
Anyway, I believe you’re hitting a known bug in macOS 13 (FB11745075
). The bug affects anyone who uses NSWorkspace
, and that includes the open
tool. I took a TSI about this last year and was able to work around the bug by sending an Apple event directly. I’ve pasted a snippet in below. However, given that you’re not calling NSWorkspace
directly, your idea of using osacript
is probably the easiest path forward for you.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
@IBAction
private func testAppleEventAction(_ sender: Any) {
self.status = "Opening with Apple event…"
let url = FileManager.default.temporaryDirectory.appendingPathComponent("tmp.sh")
let script = """
#! /bin/sh
echo 'Hail Teapot! (Apple event)'
"""
do {
try script.write(to: url, atomically: true, encoding: .utf8)
let success = chmod(url.path, 0o755) >= 0
guard success else { throw POSIXError(.init(rawValue: errno)!) }
} catch let error as NSError {
self.status = "Did not open, write error (\(error.domain) / \(error.code))"
return
}
guard let terminal = NSRunningApplication.runningApplications(withBundleIdentifier: "com.apple.Terminal").first else {
self.status = "Terminal is not open."
return
}
// Create a 'aevt' / 'odoc' Apple event.
let target = NSAppleEventDescriptor(processIdentifier: terminal.processIdentifier)
let event = NSAppleEventDescriptor(
eventClass: AEEventClass(kCoreEventClass),
eventID: AEEventID(kAEOpenDocuments),
targetDescriptor: target,
returnID: AEReturnID(kAutoGenerateReturnID),
transactionID: AETransactionID(kAnyTransactionID)
)
// Set its direct option to a list containing our script file URL.
let scriptURL = NSAppleEventDescriptor(fileURL: url)
let itemsToOpen = NSAppleEventDescriptor.list()
itemsToOpen.insert(scriptURL, at: 0)
event.setParam(itemsToOpen, forKeyword: keyDirectObject)
// Send the Apple event.
do {
let reply = try event.sendEvent(options: [.waitForReply], timeout: 60.0)
// AFAICT there’s no point looking at the reply here. Terminal
// doesn’t report errors this way.
_ = reply
// If the event was sent successfully, bring Terminal to the front.
terminal.activate()
} catch let error as NSError {
self.status = "Did not open (\(error.domain) / \(error.code))"
return
}
self.status = "Did open."
}