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.