179

I started my search by wanting to know how I could share to other apps in iOS. I discovered that two important ways are

  • UIActivityViewController
  • UIDocumentInteractionController

These and other methods are compared in this SO answer.

Often when I am learning a new concept I like to see a basic example to get me started. Once I get something basic set up I can modify it how I like later.

There are many SO questions related to UIActivityViewController, but I couldn't find any that were just asking for a simple example. Since I just learned how to do this, I will provide my own answer below. Feel free to add a better one (or an Objective-C version).

Community
  • 1
  • 1
Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393

7 Answers7

341

UIActivityViewController Example Project

Set up your storyboard with two buttons and hook them up to your view controller (see code below).

enter image description here

Add an image to your Assets.xcassets. I called mine "lion".

enter image description here

Code

import UIKit
class ViewController: UIViewController {
    
    // share text
    @IBAction func shareTextButton(_ sender: UIButton) {
        
        // text to share
        let text = "This is some text that I want to share."
        
        // set up activity view controller
        let textToShare = [ text ]
        let activityViewController = UIActivityViewController(activityItems: textToShare, applicationActivities: nil)
        activityViewController.popoverPresentationController?.sourceView = self.view // so that iPads won't crash
        
        // exclude some activity types from the list (optional)
        activityViewController.excludedActivityTypes = [ UIActivity.ActivityType.airDrop, UIActivity.ActivityType.postToFacebook ]
        
        // present the view controller
        self.present(activityViewController, animated: true, completion: nil)
        
    }
    
    // share image
    @IBAction func shareImageButton(_ sender: UIButton) {
        
        // image to share
        let image = UIImage(named: "Image")
        
        // set up activity view controller
        let imageToShare = [ image! ]
        let activityViewController = UIActivityViewController(activityItems: imageToShare, applicationActivities: nil)
        activityViewController.popoverPresentationController?.sourceView = self.view // so that iPads won't crash
        
        // exclude some activity types from the list (optional)
        activityViewController.excludedActivityTypes = [ UIActivity.ActivityType.airDrop, UIActivity.ActivityType.postToFacebook ]
        
        // present the view controller
        self.present(activityViewController, animated: true, completion: nil)
    }
    
}

Result

Clicking "Share some text" gives result on the left and clicking "Share an image" gives the result on the right.

enter image description here

Notes

  • I retested this with iOS 11 and Swift 4. I had to run it a couple times in the simulator before it worked because it was timing out. This may be because my computer is slow.
  • If you wish to hide some of these choices, you can do that with excludedActivityTypes as shown in the code above.
  • Not including the popoverPresentationController?.sourceView line will cause your app to crash when run on an iPad.
  • This does not allow you to share text or images to other apps. You probably want UIDocumentInteractionController for that.

See also

Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393
  • 1
    Why some examples show array of 1 item, and some shows 2? Assuming sharing an image. – Lim Thye Chean Aug 21 '17 at 09:34
  • @ Suragch: Hi I want to share a referall code in the text and need that code to be copied on click or tap as it happens when we send a number. – Ishika Apr 17 '18 at 12:51
115

Share : Text

@IBAction func shareOnlyText(_ sender: UIButton) {
    let text = "This is the text....."
    let textShare = [ text ]
    let activityViewController = UIActivityViewController(activityItems: textShare , applicationActivities: nil)
    activityViewController.popoverPresentationController?.sourceView = self.view 
    self.present(activityViewController, animated: true, completion: nil)
}
}

Share : Image

@IBAction func shareOnlyImage(_ sender: UIButton) {
    let image = UIImage(named: "Product")
    let imageShare = [ image! ]
    let activityViewController = UIActivityViewController(activityItems: imageShare , applicationActivities: nil)
    activityViewController.popoverPresentationController?.sourceView = self.view 
    self.present(activityViewController, animated: true, completion: nil)
 }

Share : Text - Image - URL

   @IBAction func shareAll(_ sender: UIButton) {
    let text = "This is the text...."
    let image = UIImage(named: "Product")
    let myWebsite = NSURL(string:"https://stackoverflow.com/users/4600136/mr-javed-multani?tab=profile")
    let shareAll= [text , image! , myWebsite]
    let activityViewController = UIActivityViewController(activityItems: shareAll, applicationActivities: nil)
    activityViewController.popoverPresentationController?.sourceView = self.view 
    self.present(activityViewController, animated: true, completion: nil)
   }

enter image description here

Mr.Javed Multani
  • 12,549
  • 4
  • 53
  • 52
  • 6
    hey its not working. In FB only link is share not image and text. – Ekta Padaliya Mar 23 '18 at 10:35
  • @ScriptKitty. Is messages app configured properly with an i cloud account? – Awais Fayyaz Oct 11 '18 at 07:53
  • 1
    @EktaPadaliya. According to FB update policy, either a URL or an image can be shared. text can't – Awais Fayyaz Oct 11 '18 at 07:54
  • https://medium.com/@javedmultani16/basic-example-for-sharing-text-or-image-with-uiactivityviewcontroller-in-swift-8de22562a850 – Mr.Javed Multani Nov 04 '19 at 06:43
  • 2
    @Mr.JavedMultani image is not shared in whatsapp – NickCoder Mar 05 '20 at 07:16
  • Hi i want to audio and text if a select both in array then only text shows to share and how to add your app logo as audio file default logo in share intent – Haider Awan Jan 21 '22 at 18:12
  • Hi @Mr.JavedMultani, is not working for me. I'm sharing 3 items (`text`, `image`, `file`) is not working for me. – Harsha Jun 08 '22 at 07:23
  • @Harsha above example is for Text - Image - URL, if you want to share file then you need to mention path from document directory/local and can pass it. – Mr.Javed Multani Jun 08 '22 at 08:52
  • yes, file sharing is working but text is not getting shared along with the file. Check here https://stackoverflow.com/questions/72596837/sharing-an-ics-file-along-with-some-text-is-not-working – Harsha Jun 13 '22 at 02:08
17

Just as a note you can also use this for iPads:

activityViewController.popoverPresentationController?.sourceView = sender

So the popover pops from the sender (the button in that case).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
13

I found this to work flawlessly if you want to share whole screen.

@IBAction func shareButton(_ sender: Any) {

    let bounds = UIScreen.main.bounds
    UIGraphicsBeginImageContextWithOptions(bounds.size, true, 0.0)
    self.view.drawHierarchy(in: bounds, afterScreenUpdates: false)
    let img = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    let activityViewController = UIActivityViewController(activityItems: [img!], applicationActivities: nil)
    activityViewController.popoverPresentationController?.sourceView = self.view
    self.present(activityViewController, animated: true, completion: nil)
}
Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393
Diavel Rider
  • 351
  • 3
  • 6
10

I've used the implementation above and just now I came to know that it doesn't work on iPad running iOS 13. I had to add these lines before present() call in order to make it work

//avoiding to crash on iPad
if let popoverController = activityViewController.popoverPresentationController {
     popoverController.sourceRect = CGRect(x: UIScreen.main.bounds.width / 2, y: UIScreen.main.bounds.height / 2, width: 0, height: 0)
     popoverController.sourceView = self.view
     popoverController.permittedArrowDirections = UIPopoverArrowDirection(rawValue: 0)
}

That's how it works for me

func shareData(_ dataToShare: [Any]){

        let activityViewController = UIActivityViewController(activityItems: dataToShare, applicationActivities: nil)

        //exclude some activity types from the list (optional)
        //activityViewController.excludedActivityTypes = [
            //UIActivity.ActivityType.postToFacebook
        //]

        //avoiding to crash on iPad
        if let popoverController = activityViewController.popoverPresentationController {
            popoverController.sourceRect = CGRect(x: UIScreen.main.bounds.width / 2, y: UIScreen.main.bounds.height / 2, width: 0, height: 0)
            popoverController.sourceView = self.view
            popoverController.permittedArrowDirections = UIPopoverArrowDirection(rawValue: 0)
        }

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

You may use the following functions which I wrote in one of my helper class in a project.

just call

showShareActivity(msg:"message", image: nil, url: nil, sourceRect: nil) 

and it will work for both iPhone and iPad. If you pass any view's CGRect value by sourceRect it will also shows a little arrow in iPad.

func topViewController()-> UIViewController{
    var topViewController:UIViewController = UIApplication.shared.keyWindow!.rootViewController!

    while ((topViewController.presentedViewController) != nil) {
        topViewController = topViewController.presentedViewController!;
    }

    return topViewController
}

func showShareActivity(msg:String?, image:UIImage?, url:String?, sourceRect:CGRect?){
    var objectsToShare = [AnyObject]()

    if let url = url {
        objectsToShare = [url as AnyObject]
    }

    if let image = image {
        objectsToShare = [image as AnyObject]
    }

    if let msg = msg {
        objectsToShare = [msg as AnyObject]
    }

    let activityVC = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil)
    activityVC.modalPresentationStyle = .popover
    activityVC.popoverPresentationController?.sourceView = topViewController().view
    if let sourceRect = sourceRect {
        activityVC.popoverPresentationController?.sourceRect = sourceRect
    }

    topViewController().present(activityVC, animated: true, completion: nil)
}
Mahmud Ahsan
  • 1,755
  • 19
  • 18
1

iOS Share text or image

present UIActivityViewController

let controller = UIActivityViewController(activityItems: [someObject], applicationActivities: nil) 
//someObject can be UIImage, NSURL, String... iOS decide how to handle it properly

controller.popoverPresentationController?.sourceView = self.view

//add completionWithItemsHandler
controller.completionWithItemsHandler = {
    (
        activityType: UIActivity.ActivityType?,
        completed: Bool,
        arrayReturnedItems: [Any]?,
        error: Error?
    ) in
    
    if let error = error {
        //error occured
        return
    }
    
    if completed {
        if let activityType = activityType {
            switch activityType {
            case .saveToCameraRoll:
                break
            case .copyToPasteboard:
                break
            case .addToReadingList:
                break
            case .airDrop:
                break
            default:
                //all others
                break
            }
        }
    } else {
        //Cancel
    }
}

self.present(controller, animated: true)

Save image into library

If you are going to save image into library add NSPhotoLibraryAddUsageDescription into app's .plist file or you get runtime error:

This app has crashed because it attempted to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSPhotoLibraryAddUsageDescription key with a string value explaining to the user how the app uses this data.

additionally you can exclude this opportunity:

controller.excludedActivityTypes = [.saveToCameraRoll]

variant with completionWithItemsHandler which can helps to add post logic or handle errors.

For example I run into next error when saving UIImage into Photo library in a corresponding handler:

Error Domain=ALAssetsLibraryErrorDomain Code=-1 "Unknown error" UserInfo={NSLocalizedDescription=Unknown error, NSUnderlyingError=0x600003f85110 {Error Domain=PHPhotosErrorDomain Code=3303 "(null)"}}

As figured out I tried to save CIImage. As a variant you can convert it to CGImage

let context = CIContext()
guard let cgImage = context.createCGImage(output, from: output.extent) else { return nil }
return UIImage(cgImage: cgImage)

Customize UIActivityViewController

class ImageActivityItemSource: NSObject, UIActivityItemSource {
    let image: UIImage
    let title: String
    
    public init(image: UIImage, title: String) {
        self.image = image
        self.title = title
    }
    
    func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
        return self.image
    }
    
    func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any? {
        return self.image
    }
    
    public func activityViewControllerLinkMetadata(_ activityViewController: UIActivityViewController) -> LPLinkMetadata? {
        let image = self.image
        let imageProvider = NSItemProvider(object: image)
        let metadata = LPLinkMetadata()
        metadata.title = self.title
        metadata.imageProvider = imageProvider
        return metadata
    }
}

using:

let imageActivityItemSource = ImageActivityItemSource(image: image, title: "Share this image with others")
let ac = UIActivityViewController(activityItems: [imageActivityItemSource], applicationActivities: nil)
yoAlex5
  • 29,217
  • 8
  • 193
  • 205