SharePlay updates in iOS 15.4

This article covers the practical SharePlay additions highlighted in the article: starting a FaceTime call directly from an app, understanding the SharePlay option in the share sheet, leaving versus ending a session, requesting foreground presentation, and showing the system's built-in SharePlay notices.

System interface for starting a FaceTime call from a SharePlay-enabled app

This post is a follow-up to earlier SharePlay setup guides. It focuses on the smaller but useful API changes around the iOS 15.4 cycle.

This article was written on February 18, 2022, while iOS 15.4 was still in beta. The underlying ideas are straightforward: Apple was making it easier to start a SharePlay-capable FaceTime flow from within an app and to better control how SharePlay behavior appears in system UI.

This article narrows the scope to a few concrete tasks instead of revisiting the whole SharePlay stack: direct FaceTime call launch, share sheet behavior, session lifecycle control, and system-provided notices.

Context This article describes the state of these APIs as of February 18, 2022. Some wording in the original refers to iOS 15.4 as a beta release.

iOS 15.4 added a cleaner path for starting a FaceTime call directly from a SharePlay-capable app.

The main API here is GroupActivitySharingController. If there is no active FaceTime call in progress, the system can present a contact-picker style UI that lets the user choose participants and start the call from your app.

if #available(iOS 15.4, *) {
    guard let sharingController = try? GroupActivitySharingController(GroupActivityDefinition()) else {
        return
    }
    self.present(sharingController, animated: true)
}

In that snippet, GroupActivityDefinition is the app's own type that conforms to GroupActivity. The system uses that activity definition to understand what will be shared once the call starts.

The article also shows how to do the same thing from SwiftUI by locating the current key window and presenting the controller through its root view controller.

extension UIApplication {
    var keyWindow: UIWindow? {
        return UIApplication.shared.connectedScenes
            .filter { $0.activationState == .foregroundActive }
            .first(where: { $0 is UIWindowScene })
            .flatMap({ $0 as? UIWindowScene })?
            .windows
            .first(where: \.isKeyWindow)
    }
}

if #available(iOS 15.4, *) {
    Button {
        guard let sharingController = try? GroupActivitySharingController(GroupActivityDefinition()) else {
            return
        }
        UIApplication.shared.keyWindow?.rootViewController?.present(sharingController, animated: true)
    } label: {
        Label("Start a FaceTime call", systemImage: "video.badge.plus")
    }
}
SharePlay FaceTime invitation interface
The system UI can suggest FaceTime participants and let the user start the call directly from the app flow.

When the app supports SharePlay, the share sheet can expose a SharePlay option. You can also remove it when the shared item is unrelated.

This article points out that in iOS 15.4 and later, a SharePlay-capable app may show a SharePlay option in the system share sheet. If the current item does not make sense for SharePlay, you can explicitly exclude that option.

let shareSheet = UIActivityViewController(
    activityItems: [URL(string: "https://apple.com")!],
    applicationActivities: nil
)
shareSheet.excludedActivityTypes = [.sharePlay]
UIApplication.shared.keyWindow?.rootViewController?.present(shareSheet, animated: true)

The example in this article uses a plain URL to make the point: not every shared item should surface SharePlay, so the API gives you a way to opt out when the experience would be misleading.

There is an important difference between leaving a session yourself and ending the activity for everyone.

The article calls out two methods that look similar but have different consequences. If one participant wants to leave while keeping the session active for everyone else, use leave().

groupSession?.leave()

If the activity itself should stop for the whole group, use end() instead.

groupSession?.end()

That distinction matters because it maps directly to user intent: personal exit versus global shutdown.

The system can also help by bringing the app forward when necessary and by showing standardized SharePlay notices.

If the shared activity only makes sense while the app is in the foreground, the session can ask the system to bring the experience forward:

groupSession.requestForegroundPresentation()

The article also covers the built-in notice UI. These notices appear with participant avatars and use a constrained set of GroupSessionEvent.Action values supplied by the system.

groupSession?.showNotice(
    .init(originator: originator, action: .play, url: nil)
)
System SharePlay notice UI with participant avatars
The built-in notice UI keeps SharePlay messaging visually consistent with the rest of the system.

This article links to Apple's documentation for the available GroupSessionEvent.Action options, because the API intentionally limits those notices to system-defined actions instead of arbitrary custom messaging.

The value of this update was not a whole new framework. It was removing friction around real SharePlay app flows.

Starting FaceTime from the app, managing whether SharePlay shows up in the share sheet, differentiating leave() from end(), and using the system's own notice UI all make SharePlay feel less like a special-case feature and more like part of the normal platform flow.

That is why this post works well as a short reference. It does not try to teach the entire GroupActivities framework again. It isolates the changes that matter once you already have a SharePlay-capable app.