从最小的独立 Objective-C 程序中抛出 MacOS 通知?

Throwing a MacOS notification from a minimal standalone Objective-C program?

我正在尝试在 C 代码库中实现 MacOS 上的推送通知。理想情况下,只有一个 Objective-C 文件包含 (1) 我可以调用的 public C 函数和 (2) 我可以用来发出通知的一些 Objective-C 代码。这样,可以在构建过程中无缝地编译和 linked 源文件。

为此,我一直在尝试创建一个最小的示例,它可以只用一个 .m 文件(而不是整个 XCode 项目)抛出通知,就像讨论的那样在 NSUserNotificationCenter not showing notifications。但是,有两个问题:

  1. 尽管尝试了上述 link 中的解决方案,但我仍然无法使代码正常工作。它编译并运行但不抛出通知。
  2. 如果可能,我们想切换到 new user notifications API。不过,如果暂时无法做到这一点,也没什么大不了的。

这是我到目前为止尝试过的方法:

#import <Foundation/Foundation.h>
#import <Foundation/NSUserNotification.h>

@interface AppDelegate : NSObject <NSUserNotificationCenterDelegate>
@end

@implementation AppDelegate

- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center 
                               shouldPresentNotification:(NSUserNotification *)notification {
  return YES;
}

- (void)throwNotification {
    NSUserNotification *userNotification = [[NSUserNotification alloc] init];
    userNotification.title = @"Some title";
    userNotification.informativeText = @"Some text";

    printf("trying to throw {%s %s}\n", [[userNotification title] UTF8String], [[userNotification informativeText] UTF8String]);

    [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:userNotification];
}

@end

int main (int argc, const char * argv[]) {
    AppDelegate *app = [[AppDelegate alloc] init];
    [app throwNotification];

    return 0;
}

这是用cc -framework Foundation -o app main.m编译的。

如有任何见解,我们将不胜感激!

问题是为了显示通知,您需要 a proper bundle identifier

我们将在 bit of the code from here 中等待通知显示。我们可以将一个 Info.plist 文件嵌入到编译后的二进制文件中,这将完成与名为 notify.m:

的文件中的调配代码相同的事情
#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>

@interface AppDelegate : NSObject<NSUserNotificationCenterDelegate>

@property (nonatomic, assign) BOOL keepRunning;

@end

int main (int argc, const char * argv[])
{
    @autoreleasepool {
        NSApplication *app = [NSApplication sharedApplication];
        AppDelegate *appdel = [[AppDelegate alloc] init];
        app.delegate = appdel;
        NSUserNotificationCenter *nc = [NSUserNotificationCenter defaultUserNotificationCenter];
        nc.delegate = appdel;
        appdel.keepRunning = TRUE;
        NSUserNotification *userNotification = [[NSUserNotification alloc] init];
        userNotification.title = @"Some title";
        userNotification.informativeText = @"Some text";

        [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:userNotification];
        while (appdel.keepRunning) {
            [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
        }
    }

    return 0;
}

@implementation AppDelegate

- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center
                               shouldPresentNotification:(NSUserNotification *)notification {
  return YES;
}

- (void)userNotificationCenter:(NSUserNotificationCenter *)center didDeliverNotification:(NSUserNotification *)notification
{
    self.keepRunning = NO;
}

@end

我构建了一个包含以下内容的 Info.plist 文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>CFBundleIdentifier</key>
  <string>com.apple.finder</string>
</dict>
</plist>

Please use an appropriate bundle identifier, as com.apple.finder will cause all these notifications to appear to come from macOS Finder, which might be confusing to users. I then compile it using:

clang -o notify -framework Cocoa notify.m -Wl,-sectcreate,_\_TEXT,__info_plist,Info.plist

there's a \ in that build line to avoid the markdown parsing of the underscores, but it's not needed for the actual build command line.