Sharing to Instagram does not work using the `UIActivityItemSource` protocol

3.9k views Asked by At

I share text and an image using the UIActivityViewController. The image is from activityImage which is an UIImage(). The custom text is from activityText() which is returned from an UIActivityItemSource protocol.

The trouble is, Instagram is only visible in the UIActivityViewController under certain conditions.

To summerize the tests below:

  • Instagram is only visible in the UIActivityViewController for activityItems: [activityImage] and activityItems: [activityImage, NSNull()]

  • Instagram is hidden for activityItems: [activityImage, activityText()] even when the returned UIActivityItemSource protocol value is "", nil, NSNull().

The issue is that the UIActivityItemSource protocol needs to be called so that different sharing platforms can be managed separately.


Questions:

  • How can I share to Instagram when calling the UIActivityItemSource protocol?

  • What are the alternatives to "", nil and NSNull() that I could try when calling the UIActivityItemSource protocol?


Code:

class activityText: NSObject, UIActivityItemSource {
    @objc func activityViewControllerPlaceholderItem(activityViewController: UIActivityViewController) -> AnyObject {
        return ""
    }
    @objc func activityViewController(activityViewController: UIActivityViewController, itemForActivityType activityType: String) -> AnyObject? {
        switch activityType {
        case UIActivityTypeMessage:
            return "Special text when sharing to Messages."
        default:
            return ""
        }
    }
}

func shareEverwhere() {
      var activityImage: UIImage() 
      let activity = UIActivityViewController(activityItems: [activityImage, activityText()], applicationActivities: nil)
      self.presentViewController(activity, animated: true, completion: nil)
}

Tests:

Instagram is visible in the UIActivityViewController

let activity = UIActivityViewController(activityItems: [activityImage], applicationActivities: nil)

or

let activity = UIActivityViewController(activityItems: [activityImage, NSNull()], applicationActivities: nil)

Instagram is hidden in the UIActivityViewController

let activity = UIActivityViewController(activityItems: [activityImage, ""], applicationActivities: nil)

or

let activity = UIActivityViewController(activityItems: [activityImage, activityText()], applicationActivities: nil)

or

let activity = UIActivityViewController(activityItems: [activityImage, activityText()], applicationActivities: nil)
class activityText: NSObject, UIActivityItemSource {
    @objc func activityViewControllerPlaceholderItem(activityViewController: UIActivityViewController) -> AnyObject {
        return ""
    }
    @objc func activityViewController(activityViewController: UIActivityViewController, itemForActivityType activityType: String) -> AnyObject? {
        return NSNull()
    }
}

or

let activity = UIActivityViewController(activityItems: [activityImage, activityText()], applicationActivities: nil)
class activityText: NSObject, UIActivityItemSource {
    @objc func activityViewControllerPlaceholderItem(activityViewController: UIActivityViewController) -> AnyObject {
        return ""
    }
    @objc func activityViewController(activityViewController: UIActivityViewController, itemForActivityType activityType: String) -> AnyObject? {
            return nil
    }
}

or

let activity = UIActivityViewController(activityItems: [activityImage, activityText()], applicationActivities: nil)
class activityText: NSObject, UIActivityItemSource {
    @objc func activityViewControllerPlaceholderItem(activityViewController: UIActivityViewController) -> AnyObject {
        return ""
    }
    @objc func activityViewController(activityViewController: UIActivityViewController, itemForActivityType activityType: String) -> AnyObject? {
            return ""
    }
}
2

There are 2 answers

2
Olivier Brand On

The question was asked and answered at: Share image with hashtag via UIActivityViewController (Twitter, Facebook, Instagram)

        UIActivityViewController *activityViewController =
 [[UIActivityViewController alloc] initWithActivityItems:@[vm.image, [[ActivityStringItemSource alloc] initWithString:attributedString]] applicationActivities:nil];

And the class that implements the return of the string (or not) is:

@interface ActivityStringItemSource()<UIActivityItemSource>

@property(strong, nonatomic) NSMutableAttributedString *stringContent;
@end

@implementation ActivityStringItemSource

- (instancetype)initWithString:(NSMutableAttributedString *) placeholder
{
    self = [super init];
    if (self) {
        _stringContent = placeholder;
    }
    return self;
}

- (id)activityViewControllerPlaceholderItem:(UIActivityViewController *)activityViewController {
    return [NSObject new];
}

- (id)activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(UIActivityType)activityType {
    if([activityType containsString:@"instagram"]) {
        return nil;
    } else {
        return _stringContent;
    }
}

@end

The key, as pointed by the original answer is to return an NSObject (the class extends NSObject). Then in the item selection, just test instagram to return nil and otherwise return your string.

0
buxik On

After testing only you have to do is add your image to activityViewControllerPlaceholderItem

final class MyImageItemSource: NSObject, UIActivityItemSource {

    final let image: UIImage

    init(image: UIImage) {
        self.image = image
    }

    func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
        image
    }

    func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any? {
        image
    }

}