使用 NSWorkspace 打开应用程序之间的 URL 时如何发送和接收 NSAppleEventDescriptor? [英] How to send and receive NSAppleEventDescriptor when using NSWorkspace to open URLs between apps?

查看:32
本文介绍了使用 NSWorkspace 打开应用程序之间的 URL 时如何发送和接收 NSAppleEventDescriptor?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

NSWorkspace 有方法 open(_:withAppBundleIdentifier: [...] ):

<块引用>

从一组 URL 中打开一个或多个文件.

func open(_ urls: [URL],withAppBundleIdentifier bundleIdentifier: String?,选项:NSWorkspace.LaunchOptions = [],additionalEventParamDescriptor 描述符:NSAppleEventDescriptor?,launchIdentifiers 标识符:) ->布尔值


您要打开的应用程序的 NSApplicationDelegate 具有相应的方法,可以调用这些方法来打开您提供的 URL:

func application(_ sender: NSApplication, openFile filename: String) ->布尔值func 应用程序(_ 发送者:NSApplication,openFiles 文件名:[String])


回到 open(_:withAppBundleIdentifier: [...]),该方法有一个 NSAppleEventDescriptor 参数:

<块引用>

additionalEventParamDescriptor 描述符:NSAppleEventDescriptor?
在 AppleEvent 样式描述符中指定的其他选项.例如,您可以使用此参数指定启动应用程序时要打开的其他文档.


我想向将打开文件的应用发送更多信息.

这将类似于通知中的 userInfo 字典使用.

我已经构建了一个 NSAppleEventDescriptor 对象来表示这些信息.我可以在 NSWorkspace open( ... ) 函数中设置这个事件描述符.

但是我如何在目标应用的应用程序委托中接收这个事件描述符?

application(_: openFile:) 函数没有用于事件描述符或任何其他userInfo"类型附加信息的参数.


代码

根据答案和其他问题,我确定了以下解决方案.我现在正在为 Apple Events 获取触发处理程序.但是我在 NSWorkspace 函数上设置的 Apple Event 不是在处理程序中收到的那个!我如何获得我的 Apple 活动?


发送

让 appleEvent = NSAppleEventDescriptor(eventClass: AEEventClass(kCoreEventClass),事件ID:AEEventID(kAEOpenDocuments),目标描述符:无,返回ID:AEReturnID(kAutoGenerateReturnID),交易 ID:AETransactionID(kAnyTransactionID))appleEvent.setDescriptor(NSAppleEventDescriptor(string: "THIS IS A TEST"), forKeyword: keyDirectObject)让 didOpen = AppKit.NSWorkspace.shared.open([URL(fileURLWithPath: "/path/image.png")],withAppBundleIdentifier: bundleID,选项:[.withErrorPresentation],additionalEventParamDescriptor: appleEvent,启动标识符:无)

发送 Apple 事件:

<块引用>

<NSAppleEventDescriptor: 'aevt'\'odoc'{ '----':'utxt'("这是一个测试") }>


接收

class AppDelegate: NSObject, NSApplicationDelegate {func applicationDidFinishLaunching(_ aNotification: Notification) {NSAppleEventManager.shared().setEventHandler(self,andSelector: #selector(handle(event:replyEvent:)),forEventClass: AEEventClass(kCoreEventClass),andEventID: AEEventID(kAEOpenDocuments))}@objc func 句柄(事件:NSAppleEventDescriptor?,replyEvent:NSAppleEventDescriptor?){守卫让事件=事件,event.eventClass == AEEventClass(kCoreEventClass) &&event.eventID == AEEventID(kAEOpenDocuments) else {返回}守卫让 additionalEventParamDescriptor = event.paramDescriptor(forKeyword: keyAEPropData) else {返回}守卫让 directObject = additionalEventParamDescriptor.paramDescriptor(forKeyword: keyDirectObject) else {返回}打印(直接对象)}}

收到苹果事件:

<块引用>

<NSAppleEventDescriptor: 'aevt'\'odoc'{ '----':[ 'bmrk'(888/$626F6F6B7803000000000 [....] 00000AC01000000000000...$) ]

解决方案

kAEOpenDocuments 事件方法

- (void)applicationWillFinishLaunching:(NSNotification *)notification {[[NSAppleEventManager sharedAppleEventManager] setEventHandler:self andSelector:@selector(handleAppleEvent:withReplyEvent:) forEventClass:kCoreEventClass andEventID:kAEOpenDocuments];}- (void)handleAppleEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent {}

-[NSWorkspace openURLs: ...] 生成一个 kAEOpenDocuments 事件,其中包含作为沙盒保存书签数据的 URL.(参见 +[NSURL URLByResolvingBookmarkData: options: relativeToURL: bookmarkDataIsStale: error:]).

additionalEventParamDescriptor:

当使用带有自定义参数的 kAEOpenDocuments 创建 additionalEventParamDescriptor 时,此事件似乎与来自 -[NSWorkspace openURLs: ...].

NSAppleEventDescriptor *targetDescriptor = nil;NSAppleEventDescriptor *appleEvent = nil;targetDescriptor = [NSAppleEventDescriptor descriptorWithDescriptorType:typeApplicationBundleID数据:targetBundleID];appleEvent = [NSAppleEventDescriptor appleEventWithEventClass:kCoreEventClasseventID:kAEOpenDocuments目标描述符:目标描述符returnID:kAutoGenerateReturnID交易 ID:kAnyTransactionID];[appleEvent setParamDescriptor:[NSAppleEventDescriptor descriptorWithString:@"你真好看"]forKeyword:'urln'];[[NSWorkspace sharedWorkspace] openURLs:@[ [[NSBundle mainBundle] resourceURL] ]withAppBundleIdentifier:bundleIdentifier选项:NSWorkspaceLaunchNewInstanceadditionalEventParamDescriptor:appleEvent启动标识符:NULL];

示例 lldb 输出:

<块引用>

NSAppleEventDescriptor: 'aevt'\'odoc'{ ~'prdt':'aevt'\'odoc'{'urln':'utxt'("你真好看") }, '----':['bmrk'(1432/$626F6F6B980 ...) }

注意:当为 kAEOpenDocuments 设置 NSAppleEventManager 时,这会覆盖 application:openFile 的 AppKits 内置功能:code> 或 application:openFiles: 方法.自定义事件处理程序需要实现所有这些.

自定义事件方法

根据我的发现,发送带有自定义事件 ID 的自定义事件类不会触发事件处理程序.¯_(ツ)_/¯

NSWorkspace has the method open(_:withAppBundleIdentifier: [...] ):

Opens one or more files from an array of URLs.

func open(_ urls: [URL], 
     withAppBundleIdentifier bundleIdentifier: String?, 
     options: NSWorkspace.LaunchOptions = [], 
     additionalEventParamDescriptor descriptor: NSAppleEventDescriptor?, 
     launchIdentifiers identifiers:) -> Bool


The NSApplicationDelegate of the app you want to open has corresponding methods that are called to open the URL(s) you provide:

func application(_ sender: NSApplication, openFile filename: String) -> Bool
func application(_ sender: NSApplication, openFiles filenames: [String])


Back to open(_:withAppBundleIdentifier: [...]), that method has an NSAppleEventDescriptor parameter:

additionalEventParamDescriptor descriptor: NSAppleEventDescriptor?
Additional options specified in an AppleEvent-style descriptor. For example, you could use this parameter to specify additional documents to open when the app is launched.


I would like to send additional information to the app that will open the files.

This would be used similarly to the userInfo dictionary on a notification.

I've constructed a NSAppleEventDescriptor object to represent this information. I can set this event descriptor in the NSWorkspace open( ... ) function.

But how do I receive this event descriptor in Application Delegate of the target app?

The application(_: openFile:) functions have no parameters for the event descriptors or any other "userInfo"-type additional information.


Code

Based on answers and other questions, I settled on the solution below. I am now getting a triggered handler for Apple Events. But the Apple Event that I am setting on the NSWorkspace function is not the one that is received in the handler! How do I get my Apple Event instead?


Send

let appleEvent = NSAppleEventDescriptor(eventClass:       AEEventClass(kCoreEventClass),
                                        eventID:          AEEventID(kAEOpenDocuments),
                                        targetDescriptor: nil,
                                        returnID:         AEReturnID(kAutoGenerateReturnID),
                                        transactionID:    AETransactionID(kAnyTransactionID))
appleEvent.setDescriptor(NSAppleEventDescriptor(string: "THIS IS A TEST"), forKeyword: keyDirectObject)

let didOpen = AppKit.NSWorkspace.shared.open([URL(fileURLWithPath: "/path/image.png")],
                                             withAppBundleIdentifier: bundleID,
                                             options: [.withErrorPresentation],
                                             additionalEventParamDescriptor: appleEvent,
                                             launchIdentifiers: nil)

Sent Apple Event:

<NSAppleEventDescriptor: 'aevt'\'odoc'{ '----':'utxt'("THIS IS A TEST") }>


Receive

class AppDelegate: NSObject, NSApplicationDelegate {
    
    func applicationDidFinishLaunching(_ aNotification: Notification) {
        NSAppleEventManager.shared().setEventHandler(self,
                                                     andSelector: #selector(handle(event:replyEvent:)),
                                                     forEventClass: AEEventClass(kCoreEventClass),
                                                     andEventID: AEEventID(kAEOpenDocuments))
    }
    
    @objc func handle(event: NSAppleEventDescriptor?, replyEvent: NSAppleEventDescriptor?) {
        guard let event = event,
            event.eventClass == AEEventClass(kCoreEventClass) && event.eventID == AEEventID(kAEOpenDocuments) else {
            return
        }

        guard let additionalEventParamDescriptor = event.paramDescriptor(forKeyword: keyAEPropData) else {
            return
        }

        
        guard let directObject = additionalEventParamDescriptor.paramDescriptor(forKeyword: keyDirectObject) else {
            return
        }
        
        print(directObject)
    }
    
}

Received Apple Event:

<NSAppleEventDescriptor: 'aevt'\'odoc'{ '----':[ 'bmrk'(888/$626F6F6B7803000000000 [....] 00000AC01000000000000...$) ] }>

解决方案

kAEOpenDocuments events approach

- (void)applicationWillFinishLaunching:(NSNotification *)notification {
    [[NSAppleEventManager sharedAppleEventManager] setEventHandler:self andSelector:@selector(handleAppleEvent:withReplyEvent:) forEventClass:kCoreEventClass andEventID:kAEOpenDocuments];
}

- (void)handleAppleEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent {

}

-[NSWorkspace openURLs: ...] generates an kAEOpenDocuments event that contains the URLs as sandbox save bookmark data. (See +[NSURL URLByResolvingBookmarkData: options: relativeToURL: bookmarkDataIsStale: error:]).

The additionalEventParamDescriptor:

When creating the additionalEventParamDescriptor with kAEOpenDocuments with a custom parameters, this event seems to get merged with the underlaying kAEOpenDocuments event from -[NSWorkspace openURLs: ...].

NSAppleEventDescriptor *targetDescriptor = nil;
NSAppleEventDescriptor *appleEvent = nil;

targetDescriptor = [NSAppleEventDescriptor descriptorWithDescriptorType:typeApplicationBundleID
                                                                   data:targetBundleID];
appleEvent = [NSAppleEventDescriptor appleEventWithEventClass:kCoreEventClass
                                                      eventID:kAEOpenDocuments
                                             targetDescriptor:targetDescriptor
                                                     returnID:kAutoGenerateReturnID
                                                transactionID:kAnyTransactionID];
[appleEvent setParamDescriptor:[NSAppleEventDescriptor descriptorWithString:@"You're so good looking"]
                    forKeyword:'urln'];

[[NSWorkspace sharedWorkspace] openURLs:@[ [[NSBundle mainBundle] resourceURL] ]
                withAppBundleIdentifier:bundleIdentifier
                                options:NSWorkspaceLaunchNewInstance
         additionalEventParamDescriptor:appleEvent
                      launchIdentifiers:NULL];

Sample lldb output:

NSAppleEventDescriptor: 'aevt'\'odoc'{ ~'prdt':'aevt'\'odoc'{ 'urln':'utxt'("You're so good looking") }, '----':[ 'bmrk'(1432/$626F6F6B980 ...) }

Note: When setting the NSAppleEventManager for kAEOpenDocuments this overwrites AppKits build-in functionality of the application:openFile: or application:openFiles: methods. The custom event handler needs to implement all that.

custom events approach

Based on my findings sending a custom event class with a custom event ID does not trigger the event handler. ¯_(ツ)_/¯

这篇关于使用 NSWorkspace 打开应用程序之间的 URL 时如何发送和接收 NSAppleEventDescriptor?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆