How to: Implementing “Shared with You” APIs

Short tutorial about adopting the Shared with You framework available in iOS 16.

Published: Feb. 18, 2023
See books

One of the new frameworks that iOS 16 brought is the 3rd party support for Shared with You. This is an Apple feature that let’s app access links that the user received via iMessage from their contacts.

The idea is that the user can quickly access recommended content directly in the particular app without digging through older messages. So instead of searching the conversation for the podcast link, you can easily find it in the Podcasts app.

Intro and prerequisites

The difficulty of implementing this depends on whether your app supports Universal Links. Because this directly ties into this older feature. If you don’t support Universal Links, you will need to do so before you can dive into Shared with You.

With the Universal Links prerequisite explained, we can simplify the whole Shared with You. The framework boils down to a way to access received links tied to your app and the anonymous info about the senders.

Also, before we get further, this article will deal with just basic Shared with You implementation that surfaces the received links. There is a whole set of APIs for dealing with collaboration that we won’t go into. And keep in mind that the view components are UIKit (or AppKit on macOS).

Implementation steps

The first is to add the “Shared with You” capability to your project. Once you do this, you can start using the parts needed.

At a minimum you need to implement some sort of presenting the received links, ideally with attribution views. The rest is up to you. I will showcase the practical implementation I did in SwitchBuddy app, which I will be shipping soon in a new update. However, I want to add that this might not be “the best practice”.

SwitchBuddy - Nintendo Switch companion Shared with You

Since my app supports older iOS versions, I needed to put this implementation behind the available attributes.

I decided to have a “link card” and put the received stuff on dedicated screen. For this, I have this helper class:

import Foundation
import SharedWithYou
import Combine

@available(iOS 16, *)
final class SharedWithYouSupport: NSObject, SWHighlightCenterDelegate {
    static let shared = SharedWithYouSupport()
    private let highlightCenter = SWHighlightCenter()
    let highlightsChanged = PassthroughSubject<Void, Never>()

    private override init() {
        super.init()

        highlightCenter.delegate = self
    }

    var highlights: [SWHighlight] {
        return highlightCenter.highlights
    }

    var hasHighlights: Bool {
        return highlightCenter.highlights.isEmpty == false
    }

    func highlightCenterHighlightsDidChange(_ highlightCenter: SWHighlightCenter) {
        highlightsChanged.send()
    }
}

Only a little code, right? The SWHighlightCenter is the main gateway for the links. You get the SWHighlight, a container that holds the actual URL and unique identifier we will use soon.

I am using the Combine publisher as a simple “notification” to know when highlights changed to update the count on my “link card” or to refresh the links screen if the user is currently looking at it.

Showing the link content

The next step is to show the highlights. For this, I decided to experiment with LPLinkView from the LinkPresentation framework. This view gives you (the same?) link previews you can see in the Messages app.

My initial reason was that I thought I could pass the URL to this view and be done with it. It has init that takes a URL as a single parameter. However, this is used only to create a placeholder view.

To get LPLinkView to display anything useful, you need to provide it with LPLinkMetadata object. To get these data, you can use LPMetadataProvider and call startFetchingMetadata.

Apple also recommends caching this metadata which is a sensible idea. My other reason for choosing this approach is that I don’t have all the data available locally for all possible links, and I would need to do a network call either way.

If you can easily parse the URL and present preview data without needing a network call, that would work better.

Adding link attribution

No matter how you decide to show the link preview, you should add the SWAttributionView, which shows the contact that sent the link, and tapping on it opens a special Messages window where the user can reply to the message that contains the shared link.

The usage can look something like this:

let attributionView = SWAttributionView()
attributionView.translatesAutoresizingMaskIntoConstraints = false
attributionView.highlight = highlight
attributionView.displayContext = .detail

attributionView.horizontalAlignment = .leading

You can also specify the backgroundStyle depending on what is behind this view.

Conclusion

And that is it! Thanks for reading and let me know if you know how to improve the code above.

One of the pitfalls I ran into is LPLinkMetadata not being friends with Codable so disk caching is something I skipped for now. It supports the NSSecureCoding but I wasn’t able to make it work in a reasonable timeframe.

Resources

Filip Němeček profile photo

WRITTEN BY

Filip Němeček @nemecek_f@iosdev.space

iOS blogger and developer with interest in Python/Django. Want to see most recent projects? 👀

iOS blogger and developer with interest in Python/Django. Want to see most recent projects? 👀