使用Swift运行AppleScript无法正常工作

6
我正在制作一个简单的菜单栏应用程序,可以执行一些操作,例如在Mojave中切换深色模式。
为此,编写一个AppleScript是可行的,并且在直接运行脚本时可以100%正常工作。为了将其实现到菜单栏应用程序中,我尝试在网上搜索,但唯一找到的答案是在这个链接中:Can you execute an Applescript script from a Swift Application 然而,当我尝试第一个解决方案时,在控制台中出现了错误提示:
script: /Users/username/Documents/myscript.scpt: Operation not permitted

我的代码是这样的:

let proc = Process()
proc.launchPath = "/usr/bin/script"
proc.arguments = ["/Users/username/Documents/myscript.scpt"]
proc.launch()

我尝试了另一种解决方案,这次使用了NSAppleScript:

let myAppleScript = "tell application \"System Events\" \ntell appearance preferences to set dark mode to not dark mode \nend tell"
var error: NSDictionary?
if let scriptObject = NSAppleScript(source: myAppleScript) {
    if let output: NSAppleEventDescriptor = scriptObject.executeAndReturnError(&error) {
        print(output.stringValue)
    } else if (error != nil) {
        print("error: \(error)")
    }
}

然而,这次我收到了一个错误,内容是:
error: Optional({
    NSAppleScriptErrorAppName = "System Events";
    NSAppleScriptErrorBriefMessage = "Application isn\U2019t running.";
    NSAppleScriptErrorMessage = "System Events got an error: Application isn\U2019t running.";
    NSAppleScriptErrorNumber = "-600";
    NSAppleScriptErrorRange = "NSRange: {86, 9}";
})

但是,如果我将脚本更改为更简单的内容(例如“显示通知”测试”),第二个解决方案就可以完美运行。

这意味着第二个解决方案可以正常运行AppleScript,但似乎无法调用系统事件。 我该如何解决这个问题?


然而,当我尝试第一种解决方案时,控制台中出现了错误提示:“未经用户同意,您不应访问该路径。” - El Tomato
好的,那很有道理。有没有办法访问它,还是这个解决方案已经走到了死胡同? - akmin
3个回答

8

如果应用程序被沙盒化,就会出现此错误。

您有两个选项:

  1. System Events 添加 com.apple.security.temporary-exception.apple-events 权限
  2. 将脚本放置在应用程序的 Application Scripts 文件夹中,并使用 NSUserAppleScriptTask 从该位置运行它

Application Scripts 文件夹仅用于用户脚本;您的应用程序可以从中读取,但无法写入。应用程序中的脚本应嵌入到应用程序包中,并使用 NSAppleScript(对于简单任务而言已足够)或 AppleScript-ObjC 进行调用,并声明必要的沙盒权限。这样可以保护每个人。macOS 的安全模型可能有些笨拙,但正确的解决方法是提交 Radar 请求,而不是试图规避它;否则只会让您的应用被 AppStore 拒绝。 - foo
@foo,看起来NSAppleScript和OSAScript都有内存泄漏问题,所以我不再使用它们。我使用一个名为bash()的函数调用osascript。我想osascript也可能会有泄漏问题,但这并不重要,因为整个进程运行后就会自动消失并释放所有分配的资源。bash()使用Swift中的Process类创建进程。 - Kaydell
我认为#1的沙盒机制有问题,Vadian。如你所述,我在我的临时例外权利下添加了com.apple.systemevents和com.apple.applescript,但我仍然收到“执行错误:System Events got an error: Application isn’t running. (-600)”的错误信息。我是否遗漏了一些显而易见的东西? - ajc6432

0

0

我遇到了这个错误,因为我的应用程序被沙盒化了,尽管在某些地方关闭了沙盒。禁用沙盒化需要我走了几个步骤,但我不确定哪些是必要的。我尝试了this question中列出的大部分方法。

看起来至少有以下两个步骤是必要的:

1. 在应用程序授权文件中禁用沙盒

可以在Xcode中完成,通过打开带有金色勾号/星号图标的文件,并在“App Sandbox”的下拉菜单中选择“NO”。

或者,可以通过编辑应用程序的.entitlements文件来实现:

<key>com.apple.security.app-sandbox</key>
<false/>

2. 在 Info.plist 文件中添加 Apple Events 发送使用说明

同样,这可以通过两种方式完成,一种是在 Xcode 中导航到 Info 文件,添加键 Privacy - AppleEvents Sending Usage Description,并输入一个字符串来请求访问权限(据我所知,这可以是任何字符串)。

另一种方法是通过编辑应用的 Info.plist 文件来实现:

<key>NSAppleEventsUsageDescription</key>
<string>(your request string here)</string>

无论如何,在更改这两个设置之后(可能还有更多,我点击了很多按钮),然后我必须重新构建应用程序,再次触发AppleScript,并获得一个提示来允许访问。这使我进入了系统设置的隐私与安全>辅助功能面板,在那里我可以切换开关以授予我的应用程序辅助功能。
特别感谢this answer帮助我解决了这个问题!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接