1

显然,有一种方法可以使我的 GUI 应用程序可以使用 AppleScript 编写脚本。例如,我可以有一个命令行应用程序(例如从 LaunchDaemon 运行),它告诉我的 GUI 应用程序发布侧边栏通知。有没有人有一个简单的例子来解释这一点?我在 Apple 网站上看到的所有内容都很难理解。

我想创建一条 AppleScript 消息,例如:

tell "My App" to notify with title "Title" subtitle "subtitle" text "some text"

在我的 CLI 应用程序中,然后我的 GUI 应用程序唤醒、接收并处理它。

4

1 回答 1

5

这比我想象的要容易!需要注意的一些事项:

  • 您必须启用您的 Cocoa 应用程序以在 Info.plist 文件中接收带有两个特殊参数的 AppleScript 事件:NSAppleScriptEnabledOSAScriptingDefinition.
  • 一个称为 sdef 文件的特殊 XML 文件将您的 AppleScript 语法直接映射到一个 Objective C 类来处理它。
  • 该类必须是子类NSScriptCommand及其方法performDefaultImplementation,然后您可以访问[self directParameter][self evaluatedArguments]
  • 因此,当您发送 AppleScript 命令时,您的应用程序会自动打开(即使已关闭),并且不会加载它的多个实例,这很好。然后,如果 AppleScript 中的语法正确,它会将其发送到该类进行处理。sdef 文件指示哪个类。
  • 如果这是您想要的,您的命令也可以发回响应。或者它可以选择不这样做。

1. 打开您想要接收 AppleScript 事件的 OSX Cocoa 应用程序项目。

2. 添加一个commands.sdef文件,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dictionary SYSTEM "file://localhost/System/Library/DTDs/sdef.dtd">
<dictionary xmlns:xi="http://www.w3.org/2003/XInclude">
    <!-- commented out next line because it has a bug ".sdef warning for argument 'FileType' of command 'save' in suite 'Standard Suite': 'saveable file format' is not a valid type name" -->
    <!-- <xi:include href="file:///System/Library/ScriptingDefinitions/CocoaStandard.sdef" xpointer="xpointer(/dictionary/suite)"/> -->
    <suite name="Acceptable Commands" code="SVrb" description="">
        <command name="notify user with title" code="SVrbDpCm" description="">
            <cocoa class="myCommand"/>
            <direct-parameter description="">
                <type type="text"/>
            </direct-parameter>
            <parameter name="subtitle" code="arg2" type="text" optional="yes"
                    description="">
                    <cocoa key="subtitle"/>
            </parameter>
            <parameter name="text" code="arg3" type="text" optional="yes"
                    description="">
                    <cocoa key="text"/>
            </parameter>
            <!-- uncomment below if you want to return a result string -->
            <!-- <result type="text" description=""/> -->
        </command>
    </suite>
</dictionary>

3. 添加一个 myCommand.mm 文件,内容如下:

#import <Cocoa/Cocoa.h>

@interface myCommand : NSScriptCommand
@end

@implementation myCommand : NSScriptCommand

- (id)performDefaultImplementation {
    NSString *sResult = @"";
    NSString *sTitle = [self directParameter];
    NSDictionary *asArgs = [self evaluatedArguments];
    NSString *sSubTitle = [asArgs objectForKey:@"subtitle"];
    NSString *sText = [asArgs objectForKey:@"text"];
    sResult = [sResult stringByAppendingFormat:@"TITLE=%@ SUBTITLE=%@ TEXT=%@",sTitle,sSubTitle,sText];
    NSUserNotification *n = [[NSUserNotification alloc] init];
    n.title = sTitle;
    if (![sSubTitle isEqualToString:@""]) {
        n.subtitle = sSubTitle;
    }
    n.informativeText = sText;
    [NSUserNotificationCenter.defaultUserNotificationCenter deliverNotification:n];
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
    return sResult;
}

@end

4. 确保 AppKit.framework 是像往常一样的链接二进制文件。

5. 编辑您的 Info.plist 文件并添加两个参数。(注意,下面是它们的原始键名。)

NSAppleScriptEnabled = YES
OSAScriptingDefinition = commands.sdef

6. 编译您的项目。然后,右键单击 XCode 中黄色 Products 文件夹下的产品,然后选择 Show in Finder。

7. 单击您在 Finder 中看到的应用程序图标,然后按下左选项键。然后,在按住 Option 键的同时,转到 Finder 的编辑菜单并选择复制路径名。这会将您的应用程序的长路径名(在将其安装到 /Applications 之前)放在剪贴板上。

8. 只是为了测试这个,打开一个终端窗口然后输入这个,将下面的路径替换为你的 Cocoa 应用程序的路径。

osascript -e 'tell app "/crazy/long/path/Example.app" to notify user with title "My Title" subtitle "my sub" text "my text"'

9. 如果您的应用程序尚未打开,您应该会看到您的应用程序打开了一个停靠图标,然后在右上角您会看到一个通知出现在您的侧边栏通知中。如果您已经安装了一个 GUI 应用程序,它也会有您的 GUI 应用程序的图标。请注意,如果您多次运行该命令,AppleScript 是智能的,不会多次加载您的应用程序。另请注意,如果您单击侧边栏通知,它将打开您的应用程序屏幕(而不是将其图标化到停靠栏)。

更多信息

• 您可以修改第 2 步和第 3 步中的代码以执行不同的命令并对其采取不同的操作。

• 如果您需要,您可以修改您的 sdef(参见注释行)以返回结果。(非常适合调试!)

• 您的 sdef 文件可以包含用于不同类的单独命令。有关如何完成此操作,请参阅Apple 的示例

• sdef 文件有一些奇怪的语法,例如“code”参数。更多信息可在此处获得

• 如果您的应用程序与 LaunchDaemon 一起工作,但 LaunchDaemon 需要发送侧边栏通知,则此 AppleScript 连接非常有用。当然,有代码可以实现这一点,甚至有一个技巧可以让 LaunchDaemon 图标显示您的应用程序图标而不是终端图标,但它不能做的一件事是当您单击侧边栏通知时它打开 GUI 应用程序。相反,当单击该侧边栏通知时,它会打开 LaunchDaemon,这是一个不受欢迎的结果。因此,您可以使用这种 AppleScript 技术来唤醒您的 LaunchDaemon 并通知其 GUI 应用程序伴侣发送通知。这样,当单击侧边栏通知时,它会打开 GUI 应用程序,而不是 LaunchDaemon。

• 让另一个应用程序发送一些 AppleScript 很简单:

NSString *sScript = @"tell app \"/Applications/Calculator.app\" to activate";
NSAppleScript *oScript = [[NSAppleScript alloc] initWithSource:sScript];
NSDictionary *errorDict; 
NSAppleEventDescriptor *result = [oScript executeAndReturnError:&errorDict];
于 2016-04-17T01:08:08.517 回答