Develop

Application sample overview

Updated: May 8, 2026

Overview

This sample demonstrates the Application API in the Meta Horizon Platform SDK. It shows how to query app version information, launch other apps with deeplink options, and manage app downloads and updates on Meta Quest devices. View the sample source code on GitHub.

What you will learn

  • Initialize the Horizon Platform SDK using HorizonServiceConnection
  • Query application version information with Application.getVersion()
  • Launch other apps with deeplink options using Application.launchOtherApp()
  • Manage app downloads and updates with startAppDownload(), cancelAppDownload(), and installAppUpdateAndRelaunch()
  • Structure SDK API calls with coroutine-based loading and error states

Requirements

  • Meta Quest device with developer mode enabled
  • Android Studio (recommended: latest stable version)
  • Kotlin development environment
For detailed developer mode setup instructions, see Mobile device setup.

Get started

Clone the Horizon Platform SDK samples repository and open the application project in Android Studio. Replace the APPLICATION_ID placeholder in MainActivity.kt with your own application ID from the Meta Developer Dashboard. Build the project and deploy it to your Meta Quest device via ADB. For complete build instructions and version requirements, see the sample’s README.

Explore the sample

The sample uses MVVM architecture with Jetpack Compose UI and a ViewModel managing SDK interactions.
FileWhat it demonstratesKey concepts
MainActivity.kt
SDK initialization and UI entry point
HorizonServiceConnection.connect() pattern, Compose setup, state collection with collectAsStateWithLifecycle()
ApplicationViewModel.kt
Application API usage, state management
Application() instantiation, coroutine-based SDK calls on Dispatchers.IO, StateFlow with data class UiState pattern
ApplicationViewModelTest.kt
Unit testing ViewModel state
Testing state defaults and immutability with data class copy()
app/build.gradle.kts
SDK integration and dependencies
Core and application module dependencies, Compose BOM configuration

Runtime behavior

When you run this sample, you see a screen titled Application Sample with five buttons. Tapping Get Version queries the current app version and displays the JSON response in a card below the buttons. Launch Other App opens Beat Saber (if installed) with a deeplink message and destination API name. The three download-related buttons — Start App Download, Cancel App Download, and Install App Update and Relaunch — demonstrate download and update lifecycle management. Each button shows a loading indicator while the API call executes, then displays either the JSON result or an error message in a colored card.

Key concepts

SDK initialization pattern

The sample initializes the Horizon Platform SDK in MainActivity.onCreate() before setting up the Compose UI. The HorizonServiceConnection.connect() method takes three parameters: your application ID, the application context, and a coroutine scope (typically lifecycleScope). This initialization pattern is shared across all Horizon Platform SDK samples.

Reusable action execution wrapper

The ApplicationViewModel defines an executeAction function that wraps SDK calls with standardized loading and error handling. This pattern eliminates repetitive try/catch blocks and state management code across all five API methods. The wrapper sets isLoading = true, executes the SDK call on Dispatchers.IO, captures the JSON result or error message, and updates the UI state accordingly.
See the executeAction() method in ApplicationViewModel.kt.

Builder pattern for API options

The launchOtherApp() method demonstrates the options pattern used throughout the Horizon Platform SDK. The sample uses ApplicationOptions.builder() to configure a deeplink message and destination API name, then calls .build() to create the immutable options object.
See the launchOtherApp() method in ApplicationViewModel.kt.

Coroutine-based state management

The sample uses MutableStateFlow<ApplicationUiState> to manage UI state and exposes it as an immutable StateFlow. The Compose UI collects this flow with collectAsStateWithLifecycle(), ensuring state updates survive configuration changes and automatically cancel collection when the lifecycle stops. All SDK calls launch in viewModelScope on Dispatchers.IO to keep the main thread responsive.

Extend the sample

  • Modify the “Launch Other App” target to launch a different app by changing the application ID passed to launchOtherApp().
  • Experiment with different deeplink messages and destination API names.
  • Add error-specific handling by replacing the generic catch(Exception) block with targeted handlers for different failure modes.