问题
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...$) ] }>
回答1:
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. ¯_(ツ)_/¯
来源:https://stackoverflow.com/questions/57438168/how-to-send-and-receive-nsappleeventdescriptor-when-using-nsworkspace-to-open-ur