objective-c - 可编写脚本的应用程序示例

标签 objective-c macos cocoa applescript scriptable

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

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

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


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

最佳答案

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


您必须使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 =是
OSAScriptingDefinition =命令.sdef

6.编译您的项目。然后,右键单击XCode中黄色“产品”文件夹下的产品,然后选择“在Finder中显示”。

7.单击您在Finder中看到的该应用程序图标,然后向下按左Option键。然后,在按住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's example

•sdef文件具有一些奇怪的语法,例如“ code”参数。更多info is available here

•如果您的应用程序可以与LaunchDaemon结合使用,但是LaunchDaemon需要发送边栏通知,则此AppleScript连接非常有用。当然,有代码可以做到这一点,甚至还有一个技巧可以使LaunchDaemon图标显示您的应用程序图标而不是Terminal图标,但是它不能做的一件事就是使它变为当您单击该侧边栏通知时打开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];

关于objective-c - 可编写脚本的应用程序示例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36663424/

相关文章:

objective-c - 单击 NSTextField 标签以模拟指向文件夹的超链接

ios - 使用 ObjC 类包含在 .cpp 文件中时出错(unqualified-id @class)

macos - 由于明显的 VirtualBox 正在运行,重新安装 Boot2Docker 失败 - 如何关闭它们?

macos - NPM 安装失败

mysql - Mac OS X、MySQL 首选项面板不工作

ios - 什么 NSDateFormat 是 1991-07-26T05 :45:50. 163

objective-c - 核心数据 NSFetchRequest 问题

objective-c - OS X Windows 风格的应用栏

cocoa : Scale Image dragged into an ImageWell

ios - JsonModelLib : Unable to parse if a variable does not exists in JSON