URL Scheme - Qt 和 Mac

7

我正在尝试为我的应用程序实现自定义URL方案。我已添加了Info.plist所需的行。在调用指定的URL(例如:myapp://)后,应用程序会启动。

如果我想处理URL,我找到了以下步骤:

@interface EventHandler : NSObject {
}
@end

@implementation EventHandler
- (id)init {
    self = [super init];

    if (self) {
        NSLog(@"eventHandler::init");

        NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
        [defaultCenter addObserver:self
                        selector:@selector(applicationDidFinishLaunching:)
//                        name:NSApplicationWillFinishLaunchingNotification
          name:NSApplicationDidFinishLaunchingNotification
                        object:nil];
    }
    return self;
}

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    NSAppleEventManager *appleEventManager = [NSAppleEventManager sharedAppleEventManager];
    [appleEventManager setEventHandler:self andSelector:@selector(handleGetURLEvent:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL];
}

- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
{
    NSString* url = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
    NSLog(@"%@", url);
}

@end

如果应用程序正在运行,则上述代码有效,但是如果调用URL并且应用程序已终止,则不会捕获事件。我认为这是因为 NSApplicationDidFinishLaunchingNotification。将其更改为 NSApplicationWillFinishLaunchingNotification 导致未捕获任何事件。也许Qt在我之前处理了它,但我找不到解决问题的方法。


似乎监听NSApplicationDidBecomeActiveNotification通知可以解决问题。但我认为这不是最好的方法,所以我会保持问题开放,等待更好的想法 :) - birmacher
2个回答

9

我也试图让我的基于Qt的应用程序在Mac上处理自定义URL方案,并走了与原帖作者相同的路线。事实证明,Qt4已经支持Mac上的URL事件,无需编写Objective-C代码来接收它们。这实际上是您未能在响应NSApplicationWillFinishLaunchingNotification设置事件处理程序时接收任何URL事件的原因:Qt在此之后注册了自己的处理程序。

当触发具有您自定义方案的URL时,您的Qt应用程序将接收到FileOpenEvent。请注意,接收事件的是QApplication实例。您可以通过使应用程序子类化QApplication或在标准QApplication上安装事件过滤器来捕获它。我选择了第二种方法。

这是我的自定义事件过滤器类FileOpenEventFilter的eventFilter方法。当事件包含非空URL时,它只会发出urlOpened信号。它还保存最后打开的URL,以防我的主窗口尚未完全初始化时事件到达(当单击自定义URL时,在我的应用程序不运行时会发生这种情况)。

bool FileOpenEventFilter::eventFilter(QObject* obj, QEvent* event)
{
    if (event->type() == QEvent::FileOpen)
    {
        QFileOpenEvent* fileEvent = static_cast<QFileOpenEvent*>(event);
        if (!fileEvent->url().isEmpty())
        {
            m_lastUrl = fileEvent->url().toString();
            emit urlOpened(m_lastUrl);
        }
        else if (!fileEvent->file().isEmpty())
        {
            emit fileOpened(fileEvent->file());
        }

        return false;
    }
    else
    {
        // standard event processing
        return QObject::eventFilter(obj, event);
    }
}

1
我在应用程序代理的 applicationWillFinishLaunching: 方法中注册了我的处理程序,并且我没有遗漏任何事件。你可能太晚初始化你的 EventHandler 对象而无法收到通知。如果你想将它保持为一个单独的类,那没关系,但是你应该在应用程序代理的 applicationWillFinishLaunching: 方法中创建你的对象并将其注册到 NSAppleEventManager 中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接