Implementing the UIActivityItemSource protocol

2019-02-16 11:05发布

I have these protocol methods,

activityViewControllerPlaceholderItem: and activityViewController:itemForActivityType:

but they never get called. How do I tell the UIActivityViewController to call them?

I also have an UIActivityItemProvider subclass, however I'm confused as to who calls these 2 methods. I'd really appreciate some sample code, as I can't find anything on the web. :)

标签: ios ios6
4条回答
老娘就宠你
2楼-- · 2019-02-16 11:16

According to the documentation. The array of activity items that you pass to
-initWithActivityItems:applicationActivities: can be an array of data objects, like strings or images, or it can be array of objects that implement the UIActivityItemSource protocol.

If you pass an array of objects that implement the UIActivityItemSource protocol then your instance of UIActivityViewController will call those methods on your activity items. Those objects do not necessarily have to be subclasses of UIActivityItemProvider. UIActivityItemProvider is just a class that conforms to this protocol.

查看更多
Summer. ? 凉城
3楼-- · 2019-02-16 11:17

Piggybagging off of what JotWee and Sihad Begovic had provided, here's the Swift 5.0 version of making your ViewController adopts the UIActivityItemSource protocol and using share barButtonItem to trigger the sharing of objects with other apps on your iPhone(s), and or, iPad(s):

Inside the viewDidLoad method of your ViewController class, implement the following:

 navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(shareBarButtonItemClicked(_:)))

And somewhere outside your viewDidLoad method, but inside your ViewController class, let us implement the shareBarButtonItemClicked method as below:

@objc func shareBarButtonItemClicked(_ sender: UIBarButtonItem) {
    //Here, iOS requires that you use self for your array of items 
    let items = [self]
    let activityVC = UIActivityViewController(activityItems: items, applicationActivities: nil)

    //App activities to be excluded from sharing to
    activityVC.excludedActivityTypes = [
        UIActivityType.airDrop,
        UIActivityType.print,
        UIActivityType.saveToCameraRoll,
        UIActivityType.addToReadingList
    ]

    if UIDevice.current.userInterfaceIdiom == .pad {
        if activityVC.responds(to: #selector(getter: UIViewController.popoverPresentationController)) {
            activityVC.popoverPresentationController?.barButtonItem = sender
        }
    }

    self.present(activityVC, animated: true, completion: nil)
}

Now here's where things gets interesting. We need to make your ViewController class conform to the UIActivityItemSource protocol and implement its required methods as below:

extension ReferAFriendViewController: UIActivityItemSource {
func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
    return String(describing: "Sharing my awesome app")
}

func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivityType) -> Any? {
    return String(describing: "Sharing my awesome app")
}

// Now you can modify and use the same above method if you want different messages/info to be presented for different apps user selects to share with. 
// The Secret is utilizing the activityType parameter. 
// You just have to uncomment below method and swap it with above method.

/*
func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivityType) -> Any? {
    if activityType == .postToTwitter {
    return "Download #MyAwesomeApp via @vickSwift."
    } else if activityType == .mail {
        return String(describing: "My awesome app is lit. So download it")
    } else {
        return String(describing: "Download my awesome app")
    }
}
*/

// Now note that when you share your app via a mail app, you might need to provide `subject` line. 
// In fact, the `UIActivityItemSource` protocol provide us an optional delegate method to accomplish just that; implemented below: 
func activityViewController(_ activityViewController: UIActivityViewController, subjectForActivityType activityType: UIActivityType?) -> String {
    return String(describing: "My Awesome app email's subject title")
}
}

And that's how you adopt your class to conform to the UIActivityItemSource protocol and implement its methods. For more readings, I find this web article from HackingWithSwift website very really insightful.

Happy coding!

查看更多
ゆ 、 Hurt°
4楼-- · 2019-02-16 11:27

The answer by JotWee helped me out.

There is no need for sub classing, UIActivityItemSource protocol methods can be implemented in view controller where share button is implemented.

Very important to add self in activity items array, like this (as JotWee suggested):

NSArray *activityItems = [NSArray arrayWithObjects:self, url, image, nil];

Here is my final implementation:

ViewController.h

@interface ViewController : UIViewController <UIActivityItemSource>

ViewController.m

- (void)shareBarButtonItemClick:(UIBarButtonItem *)sender
{
    NSURL *url = [NSURL URLWithString:@"http://example.com"];
    NSURL *imageUrl = [NSURL URLWithString:@"http://example.com/images/1.jpg"];
    UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:imageUrl]];

    NSArray *activityItems = [NSArray arrayWithObjects:self, url, image, nil];

    UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:nil];

    [self presentViewController:activityViewController animated:YES completion:nil];
}

- (id)activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(NSString *)activityType
{
    return @"Summary Text";
}

- (id)activityViewControllerPlaceholderItem:(UIActivityViewController *)activityViewController
{
    return @"";
}

- (NSString *)activityViewController:(UIActivityViewController *)activityViewController subjectForActivityType:(NSString *)activityType
{
    return @"Subject";
}
查看更多
Luminary・发光体
5楼-- · 2019-02-16 11:38

You can implement the protocol wherever you want, even your viewcontroller is fine. Just instantiate the activityViewController with initWithActivityItems:@[self].

查看更多
登录 后发表回答