NSSharingService Sharing Submenu
Asked Answered
C

3

15

How do I add the Share submenu in a Mac app? An example is Safari > File > Share. I poked at the Apple SharingServices sample code, but it does not include a working menu item.

enter image description here

Right now I have a button that displays a picker of available sharing services when tapped:

NSMutableArray *shareItems = [NSMutableArray arrayWithObject:[self.noteSynopsisView string]];
NSSharingServicePicker *sharingServicePicker = [[NSSharingServicePicker alloc] initWithItems:shareItems];
sharingServicePicker.delegate = self;
[sharingServicePicker showRelativeToRect:[self.shareButton bounds] ofView:self.shareButton preferredEdge:NSMaxYEdge];

I've also defined a Share submenu item under the File menu for my MainWindow.xib.

As I understand it, the NSSharingService list is being generated on the fly. So I can't really predefine the services to the menu item I have created in Interface Builder.

Thanks for your help.

Cleghorn answered 11/9, 2012 at 22:3 Comment(0)
A
17

Look at NSSharingService's +sharingServicesForItems:. In a -validateMenuItem: method you could create a submenu using the -title and -image of the NSSharingServices it returns. Associate each service with each menu item, and point the action of each menu item at this:

- (IBAction)shareFromService:(id)sender {
  [[sender representedObject] performWithItems: arrayOfItemsToShare];
}

It's really quite simple. Apple did a good job on this one.

Apperceive answered 19/9, 2012 at 1:54 Comment(3)
+1 A thanks from me as well! I was able to make this happen in the willOpen: delegate method of the NSMenu object.Charmain
Rather than validateMenuItem, it probably should be done in the menuNeedsUpdate: delegate. Thanks for the direction.Asset
I also note this does not include the "More" entry, not the Recent entries that the NSSharingServicePicker shows.Asset
H
7

I find the gist can help you easily create a submenu of proper services. https://gist.github.com/eternalstorms/4132533

It's a NSSharingServicePicker category.

Heraldic answered 6/3, 2013 at 7:29 Comment(0)
B
3

Swift version:

extension NSSharingServicePicker {
    
    class func menu(forSharingItems items: [AnyHashable]) -> NSMenu? {
        
        let sharingServices = NSSharingService.sharingServices(forItems: items)
        
        if sharingServices.isEmpty {
            return nil
        }
        
        let menu = NSMenu()
        
        for service in sharingServices {
            
            let item = MenuItem(label: service.title, action: #selector(_openSharingService), target: self, userInfo: ["sharingItems": items])
            
            item.image = service.image
            item.representedObject = service
            item.target = self
            menu.addItem(item)
            
        }
        
        return menu
        
    }
    
    @objc class private func _openSharingService(sender: MenuItem) {
        
        guard let items = sender.userInfo["sharingItems"] as? [AnyHashable], let service = sender.representedObject as? NSSharingService else {
            return
        }
        
        service.perform(withItems: items)
        
    }
    
}

class MenuItem: NSMenuItem {
    
    var userInfo: [String : Any] = [:]
    
    init(label: String, action: Selector?, target: AnyObject?, userInfo: [String : Any]) {
        self.userInfo = userInfo
        super.init(title: label, action: action, keyEquivalent: "")
    }
    
    required init(coder decoder: NSCoder) {
        super.init(coder: decoder)
    }
    
}
Bestride answered 1/4, 2021 at 7:47 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.