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

2025 Audio & VideoSpatial Computing

WWDC25 · 23 min · Audio & Video / Spatial Computing

Share visionOS experiences with nearby people

Learn how to create shared experiences for people wearing Vision Pro in the same room. We’ll show you how to integrate SharePlay and leverage ARKit in your app, introduce the updated window sharing flows for nearby and FaceTime participants, and cover new API designed for seamless collaboration. Discover best practices to make your collaborative features stand out, easily discoverable, and engaging for people together in the same space.

Watch at developer.apple.com ↗

Transcript all transcripts

Chapters

  • 0:00 — Introduction
  • 0:56 — Learn about nearby sharing
  • 4:21 — Build nearby activities
  • 5:35 — Allow sharing from the share menu
  • 9:15 — Enhance for nearby participants
  • 10:37 — Place content relative to people
  • 13:20 — Coordinate shared media playback
  • 15:38 — Support multiple windows
  • 16:50 — Share anchored content

Code shown on screen · 9 snippets

Expose an activity with GroupActivities and SwiftUI swift · at 6:21 ↗
// Expose an activity with GroupActivities and SwiftUI

import SwiftUI
import GroupActivities

struct BoardGameActivity: GroupActivity, Transferable {
    var metadata: GroupActivityMetadata = {
        var metadata = GroupActivityMetadata()
        metadata.title = "Play Together"
        return metadata
    }()
}

struct BoardGameApp: App {
    var body: some Scene {
        WindowGroup {
            BoardGameView()
            ShareLink(item: BoardGameActivity(), preview: SharePreview("Play Together"))
                .hidden()
        }
        .windowStyle(.volumetric)
    }
}

struct BoardGameView: View {
    var body: some View {
        // Board game content
    }
}
Join a GroupSession with GroupActivities swift · at 7:14 ↗
// Join a GroupSession with GroupActivities

func observeSessions() async {

    // Sessions are created automatically when the activity is activated
    for await session in BoardGameActivity.sessions() {

        // Additional configuration and setup

        // Join SharePlay
        session.join()
    }
}
Join and configure a GroupSession with GroupActivities swift · at 8:57 ↗
// Join a GroupSession with GroupActivities

func observeSessions() async {

    // Sessions are created automatically when the activity is activated
    for await session in BoardGameActivity.sessions() {

        // Additional configuration and setup

        guard let systemCoordinator = await session.systemCoordinator else { continue }
        systemCoordinator.configuration.supportsGroupImmersiveSpace = true

        // Join SharePlay
        session.join()
    }
}
Check for nearby participants with GroupActivities swift · at 9:59 ↗
// Check for nearby participants with GroupActivities

func observeParticipants(session: GroupSession<BoardGameActivity>) async {
    for await activeParticipants in session.$activeParticipants.values {
        let nearbyParticipants = activeParticipants.filter {
            $0.isNearbyWithLocalParticipant && $0 != session.localParticipant
        }
    }
}
Observe local participant pose with GroupActivities swift · at 11:42 ↗
// Observe local participant pose with GroupActivities

func observeLocalParticipantState(session: GroupSession<BoardGameActivity>) async {
    guard let systemCoordinator = await session.systemCoordinator else { return }

    for await localParticipantState in systemCoordinator.localParticipantStates {
        let localParticipantPose = localParticipantState.pose
        // Place presented content relative to the local participant pose
    }
}
Associate a specific window with GroupActivities and SwiftUI swift · at 15:54 ↗
// Associate a specific window with GroupActivities and SwiftUI

import SwiftUI
import GroupActivities

struct BoardGameApp: App {
    var body: some Scene {
        WindowGroup {
            BoardGameView()
            ShareLink(item: BoardGameActivity(), preview: SharePreview("Play Together"))
                .hidden()
        }
        .windowStyle(.volumetric)
        
        WindowGroup(id: "InstructionalVideo") {
            InstructionalVideoView()
                .groupActivityAssociation(.primary("InstructionalVideo"))
        }
    }
}

struct BoardGameView: View {
    var body: some View {
        // Board game content
    }
}

struct InstructionalVideoView: View {
    var body: some View {
        // Video content
    }
}
Create a world anchor with ARKit swift · at 18:27 ↗
// Create a world anchor with ARKit

import ARKit

class AnchorController {

    func setUp(session: ARKitSession, provider: WorldTrackingProvider) async throws {
        try await session.run([provider])
    }

    func createAnchor(at transform: simd_float4x4, provider: WorldTrackingProvider) async throws {
        let anchor = WorldAnchor(originFromAnchorTransform: transform)
        try await provider.addAnchor(anchor)
    }

    func observeWorldTracking(provider: WorldTrackingProvider) async {
       for await update in provider.anchorUpdates {
            switch update.event {
            case .added, .updated, .removed:
                // Add, update, or remove furniture
                break
            }
        }
    }
}
Observe sharing availability with ARKit swift · at 20:02 ↗
// Observe sharing availability with ARKit

func observeSharingAvailability(provider: WorldTrackingProvider) async {
    for await sharingAvailability in provider.worldAnchorSharingAvailability {
         if sharingAvailability == .available {
             // Store availability to check when creating a new shared world anchor
         }
     }
}
Create a shared world anchor with ARKit swift · at 20:24 ↗
// Create a shared world anchor with ARKit

import ARKit

class SharedAnchorController {
    
    func setUp(session: ARKitSession, provider: WorldTrackingProvider) async throws {
        try await session.run([provider])
    }

    func createAnchor(at transform: simd_float4x4, provider: WorldTrackingProvider) async throws {
        let anchor = WorldAnchor(originFromAnchorTransform: transform,
                                 sharedWithNearbyParticipants: true)
        try await provider.addAnchor(anchor)
    }

    func observeWorldTracking(provider: WorldTrackingProvider) async {
       for await update in provider.anchorUpdates {
            switch update.event {
            case .added, .updated, .removed:
                // Add, update, or remove furniture. Updates with shared anchors from others!
                let anchorIdentifier = update.anchor.id
            }
        }
    }
}

Resources