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
}
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):
... 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
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With