Develop

Group Presence sample overview

Updated: May 8, 2026

Overview

The Group Presence sample shows how to set and clear multiplayer presence information, manage destination and joinability state, and listen for join intents when other users attempt to join your session. It uses MVVM architecture with reactive state management using Kotlin Flows, targeting developers building multiplayer or social experiences on Meta Quest devices. View the sample source code on GitHub.

What you will learn

  • Initializing the Horizon Platform SDK using HorizonServiceConnection
  • Building and setting group presence options including deeplink messages, destinations, lobby IDs, and match session IDs
  • Updating presence state dynamically using individual setter methods
  • Listening for and handling join intents from other users using Kotlin Flows
  • Structuring a presence-aware Android application using MVVM with Compose UI

Requirements

  • Meta Quest device with Developer Mode enabled
  • Android development environment with Kotlin support
For detailed build prerequisites and SDK version requirements, see the repository README. For platform setup instructions, see the Horizon Platform SDK setup guide.

Get started

Clone the horizon-platform-sdk-samples repository and open the grouppresence project in Android Studio. Connect your Meta Quest device via USB, ensure Developer Mode is enabled, and run the app from the IDE. For complete build instructions and dependency configuration, see the sample README.

Explore the sample

FileWhat it demonstratesKey concepts
MainActivity.kt
SDK initialization and Compose UI setup
HorizonServiceConnection.connect() with application ID, context, and coroutine scope
GroupPresenceViewModel.kt
Complete Group Presence API usage
GroupPresence() instantiation, GroupPresenceOptions builder pattern, StateFlow, Flow-based join intent handling
GroupPresenceViewModelTest.kt
Unit testing for UI state
GroupPresenceUiState data class validation and copy behavior

Runtime behavior

When you run this sample, you see a screen titled Group Presence Sample with two sections of buttons and an output area. The Group Presence section contains Set and Clear buttons in the top row, with Set Destination and Set Joinable buttons in the second row. The Events section contains a Listen for Join Intent button. Each button triggers a Group Presence API call and displays the result or error message in the output area below.

Key concepts

SDK initialization

The sample initializes the Horizon Platform SDK once in MainActivity.onCreate():
HorizonServiceConnection.connect(
    applicationId, applicationContext, lifecycleScope
)

Building group presence options

The sample uses the builder pattern to construct GroupPresenceOptions:
val options = GroupPresenceOptions.builder()
    .withDeeplinkMessageOverride("custom_deeplink")
    .withDestinationApiName("lobby_01")
    .withIsJoinable(true)
    .withLobbySessionId("lobby_session_01")
    .withMatchSessionId("match_session_01")
    .build()
See the setGroupPresence() method in GroupPresenceViewModel.kt.

Handling join intents

The sample listens for join intents using a Flow:
val details = groupPresence.joinIntentReceived().first()
The joinIntentReceived() method returns a Flow that emits join intent details whenever another user attempts to join your session. The sample uses .first() to collect a single emission. For continuous monitoring, use collect() instead.

Extend the sample

  • Add persistent presence state: Store the current group presence configuration locally and restore it when the app restarts.
  • Implement multi-user join handling: Replace .first() with collect() to continuously monitor join intents from multiple users.
  • Combine with Rich Presence: Integrate the Rich Presence API to display additional context about the user’s current activity.