使用从 CLI 应用程序发送的 NSUserNotification 处理点击事件

Handling Click Events with NSUserNotification Sent from CLI App

我在 Objective C 中创建了一个 OSX 命令行应用程序,它现在触发侧边栏通知事件,如下所示:

NSUserNotification *n = [[NSUserNotification alloc] init];
n.title = @"My Title";
n.subtitle = @"my subtitle";
n.informativeText = @"some informative text";
[NSUserNotificationCenter.defaultUserNotificationCenter deliverNotification:n];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];

我什至用 this technique 让它使用另一个应用程序的图标而不是黑色终端图标。

然而,现在的问题是,当您单击该项目时,它会启动命令行应用程序,而不是我想要的应用程序。如何让点击侧边栏通知启动我单独的 GUI 应用程序?

编辑:也许我需要使用 AppleScript 告诉我的 CLI 应用程序调用我的 GUI 应用程序并指示它发送通知?这样,事件委托就设置为 GUI 应用程序,而不是 CLI 应用程序。如果是这样的话,我不知道如何启动 AppleScript 并将消息传递给我的 GUI 应用程序,也不知道 GUI 应用程序如何读取该消息。

解决办法就是不要这样做。如果您有一个 CLI 应用程序需要 post 向用户发送侧边栏通知,并且当用户单击它时,它会打开一个 GUI 配套应用程序,那么有两种方法可以处理此问题:

• 使您的 GUI 应用程序可编写脚本,以便它可以从您的 CLI 应用程序接收 AppleScript 消息并对其执行操作(例如发送侧边栏通知)。这是解释。这是最优雅的技术。

• 或者,您可以按照以下示例制作无 GUI Cocoa 应用程序,充当 CLI 应用程序和 GUI 配套应用程序之间的中介。

无 GUI Cocoa 应用中介技术

1。创建所谓的 GUI-less Cocoa application ,它将充当 CLI 应用程序和 GUI 应用程序之间的中介。如果您创建了一个 CLI 应用程序,这将消除丑陋的终端 window 的打开。步骤:

一个。创建一个新的默认 Cocoa 应用程序。

b。从 Info.plist.

中删除 NSMainNibFile 条目

c。删除 XIB 文件和默认的 AppDelegate 内容(.m、.h)。

d。在 main() 函数的 main.m 中注释掉对 NSApplicationMain 的调用。

e。将 LSUIElement 键添加到您的 Info.plist 并将其设置为 YES。

2。通过将已编译的 GUI 应用程序中的 AppIcon.icns 文件复制到 main.m 文件所在的同一目录中的此无 GUI 应用程序中,为该无 GUI 应用程序设置一个图标。然后,在无 GUI 应用程序的 Info.plist 中,将 CFBundleIconFile 设置为简单的 AppIcon。然后,对您的项目执行清理,以便它使用这个新图标。注意 -- XCode 无法正确显示图标可能会很奇怪,但是当您在 Finder 中查看它时就没问题了。

3。将无 GUI Cocoa 应用程序的 main.m 设置为:

#import <Cocoa/Cocoa.h>

int main(int argc, const char * argv[]) {


    NSString *sTitle = @"";
    NSString *sSubTitle = @"";
    NSString *sText = @"";
    try {
        sTitle = @(argv[1]);
        sSubTitle = @(argv[2]);
        sText = @(argv[3]);
    } catch (...) {
    }

    if ([sTitle isEqualToString:@""]) {
        NSString *script = @"tell app \"";
        // change me to your real GUI application path
        script = [script stringByAppendingString:@"/Applications/Example.app"];
        script = [script stringByAppendingString:@"\" to activate"];
        NSAppleScript *appleScript = [[NSAppleScript alloc] initWithSource:script];
        [appleScript executeAndReturnError:nil];
        exit(0);
    }

    
    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 0;

}

4。编译此应用程序并将此应用程序文件夹粘贴到您的 /Applications/Example.app/Contents/Resources(当然要更改)文件夹中。

5。现在您可以使用 CLI 应用程序中的以下代码发送通知,并将使用您的 GUI 应用程序中使用的图标,这非常令人愉快。当用户单击通知时,它将打开您的 GUI 应用程序而不是无 GUI 应用程序。 (实际上,当您单击侧边栏通知时,它会打开无 GUI 应用程序,但那是不可见的。无 GUI 应用程序看不到任何参数传递给它,因此它不会显示另一个通知。相反,它知道通过 AppleScript 启动您的 GUI 应用程序。)

#include <string>

std::string sTitle = "Sample Title";
std::string sSubTitle = "sample subtitle";
std::string sText = "some text";
std::string sCmd = "open -a \"";
// change me to the path of your GUI application
sCmd += "/Applications/Example.app";
// change notify.app to the name of your GUI-less application
sCmd += "/Contents/Resources/notify.app";
sCmd += "\" --args ";
sCmd += "\"" + sTitle + "\" ";
sCmd += "\"" + sSubTitle + "\" ";
sCmd += "\"" + sText + "\"";
system(sCmd.c_str());