StateFlowiap directory in Android Studio. Replace the APPLICATION_ID property in MainActivity.kt with your actual Application ID — if you skip this step, the sample throws an IllegalStateException when initializing the SDK connection. Build and deploy the sample to your Quest device. For detailed build and deployment steps, see the sample’s README.| File | What it demonstrates | Key concepts |
|---|---|---|
MainActivity.kt | Entry point, SDK initialization, and Compose UI | HorizonServiceConnection.connect(), IapScreen composable |
IapViewModel.kt | IAP business logic and state management | Iap() instantiation, four API methods, StateFlow with IapUiState data class |
IapViewModelTest.kt | Unit tests for ViewModel state | Default state validation, immutable state copy behavior |
app/build.gradle.kts | Build configuration | psdk-core and psdk-iap dependencies, SDK levels |
SKU-sub-1, sku-consumable-1, sku-dur-1, sku-dur-2, sku1, sku2). Select one or more SKUs, then tap Get Products to retrieve product details including name and price. Tap Get Purchases to query your existing purchases. To test the checkout flow, select exactly one SKU and tap Launch Checkout — after completing the flow, the purchase JSON appears in the output area. Tap Consume Purchase to consume a consumable item. Results and errors appear in the output area with errors displayed in red.MainActivity.onCreate() before setting up the Compose UI:HorizonServiceConnection.connect(
APPLICATION_ID, applicationContext, lifecycleScope
)
IapViewModel creates the IAP client with a no-argument constructor:private val iap = Iap()
HorizonServiceConnection.connect().val pagedResults = iap.getProductsBySku(viewModelScope, skus)
pagedResults.fetchInitialPage().get()
val products = pagedResults.getFetchedPages()
.firstOrNull()?.getContents() ?: emptyList()
IapViewModel.kt.IapUiState data class exposed through StateFlow for reactive state management. All API calls run on Dispatchers.IO and update state through the immutable copy pattern:_uiState.update {
it.copy(isLoading = false, resultMessage = text)
}