Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS: Sharing via UIActivityViewController does not work with UIActivityItemSource

Tags:

ios

swift

I wanted to further customize how content is shared from my app and instead of providing UIActivityViewController with image and title use the UIActivityItemSource protocol to implement methods that provide this content.

So I created extension for my model Scan like this:

extension Scan: UIActivityItemSource {
    func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
        return self.title as Any
    }

    func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any? {
        return self.orderedDocuments.map({ $0.image }) as Any
    }

    func activityViewController(_ activityViewController: UIActivityViewController, thumbnailImageForActivityType activityType: UIActivity.ActivityType?, suggestedSize size: CGSize) -> UIImage? {
        return self.thumbnailImage
    }

    func activityViewController(_ activityViewController: UIActivityViewController, subjectForActivityType activityType: UIActivity.ActivityType?) -> String {
        return "Scan from: \(String(describing: self.created))"
    }
}

But when I pass instance of Scan to the UIActivityViewController it opens but it is empty. I cannot see the title, preview or the actual images.. These methods are getting called.

I am presenting the UIActivityViewController like this as there is not much to customize:

func share(_ scan: Scan) {

        let shareController = UIActivityViewController(activityItems: [scan], applicationActivities: nil)

        present(shareController, animated: true)
}

The Scan is Core Data entity but I tried creating separate class just for sharing and that did not work either.

EDIT: So I got some progress with metadata like this:

func activityViewControllerLinkMetadata(_ activityViewController: UIActivityViewController) -> LPLinkMetadata? {
        guard let image = self.orderedDocuments.first?.image else { return nil }
        let imageProvider = NSItemProvider(object: image)
        let metadata = LPLinkMetadata()
        metadata.imageProvider = imageProvider
        metadata.title = title
        return metadata
    }

It at least shows proper title and thumbnail. I have seen some apps even displaying subtitle and file size which I guess is not possible for in-memory images?

I still have issues with sharing more than one image.

My updated activity controller methods:

func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any? {
        return self.orderedDocuments.first?.image
    }

    func activityViewController(_ activityViewController: UIActivityViewController, dataTypeIdentifierForActivityType activityType: UIActivity.ActivityType?) -> String {
        return kUTTypePNG as String
    }
like image 860
Filip Avatar asked Apr 18 '20 14:04

Filip


Video Answer


1 Answers

Regarding:

I have seen some apps even displaying subtitle and file size which I guess is not possible for in-memory images?

It's silly, but can be done with:

linkMetaData.originalURL = URL(fileURLWithPath: "Insert whatever info here")

For example, for a result like this (custom thumbnail, custom title and subtitle with file size):

myBaby

... the code is:

func activityViewControllerLinkMetadata(_ activityViewController: UIActivityViewController) -> LPLinkMetadata? {

    let linkMetaData = LPLinkMetadata()

    // Thumbnail
    linkMetaData.iconProvider = NSItemProvider(object: someValidUIImage)

    // Title
    linkMetaData.title = "Ohay title!"

    // Subtitle with file size
    let prefix = "PNG Image"

    let fileSizeResourceValue = try! someValidURL.resourceValues(forKeys: [.fileSizeKey])
    let fileSizeInt = fileSizeResourceValue.fileSize

    let byteCountFormatter = ByteCountFormatter()
    byteCountFormatter.countStyle = .file
    let fileSizeString = byteCountFormatter.string(fromByteCount: Int64(fileSizeInt))

    let suffix = "・\(fileSizeString)"

    //👇
    linkMetaData.originalURL = URL(fileURLWithPath: "\(prefix)\(suffix)")

    return linkMetaData
}
like image 145
backslash-f Avatar answered Oct 08 '22 04:10

backslash-f