How to get and show screenshot in share button? - ios

Below I have tried to code so the screenShot function will take a full screenshot of my viewController. I am trying to figure out how I could take the screenshot and put it in into my activityItems in the sharePressed action, so it will show the screenshot when you try to share.
func captureScreen() -> UIImage? {
UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, UIScreen.main.scale)
view.layer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
#IBAction func sharePressed(_ sender: Any) {
let activityVC = UIActivityViewController(activityItems: [""], applicationActivities: nil)
activityVC.popoverPresentationController?.sourceView = self.view
self.present(activityVC, animated: true, completion: nil)
}

#IBAction func sharePressed(_ sender: Any) {
let imgScreenshot = captureScreen()
if let imgScreenshot = imgScreenshot {
let objectsToShare = ["Post message", imgScreenshot] as [Any]
let activityVC = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil)
activityVC.excludedActivityTypes = [UIActivityType.airDrop, UIActivityType.addToReadingList]
self.present(activityVC, animated: true, completion: nil)
}
}

Related

Sharing text and Url to Facebook Messenger with UIActivityViewController but failing

I want to share both text and url to Facebook Messenger using UIActivityViewController.
But when i success send and open my Messenger, i only get url.
Is it possible send text and url to Facebook Messenger using UIActivityViewController at the same time?
Here is my code
#IBAction func sharedLink(_ sender: Any) {
let url = NSURL(string: "https://www.google.com.tw")!
let text = "test" as AnyObject
let shareObject: [AnyObject] = [text, url as AnyObject]
let vc = UIActivityViewController(activityItems: shareObject, applicationActivities: [])
vc.completionWithItemsHandler = { (type,completed,items,error) in
if completed { vc.dismiss(animated: true, completion: nil) }
}
present(vc, animated: true, completion: nil)
}
Here is my screenshot
In my case,
#IBAction func sharedLink(_ sender: Any) {
let urlString = "https://www.google.com.tw"
let url = NSURL(string: urlString)!
let text = "test" as AnyObject
let shareObject: [AnyObject] = ["\(text), \(urlString)"]
let vc = UIActivityViewController(activityItems: shareObject, applicationActivities: [])
vc.completionWithItemsHandler = { (type,completed,items,error) in
if completed { vc.dismiss(animated: true, completion: nil) }
}
present(vc, animated: true, completion: nil)
}

How to embed text to animated gif and save the gif?

I am trying to save the gif with embedded text on it.
I tried adding subview on top of the gif and make the view transparent but I don't know how to add both files and save them as one.
#IBAction func shareAction(_ sender: Any) {
let shareImage = generateMemedImage()
let data = shareImage.pngData()! as NSData
let nsdata:NSData = NSData(contentsOf: gifurl)!
var array:[NSData] = []
array.append(data)
array.append(nsdata)
let activityController = UIActivityViewController(activityItems: array, applicationActivities: nil)
present(activityController, animated: true, completion: nil)
activityController.completionWithItemsHandler = {(activity, completed, items, error) in
if (completed){
// self.save()
self.navigationController?.popViewController(animated: true)
self.dismiss(animated: true, completion: nil)
}
}
}
func generateMemedImage() -> UIImage {
// Render view to an image
topToolbar.isHidden = true
bottomToolBar.isHidden = true
UIGraphicsBeginImageContext(self.view.frame.size)
view.drawHierarchy(in: self.view.frame, afterScreenUpdates: true)
let memedImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
topToolbar.isHidden = false
bottomToolBar.isHidden = false
return memedImage
}

share PDF file with UIActivityViewController

I am trying to share a PDF file using UIActivityViewController but when I press the button I do not have options to share the file
How can I show these options ?
![](https://i.stack.imgur.com/ywDQw.jpg
import UIKit
import PDFKit
import MessageUI
import UIKit.UIGestureRecognizerSubclass
class BookViewController: UIViewController, UIPopoverPresentationControllerDelegate, PDFViewDelegate, ActionMenuViewControllerDelegate, OutlineViewControllerDelegate, MFMailComposeViewControllerDelegate {
#IBOutlet weak var btn: UIButton!
var pdfDocument: PDFDocument?
#IBOutlet weak var pdfView: PDFView!
#IBOutlet weak var webview: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
pdfView.autoScales = true
pdfView.displayMode = .singlePage
pdfView.displayDirection = .horizontal
pdfView.usePageViewController(true, withViewOptions: [UIPageViewControllerOptionInterPageSpacingKey: 20])
pdfView.document = pdfDocument
resume()
// ActivityViewController
}
override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) {
coordinator.animate(alongsideTransition: { (context) in
}, completion: nil)
}
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}
func actionMenuViewControllergmailDocument(_ actionMenuViewController: ActionMenuViewController) {
}
func actionMenuViewControllerShareDocument(_ actionMenuViewController: ActionMenuViewController) {
}
func actionMenuViewControllerPrintDocument(_ actionMenuViewController: ActionMenuViewController) {
}
func outlineViewController(_ outlineViewController: OutlineViewController, didSelectOutlineAt destination: PDFDestination) {
resume()
pdfView.go(to: destination)
}
private func resume() {
let backButton = UIBarButtonItem(image: #imageLiteral(resourceName: "Chevron"), style: .plain, target: self, action: #selector(back(_:)))
let actionButton = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(showActionMenu(_:)))
navigationItem.leftBarButtonItems = [backButton, actionButton]
pdfView.isHidden = false
}
#objc func resume(_ sender: UIBarButtonItem) {
resume()
}
#objc func back(_ sender: UIBarButtonItem) {
navigationController?.popViewController(animated: true)
}
#objc func showActionMenu(_ sender: UIBarButtonItem) {
if let viewController = storyboard?.instantiateViewController(withIdentifier: String(describing: ActionMenuViewController.self)) as? ActionMenuViewController {
let activityVC = UIActivityViewController(activityItems: [self.pdfDocument!], applicationActivities: nil)
activityVC.popoverPresentationController?.sourceView = self.view
self.present(activityVC, animated: true, completion: nil)
}
}
}
In SWIFT 4
#IBAction func sharePDF(_ sender: : Any) {
let fm = FileManager.default
var pdfURL = (fm.urls(for: .documentDirectory, in: .userDomainMask)).last! as URL
pdfURL = pdfURL.appendingPathComponent("GridLines.pdf") as URL
//Rename document name to "Hello.pdf"
let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("Hello.pdf") as NSURL
do {
let data = try Data(contentsOf: pdfURL)
try data.write(to: url as URL)
let activitycontroller = UIActivityViewController(activityItems: [url], applicationActivities: nil)
if activitycontroller.responds(to: #selector(getter: activitycontroller.completionWithItemsHandler))
{
activitycontroller.completionWithItemsHandler = {(type, isCompleted, items, error) in
if isCompleted
{
print("completed")
}
}
}
activitycontroller.excludedActivityTypes = [UIActivityType.airDrop]
activitycontroller.popoverPresentationController?.sourceView = self.view
self.present(activitycontroller, animated: true, completion: nil)
}
catch {
//ERROR
}
}
You can also share the PDF data itself using the dataRepresentation() function
guard let data = document?.dataRepresentation() else { return }
let activityController = UIActivityViewController(activityItems: [data], applicationActivities: nil)
present(activityController, animated: true)
Cheers
Try like this
let fileManager = FileManager.default
let docsurl = try! fileManager.url(for:.documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
let documentoPath = docsurl.appendingPathComponent("yourfile.pdf")
if fileManager.fileExists(atPath: documentoPath){
let pdfData = NSData(contentsOfFile: documentoPath)
var activityViewController = UIActivityViewController(activityItems: ["Your title that you wanna share", pdfData], applicationActivities: nil) // and present it
present(activityViewController, animated: true) {() -> Void in }
}
Its working fine ... I use it .
You already have a PDFDocument object, so reconstructing the file url is unnecessary. Simply pass your PDFDocument's documentURL property instead:
let activityVC = UIActivityViewController(activityItems: [self.pdfDocument!.documentURL!], applicationActivities: nil)
Try with this
let fileManager = FileManager.default
let docsurl = try! fileManager.url(for:.documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
let documentoPath = docsurl.appendingPathComponent("documento.pdf")
if fileManager.fileExists(atPath: documentoPath){
let documento = NSData(contentsOfFile: documentoPath)
let activityViewController: UIActivityViewController =
UIActivityViewController(activityItems: [documento!],
applicationActivities: nil)
activityViewController.popoverPresentationController?.sourceView=self.view
present(activityViewController, animated: true, completion: nil)
}
else {
print("document was not found")
}
Call this method on button click
func sharePdf() {
let activityViewController = UIActivityViewController(activityItems: [pdfView.document!.dataRepresentation()!], applicationActivities: nil)
present(activityViewController, animated: true)
}
For sharing image just change the activity item
func shareImg() {
let activityViewController = UIActivityViewController(activityItems: [imageView.image!], applicationActivities: nil)
present(activityViewController, animated: true)
}
You can share multiple items at once, by adding it in activityItems array

How to implement "share button" in Swift

This is the some peace of code for twitter... I want to know how to get the share action view like we get in iOS stock photos app...
#IBAction func twitterButton(sender: AnyObject) {
let image: UIImage = UIImage(named: "LaunchScreenImage.png")!
let twitterControl = SLComposeViewController(forServiceType: SLServiceTypeTwitter)
twitterControl.setInitialText("")
twitterControl.addImage(image)
let completionHandler = {(result:SLComposeViewControllerResult) -> () in
twitterControl.dismissViewControllerAnimated(true, completion: nil)
switch(result){
case SLComposeViewControllerResult.Cancelled:
print("User canceled", terminator: "")
case SLComposeViewControllerResult.Done:
print("User tweeted", terminator: "")
}
}
twitterControl.completionHandler = completionHandler
self.presentViewController(twitterControl, animated: true, completion: nil)
}
Swift 5:
// Setting description
let firstActivityItem = "Description you want.."
// Setting url
let secondActivityItem : NSURL = NSURL(string: "http://your-url.com/")!
// If you want to use an image
let image : UIImage = UIImage(named: "your-image-name")!
let activityViewController : UIActivityViewController = UIActivityViewController(
activityItems: [firstActivityItem, secondActivityItem, image], applicationActivities: nil)
// This lines is for the popover you need to show in iPad
activityViewController.popoverPresentationController?.sourceView = (sender as! UIButton)
// This line remove the arrow of the popover to show in iPad
activityViewController.popoverPresentationController?.permittedArrowDirections = UIPopoverArrowDirection.down
activityViewController.popoverPresentationController?.sourceRect = CGRect(x: 150, y: 150, width: 0, height: 0)
// Pre-configuring activity items
activityViewController.activityItemsConfiguration = [
UIActivity.ActivityType.message
] as? UIActivityItemsConfigurationReading
// Anything you want to exclude
activityViewController.excludedActivityTypes = [
UIActivity.ActivityType.postToWeibo,
UIActivity.ActivityType.print,
UIActivity.ActivityType.assignToContact,
UIActivity.ActivityType.saveToCameraRoll,
UIActivity.ActivityType.addToReadingList,
UIActivity.ActivityType.postToFlickr,
UIActivity.ActivityType.postToVimeo,
UIActivity.ActivityType.postToTencentWeibo,
UIActivity.ActivityType.postToFacebook
]
activityViewController.isModalInPresentation = true
self.present(activityViewController, animated: true, completion: nil)
This is how I implemented sharing with Swift 4/5 using a right button on the Navigation Controller. It includes an image, text and link.
SWIFT 4/5
On ViewDidLoad
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Share", style: .plain, target: self, action: #selector(share(sender:)))
Create the function
#objc func share(sender:UIView){
UIGraphicsBeginImageContext(view.frame.size)
view.layer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
let textToShare = "Check out my app"
if let myWebsite = URL(string: "http://itunes.apple.com/app/idXXXXXXXXX") {//Enter link to your app here
let objectsToShare = [textToShare, myWebsite, image ?? #imageLiteral(resourceName: "app-logo")] as [Any]
let activityVC = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil)
//Excluded Activities
activityVC.excludedActivityTypes = [UIActivity.ActivityType.airDrop, UIActivity.ActivityType.addToReadingList]
//
activityVC.popoverPresentationController?.sourceView = sender
self.present(activityVC, animated: true, completion: nil)
} }
#IBAction func shareButtonClicked(sender: AnyObject)
{
//Set the default sharing message.
let message = "Message goes here."
//Set the link to share.
if let link = NSURL(string: "http://yoururl.com")
{
let objectsToShare = [message,link]
let activityVC = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil)
activityVC.excludedActivityTypes = [UIActivityTypeAirDrop, UIActivityTypeAddToReadingList]
self.presentViewController(activityVC, animated: true, completion: nil)
}
}
This will allow you to present a UIActivityViewController to share a link and a message with any application that will accept them.
Details
Xcode 11.4.1 (11E503a), Swift 5.2
Solution
TopViewController solution
extension UIApplication {
class var topViewController: UIViewController? { return getTopViewController() }
private class func getTopViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let nav = base as? UINavigationController { return getTopViewController(base: nav.visibleViewController) }
if let tab = base as? UITabBarController {
if let selected = tab.selectedViewController { return getTopViewController(base: selected) }
}
if let presented = base?.presentedViewController { return getTopViewController(base: presented) }
return base
}
private class func _share(_ data: [Any],
applicationActivities: [UIActivity]?,
setupViewControllerCompletion: ((UIActivityViewController) -> Void)?) {
let activityViewController = UIActivityViewController(activityItems: data, applicationActivities: nil)
setupViewControllerCompletion?(activityViewController)
UIApplication.topViewController?.present(activityViewController, animated: true, completion: nil)
}
class func share(_ data: Any...,
applicationActivities: [UIActivity]? = nil,
setupViewControllerCompletion: ((UIActivityViewController) -> Void)? = nil) {
_share(data, applicationActivities: applicationActivities, setupViewControllerCompletion: setupViewControllerCompletion)
}
class func share(_ data: [Any],
applicationActivities: [UIActivity]? = nil,
setupViewControllerCompletion: ((UIActivityViewController) -> Void)? = nil) {
_share(data, applicationActivities: applicationActivities, setupViewControllerCompletion: setupViewControllerCompletion)
}
}
Usage
UIApplication.share("Text to share")
let data = ["Text, Image and url", image, url] as [Any]
UIApplication.share(data)
Full sample
Do not forget to add the solution code here (look above)
import UIKit
class ViewController: UIViewController {
private weak var imageView: UIImageView?
override func viewDidLoad() {
super.viewDidLoad()
var button = UIButton(frame: CGRect(x: 50, y: 50, width: 200, height: 40))
button.setTitle("Share text", for: .normal)
button.addTarget(self, action: #selector(shareButtonTapped), for: .touchUpInside)
button.setTitleColor(.blue, for: .normal)
view.addSubview(button)
button = UIButton(frame: CGRect(x: 50, y: 80, width: 200, height: 40))
button.setTitle("Share text & image", for: .normal)
button.addTarget(self, action: #selector(shareCombinedData), for: .touchUpInside)
button.setTitleColor(.blue, for: .normal)
view.addSubview(button)
let imageView = UIImageView(frame: CGRect(x: 50, y: 120, width: 200, height: 200))
imageView.image = UIImage(named: "image")
imageView.isUserInteractionEnabled = true
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
imageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(imageViewTapped)))
view.addSubview(imageView)
self.imageView = imageView
}
#objc func shareButtonTapped() { UIApplication.share("Text to share") }
#objc func imageViewTapped() {
guard let image = imageView?.image else { return }
UIApplication.share(image)
}
#objc func shareCombinedData() {
guard let image = imageView?.image, let url = URL(string: "http://google.com") else { return }
let data = ["Text, Image and url", image, url] as [Any]
UIApplication.share(data)
}
}
Sample result
I develop #onemillion 's answer:) You can use this for Swift 3
override func viewDidLoad() {
super.viewDidLoad()
share(message: "selam", link: "htttp://google.com")
}
func share(message: String, link: String) {
if let link = NSURL(string: link) {
let objectsToShare = [message,link] as [Any]
let activityVC = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil)
self.present(activityVC, animated: true, completion: nil)
}
}
UPDATED FOR SWIFT 3.0
// first function to add the button to your navigation bar
func addingNavBarBtn () {
// setting button's image
let comunicateImage = UIImage(named: "NavfShare")
let comunicateBtn = UIBarButtonItem(image: comunicateImage, style: .plain, target: self, action: #selector(shareButtonPressed))
comunicateBtn.tintColor = UIColor.white
self.navigationItem.rightBarButtonItem = comunicateBtn
}
//setting button's action
func shareButtonPressed(){
//checking the object and the link you want to share
let urlString = "https://www.google.com"
let linkToShare = [urlString!]
let activityController = UIActivityViewController(activityItems: linkToShare, applicationActivities: nil)
self.present(activityController, animated: true, completion: nil)
}
let items = ["Your Sharing Content"];
let activity = UIActivityViewController(activityItems: items, applicationActivities: nil);
self.present(activity, animated: true, completion: nil)
Improving on JP Aquino's code for Swift 5 for share action rightBarButtonItem on the Navigation Controller.
In viewDidLoad of your ViewController, do this:
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(shareBarButtonItemClicked(_:)))
Then implement the shareBarButtonItemClicked method as below somewhere inside your ViewController:
#objc func shareBarButtonItemClicked(_ sender: UIBarButtonItem) {
// Text to share with other apps
let textToShare = String(describing: "My awesome app")
// URL, and or, and image to share with other apps
guard let myAppURLToShare = URL(string: "http://itunes.apple.com/app/idXXXXXXXXX"), let image = UIImage(named: "image.jpg") else {
return
}
let items = [textToShare, myAppURLToShare, image] as [Any]
let avc = UIActivityViewController(activityItems: items, applicationActivities: nil)
//Apps to exclude sharing to
avc.excludedActivityTypes = [
UIActivityType.airDrop,
UIActivityType.print,
UIActivityType.saveToCameraRoll,
UIActivityType.addToReadingList
]
//If user on iPad
if UIDevice.current.userInterfaceIdiom == .pad {
if avc.responds(to: #selector(getter: UIViewController.popoverPresentationController)) {
avc.popoverPresentationController?.barButtonItem = sender
}
}
//Present the shareView on iPhone
self.present(avc, animated: true, completion: nil)
}
Happy coding!
#IBAction func shareButtonAction(_ sender: UIButton) {
let activityVC = UIActivityViewController(activityItems: ["Whatever you want to share"], applicationActivities: nil)
activityVC.popoverPresentationController?.sourceView = sender
present(activityVC, animated: true, completion: nil)
activityVC.completionWithItemsHandler = { (activityType, completed:Bool, returnedItems:[Any]?, error: Error?) in
if completed {
self.dismiss(animated: true, completion: nil)
}
}
}
IOS 16
As of IOS 16 there is now a sharelink button, just pass in your link as the link.
#available(iOS 16.0, *)
ShareLink(item: link) {
Label("Click To Share", systemImage: "swift")
}

Basic example for sharing text or image with UIActivityViewController in Swift

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).
UIActivityViewController Example Project
Set up your storyboard with two buttons and hook them up to your view controller (see code below).
Add an image to your Assets.xcassets. I called mine "lion".
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.
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
Add sharing to your Swift app via UIActivityViewController
UIActivity​View​Controller from NSHipster
UIActivityViewController documentation
Share extension documentation
comparison with UIDocumentInteractionController
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)
}
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).
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)
}
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)
}
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)
}
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
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)
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.
or just 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)

Resources