[macOS翻译]在 macOS Mojave 上的 Mac 应用程序中执行 AppleScript 和处理 AppleEvent 沙盒

517 阅读7分钟

本文由 简悦 SimpRead转码,原文地址 www.jessesquires.com

最近的一个周末,我制作了一个小小的 Mac 应用程序(稍后详述)。我想实现的目标是:......。

最近的一个周末,我制作了一个小小的 Mac 应用程序(稍后详述)。我想实现的目标需要执行 AppleScript,就像 macOS 上的许多东西一样。这看起来很简单,但当然,macOS Mojave 中新的 应用程序沙盒 限制挡了我的路。

执行 AppleScript

在 Mac 应用程序中运行 AppleScript 出奇地简单。你只需创建一个 NSAppleScript 实例即可。Swift 的多行字符串字面意义让它变得尤为出色。你可以在脚本编辑器中编写脚本,然后逐字复制到 Swift 源代码中。AppleScript 强大而实用。我写了 这个 来将当前打开的 Safari 标签发送到 OmniFocus。

// Example:
//
// AppleScript that tells Safari to search for "macOS"

let source = """
tell application "Safari" to search the web for "macOS"
"""

let script = NSAppleScript(source: source)!
let error: NSDictionary?
script.executeAndReturnError(&error)

我的脚本与 "System Events"(系统事件)交互,它提供了大量杂项系统级功能。我通过脚本编辑器应用程序验证了我的脚本是否按预期运行,但在 Mac 应用程序中执行时却无法运行。

脚本添加错误

Xcode 控制台中的第一个错误似乎与我的应用程序完全无关。

skipped scripting addition "/Library/ScriptingAdditions/Adobe Unit Types.osax" because it is not SIP-protected.

我对 "脚本添加 "并不熟悉,但我发现Mojave 中的一些重大变化 基本上扼杀了这一功能。(令人震惊)。不出所料,这个错误实际上与我的应用程序完全无关--这个名为 Adobe Unit Types.osax 的文件属于 Adobe。(我不知道为什么 Xcode 会在控制台中为 我的应用程序 显示这个错误。过滤掉这些不相关的日志似乎很简单。这给开发人员带来了困惑。无论如何,这是个预示未来痛苦的好方法。

系统事件未运行

控制台中的另一个错误是由我的代码引起的。这是调用 script.executeAndReturnError(&error) 后打印 error 参数的内容。

{
    NSAppleScriptErrorAppName = "System Events";
    NSAppleScriptErrorBriefMessage = "Application isn't running.";
    NSAppleScriptErrorMessage = "System Events got an error: Application isn't running.";
    NSAppleScriptErrorNumber = "-600";
    NSAppleScriptErrorRange = "NSRange: {151, 9}";
}

有意思。系统事件肯定 正在 运行。据我所知,它一直在运行。我猜这是权限问题。没过多久,我就找到了 Daniel JalkutFelix Schwarz 的这些帖子:

我没有密切关注 Mac 开发人员的动态,但看起来这些 API 从 Mojave 的早期测试版开始就存在问题。我建议阅读这些帖子,以了解全貌。简而言之,Mojave 中对 AppleEvents(macOS 的自动化机制,如 AppleScript)和其他应用程序之间的通信设置了新的沙盒限制。这些帖子清楚地解释了问题所在,以及新限制如何对开发者和用户产生负面影响。

更新 plist 密钥和权限

根据上述阅读,解决方案是在我的 Info.plist 中添加 NSAppleEventsUsageDescription 密钥。这正是 iOS 权限的操作方式,因此对我来说是一个熟悉的解决方案。不幸的是,应用程序仍然无法运行。我继续看到 "系统事件未运行 "的错误。

经过一番探索,我了解到了埋藏在 this StackOverflow post 中的 com.apple.security.temporary-exception.apple-events 权限。现在我可以在 Mac 开发人员文档中搜索了,我找到了关于临时异常权限的指南

临时例外权限允许 MacOS 应用程序执行某些操作,否则 App Sandbox 将禁止这些操作。

如果你需要申请临时例外权限,请使用 Apple 的错误报告系统,让 Apple 知道哪些操作对你无效。Apple 在开发 macOS 平台时会考虑功能请求。

AppleEvents 中有一整节是关于临时例外的。

不过,使用 App Sandbox,除非配置了 "scripting-targets "权限或 "apple-events "临时例外权限,否则你无法向其他应用程序发送 Apple 事件。

scripting-targets权限是请求向提供脚本访问组的应用程序发送苹果事件的首选方式,如 App Sandbox Entitlement Keys 中所述。

我需要在我的 App.entitlements 文件中添加以下权限。密钥名称中的 "临时例外 "令人担忧。我想知道 Mac 应用商店是否允许这样做?不过,现在我的应用程序可以正常运行了。有进步

<key>com.apple.security.temporary-exception.apple-events</key>
<array>
    <string>com.apple.systemevents</string>
</array>

发现脚本目标

尽管我对这一权利并不确定,但我还是决定向 Mac App Store 提交我的应用程序,看看会发生什么。(当然,它被拒绝了,因为该权限例外 "未被苹果核心安全团队授予"。尽管如此,我还是下定决心要想办法让它成功。根据上面的文档,"App Store 批准的 "权限似乎是 "脚本目标 "权限。

脚本目标权限包含一个字典,其中每个条目都以目标应用程序的代码签名标识符为键,以脚本访问组数组为值。脚本访问组由字符串标识,是特定于应用程序的。

指南 为邮件应用程序提供了以下示例。

<key>com.apple.security.temporary-exception.apple-events:before:10.8</key>
    <string>com.apple.mail</string>

<key>com.apple.security.scripting-targets</key>
<dict>
    <key>com.apple.mail</key>
    <array>
        <string>com.apple.mail.compose</string>
    </array>
</dict>

脚本访问组由支持通过 AppleScript 编写脚本的应用程序提供。访问组定义了可编写脚本的操作组,您可以在本 WWDC 演讲中了解更多相关信息。有几种方法可以发现应用程序中哪些操作可使用脚本。你可以打开 "脚本编辑器",选择 "文件 > 打开字典...",然后选择你想自动运行的应用程序,并探索其中的可能性。这对于编写 AppleScript 脚本来说非常简单,但我找不到任何可以指定哪些操作属于访问组的内容。为此,你需要使用 sdef 工具,即脚本定义提取器。

sdef /Applications/Mail.app

这将把指定应用程序的脚本定义转储到 stdout。我建议将输出转入一个文件,以便用编辑器打开。

sdef /Applications/Mail.app > ~/Desktop/mail_sdef.xml

有了这个文件,你就可以在定义文件中搜索 "access-group"。对于邮件应用程序,你最终会找到

<access-group identifier="com.apple.mail.compose" access="rw"/>

酷毙了。现在我对脚本目标和访问组有了更好的理解。剩下的工作就是找出我需要为系统事件指定的访问组,这样我就可以使用已获批准的 com.apple.security.scripting-targets 权限了。

sdef /System/Library/CoreServices/System\ Events.app > ~/Desktop/system_events_sdef.xml

失望随之而来。我需要的访问组不在这里。事实上,唯一可用的是 com.apple.systemvents.window.position,它看起来像是因为 Craig Hockenberry 的这个雷达添加的。大约四年过去了,也没有添加其他访问组。

应用程序沙箱过于有限

一般来说,应用程序沙盒 似乎是保护用户的好功能。但在实践中,开发人员不得不在迷宫般的晦涩权限选项中穿梭,这让他们非常沮丧,其中有些选项还不符合我们想要提供的功能。对用户来说,最终结果就是权限对话框极其混乱。

即使是Transmit 5 即将重返 Mac App Store的大新闻也不那么令人乐观,因为它仍然缺少一些功能,而且需要种不同的临时权限例外,其中有些必须申请特殊权限才能使用。要我说,这对开发人员来说算不上什么 "胜利"。这是我多年从事 iOS 开发后第一次真正尝试编写 Mac 应用程序,我的大部分时间都花在了了解沙箱如何工作以及我需要指定哪些权限上。

我很快就会发表一篇关于该应用的文章。


www.deepl.com 翻译