可编写脚本的应用程序示例
Scriptable Application Example
显然,有一种方法可以让我的 GUI 应用程序可以使用 AppleScript 编写脚本。因此,例如,我可以有一个命令行应用程序(如来自 LaunchDaemon 的 运行)告诉我的 GUI 应用程序 post 侧边栏通知。有没有人有一个简单的例子来解释这个?我在 Apple 网站上看到的一切都很难理解。
我想创建一条 AppleScript 消息,例如:
tell "My App" to notify with title "Title" subtitle "subtitle" text "some text"
在我的 CLI 应用程序中,然后我的 GUI 应用程序唤醒、接收并处理它。
这比我想象的要容易!一些注意事项:
- 您必须启用您的 Cocoa 应用程序以在您的 Info.plist 文件中接收带有两个特殊参数的 AppleScript 事件:
NSAppleScriptEnabled
和 OSAScriptingDefinition
.
- 一个名为 sdef 文件的特殊 XML 文件将您的 AppleScript 语法直接映射到 Objective C class 来处理它。
- class 必须子class
NSScriptCommand
及其方法 performDefaultImplementation
,然后您可以访问其中的 [self directParameter]
和 [self evaluatedArguments]
。
- 因此,当您发送 AppleScript 命令时,您的应用程序会自动打开(即使已关闭),并且不会加载它的多个实例,这很好。然后,如果 AppleScript 中的语法正确,它会将其发送到 class 进行处理。 sdef 文件指示哪个 class.
- 如果您需要,您的命令还可以发回响应。或者它可以选择不这样做。
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 = commands.sdef
6.编译你的项目。然后,右击XCode中黄色Products文件夹下的产品,选择Show in Finder
7.单击您在 Finder 中看到的应用程序图标,然后按下左 Option 键。然后,在按住 Option 键的同时,转到 Finder 的“编辑”菜单并选择“复制路径名”。这会将应用程序的长路径名(在将其安装到 /Applications 之前)放在剪贴板上。
8。只是为了测试这个,打开一个终端 window 然后输入这个,将下面的路径替换为你的 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(参见注释行)以返回 return 结果,如果您需要的话。 (非常适合调试!)
• 您的 sdef 文件可以有单独的命令来分隔 classes。请参阅 Apple's example 了解这是如何完成的。
• sdef 文件有一些奇怪的语法,例如“代码”参数。更多 info is available here.
• 如果您有一个与 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];
显然,有一种方法可以让我的 GUI 应用程序可以使用 AppleScript 编写脚本。因此,例如,我可以有一个命令行应用程序(如来自 LaunchDaemon 的 运行)告诉我的 GUI 应用程序 post 侧边栏通知。有没有人有一个简单的例子来解释这个?我在 Apple 网站上看到的一切都很难理解。
我想创建一条 AppleScript 消息,例如:
tell "My App" to notify with title "Title" subtitle "subtitle" text "some text"
在我的 CLI 应用程序中,然后我的 GUI 应用程序唤醒、接收并处理它。
这比我想象的要容易!一些注意事项:
- 您必须启用您的 Cocoa 应用程序以在您的 Info.plist 文件中接收带有两个特殊参数的 AppleScript 事件:
NSAppleScriptEnabled
和OSAScriptingDefinition
. - 一个名为 sdef 文件的特殊 XML 文件将您的 AppleScript 语法直接映射到 Objective C class 来处理它。
- class 必须子class
NSScriptCommand
及其方法performDefaultImplementation
,然后您可以访问其中的[self directParameter]
和[self evaluatedArguments]
。 - 因此,当您发送 AppleScript 命令时,您的应用程序会自动打开(即使已关闭),并且不会加载它的多个实例,这很好。然后,如果 AppleScript 中的语法正确,它会将其发送到 class 进行处理。 sdef 文件指示哪个 class.
- 如果您需要,您的命令还可以发回响应。或者它可以选择不这样做。
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 = commands.sdef
6.编译你的项目。然后,右击XCode中黄色Products文件夹下的产品,选择Show in Finder
7.单击您在 Finder 中看到的应用程序图标,然后按下左 Option 键。然后,在按住 Option 键的同时,转到 Finder 的“编辑”菜单并选择“复制路径名”。这会将应用程序的长路径名(在将其安装到 /Applications 之前)放在剪贴板上。
8。只是为了测试这个,打开一个终端 window 然后输入这个,将下面的路径替换为你的 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(参见注释行)以返回 return 结果,如果您需要的话。 (非常适合调试!)
• 您的 sdef 文件可以有单独的命令来分隔 classes。请参阅 Apple's example 了解这是如何完成的。
• sdef 文件有一些奇怪的语法,例如“代码”参数。更多 info is available here.
• 如果您有一个与 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];