I am attempting to share an image with a hashtag using UIActivityViewController and I am encountering some strange behavior when attempting to share to Twitter, Facebook and Instagram. There does not seem to be a lot of documentation about these service's share extensions.
Scenario 1: Init controller with activity item array with image and text
If I initialize the controller like so, Twitter and Facebook will show up in the controller (no Instagram as it does not support text items), and both will programmatically pre-populate the hashtag in the text entry field:
let activityVC = UIActivityViewController(activityItems: [myHashtagString, myImage], applicationActivities: nil)
Scenario 2: Init controller with only image
In this scenario, all networks show up, but I (obviously) lose the automatic hashtag feature:
let activityVC = UIActivityViewController(activityItems: [myImage], applicationActivities: nil)
Scenario 3: UIActivityItemSource subclass
If I make my own UIActivityItemSource subclass, I can almost get everything to work. However, and this is what I cannot figure out, using the protocol methods as I have below results in the automatic hashtag working for Facebook, but not Twitter. How can this be possible -- is there a special key needed for Twitter? There must be a way for it to work if it works in Scenario #1...
Interestingly, this method works for both Twitter and Facebook if I insert a URL (commented out). So why on earth won't the text work for Twitter!?
let activityItem = CustomItemSource(image: image, message: "#TestTag")
let activityVC = UIActivityViewController(activityItems: [activityItem], applicationActivities: nil)
...
class CustomItemSource: NSObject, UIActivityItemSource {
private var image: UIImage!
private var message: String!
// MARK: Init
init(image: UIImage, message: String) {
super.init()
self.image = image
self.message = message
}
// MARK: Item Source Protocol
func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
return image
}
func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivityType) -> Any? {
if activityType == .postToTwitter || activityType == .postToFacebook {
//return ["url": URL(string: "https://www.google.com")!, "image": image]
return ["text": message, "image": image]
}
else {
return ["image": image]
}
}
}
Define two UIActivityItemSource
classes, one for Image and one for Text.
In first one only return the image.
In second one return NSObject()
for placeHolder, and return Text
or nil
depending on activity. By returning NSObject()
, UIActivity will allow all services to be available.
UIActivityViewController(activityItems: [ImageProvider(), TextProvider()], applicationActivities: nil)
and providers:
class TextProvider: NSObject, UIActivityItemSource {
func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
return NSObject()
}
func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivityType) -> Any? {
if activityType == .postToTwitter || activityType == .postToFacebook {
return "Tweet with #Hashtag"
}
return nil
}
}
class ImageProvider: NSObject, UIActivityItemSource {
func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
return UIImage(named: ...)
}
func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivityType) -> Any? {
return UIImage(named: ...)
}
}
First of all, Keys are not really sensitive, The only sensitive-key was "subject" for email and apps supporting it, which is implemented in UIActivityController
's API and we can set it directly. It doesn't matter if you provide UIImage
with key "image" or "1".
As it turns out, Twitter activity will not work if it's text is not returned directly in ...itemForActivity...
method. So the solution is to separate item sources.
Twitter activity also will not work, if placeholder
receives anything other than String
, but by returning String
Instagram activity will not work, So by returning NSObject()
Type will be ignored and all services will be available.
if you want to limit some services use UIActivityViewController.excludedActivityTypes
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With