5

Question

What changes to the code below must be made to ensure Messenger plays nicely with UIActivityViewController and shares both the image and text, or at the very least, the image?


Background

I am using UIActivityViewController to share text and images from my app and send them to email, messages and other sharing apps. UIActivityViewController is great and works in a simple and standard way with most apps… but, I’m having issues with Messenger (Facebook Messenger) which doesn’t want to cooperate.

In the below code, I tap a UIButton which takes a snapshot image of the screen, turns it into a .png, and then sends the prepared image (imageShare) along with my prepared text (textShare) to the UIActivityViewController. This simple method allows my app to successfully share to email, messages and many other sharing apps except Messenger.

(Side note, Facebook is only able to share the prepared image (imageShare) but not the text.)


Issues

These are the problems when trying to share with UIActivityViewController to Messenger :

  • When sharing activityItems: [textShare, imageShare]

    • Messenger only sends the shared text.
  • When sharing activityItems: [textShare]

    • The option to share to Messenger is not even available in UIActivityViewController.
  • When sharing activityItems: [imageShare]

    • An error is displayed: “Couldn't Load Content. There was a problem while loading your content. Please try again.”

Code

@IBAction func myButton(sender: UIButton) {

    // Take snapshot of screen
    let imageSnapshot: UIImage!
    UIGraphicsBeginImageContextWithOptions(self.view.frame.size, false, 0)
    self.view.drawViewHierarchyInRect(CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height), afterScreenUpdates: false)
    imageSnapshot = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    // Prepare text to share
    let textShare: String!
    textShare = "This is my original text."

    // Prepare image to share
    let imageShare: NSData
    imageShare = UIImagePNGRepresentation(imageSnapshot)!

    // Share text and image
    let activity = UIActivityViewController(activityItems: [textShare, imageShare], applicationActivities: nil)
    if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
        self.presentViewController(activity, animated: true, completion: nil)
    }

}

Image

iOS presenting the UIActivityViewController with available applications.

UIActivityViewController screenshot

shim
  • 9,289
  • 12
  • 69
  • 108
user4806509
  • 2,925
  • 5
  • 37
  • 72

3 Answers3

0

Try to use UIImage instead NSData. You can convert UIImage to AnyObject and add to your array.

Also look at this question: Sharing image using UIActivityViewController

Alexander Zakatnov
  • 1,646
  • 1
  • 15
  • 16
  • Thanks for the suggestion. When I change `NSData` to `UIImage` I get an error: `Cannot assign value of type 'NSData' to type 'UIImage'. Would you be able to expand on your answer showing the code change in context please? – user4806509 Jul 17 '17 at 13:41
  • He's not saying to literally replace the type (next to `imageShare`) `NSData` with `UIImage` but rather to send the `UIImage` instance instead of creating an `NSData` instance from the `UIImage` you already have. – shim Jul 17 '17 at 21:02
0
let textShare = "This is my original text."
var shareObject = [AnyObject]()
if textShare != nil {
    shareObject.append(textShare as AnyObject)
}

let Yourimage = UIImage(named: "image.png")
let imageData = UIImagePNGRepresentation(Yourimage!) as NSData? 

if let data = imageData {
    shareObject.append(data)
}

if shareObject.count > 0 { // check condition for text and image
    let activityViewController = UIActivityViewController(activityItems: shareObject, applicationActivities: nil)
    activityViewController.popoverPresentationController?.sourceView = self.view
    present(activityViewController, animated: true, completion: nil)
}
shim
  • 9,289
  • 12
  • 69
  • 108
Lalit kumar
  • 1,797
  • 1
  • 8
  • 14
  • Thanks, for the answer but this doesn't correct the issue, the image is still missing, only the text is displayed. – user4806509 Jul 17 '17 at 13:47
0

So in the end what was needed was an extra step of converting NSData back into UIImage.

Note, the one issue with this approach of converting NSData back into UIImage is that it produces image quality that is either lossless (i.e. Message and Mail) or lossy (i.e. Notes, Photos, Messenger).

Interestingly Messages, Mail, and a variety of third party sharing apps were quite content sharing the NSData in the UIActivityViewController whereas Messenger would just not tolerate it. (I'd be interested to understand why exactly?)


The changes

From this:

    // Prepare image to share
    let imageShare: NSData
    imageShare = UIImagePNGRepresentation(imageSnapshot)!

To that:

    // Prepare image to share
    let imageShareData: NSData
    imageShareData = UIImagePNGRepresentation(imageSnapshot)!
    let imageShare = UIImage(data: imageShareData)!

The final working code

@IBAction func myButton(sender: UIButton) {

    // Take snapshot of screen
    var imageSnapshot: UIImage!
    UIGraphicsBeginImageContextWithOptions(self.view.frame.size, false, 0)
    self.view.drawViewHierarchyInRect(CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height), afterScreenUpdates: false)
    imageSnapshot = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    // Prepare text to share
    let textShare: String!
    textShare = "This is my original text."

    // Prepare image to share
    let imageShareData: NSData
    imageShareData = UIImagePNGRepresentation(imageSnapshot)!
    let imageShare = UIImage(data: imageShareData)!

    // Share text and image
    let activity = UIActivityViewController(activityItems: [textShare, imageShare], applicationActivities: nil)
    if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
        self.presentViewController(activity, animated: true, completion: nil)
    }

}
user4806509
  • 2,925
  • 5
  • 37
  • 72
  • You have a `UIImage`, you're converting it to `NSData` and then you've converted it back into a `UIImage` without doing anything to it. Just eliminate the unnecessary steps and send the original `UIImage` instance. – shim Jul 17 '17 at 21:04
  • Thanks @shim. The issue is the original UIImage appears to be a lossy jpg when saved. I'm wanting to preserve a crisp screenshot which is why I am converting to png. – user4806509 Jul 17 '17 at 21:08
  • Then why did you ask [this question](https://stackoverflow.com/q/45153494/1032372)? – shim Jul 17 '17 at 21:10