Swift mac应用程序打开后如何执行命令

Swift mac应用程序打开后如何执行命令,swift,macos,Swift,Macos,我想在我的应用程序打开系统终端应用程序后执行命令。我使用以下命令打开终端应用程序: 让url=NSURL(fileURLWithPath:“/System/Applications/Utilities/Terminal.app”,isDirectory:true)作为url let configuration=NSWorkspace.OpenConfiguration() NSWorkspace.shared.openApplication(位于:url,配置:configuration,com

我想在我的应用程序打开系统终端应用程序后执行命令。我使用以下命令打开终端应用程序:

让url=NSURL(fileURLWithPath:“/System/Applications/Utilities/Terminal.app”,isDirectory:true)作为url
let configuration=NSWorkspace.OpenConfiguration()
NSWorkspace.shared.openApplication(位于:url,配置:configuration,completionHandler:{app,错误在
//app.executeMyCommand(“echo hello”)
})
在它打开之后,我想执行命令“echo hello”,如completionHandler所示。
如何实现这一点?

一种可能是使用“AppleScriptObjc”通过来自Swift的AppleScript控制终端

下面是一个完整的自包含示例:

ViewController.swift

import Cocoa
import AppleScriptObjC

class ViewController: NSViewController {

    var terminalBridge: TerminalBridging?

    override func viewDidLoad() {
        super.viewDidLoad()
        Bundle.main.loadAppleScriptObjectiveCScripts()
        let terminalBridgeClass: AnyClass = NSClassFromString("TerminalBridge")!
        self.terminalBridge = terminalBridgeClass.alloc() as? TerminalBridging
    }

    @IBAction func onExecute(_ sender: Any) {
        self.terminalBridge?.executeCommand("echo hello")
    }
    
}
import Cocoa

@objc(NSObject) protocol  TerminalBridging {

    func executeCommand(_ cmd: String)
    
}
终端新娘。swift

import Cocoa
import AppleScriptObjC

class ViewController: NSViewController {

    var terminalBridge: TerminalBridging?

    override func viewDidLoad() {
        super.viewDidLoad()
        Bundle.main.loadAppleScriptObjectiveCScripts()
        let terminalBridgeClass: AnyClass = NSClassFromString("TerminalBridge")!
        self.terminalBridge = terminalBridgeClass.alloc() as? TerminalBridging
    }

    @IBAction func onExecute(_ sender: Any) {
        self.terminalBridge?.executeCommand("echo hello")
    }
    
}
import Cocoa

@objc(NSObject) protocol  TerminalBridging {

    func executeCommand(_ cmd: String)
    
}
终端桥。applescript

import Cocoa
import AppleScriptObjC

class ViewController: NSViewController {

    var terminalBridge: TerminalBridging?

    override func viewDidLoad() {
        super.viewDidLoad()
        Bundle.main.loadAppleScriptObjectiveCScripts()
        let terminalBridgeClass: AnyClass = NSClassFromString("TerminalBridge")!
        self.terminalBridge = terminalBridgeClass.alloc() as? TerminalBridging
    }

    @IBAction func onExecute(_ sender: Any) {
        self.terminalBridge?.executeCommand("echo hello")
    }
    
}
import Cocoa

@objc(NSObject) protocol  TerminalBridging {

    func executeCommand(_ cmd: String)
    
}
注意后缀。applescript很重要。根据您的喜好定制它

script TerminalBridge

    property parent : class "NSObject"

    to executeCommand:cmd
        tell application "Terminal"
            do script (cmd as text)
        end tell
    end executeCommand:

end script
在Xcode中设置项目

  • 在XCode中,在项目导航器中选择根节点
  • 然后选择目标并在“框架、库和嵌入内容”下添加“AppleScriptObjC.framework”,并使用defult“不嵌入”设置
  • 在“签名和功能”下,删除“应用程序沙盒”,改为添加“强化运行时”
  • 向下滚动并在“资源访问”下选择“Apple事件”
  • 在项目导航器中选择“Info.plist”
  • 添加“NsappleEventSageDescription”键和一些有用的解释
演示

第一次运行时,您会看到:

如果您按“确定”,第一次运行时会自动将一个条目添加到“系统首选项/安全和隐私/隐私”。然后执行命令

另一种解决方案:

使用
NSAppleScript
执行AppleScript:

let terminalScript = "echo hello"
/* oneliner * /
let AppleScriptSrc = "tell app \"Terminal\" to do script \"\(terminalScript)\""
/ **/
/* or a script */
let AppleScriptSrc = """
    tell app "Terminal"
        activate
        if number of windows > 0
            do script "\(terminalScript)" in tab 1 of window 1
        else
            do script "\(terminalScript)"
        end if
    end tell
"""
/**/
if let AppleScript = NSAppleScript(source: AppleScriptSrc) {
    var error: NSDictionary?
    AppleScript.executeAndReturnError(&error)
    if error != nil {
        print("Error: \(String(describing: error))")
    }
}
要允许发送Apple事件,请执行以下操作:

  • 在“签名和功能”、“强化运行时”下,选中“Apple事件”
  • 在info.plist中添加一行“隐私-AppleeEvents发送使用说明”
  • 在权利中添加一行“com.apple.security.temporary exception.apple events”和项目“com.apple.Terminal”
另一种解决方案:

向终端发送
do脚本
Apple事件:

let terminalScript = "echo hello"
if let url = NSWorkspace.shared.urlForApplication(withBundleIdentifier: "com.apple.Terminal") {
    let configuration = NSWorkspace.OpenConfiguration()
    let doScriptEvent = NSAppleEventDescriptor(eventClass: kAECoreSuite,
        eventID: kAEDoScript, targetDescriptor: nil, returnID: AEReturnID(kAutoGenerateReturnID),
        transactionID: AETransactionID(kAnyTransactionID))
    doScriptEvent.setParam(NSAppleEventDescriptor(string: terminalScript), forKeyword:keyDirectObject)
    configuration.appleEvent = doScriptEvent
    NSWorkspace.shared.openApplication(at: url, configuration: configuration, completionHandler: { app, error in
        if error != nil {
            print("Error: \(String(describing: error))")
        }
    })
}
要允许发送Apple事件,请执行以下操作:

  • 在“签名和功能”、“强化运行时”下,选中“Apple事件”
  • 在info.plist中添加一行“隐私-AppleeEvents发送使用说明”
  • 在权利中添加一行“com.apple.security.temporary exception.apple events”和项目“com.apple.Terminal”

是否要在特定路径上启动终端应用程序?该命令是否应该在特定窗口中执行?不,路径与窗口无关。主要目的是打开终端窗口并执行命令。为什么不使用
Process
执行命令?@JoakimDanielson没有理由不使用
Process