SharePlay and Personas

One of the big benefits of VisionOS is the feeling of presence when in FaceTime. So how do you hook it into your apps and games?

//start an activity
let activity = GameShareActivity()
_ = try await activity.activate()

With an activity you can check sessions:

//listen for sessions
for await session in GameShareActivity.sessions() {
}

And with sessions you can listen for messages:

self.session = session
let messenger = GroupSessionMessenger(session: session)
self.messenger = messenger

for await (message, _) in messenger.messages(of: String.self) {
}

And of course, you'll need something to send messages:

await messenger?.send(data)

What is the data? There are a few options, I keep it as a string which as a bunch of json I can handle as I want.

Putting it all together

class SharePlayManager: ObservableObject {
    static let shared = SharePlayManager()
    
    private var session: GroupSession<GameShareActivity>? = nil
    private var messenger: GroupSessionMessenger? = nil
    private var sessionListeningTask: Task<Void, Never>? = nil
    private var isListening = false
    
    init() {
        // Start listening for SharePlay sessions immediately when app launches
        startListeningForSessions()
    }

    private func startListeningForSessions() {
        guard !isListening else { return }
        isListening = true
        
        sessionListeningTask = Task {
            for await session in GameShareActivity.sessions() {
                await handleSession(session)
                break // Only handle the first session
            }
        }
    }
    
    private func handleSession(_ session: GroupSession<GameShareActivity>) async {
        self.session = session
        let messenger = GroupSessionMessenger(session: session)
        self.messenger = messenger
        
        // Setup message listener
        Task.detached { [weak self] in
            for await (message, _) in messenger.messages(of: String.self) {
                //handle message received
            }
        }
        
        session.join()
    }
    
    func startSharePlay() async {
        Task {
            do {
                let activity = GameShareActivity()
                _ = try await activity.activate()
                // The session will be automatically detected by our listener
            } catch {
                print("Failed to start SharePlay: \(error)")
            }
        }
    }
    
    func sendGameEvent(_ data: String) async {
        Task {
            do {
                try await messenger?.send(data)
            } catch {
                print("Failed to send message: \(error)")
            }
        }
    }
}

Wait, what about Personas and all that?

Automatically handled 😃 But if you want to tweak some things, here are some options:

let systemCoordinator = await session.systemCoordinator
var configuration = SystemCoordinator.Configuration()
 
// make this change
configuration.supportsGroupImmersiveSpace = true
 
configuration.spatialTemplatePreference = .sideBySide
systemCoordinator?.configuration = configuration

All done!

Subscribe to Hands on Vision

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe