Vue NativeVue Native
Guide
Components
Composables
Navigation
Architecture
  • iOS
  • Android
  • macOS
GitHub
Guide
Components
Composables
Navigation
Architecture
  • iOS
  • Android
  • macOS
GitHub
  • Device & System

    • useNetwork
    • useAppState
    • useColorScheme
    • useDeviceInfo
    • useBattery
    • useDimensions
    • usePlatform
  • Storage & Files

    • useAsyncStorage
    • useSecureStorage
    • useFileSystem
    • useDatabase
  • Sensors & Hardware

    • useGeolocation
    • useBiometry
    • useHaptics
    • useSensors
    • useBluetooth
  • Media

    • useCamera
    • useImagePicker
    • useAudio
    • useCalendar
    • useContacts
  • Networking

    • useHttp
    • useWebSocket
  • Permissions

    • usePermissions
  • Navigation

    • useBackHandler
    • useSharedElementTransition
  • UI

    • useKeyboard
    • useClipboard
    • useAccessibility
    • useShare
    • useLinking
    • useAnimation
    • useGesture
    • useTeleport
    • useNotifications
    • useI18n
    • usePerformance
    • useInspector
  • Authentication

    • useAppleSignIn
    • useGoogleSignIn
  • Monetization & Updates

    • useIAP
    • useOTAUpdate
    • useBackgroundTask
  • Desktop (macOS)

    • useWindow
    • useMenu
    • useFileDialog
    • useDragDrop

useIAP

In-App Purchases composable backed by StoreKit 2 (iOS) and Google Play Billing Library (Android). Supports one-time purchases, subscriptions, restoring purchases, and transaction monitoring.

Setup

iOS

No additional setup required. StoreKit 2 is built into iOS 15+. Configure your products in App Store Connect.

Android

Add the Google Play Billing Library to your build.gradle:

dependencies {
    implementation 'com.android.billingclient:billing:6.0.1'
}

Configure your products in the Google Play Console.

Usage

<script setup>
import { ref } from '@thelacanians/vue-native-runtime'
import { useIAP } from '@thelacanians/vue-native-runtime'

const { products, getProducts, purchase, restorePurchases, isReady, error } = useIAP()

// Load products when ready
async function loadProducts() {
  await getProducts(['com.myapp.premium', 'com.myapp.coins100'])
}

async function buyPremium() {
  const result = await purchase('com.myapp.premium')
  if (result) {
    console.log('Purchased:', result.transactionId)
  }
}
</script>

<template>
  <VView :style="{ flex: 1, padding: 20 }">
    <VButton :onPress="loadProducts">
      <VText>Load Products</VText>
    </VButton>

    <VView v-for="product in products" :key="product.id" :style="{ marginTop: 10 }">
      <VText>{{ product.displayName }} - {{ product.displayPrice }}</VText>
      <VButton :onPress="() => purchase(product.id)">
        <VText>Buy</VText>
      </VButton>
    </VView>

    <VText v-if="error" :style="{ color: 'red', marginTop: 10 }">{{ error }}</VText>
  </VView>
</template>

API

useIAP(): {
  products: Ref<Product[]>
  isReady: Ref<boolean>
  error: Ref<string | null>
  getProducts: (skus: string[]) => Promise<Product[]>
  purchase: (sku: string, options?: PurchaseOptions) => Promise<Purchase | null>
  restorePurchases: () => Promise<Purchase[]>
  getActiveSubscriptions: () => Promise<Purchase[]>
  showManageSubscriptions: () => Promise<void>
  onTransactionUpdate: (callback: (update: TransactionUpdate) => void) => () => void
}

Reactive State

PropertyTypeDescription
productsRef<Product[]>Products loaded by getProducts(). Updated reactively.
isReadyRef<boolean>true once the billing client is initialized.
errorRef<string | null>Last error message, or null. Cleared before each operation.

Methods

getProducts(skus)

Fetch product information from the store.

ParameterTypeDescription
skusstring[]Array of product identifiers to fetch.

Returns Promise<Product[]>. Also updates the reactive products ref.

purchase(sku, options?)

Initiate a purchase flow for the given product.

ParameterTypeDescription
skustringProduct identifier to purchase.
options.appAccountTokenstring?iOS: a UUID tying the purchase to your user. It comes back on every transaction and in App Store Server Notifications.

Returns Promise<Purchase | null>. Returns null on failure (error set in error ref).

restorePurchases()

Restore all previous purchases. Useful for users who reinstall the app or switch devices.

Returns Promise<Purchase[]>.

getActiveSubscriptions()

Get all currently active auto-renewable subscriptions.

Returns Promise<Purchase[]>.

showManageSubscriptions()

Open the system screen where the user manages or cancels subscriptions: the StoreKit sheet on iOS, the Play Store subscription center on Android.

onTransactionUpdate(callback)

Register a callback for transaction state changes. Useful for monitoring pending transactions.

ParameterTypeDescription
callback(update: TransactionUpdate) => voidCalled when a transaction state changes.

Returns a cleanup function to unsubscribe.

Types

Product

PropertyTypeDescription
idstringProduct identifier (SKU).
displayNamestringLocalized product name.
descriptionstringLocalized product description.
pricenumberPrice as a number.
displayPricestringFormatted price string (e.g. "$9.99").
currencyCodestringISO 4217 currency code.
typeProductTypeProduct type.

ProductType

'consumable' | 'nonConsumable' | 'autoRenewable' | 'nonRenewable'

Purchase

PropertyTypeDescription
productIdstringThe purchased product's identifier.
transactionIdstringUnique transaction identifier.
originalTransactionIdstring?Original transaction ID (for renewals).
purchaseDatestringISO 8601 purchase date.
expiresDatestring?Expiration date for subscriptions.
jwsRepresentationstring?iOS: the App Store–signed transaction (JWS). Verify it on your server (App Store Server Library) before granting anything.
appAccountTokenstring?iOS: the token passed to purchase(), lowercased.
environmentstring?iOS 16+: Production, Sandbox or Xcode.

PurchaseOptions

PropertyTypeDescription
appAccountTokenstring?iOS: UUID string attached to the transaction.

TransactionUpdate

PropertyTypeDescription
productIdstringProduct identifier.
stateTransactionStateCurrent state of the transaction.
transactionIdstring?Transaction identifier.
errorstring?Error message if state is 'failed'.
jwsRepresentation, originalTransactionId, expiresDate, appAccountTokeniOS: same as on Purchase, for renewals and refunds that arrive while the app runs.

TransactionState

'purchasing' | 'purchased' | 'failed' | 'restored' | 'deferred' | 'revoked'

Server Verification (iOS)

Never unlock paid features from the client's word alone. Send jwsRepresentation to your server, verify its signature with Apple's App Store Server Library, and check that its appAccountToken matches the signed-in user:

const result = await purchase('com.myapp.premium.monthly', { appAccountToken: user.purchaseToken })
if (result?.jwsRepresentation) {
  await fetch('https://api.example.com/iap/verify', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ jws: result.jwsRepresentation }),
  })
}

Restore Purchases Example

<script setup>
import { ref } from '@thelacanians/vue-native-runtime'
import { useIAP } from '@thelacanians/vue-native-runtime'

const { restorePurchases, error } = useIAP()
const restoredCount = ref(0)

async function handleRestore() {
  const restored = await restorePurchases()
  restoredCount.value = restored.length
}
</script>

<template>
  <VView :style="{ padding: 20 }">
    <VButton :onPress="handleRestore">
      <VText>Restore Purchases</VText>
    </VButton>
    <VText v-if="restoredCount > 0">Restored {{ restoredCount }} purchase(s)</VText>
    <VText v-if="error" :style="{ color: 'red' }">{{ error }}</VText>
  </VView>
</template>

Subscription Example

<script setup>
import { ref, onMounted } from '@thelacanians/vue-native-runtime'
import { useIAP } from '@thelacanians/vue-native-runtime'

const { getProducts, purchase, getActiveSubscriptions, products, error } = useIAP()
const activeSubs = ref([])

onMounted(async () => {
  await getProducts(['com.myapp.monthly', 'com.myapp.yearly'])
  activeSubs.value = await getActiveSubscriptions()
})

async function subscribe(sku) {
  const result = await purchase(sku)
  if (result) {
    activeSubs.value = await getActiveSubscriptions()
  }
}
</script>

<template>
  <VView :style="{ flex: 1, padding: 20 }">
    <VText :style="{ fontSize: 20, fontWeight: 'bold' }">Subscriptions</VText>

    <VView v-for="product in products" :key="product.id" :style="{ marginTop: 10 }">
      <VText>{{ product.displayName }} - {{ product.displayPrice }}</VText>
      <VButton :onPress="() => subscribe(product.id)">
        <VText>Subscribe</VText>
      </VButton>
    </VView>

    <VText :style="{ marginTop: 20, fontWeight: 'bold' }">
      Active Subscriptions: {{ activeSubs.length }}
    </VText>
  </VView>
</template>

Platform Support

PlatformSupport
iOSStoreKit 2. Requires iOS 15.0+.
AndroidGoogle Play Billing Library 6.x.

Notes

  • The billing client is automatically initialized when useIAP() is called. Check isReady before making purchases.
  • All methods clear the error ref before executing. Check error after each call for failure details.
  • On iOS, transactions are automatically verified using StoreKit 2's built-in verification.
  • On Android, purchases are automatically acknowledged after successful purchase.
  • The onTransactionUpdate callback fires for server-side transaction updates (e.g., subscription renewals, refunds).
  • Always call getProducts() before purchase() to populate the product cache.
Edit this page
Last Updated: 10/15/26, 1:53 AM
Contributors: Abdul Hamid, Claude Opus 5.5
Next
useOTAUpdate