在Swift中使用UIActivityViewController分享文本或图像的基本示例

179

我开始搜索想知道如何在iOS中分享到其他应用程序。我发现有两种重要的方法:

  • UIActivityViewController
  • UIDocumentInteractionController

这些方法和其他方法在这个SO答案中进行了比较。

通常,当我学习一个新概念时,我喜欢看一个基本示例来让我开始。一旦我设置了基本内容,我可以稍后根据自己的需求进行修改。

有很多与UIActivityViewController相关的SO问题,但我找不到只是要求简单示例的问题。因为我刚刚学会如何做到这一点,所以我将在下面提供我的答案。欢迎添加更好的答案(或Objective-C版本)。

7个回答

342

UIActivityViewController示例项目

在故事板中设置两个按钮并将它们连接到您的视图控制器(请参见下面的代码)。

输入图像描述

向Assets.xcassets添加一张图片。我把我的叫做“lion”。

输入图像描述

代码

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)
    }
    
}

结果

点击“分享一些文本”将在左侧给出结果,点击“分享一张图片”将在右侧给出结果。

enter image description here

注释

  • 我使用iOS 11和Swift 4进行了重新测试。由于超时而需要在模拟器中运行几次才能使其工作。这可能是因为我的电脑速度较慢。
  • 如果您希望隐藏其中的一些选项,可以使用上面代码中所示的excludedActivityTypes来实现。
  • 不包含popoverPresentationController?.sourceView这一行会导致您的应用在iPad上运行时崩溃。
  • 这不允许您将文本或图像共享到其他应用程序。您可能需要使用UIDocumentInteractionController

另请参阅


1
为什么有些示例显示一个项目的数组,而有些则显示两个?假设共享一张图片。 - Lim Thye Chean
@ Suragch:你好,我想在文本中分享一个推荐码,并希望在单击或点击时将该代码复制,就像发送数字时发生的那样。 - Ishika

115

分享:文本

@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)
}
}

分享:图像

@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)
 }

分享:文本 - 图片 - 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)
   }

输入图像描述


6
嗨,它没起作用。在Facebook上只分享了链接而没有图片和文字。 - Ekta Padaliya
1
根据Facebook的更新政策,只能分享URL或图像,无法分享文本。@EktaPadaliya - Awais Fayyaz
2
@Mr.JavedMultani 在 WhatsApp 中未分享图像。 - NickCoder
嗨,我想要在数组中选择音频和文本,然后只显示文本以进行共享。如何将您的应用程序徽标添加为共享意图中的默认音频文件徽标。 - Haider Awan
@Harsha 上面的例子是针对文本-图像-URL的,如果您想分享文件,则需要提及从文档目录/本地传递路径。 - Mr.Javed Multani
显示剩余4条评论

17

请注意,您也可以在iPad上使用此方法:

activityViewController.popoverPresentationController?.sourceView = sender

因此,弹出窗口从发送者(在这种情况下为按钮)弹出。


1
activityViewController.popoverPresentationController?.sourceView = sender as? UIView 这行代码对我来说有效。 :) 谢谢 - Brian Bird
分享框在iPad上无法弹出。这个修复了我遇到的iPad问题! - Asp Upload

13

如果您想分享整个屏幕,我发现这个方法完美无缺。

@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)
}

10

我使用了上面的实现方式,但刚刚才发现它在运行iOS 13的iPad上无法正常工作。为了让它正常运行,我必须在present()调用之前添加这些代码。

//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)
}

这就是对我起作用的方式

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
你可以使用我在项目辅助类中编写的以下函数。只需要调用:
showShareActivity(msg:"message", image: nil, url: nil, sourceRect: nil) 

它适用于iPhone和iPad。如果您通过sourceRect传递任何视图的CGRect值,它也会在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)
}

完美运行! - Ravindra_Bhati
5
可以用[url, image, msg].compactMap({ $0 })替换掉一系列的if语句。 - Avi
1
当您尝试同时发送图像和消息时,此解决方案无法通过WhatsApp进行共享。 - Shankar

3
iOS分享文本或图像
展示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)

将图像保存到库中

如果您要将图像保存到库中,请在应用的.plist文件中添加NSPhotoLibraryAddUsageDescription,否则会出现运行时错误:

此应用程序崩溃,因为它尝试访问敏感数据而没有使用说明。应用程序的Info.plist必须包含一个带有字符串值的NSPhotoLibraryAddUsageDescription键,向用户解释应用程序如何使用这些数据。

此外,您还可以排除此机会:

controller.excludedActivityTypes = [.saveToCameraRoll]

具有 completionWithItemsHandler 变种,可帮助添加后处理逻辑或处理错误。

例如,在相应的处理程序中将 UIImage 保存到照片库时遇到了以下错误:

Error Domain=ALAssetsLibraryErrorDomain Code=-1 "未知错误" UserInfo={NSLocalizedDescription=未知错误, NSUnderlyingError=0x600003f85110 {Error Domain=PHPhotosErrorDomain Code=3303 "(null)"}}

经过分析,我尝试保存 CIImage。作为一种替代方法,您可以将其转换为 CGImage

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

自定义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
    }
}

使用:

let imageActivityItemSource = ImageActivityItemSource(image: image, title: "Share this image with others")
let ac = UIActivityViewController(activityItems: [imageActivityItemSource], applicationActivities: nil)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接