Composing Rich Link Previews Using LinkPresentation in Swift
LinkPresentation is a newly-available (iOS 13+) framework from Apple that enables developers to create rich links just like Apple’s own native apps do. For example, a link shared from Safari displays as a large thumbnail with details beneath it:
Links such as these are generated by the system when provided the correct metadata, as represented by an LPLinkMetadata object.
Passing the appropriate metadata to an instance of UIActivityViewController for example:
import UIKit
import LinkPresentation
class ViewController: UIViewController, UIActivityItemSource {
var metadata: LPLinkMetadata?
// The placeholder the share sheet will use while metadata loads
func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
return "Giant Panda"
}
// The item we want the user to act on.
// In this case, it's the URL to the Wikipedia page
func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any? {
return self.metadata?.url
}
// The metadata we want the system to represent as a rich link
func activityViewControllerLinkMetadata(_ activityViewController: UIActivityViewController) -> LPLinkMetadata? {
return self.metadata
}
@IBAction func shareTapped(_ sender: Any) {
let url = URL(string: "https://en.wikipedia.org/wiki/Giant_panda")!
LPMetadataProvider().startFetchingMetadata(for: url) { linkMetadata, _ in
linkMetadata?.iconProvider = linkMetadata?.imageProvider
self.metadata = linkMetadata
let activityVc = UIActivityViewController(activityItems: [self], applicationActivities: nil)
DispatchQueue.main.async {
self.present(activityVc, animated: true)
}
}
}
}
Results in this representation:
This looks great, however there’s something that could be improved inside our UIActivityViewController. The preview shows the Wikipedia logo, instead of an image of a Giant Panda:
To solve this problem, we can replace the metadata’s icon provider with its own image provider:
@IBAction func shareTapped(_ sender: Any) {
let url = URL(string: "https://en.wikipedia.org/wiki/Giant_panda")!
LPMetadataProvider().startFetchingMetadata(for: url) { linkMetadata, _ in
linkMetadata?.iconProvider = linkMetadata?.imageProvider
self.metadata = linkMetadata
let activityVc = UIActivityViewController(activityItems: [self], applicationActivities: nil)
DispatchQueue.main.async {
self.present(activityVc, animated: true)
}
}
}
This changes the thumbnail in the share sheet to the same image used in the resulting link preview:
Sometimes though, we want to build a link preview from multiple sources. Maybe we want to use a logo hosted at a different URL for any links shared from our site.
Composing metadata from multiple sources
Returning to the Giant Panda example, lets say we want to use a different image of a Giant Panda in our previews. We do this by nesting LPMetadataProvider requests.
@IBAction func shareTapped(_ sender: Any) {
let url = URL(string: "https://en.wikipedia.org/wiki/Giant_panda")!
LPMetadataProvider().startFetchingMetadata(for: url) { linkMetadata, _ in
DispatchQueue.main.async {
LPMetadataProvider().startFetchingMetadata(for: URL(string: "https://upload.wikimedia.org/wikipedia/commons/8/8d/Lightmatter_panda.jpg")!) { imageMetadata, _ in
linkMetadata?.imageProvider = imageMetadata?.imageProvider
linkMetadata?.iconProvider = imageMetadata?.imageProvider
self.metadata = linkMetadata
let activityVc = UIActivityViewController(activityItems: [self], applicationActivities: nil)
DispatchQueue.main.async {
self.present(activityVc, animated: true)
}
}
}
}
}
By fetching LPLinkMetadata from the URL of the image we want to use, we can replace our link metadata’s image and icon providers with the image provider of the new image URL.