简体   繁体   中英

Handling Click Events with NSUserNotification Sent from CLI App

I have created an OSX command line application in Objective C and it now fires sidebar notification events like so:

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

I even used this technique to make it use another application's icon instead of a black terminal icon.

The trouble now, however, is that when you click the item, it launches the command line application instead of the application that I desire. How can I make the click on the sidebar notification launch my separate GUI application?

EDIT : Perhaps I need to use AppleScript to tell my CLI application to call my GUI application and instruct it to send a notification? That way, the event delegate is set to the GUI application, not the CLI application. If that's the case, I don't know how to make AppleScript launch and pass a message to my GUI application, nor how the GUI application can read that message.

The solution is that you don't do it this way. If you have a CLI app that needs to post a sidebar notification to the user, and when the user clicks it, it opens a GUI companion application, then there are two ways to handle this:

• Make your GUI application scriptable so that it can receive an AppleScript message from your CLI app and act upon it (like send a sidebar notification). This is explained here . This is the most elegant technique.

• Or, you can follow the following example to make a GUI-less Cocoa application that acts as an intermediary between the CLI app and the GUI companion application.

GUI-less Cocoa application intermediary technique

1. Create what's called a GUI-less Cocoa application that will act as an intermediary between your CLI app and the GUI application. This eliminates the ugly terminal window from opening if you had created a CLI app. Steps:

a. Create a new default Cocoa application.

b. Remove NSMainNibFile entry out of the Info.plist.

c. Remove the XIB file and the default AppDelegate stuff (.m, .h).

d. Comment out the call to NSApplicationMain in your main.m in the main() function.

e. Add the LSUIElement key to your Info.plist and set it to YES.

2. Set an icon for this GUI-less application by copying the AppIcon.icns file from your compiled GUI application into this GUI-less application in the same directory where the main.m file is located. Then, in your Info.plist of your GUI-less application, set CFBundleIconFile to simply AppIcon. Then, do a Clean on your project so that it will use this new icon. Note -- XCode may act strange where it won't show the icon properly, but when you view it in Finder it will be fine.

3. Set your main.m of the GUI-less Cocoa application to this:

#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. Compile this application and stick this app folder inside your /Applications/Example.app/Contents/Resources (change that of course) folder.

5. Now you can use the following code from your CLI app to send the notification and will use the icon used in your GUI application, which makes is very pleasant. When the user clicks the notification, it will open your GUI application instead of the GUI-less application. (Actually, when you click the sidebar notification, it opens the GUI-less application, but that's not visible. The GUI-less application sees no parameters are passed to it, so it doesn't show another notification. Instead, it knows to launch your GUI application via AppleScript.)

#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());

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM