Search code examples
swiftmacossharephoto

NSSharingService.perform() with Send To Photos


On MacOS (catalyst app, but AppKit bundle) I am creating Share submenu in main app menu "on fly" from menu delegate like this:

func menuWillOpen(_ menu: NSMenu) {

    self.provider = NSItemProvider(contentsOf: url)! //url points to existing temporary file of type .png
    
    menu.removeAllItems()
    let srvcs = NSSharingService.sharingServices(forItems: [self.provider!])
    for srv in srvcs {
        let it = NSMenuItem(title: srv.menuItemTitle, action: #selector(openSharingService), keyEquivalent: "")
        it.image = srv.image
        it.representedObject = srv
        it.target = self
        
        menu.addItem(it)
    }
}
@objc private func openSharingService(sender: NSMenuItem) {
    let service = (sender.representedObject as! NSSharingService)
    service.perform(withItems: [self.provider!])
}

It works well for any share type, except for Send To Photos. With Send To Photos, I am getting this error in console:

2021-10-27 08:59:02.042220+0200 Calculator2[14383:7732689] [xpc.exceptions] <NSXPCConnection: 0x6000008470c0> connection to service on pid 14388 named com.apple.share.System.add-to-iphoto.apple-extension-service: Exception caught during decoding of received selector _completeRequestReturningItems:forExtensionContextWithUUID:completion:, dropping incoming message.
Exception: Exception while decoding argument 0 (#2 of invocation):
Exception: value for key 'NS.objects' was of unexpected class 'NSURL (0x7fff801889e8) [/System/Library/Frameworks/CoreFoundation.framework]'. Allowed classes are '{(
    "NSDate (0x7fff80188600) [/System/Library/Frameworks/CoreFoundation.framework]",
    "NSString (0x7fff801ba8d0) [/System/Library/Frameworks/Foundation.framework]",
    "NSNumber (0x7fff801ba3a8) [/System/Library/Frameworks/Foundation.framework]",
    "NSData (0x7fff801885d8) [/System/Library/Frameworks/CoreFoundation.framework]",
    "NSDictionary (0x7fff80188650) [/System/Library/Frameworks/CoreFoundation.framework]",
    "NSArray (0x7fff80188510) [/System/Library/Frameworks/CoreFoundation.framework]"
)}'.

Photos app is opened and image is added to it, but my app recieves the above error and its menus are all grayed out until restarted. Am I doing something wrong here?

EDIT: I tried to call service like this (passing NSImage):

            self.provider!.loadDataRepresentation(forTypeIdentifier: "public.png", completionHandler: {(data, error) in
                let img = NSImage(data: data!)
                DispatchQueue.main.async {
                    service.perform(withItems: [img])
                }
           })

... and it fails with exactly the same error. Again complaining against NSURL, even if I don't pass NSURL at all.


Solution

  • So I could not fing the error, but I managed to make workaround. I added folloowing code to my func openSharingService(), in order to recognize Add to Photos and handle it in a different way:

    if ( (service == NSSharingService(named: .addToIPhoto)) && (self.provider!.hasItemConformingToTypeIdentifier("public.png")) ) {
            self.provider!.loadObject(ofClass: NSURL.self, completionHandler: {(val, error) in
                //print(val)
                DispatchQueue.main.async {
                    let u = val as! NSURL
                    self.photosHandler(u)
                    NSWorkspace.shared.launchApplication("Photos")
                }
            })
        }
    

    self.photosHandler is a callback filled from my catalyst bundle of app, that adds photo using PHPhotoLibrary:

    PHPhotoLibrary.requestAuthorization(for: .addOnly, handler: self.OnAuthorizationDone)
    

    (OnAuthorizationDone() also has to be implemented, using PHPhotoLibrary.shared().performChanges() and PHAssetChangeRequest.creationRequestForAssetFromImage() )