【问题标题】:Mac Mountain Lion send notification from CLI appMac Mountain Lion 从 CLI 应用程序发送通知
【发布时间】:2012-07-27 14:12:16
【问题描述】:

如何从命令行应用程序向通知中心发送通知?到目前为止,我的尝试编译并运行,但没有成功通知我。

例子

#import <Cocoa/Cocoa.h>

int main(int argc, const char * argv[]) {
    NSLog(@"Running notifications");

    NSUserNotification *note = [[NSUserNotification alloc] init];
    [note setTitle:@"Test"];
    [note setInformativeText:@"Woot"];

    NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
    [center scheduleNotification: note];

    return 0;
}

然后我编译如下:

clang -framework cocoa /tmp/Notes.m

我得到了

 2012-07-29 16:08:35.642 a.out[2430:707] Running notifications

作为输出,但没有通知:(

代码设计是其中的一个因素吗?

【问题讨论】:

  • 该文档特别提到了“应用程序或帮助应用程序”,因此它可能拒绝来自命令行程序的请求。另外,看看使用deliverNotification: 是否有任何不同。
  • @KevinGrant 感谢您的建议,没有不同的结果。看起来你和 omz 对需要帮助应用程序的看法是正确的,但我会抱有更长的希望。
  • @KevinGrant 在一个有趣的注释上,deliverNotification 是我让它在 App 包中工作的唯一方法。很好的呼吁。

标签: objective-c cocoa nsnotificationcenter osx-mountain-lion nsusernotification


【解决方案1】:

github 上已经有一个终端通知器:https://github.com/julienXX/terminal-notifier

自述文件说:

它目前被打包为一个应用程序包,因为 NSUserNotification 没有 从“基础工具”工作。雷达://11956694

【讨论】:

    【解决方案2】:

    这是我必须做的。请注意,这样的运行循环具有非常小的延迟。有必要查看该通知。

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

    但是,您可能会注意到它显示的是终端图标而不是漂亮的图标。为了解决这个问题,有一种记录不充分的技术。但是,不幸的是,使用这种技术,我不知道如何将其链接到我自己的自定义图标 - 仅链接到已安装的应用程序图标。

    1. 将 Info.plist 文件添加到您的项目中。如果您的项目名为 acme,通常 XCode 会在您的项目中创建一个名为 acme 的黄色文件夹并将您的文件放在那里。因此,在此处添加一个 Info.plist,并且不要忘记在 Info 中将 I 大写。顺便说一句,不用担心将 Info.plist 文件与您的 CLI 应用程序一起分发——它会自动捆绑到二进制文件本身中。

    2. 接下来,打开 Info.plist 并添加一个新项目。它会提示您输入一些默认项目。选择捆绑标识符。现在,在此键的值部分,将其设置为 Applications 文件夹中已安装应用程序的有效捆绑标识符。所以对我来说,我的 LaunchDaemon 是需要发送通知的命令行应用程序,我在 /Applications 文件夹中有一个与之匹配的 GUI 应用程序,名为 /Applications/Acme.app。因此,在 Acme.app 的 Info.plist 文件中,我有我现有的 com.acme.myapp 包标识符。同样,该 GUI 应用程序上已经有一个图标。因此,我将我在 CLI 应用程序的 Info.plist 文件包标识符中的值设置为 com.acme.myapp 以便它使用该图标。现在,您也可以根据需要将其设置为 com.apple.finder,它会抓取 Finder 图标。 (顺便说一句,如果您知道如何将图标与 CLI 应用程序本身捆绑在一起,而不是从另一个已安装的应用程序中借用它,请告诉我。)

    3. 现在,进入您的构建设置并使用搜索框并输入“infoplist”。您将看到一个名为“Info.plist 文件”的项目。将其设置为文件的相对文件夹路径。所以,还记得我提到我的项目有一个黄色的“acme”文件夹,而我的 Info.plist 文件就在其中吗?所以,我所要做的就是在第二列(左侧表示“已解决”)和第三列下键入“acme/Info.plist”。

    4. 现在,在构建设置中,搜索“创建信息”。您将看到一个条目“在二进制文件中创建 Info.plist 部分”。在第二列和第三列中,将其设置为是。

    此问题的另一个问题是,当您单击警报时,它会启动命令行应用程序,而不是您可能想要加载的 GUI 应用程序。

    【讨论】:

      【解决方案3】:

      我发现NSUserNotificationCenter[[NSBundle mainBundle] bundleIdentifier] 返回正确的标识符时有效。所以,我写了一些你可以在 https://github.com/norio-nomura/usernotification 找到的 swizzling 代码

      它可以在没有应用程序包的情况下发送NSUserNotification

      【讨论】:

      • 这是一个非常棒的黑客攻击!用另一种方法替换一种方法并欺骗运行时调用您自己定义的方法。先生干得好!
      • 您不必再使用 swizzling hack 的方法了(不再?)。只需为您的命令行应用程序创建一个Info.plist 文件,在构建设置中链接它并设置一些包标识符。然后设置CREATE_INFOPLIST_SECTION_IN_BINARY 构建选项(您需要这个,因为命令行应用程序不是捆绑包,因此不能将 Info.plist 作为文件包含在内)。现在mainBundle 应该返回正确的包标识符并且应该显示通知。
      【解决方案4】:

      我不确定,但也许 scheduleNotification 调用是异步的,您的应用程序在任何事情发生之前就退出了。
      尝试添加:

      [[NSRunLoop currentRunLoop] run];
      

      到 main 的结尾。

      【讨论】:

      • 不幸的是,这只会导致它无限期挂起
      • 嗯,是的,电话不会返回。这只是作为测试假设的测试。通知是否发生?
      • IIRC 使用 NSUserNotificationCenter deliverNotification: 确实需要一些时间,并且退出太快会阻止通知出现,但使用 NSUserNotificationCenter scheduleNotification: 不需要额外的时间,您可以在它返回后立即退出。
      • 这就是你想要的:[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
      【解决方案5】:

      虽然我没有找到任何关于此的特定文档,但我认为您需要成为一个应用程序(捆绑包)才能传递通知。请注意,通知中心 UI 始终显示发出通知的应用程序的名称和图标。使用命令行工具是不可能的。

      不过似乎不需要代码签名。

      也许您可以编写一个助手应用程序,它只传递通知并从您的命令行工具与您的助手应用程序进行通信(例如,使用NSDistributedNotificationCenter)。

      【讨论】:

      • 不幸的是,您似乎必须拥有一个应用程序包。该代码适用于应用程序,但不适用于 cli 工具。谢谢。
      • 我真的想要一些关于要求的文档。我在 Apple 的网站上找不到任何东西。我至少已经排除了代码签名和权利是必要或充分的,尽管通过将它们添加到仍然无法发布通知的命令行应用程序以及从未签名、未授权的应用程序中获取通知。
      • @barnes53 是的,我也想看看这些要求。通过实验我们可以确定 CLI 应用程序无法做到这一点,但我想知道 Apple 的想法。不幸的是,我怀疑我们很快就会看到它。
      猜你喜欢
      • 2012-07-31
      • 2012-06-19
      • 1970-01-01
      • 1970-01-01
      • 2014-04-23
      • 1970-01-01
      • 2012-07-21
      • 2012-10-24
      • 2019-09-11
      相关资源
      最近更新 更多