Dunfey · Hotel WWDC as data, est. 1983
Front desk everything
Years
Topics

2023 Spatial Computing

WWDC23 · 25 min · Spatial Computing

Build spatial SharePlay experiences

Discover how you can use the GroupActivities framework to build unique sharing and collaboration experiences for visionOS. We’ll introduce you to SharePlay on this platform, learn how to create experiences that make people feel present as if they were in the same space, and explore how immersive apps can respect shared context between participants.

Watch at developer.apple.com ↗

Transcript all transcripts

Code shown on screen · 10 snippets

Observe the local participant state swift · at 4:08 ↗
for await session in ExploreActivity.sessions() {
    guard let systemCoordinator = await session.systemCoordinator else { continue }

    let isLocalParticipantSpatial = systemCoordinator.localParticipantState.isSpatial

    Task.detached {
        for await localParticipantState in systemCoordinator.localParticipantStates {
            if localParticipantState.isSpatial {
                // Start syncing scroll position
            } else {
                // Stop syncing scroll position
            }
        }
    }
}
Configure the spatial template preferences swift · at 6:10 ↗
for await session in ExploreActivity.sessions() {
    guard let systemCoordinator = await session.systemCoordinator else { continue }

    var configuration = SystemCoordinator.Configuration()
    configuration.spatialTemplatePreference = .sideBySide
    systemCoordinator.configuration = configuration

    session.join()
}
Configuring scene activation conditions swift · at 9:10 ↗
@main
struct ExploreTogetherApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .handlesExternalEvents(
                    preferring: ["com.example.explore-together.activity"],
                    allowing: ["com.example.explore-together.activity"]
                )
        }
    }
}
Configuring scene activation conditions swift · at 9:30 ↗
class SceneDelegate: NSObject, UISceneDelegate {

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        // ...

        scene.activationConditions.canActivateForTargetContentIdentifierPredicate =
                NSPredicate(format: "self == %@", "com.example.explore-together.activity")

        scene.activationConditions.prefersToActivateForTargetContentIdentifierPredicate =
                NSPredicate(format: "self == %@", "com.example.explore-together.activity")
    }
}
Setting scene association behavior swift · at 10:40 ↗
struct ExploreActivity: GroupActivity {
    var metadata: GroupActivityMetadata {
        var metadata = GroupActivityMetadata()
        // ...
        metadata.sceneAssociationBehavior = .content("document-1")
        return metadata
    }
}
Starting SharePlay swift · at 13:44 ↗
// Create the activity
let activity = ExploreActivity()

// Register the activity on the item provider
let itemProvider = NSItemProvider()
itemProvider.registerGroupActivity(activity)

// Create the activity items configuration
let configuration = UIActivityItemsConfiguration(itemProviders: [itemProvider])

// Provide the metadata for the group activity
configuration.metadataProvider = { key in
    guard key == .linkPresentationMetadata else { return nil }
    let metadata = LPLinkMetadata()
    metadata.title = "Explore Together"
    metadata.imageProvider = NSItemProvider(object: UIImage(named: "explore-activity")!)
    return metadata
}
self.activityItemsConfiguration = configuration
Configure group ImmersiveSpace swift · at 16:03 ↗
for await session in ExploreActivity.sessions() {
    guard let systemCoordinator = await session.systemCoordinator else { continue }

    var configuration = SystemCoordinator.Configuration()
    configuration.supportsGroupImmersiveSpace = true
    systemCoordinator.configuration = configuration
}
System Experience Displacement swift · at 17:51 ↗
// Use immersiveSpaceDisplacement to offset contents in group immersive space

var body: some Scene {
    ImmersiveSpace(id: "earth") {
        GeometryReader3D { proxy in
            let displacement = proxy.immersiveSpaceDisplacement(in: .global).inverse

            Control()
                .offset(displacement.position)
                .rotation3DEffect(displacement.rotation)
        }
    }
}
Spatial Template Preferences swift · at 20:46 ↗
// Configure the spatial template preferences with content extent

for await session in ExploreSolarActivity.sessions() {
    guard let systemCoordinator = await session.systemCoordinator else { continue }

    var configuration = SystemCoordinator.Configuration()
    configuration.supportsGroupImmersiveSpace = true
    configuration.spatialTemplatePreference = .sideBySide.contentExtent(200)
    systemCoordinator.configuration = configuration
}
Receive group immersion style to configure group immersive space swift · at 22:32 ↗
// Receive group immersion style to configure group immersive space

for await session in ExploreSolarActivity.sessions() {
    guard let systemCoordinator = await session.systemCoordinator else { continue }

    Task.detached {
        for await immersionStyle in systemCoordinator.groupImmersionStyle {
            if let immersionStyle {
                // Open an immersive space with the same immersion style
            } else {
                // Dismiss the immersive space
            }
        }
    }
}

Resources