### Install Expo Dev Client and Run
Source: https://hyochan.github.io/expo-iap/docs/2.7/guides/getting-started
Installs the expo-dev-client for development builds and then runs the application on iOS or Android. This is necessary because Expo Go does not support native modules required for in-app purchases.
```bash
npx expo install expo-dev-client
npx expo run:ios # or npx expo run:android
```
--------------------------------
### Install Expo IAP using npm
Source: https://hyochan.github.io/expo-iap/docs/2.7/guides/getting-started
Installs the expo-iap package using npm. This is the initial step for integrating in-app purchase functionality.
```bash
npm install expo-iap
```
--------------------------------
### Install Expo Modules Core for CLI Projects
Source: https://hyochan.github.io/expo-iap/docs/2.7/guides/getting-started
Installs the latest version of expo-modules-core, which is a prerequisite for React Native CLI projects before installing other Expo modules.
```bash
npx install-expo-modules@latest
```
--------------------------------
### Setup Documentation Development Environment
Source: https://hyochan.github.io/expo-iap/docs/2.9/guides/support
Instructions to set up the local environment for developing and previewing the project's documentation. This involves navigating to the docs directory, installing dependencies, and starting the development server.
```bash
cd docs
npm install
npm start
```
--------------------------------
### Run Example Project
Source: https://hyochan.github.io/expo-iap/docs/guides/support
Instructions to navigate to the example project directory, install its dependencies, and run the project on iOS or Android using Expo.
```bash
cd example
npm install
npx expo run:ios # or run:android
```
--------------------------------
### Install expo-iap
Source: https://hyochan.github.io/expo-iap/docs/2.6/guides/faq
Installs the expo-iap library using the Expo CLI. This is the primary command to get started with the library in your Expo project.
```bash
npx expo install expo-iap
```
--------------------------------
### Running the Expo IAP Example Project
Source: https://hyochan.github.io/expo-iap/docs/2.7/guides/support
Commands to install dependencies and run the example project for Expo IAP on iOS or Android.
```bash
cd example
npm install
npx expo run:ios # or run:android
```
--------------------------------
### Documentation Development Server Setup
Source: https://hyochan.github.io/expo-iap/docs/guides/support
Steps to set up and start the documentation development server locally.
```bash
cd docs
npm install
npm start
```
--------------------------------
### Run Expo Example Project
Source: https://hyochan.github.io/expo-iap/docs/2.6/guides/support
Installs dependencies and runs the example project for Expo IAP on iOS or Android using npx.
```bash
cd example
npm install
npx expo run:ios # or run:android
```
--------------------------------
### Setting up Documentation Development Environment
Source: https://hyochan.github.io/expo-iap/docs/2.7/guides/support
Steps to set up the documentation development environment for Expo IAP, including installing dependencies and starting the server.
```bash
cd docs
npm install
npm start
```
--------------------------------
### Install Pods for iOS (Bare Workflow)
Source: https://hyochan.github.io/expo-iap/docs/2.7/installation
Installs native dependencies for iOS projects using the bare workflow by running 'pod install' in the 'ios' directory.
```bash
cd ios && pod install
```
--------------------------------
### Install Expo CLI
Source: https://hyochan.github.io/expo-iap/docs/2.7/installation
Installs the Expo CLI globally, which is a prerequisite for creating development builds in the Expo managed workflow.
```bash
npm install -g @expo/cli
```
--------------------------------
### Run Expo IAP Example Project
Source: https://hyochan.github.io/expo-iap/docs/2.9/guides/support
Steps to run the example project for Expo IAP, including installing dependencies and running the project on iOS or Android using Expo CLI.
```bash
cd example
npm install
npx expo run:ios # or run:android
```
--------------------------------
### Install Expo IAP Package
Source: https://hyochan.github.io/expo-iap/docs/2.7/installation
Installs the Expo IAP package using npm. This is the initial step for integrating in-app purchase functionality into your project.
```bash
npm install expo-iap
```
--------------------------------
### Install Expo IAP Package
Source: https://hyochan.github.io/expo-iap/docs/2.6/installation
Installs the Expo IAP package using npm. This is the initial step for integrating in-app purchase functionality into your project.
```bash
npm install expo-iap
```
--------------------------------
### Install iOS Pods
Source: https://hyochan.github.io/expo-iap/docs/2.6/installation
Installs native dependencies for iOS by navigating to the 'ios' directory and running 'pod install'. This is required for the Expo Bare Workflow.
```bash
cd ios && pod install
```
--------------------------------
### Basic In-App Purchase Setup with Expo
Source: https://hyochan.github.io/expo-iap/docs/getting-started/setup-ios
Demonstrates the fundamental setup for in-app purchases using `expo-iap`. It includes initializing the IAP module, requesting products, handling purchase success and errors, and validating receipts. This example uses React hooks for managing the IAP state.
```javascript
import {useIAP, ErrorCode} from 'expo-iap';
const productIds = [
'com.yourapp.premium',
'com.yourapp.coins_100',
'com.yourapp.subscription_monthly',
];
function App() {
const {
connected,
products,
requestProducts,
requestPurchase,
validateReceipt,
} = useIAP({
onPurchaseSuccess: (purchase) => {
console.log('Purchase successful:', purchase);
// Handle successful purchase
validatePurchase(purchase);
},
onPurchaseError: (error) => {
console.error('Purchase failed:', error);
// Handle purchase error
},
});
React.useEffect(() => {
if (connected) {
requestProducts({skus: productIds, type: 'inapp'});
}
}, [connected]);
const validatePurchase = async (purchase) => {
try {
const result = await validateReceipt(purchase.transactionId);
if (result.isValid) {
// Grant user the purchased content
console.log('Receipt is valid');
}
} catch (error) {
console.error('Validation failed:', error);
}
};
return (
{products.map((product) => (
requestPurchase({request: {sku: product.id}})
>
{product.title} - {product.displayPrice}
))}
);
}
```
--------------------------------
### Prebuild Expo Project
Source: https://hyochan.github.io/expo-iap/docs/2.7/installation
Troubleshooting command for Expo projects to clean and rebuild native configurations, which can resolve issues with native modules.
```bash
npx expo prebuild --clean
```
--------------------------------
### Fetch Available Products with Expo IAP
Source: https://hyochan.github.io/expo-iap/docs/2.7/guides/getting-started
Fetches available products for purchase using the getProducts function from expo-iap. It requires a list of product IDs (SKUs) and should be called when the connection is established.
```javascript
const productIds = [
'com.example.product1',
'com.example.product2',
'com.example.subscription1',
];
useEffect(() => {
if (connected) {
getProducts({skus: productIds});
}
}, [connected, getProducts]);
```
--------------------------------
### Install Expo IAP using npm
Source: https://hyochan.github.io/expo-iap/docs/2.9/installation
Installs the expo-iap package using npm, a common package manager for Node.js projects. This is the first step in integrating in-app purchase functionality.
```bash
npm install expo-iap
```
--------------------------------
### Expo Prebuild for Clean Build
Source: https://hyochan.github.io/expo-iap/docs/installation
For Expo projects, this command uses the Expo CLI to prebuild the application with a clean slate. This is recommended for ensuring native configurations are up-to-date and free from previous build artifacts.
```bash
npx expo prebuild --clean
```
--------------------------------
### Prebuild Expo Project
Source: https://hyochan.github.io/expo-iap/docs/installation
Runs the `expo prebuild --clean` command to generate native directories and configurations for your Expo project. This is a necessary step after modifying `app.json` for native module support.
```bash
npx expo prebuild --clean
```
--------------------------------
### Initialize Expo IAP Connection
Source: https://hyochan.github.io/expo-iap/docs/2.7/guides/getting-started
Initializes the connection to the In-App Purchase API using the useIAP hook from expo-iap. It provides the connection status and other IAP-related functions.
```javascript
import {useIAP} from 'expo-iap';
import { View, Text } from 'react-native';
import React, { useEffect } from 'react';
export default function App() {
const {
connected,
products,
purchaseHistory,
getProducts,
requestPurchase,
finishTransaction,
} = useIAP();
// Initialize connection when component mounts
useEffect(() => {
// Connection is automatically handled by useIAP
}, []);
return (
Connection Status: {connected ? 'Connected' : 'Disconnected'}
{/* Your app content */}
);
}
```
--------------------------------
### Expo Prebuild for Clean Build
Source: https://hyochan.github.io/expo-iap/docs/2.9/installation
For Expo projects, this command uses the Expo CLI to prebuild the application with a clean slate. This is recommended for ensuring native configurations are up-to-date and free from previous build artifacts.
```bash
npx expo prebuild --clean
```
--------------------------------
### Expo IAP Basic Usage Example
Source: https://hyochan.github.io/expo-iap/docs/2.9/examples/complete-impl
A foundational example demonstrating the basic usage patterns for Expo's In-App Purchase (IAP) module. This snippet is suitable for developers starting with Expo IAP and aims to illustrate core functionalities.
```javascript
import * as IAP from 'expo-in-app-purchases';
async function exampleUsage() {
await IAP.connectAsync();
const products = await IAP.getProductsAsync(['product_id_1', 'product_id_2']);
console.log(products);
// Further actions like purchasing, consuming, etc.
await IAP.disconnectAsync();
}
```
--------------------------------
### Prebuild Expo Project
Source: https://hyochan.github.io/expo-iap/docs/2.6/installation
Troubleshooting command for Expo projects that cleans and rebuilds the native project files. This is useful for resolving issues related to native module linking.
```bash
npx expo prebuild --clean
```
--------------------------------
### Add Billing Permission in Android build.gradle
Source: https://hyochan.github.io/expo-iap/docs/2.7/guides/getting-started
Adds the necessary implementation dependency for Google Play Billing client version 5.0.0 within the android/app/build.gradle file. This enables in-app purchase functionality on Android.
```java
android {
defaultConfig {
// ... other configurations
}
}
dependencies {
// ... other dependencies
implementation 'com.android.billingclient:billing:5.0.0'
}
```
--------------------------------
### Clean and Rebuild Pods for iOS
Source: https://hyochan.github.io/expo-iap/docs/2.7/installation
Troubleshooting step for iOS projects in the bare workflow to resolve issues by cleaning the 'Pods' directory and 'Podfile.lock', then reinstalling pods.
```bash
cd ios
rm -rf Pods Podfile.lock
pod install
```
--------------------------------
### Install iOS Pods
Source: https://hyochan.github.io/expo-iap/docs/installation
Navigates to the `ios` directory and installs the necessary CocoaPods dependencies for your React Native project.
```bash
cd ios && pod install
```
--------------------------------
### Start Documentation Server
Source: https://hyochan.github.io/expo-iap/docs/2.6/guides/support
Starts the documentation development server locally, allowing for previewing and testing documentation changes.
```bash
cd docs
npm install
npm start
```
--------------------------------
### Expo IAP Basic Setup and Purchase Flow
Source: https://hyochan.github.io/expo-iap/docs/2.6/getting-started/setup-ios
Demonstrates the basic setup for Expo IAP, including connecting to the service, fetching product details, requesting purchases, and validating receipts. It uses the `useIAP` hook and handles purchase success and error callbacks.
```javascript
import {useIAP, ErrorCode} from 'expo-iap';
const productIds = [
'com.yourapp.premium',
'com.yourapp.coins_100',
'com.yourapp.subscription_monthly',
];
function App() {
const {connected, products, getProducts, requestPurchase, validateReceipt} =
useIAP({
onPurchaseSuccess: (purchase) => {
console.log('Purchase successful:', purchase);
// Handle successful purchase
validatePurchase(purchase);
},
onPurchaseError: (error) => {
console.error('Purchase failed:', error);
// Handle purchase error
},
});
React.useEffect(() => {
if (connected) {
getProducts(productIds);
}
}, [connected]);
const validatePurchase = async (purchase) => {
try {
const result = await validateReceipt(purchase.transactionId);
if (result.isValid) {
// Grant user the purchased content
console.log('Receipt is valid');
}
} catch (error) {
console.error('Validation failed:', error);
}
};
return (
{products.map((product) => (
requestPurchase({request: {sku: product.id}})
>
{product.title} - {product.displayPrice}
))}
);
}
```
--------------------------------
### Install Expo IAP using npm
Source: https://hyochan.github.io/expo-iap/docs/installation
Installs the expo-iap package using npm. This is the first step for integrating in-app purchases into your Expo or React Native project.
```bash
npm install expo-iap
```
--------------------------------
### Basic Expo IAP Setup and Purchase Flow
Source: https://hyochan.github.io/expo-iap/docs/2.7/getting-started/setup-ios
Demonstrates the basic setup for Expo IAP, including connecting to the service, fetching product details, requesting purchases, and validating receipts. It uses the `useIAP` hook and handles purchase success and error callbacks.
```javascript
import {useIAP, ErrorCode} from 'expo-iap';
const productIds = [
'com.yourapp.premium',
'com.yourapp.coins_100',
'com.yourapp.subscription_monthly',
];
function App() {
const {connected, products, getProducts, requestPurchase, validateReceipt} =
useIAP({
onPurchaseSuccess: (purchase) => {
console.log('Purchase successful:', purchase);
// Handle successful purchase
validatePurchase(purchase);
},
onPurchaseError: (error) => {
console.error('Purchase failed:', error);
// Handle purchase error
},
});
React.useEffect(() => {
if (connected) {
getProducts(productIds);
}
}, [connected]);
const validatePurchase = async (purchase) => {
try {
const result = await validateReceipt(purchase.transactionId);
if (result.isValid) {
// Grant user the purchased content
console.log('Receipt is valid');
}
} catch (error) {
console.error('Validation failed:', error);
}
};
return (
{products.map((product) => (
requestPurchase({request: {sku: product.id}})
}
>
{product.title} - {product.displayPrice}
))}
);
}
```
--------------------------------
### Install EAS CLI
Source: https://hyochan.github.io/expo-iap/docs/installation
Installs the EAS CLI globally, which is required for creating development builds and managing your Expo project's build process, especially for Expo Managed Workflow.
```bash
npm install -g eas-cli
```
--------------------------------
### Basic Expo IAP Setup
Source: https://hyochan.github.io/expo-iap/docs/2.9/getting-started/setup-ios
Demonstrates the basic setup for Expo IAP, including requesting products, handling purchases, and validating receipts. It uses the `useIAP` hook and requires product IDs for in-app purchases.
```javascript
import {useIAP, ErrorCode} from 'expo-iap';
const productIds = [
'com.yourapp.premium',
'com.yourapp.coins_100',
'com.yourapp.subscription_monthly',
];
function App() {
const {
connected,
products,
requestProducts,
requestPurchase,
validateReceipt,
} = useIAP({
onPurchaseSuccess: (purchase) => {
console.log('Purchase successful:', purchase);
// Handle successful purchase
validatePurchase(purchase);
},
onPurchaseError: (error) => {
console.error('Purchase failed:', error);
// Handle purchase error
},
});
React.useEffect(() => {
if (connected) {
requestProducts({skus: productIds, type: 'inapp'});
}
}, [connected]);
const validatePurchase = async (purchase) => {
try {
const result = await validateReceipt(purchase.productId);
if (result.isValid) {
// Grant user the purchased content
console.log('Receipt is valid');
}
} catch (error) {
console.error('Validation failed:', error);
}
};
return (
{products.map((product) => (
requestPurchase({request: {sku: product.id}})
>
{product.title} - {product.displayPrice}
))}
);
}
```
--------------------------------
### Install Expo Modules for React Native CLI
Source: https://hyochan.github.io/expo-iap/docs/installation
Installs the latest version of `expo-modules-core` for React Native CLI projects. This is a prerequisite for using Expo modules in a bare React Native project.
```bash
npx install-expo-modules@latest
```
--------------------------------
### Request Purchase with Expo IAP (iOS vs Android)
Source: https://hyochan.github.io/expo-iap/docs/2.7/guides/getting-started
Handles the purchase request for a given product ID, differentiating between iOS and Android platform requirements. iOS requires a single SKU, while Android accepts an array of SKUs.
```javascript
import {Platform} from 'react-native';
const handlePurchase = async (productId: string) => {
try {
if (Platform.OS === 'ios') {
// iOS: single product purchase
await requestPurchase({
request: {sku: productId},
});
} else if (Platform.OS === 'android') {
// Android: array of products (even for single purchase)
await requestPurchase({
request: {skus: [productId]},
});
}
} catch (error) {
console.error('Purchase failed:', error);
}
};
```
--------------------------------
### Install Pods for iOS
Source: https://hyochan.github.io/expo-iap/docs/2.9/installation
Installs native dependencies for iOS projects using CocoaPods. This command is run after navigating to the 'ios' directory and is essential for linking native libraries required by Expo IAP.
```bash
cd ios && pod install
```
--------------------------------
### Install Expo CLI
Source: https://hyochan.github.io/expo-iap/docs/2.6/installation
Installs the Expo CLI globally, which is required for creating custom development clients in the Expo Managed Workflow. This is necessary for using native modules like Expo IAP.
```bash
npm install -g @expo/cli
```
--------------------------------
### Initialize and Manage Expo IAP Store
Source: https://hyochan.github.io/expo-iap/docs/2.9/examples/complete-impl
This snippet shows the complete setup for an Expo In-App Purchase store. It includes initializing the store connection, loading products and subscriptions, handling purchase updates, and managing errors. It utilizes `useState` and `useEffect` hooks for state management and side effects.
```javascript
import React, {useEffect, useState} from 'react';
import {
View,
Text,
FlatList,
TouchableOpacity,
Alert,
StyleSheet,
ActivityIndicator,
Platform,
} from 'react-native';
import {useIAP, ProductPurchaseAndroid} from 'expo-iap';
// Define your product IDs
const PRODUCT_IDS = [
'com.yourapp.premium',
'com.yourapp.remove_ads',
'com.yourapp.extra_features',
];
const SUBSCRIPTION_IDS = [
'com.yourapp.premium_monthly',
'com.yourapp.premium_yearly',
];
export default function Store() {
const {
connected,
products,
subscriptions,
currentPurchase,
currentPurchaseError,
requestProducts,
requestPurchase,
finishTransaction,
} = useIAP();
const [loading, setLoading] = useState(false);
const [purchasedItems, setPurchasedItems] = useState(new Set());
// Initialize store
useEffect(() => {
if (connected) {
loadProducts();
}
}, [connected]);
// Handle purchase updates
useEffect(() => {
if (currentPurchase) {
handlePurchaseUpdate(currentPurchase);
}
}, [currentPurchase]);
// Handle purchase errors
useEffect(() => {
if (currentPurchaseError) {
handlePurchaseError(currentPurchaseError);
}
}, [currentPurchaseError]);
const loadProducts = async () => {
try {
setLoading(true);
// Load both products and subscriptions
await Promise.all([
fetchProducts({skus: PRODUCT_IDS, type: 'inapp'}),
fetchProducts({skus: SUBSCRIPTION_IDS, type: 'subs'}),
]);
console.log('Products loaded successfully');
} catch (error) {
console.error('Failed to load products:', error);
Alert.alert('Error', 'Failed to load store products');
} finally {
setLoading(false);
}
};
const handlePurchaseUpdate = async (purchase) => {
try {
console.log('Processing purchase:', purchase.productId);
// Here you would typically validate the receipt on your server
const isValid = await validatePurchase(purchase);
if (isValid) {
// Grant the purchase to the user
await grantPurchase(purchase);
// Update local state
setPurchasedItems((prev) => new Set([...prev, purchase.productId]));
// Finish the transaction
await finishTransaction({purchase});
Alert.alert(
'Purchase Successful',
`Thank you for purchasing ${purchase.productId}!`);
} else {
Alert.alert('Error', 'Purchase validation failed');
}
} catch (error) {
console.error('Error processing purchase:', error);
Alert.alert('Error', 'Failed to process purchase');
}
};
const handlePurchaseError = (error) => {
console.error('Purchase error:', error);
switch (error.code) {
case 'E_USER_CANCELLED':
// User cancelled - no need to show error
break;
case 'E_NETWORK_ERROR':
Alert.alert(
'Network Error',
'Please check your internet connection and try again.');
break;
case 'E_ITEM_UNAVAILABLE':
Alert.alert(
'Product Unavailable',
'This product is currently unavailable.');
break;
default:
Alert.alert(
'Purchase Failed',
error.message || 'Unknown error occurred');
break;
}
};
const buyProduct = async (productId) => {
if (!connected) {
Alert.alert('Error', 'Store is not connected');
return;
}
try {
console.log('Requesting purchase for:', productId);
// Platform-specific purchase requests (v2.7.0+)
await requestPurchase({
request: {
ios: {
sku: productId,
// Important: Set to false to manually handle transaction finishing
// This allows proper receipt validation before finishing the transaction
andDangerouslyFinishTransactionAutomatically: false,
},
android: {
skus: [productId],
},
},
});
} catch (error) {
console.error('Purchase request failed:', error);
Alert.alert('Error', 'Failed to initiate purchase');
}
};
const validatePurchase = async (purchase) => {
// IMPORTANT: Platform-specific validation requirements:
// - iOS: Only needs receiptData and productId
// - Android: Requires packageName, purchaseToken, and optionally accessToken
// Always check required parameters BEFORE attempting validation!
try {
// Handle both iOS and Android validation
```
--------------------------------
### Install/Uninstall Packages (npm)
Source: https://hyochan.github.io/expo-iap/docs/2.9/guides/migration
Demonstrates the npm commands to uninstall react-native-iap and install expo-iap, including the necessary pod install for iOS.
```bash
npm install react-native-iap
```
```bash
npm install expo-iap
```
```bash
npm uninstall react-native-iap
npm install expo-iap
# For iOS
cd ios && pod install && cd ..
```
--------------------------------
### Install EAS CLI
Source: https://hyochan.github.io/expo-iap/docs/2.9/installation
Installs the EAS CLI globally, which is required for creating development builds in the Expo managed workflow. EAS CLI is essential for managing builds and deploying applications built with Expo.
```bash
npm install -g eas-cli
```
--------------------------------
### Install Expo Dev Client
Source: https://hyochan.github.io/expo-iap/docs/2.9/guides/getting-started
Installs the expo-dev-client package, which is required for development builds when using native modules like expo-iap. It also shows commands to run the development build on iOS or Android.
```bash
npx expo install expo-dev-client
```
```bash
npx expo run:ios # or npx expo run:android
```
--------------------------------
### Basic Expo IAP Setup for Android
Source: https://hyochan.github.io/expo-iap/docs/getting-started/setup-android
Demonstrates the basic setup for Expo In-App Purchases (IAP) on Android. It initializes the IAP context, defines product IDs, fetches products and subscriptions, and renders them. Includes error handling for purchase events.
```javascript
import {useIAP, ErrorCode} from 'expo-iap';
const androidProductIds = [
'premium_upgrade',
'coins_100',
'monthly_subscription',
];
function App() {
const {connected, products, subscriptions, requestProducts, requestPurchase} =
useIAP({
onPurchaseSuccess: (purchase) => {
console.log('Purchase successful:', purchase);
handleSuccessfulPurchase(purchase);
},
onPurchaseError: (error) => {
console.error('Purchase failed:', error);
handlePurchaseError(error);
},
});
React.useEffect(() => {
if (connected) {
// Fetch products and subscriptions
fetchProducts({
skus: androidProductIds.filter((id) => !id.includes('subscription')),
type: 'inapp',
});
fetchProducts({
skus: androidProductIds.filter((id) => id.includes('subscription')),
type: 'subs',
});
}
}, [connected]);
return (
{/* Render products */}
{products.map((product) => (
))}
{/* Render subscriptions */}
{subscriptions.map((subscription) => (
))}
);
}
```
--------------------------------
### Clear Node Modules and Reinstall
Source: https://hyochan.github.io/expo-iap/docs/2.7/installation
Troubleshooting step to resolve installation issues by removing the 'node_modules' directory and reinstalling project dependencies.
```bash
rm -rf node_modules
npm install
```
--------------------------------
### Install Expo Modules for React Native CLI
Source: https://hyochan.github.io/expo-iap/docs/2.9/installation
Installs the latest version of expo-modules for React Native CLI projects. This command ensures that the necessary core Expo modules are available for integrating Expo libraries into existing React Native applications.
```bash
npx install-expo-modules@latest
```
--------------------------------
### Basic Expo IAP Integration for Android
Source: https://hyochan.github.io/expo-iap/docs/2.6/getting-started/setup-android
This JavaScript code demonstrates the basic setup for Expo IAP, including connecting to the service, fetching products and subscriptions, and handling purchase success or error callbacks. It uses the `useIAP` hook and defines product IDs for Android.
```javascript
import {useIAP, ErrorCode} from 'expo-iap';
const androidProductIds = [
'premium_upgrade',
'coins_100',
'monthly_subscription',
];
function App() {
const {
connected,
products,
subscriptions,
getProducts,
getSubscriptions,
requestPurchase,
} = useIAP({
onPurchaseSuccess: (purchase) => {
console.log('Purchase successful:', purchase);
handleSuccessfulPurchase(purchase);
},
onPurchaseError: (error) => {
console.error('Purchase failed:', error);
handlePurchaseError(error);
},
});
React.useEffect(() => {
if (connected) {
// Fetch products and subscriptions
getProducts(
androidProductIds.filter((id) => !id.includes('subscription')),
);
getSubscriptions(
androidProductIds.filter((id) => id.includes('subscription')),
);
}
}, [connected]);
return (
{/* Render products */}
{products.map((product) => (
))}
{/* Render subscriptions */}
{subscriptions.map((subscription) => (
))}
);
}
```
--------------------------------
### Verify Expo IAP Connection
Source: https://hyochan.github.io/expo-iap/docs/2.6/installation
A React Native component that uses the `useIAP` hook from `expo-iap` to check and log the connection status to the In-App Purchase service. This helps verify the installation.
```javascript
import {useIAP} from 'expo-iap';
function TestComponent() {
const {connected} = useIAP();
console.log('IAP Connection status:', connected);
return null;
}
```
--------------------------------
### Basic Expo IAP Setup for Android
Source: https://hyochan.github.io/expo-iap/docs/2.9/getting-started/setup-android
Demonstrates the basic setup for Expo IAP on Android, including connecting to the service, fetching products and subscriptions, and handling purchase success or errors. It utilizes the `useIAP` hook and `requestProducts` for fetching items.
```javascript
import {useIAP, ErrorCode} from 'expo-iap';
const androidProductIds = [
'premium_upgrade',
'coins_100',
'monthly_subscription',
];
function App() {
const {connected, products, subscriptions, requestProducts, requestPurchase} =
useIAP({
onPurchaseSuccess: (purchase) => {
console.log('Purchase successful:', purchase);
handleSuccessfulPurchase(purchase);
},
onPurchaseError: (error) => {
console.error('Purchase failed:', error);
handlePurchaseError(error);
},
});
React.useEffect(() => {
if (connected) {
// Fetch products and subscriptions
requestProducts({
skus: androidProductIds.filter((id) => !id.includes('subscription')),
type: 'inapp',
});
requestProducts({
skus: androidProductIds.filter((id) => id.includes('subscription')),
type: 'subs',
});
}
}, [connected]);
return (
{/* Render products */}
{products.map((product) => (
))}
{/* Render subscriptions */}
{subscriptions.map((subscription) => (
))}
);
}
```
--------------------------------
### Verify Expo IAP Connection
Source: https://hyochan.github.io/expo-iap/docs/2.9/installation
A React Native component that uses the useIAP hook from expo-iap to check the connection status to the in-app purchase service. The connection status is logged to the console, helping to verify the installation and configuration.
```javascript
import {useIAP} from 'expo-iap';
function TestComponent() {
const {connected} = useIAP();
console.log('IAP Connection status:', connected);
return null;
}
```
--------------------------------
### Clone Repository and Install Dependencies
Source: https://hyochan.github.io/expo-iap/docs/guides/support
Steps to fork the expo-iap repository, clone it locally, and install project dependencies using npm, yarn, or bun.
```bash
git clone https://github.com/your-username/expo-iap.git
cd expo-iap
```
```bash
npm install
```
```bash
yarn install
```
```bash
bun install
```
--------------------------------
### Complete Offer Code Redemption Example (iOS & Android)
Source: https://hyochan.github.io/expo-iap/docs/2.9/guides/offer-code-redemption
This comprehensive example demonstrates how to handle offer code redemption across both iOS and Android platforms using `expo-iap` and React Native's `Platform` module. It includes setting up a `purchaseUpdatedListener` to handle post-redemption purchase updates.
```javascript
import {Platform} from 'react-native';
import {
presentCodeRedemptionSheet,
openRedeemOfferCodeAndroid,
purchaseUpdatedListener,
} from 'expo-iap';
import { useEffect } from 'react';
const handleRedeemCode = async () => {
try {
if (Platform.OS === 'ios') {
// Present native iOS redemption sheet
const result = await presentCodeRedemptionSheet();
if (result) {
console.log('Redemption sheet presented');
}
} else if (Platform.OS === 'android') {
// Open Play Store for Android
await openRedeemOfferCodeAndroid();
}
} catch (error) {
console.error('Error redeeming code:', error);
}
};
// Set up listener for purchase updates after redemption
useEffect(() => {
const subscription = purchaseUpdatedListener((purchase) => {
console.log('Purchase updated after redemption:', purchase);
// Handle the new purchase/subscription
});
return () => {
subscription.remove();
};
}, []);
```
--------------------------------
### Fetch Products and Subscriptions on Connection
Source: https://hyochan.github.io/expo-iap/docs/2.7/examples/complete-impl
Fetches available products and subscriptions from the store once the Expo IAP connection is established. This useEffect hook ensures that product and subscription data are loaded into the application state when the `connected` status is true. It includes error handling for the fetching process.
```javascript
useEffect(() => {
if (!connected) return;
const initializeStore = async () => {
try {
await getProducts(productSkus);
await getSubscriptions(subscriptionSkus);
} catch (error) {
console.error('Failed to initialize store:', error);
}
};
initializeStore();
}, [connected]);
```
--------------------------------
### Initialize and Manage In-App Purchases with Expo
Source: https://hyochan.github.io/expo-iap/docs/2.7/examples/complete-impl
This snippet initializes the Expo In-App Purchase module, loads products and subscriptions, and handles the purchase lifecycle including updates and errors. It uses `useEffect` hooks to manage connection status and purchase events.
```javascript
import React, {useEffect, useState} from 'react';
import {
View,
Text,
FlatList,
TouchableOpacity,
Alert,
StyleSheet,
ActivityIndicator,
Platform,
} from 'react-native';
import {useIAP, ProductPurchaseAndroid} from 'expo-iap';
// Define your product IDs
const PRODUCT_IDS = [
'com.yourapp.premium',
'com.yourapp.remove_ads',
'com.yourapp.extra_features',
];
const SUBSCRIPTION_IDS = [
'com.yourapp.premium_monthly',
'com.yourapp.premium_yearly',
];
export default function Store() {
const {
connected,
products,
subscriptions,
currentPurchase,
currentPurchaseError,
getProducts,
getSubscriptions,
requestPurchase,
finishTransaction,
} = useIAP();
const [loading, setLoading] = useState(false);
const [purchasedItems, setPurchasedItems] = useState(new Set());
// Initialize store
useEffect(() => {
if (connected) {
loadProducts();
}
}, [connected]);
// Handle purchase updates
useEffect(() => {
if (currentPurchase) {
handlePurchaseUpdate(currentPurchase);
}
}, [currentPurchase]);
// Handle purchase errors
useEffect(() => {
if (currentPurchaseError) {
handlePurchaseError(currentPurchaseError);
}
}, [currentPurchaseError]);
const loadProducts = async () => {
try {
setLoading(true);
// Load both products and subscriptions
await Promise.all([
getProducts({skus: PRODUCT_IDS}),
getSubscriptions({skus: SUBSCRIPTION_IDS}),
]);
console.log('Products loaded successfully');
} catch (error) {
console.error('Failed to load products:', error);
Alert.alert('Error', 'Failed to load store products');
} finally {
setLoading(false);
}
};
const handlePurchaseUpdate = async (purchase) => {
try {
console.log('Processing purchase:', purchase.productId);
// Here you would typically validate the receipt on your server
const isValid = await validatePurchase(purchase);
if (isValid) {
// Grant the purchase to the user
await grantPurchase(purchase);
// Update local state
setPurchasedItems((prev) => new Set([...prev, purchase.productId]));
// Finish the transaction
await finishTransaction({purchase});
Alert.alert(
'Purchase Successful',
`Thank you for purchasing ${purchase.productId}!`);
} else {
Alert.alert('Error', 'Purchase validation failed');
}
} catch (error) {
console.error('Error processing purchase:', error);
Alert.alert('Error', 'Failed to process purchase');
}
};
const handlePurchaseError = (error) => {
console.error('Purchase error:', error);
switch (error.code) {
case 'E_USER_CANCELLED':
// User cancelled - no need to show error
break;
case 'E_NETWORK_ERROR':
Alert.alert(
'Network Error',
'Please check your internet connection and try again.');
break;
case 'E_ITEM_UNAVAILABLE':
Alert.alert(
'Product Unavailable',
'This product is currently unavailable.');
break;
default:
Alert.alert(
'Purchase Failed',
error.message || 'Unknown error occurred');
break;
}
};
const buyProduct = async (productId) => {
if (!connected) {
Alert.alert('Error', 'Store is not connected');
return;
}
try {
console.log('Requesting purchase for:', productId);
// Platform-specific purchase requests
// iOS and Android have different parameter requirements
if (Platform.OS === 'ios') {
await requestPurchase({
request: {
sku: productId,
// Important: Set to false to manually handle transaction finishing
// This allows proper receipt validation before finishing the transaction
andDangerouslyFinishTransactionAutomatically: false,
},
});
} /* Platform.OS === "android" */ else {
await requestPurchase({
request: {skus: [productId]},
});
}
} catch (error) {
console.error('Purchase request failed:', error);
Alert.alert('Error', 'Failed to initiate purchase');
}
};
const validatePurchase = async (purchase) => {
// IMPORTANT: Platform-specific validation requirements:
// - iOS: Only needs receiptData and productId
// - Android: Requires packageName, purchaseToken, and optionally accessToken
```
--------------------------------
### Reset Metro Cache
Source: https://hyochan.github.io/expo-iap/docs/2.7/installation
Troubleshooting command for React Native projects to reset the Metro bundler cache, which can help resolve build and bundling issues.
```bash
npx react-native start --reset-cache
```
--------------------------------
### Verify Expo IAP Connection
Source: https://hyochan.github.io/expo-iap/docs/2.7/installation
A React component that uses the useIAP hook from expo-iap to check and log the connection status to the In-App Purchase service.
```javascript
import {useIAP} from 'expo-iap';
function TestComponent() {
const {connected} = useIAP();
console.log('IAP Connection status:', connected);
return null;
}
```
--------------------------------
### Run Expo Prebuild
Source: https://hyochan.github.io/expo-iap/docs/2.9/installation
Executes the 'expo prebuild --clean' command to generate native iOS and Android directories with necessary configurations. This command is crucial after modifying app.json for native module integration, ensuring the project's native build files are up-to-date.
```bash
npx expo prebuild --clean
```
--------------------------------
### Handle Purchase Updates and Validation (React)
Source: https://hyochan.github.io/expo-iap/docs/2.7/guides/getting-started
This snippet shows how to use useEffect to automatically handle purchase updates when a new purchase is detected. It includes platform-specific logic for validating receipts on iOS and Android before finishing the transaction.
```javascript
useEffect(() => {
if (currentPurchase) {
// Platform-specific validation
const validateAndFinish = async () => {
try {
if (Platform.OS === 'ios') {
// iOS: Simple validation
await validateReceiptOnServer({
receiptData: currentPurchase.transactionReceipt,
productId: currentPurchase.productId,
});
} else if (Platform.OS === 'android') {
// Android: Check required parameters first
const purchaseToken = currentPurchase.purchaseTokenAndroid;
const packageName = currentPurchase.packageNameAndroid;
if (!purchaseToken || !packageName) {
throw new Error(
'Android validation requires packageName and purchaseToken',
);
}
await validateReceiptOnServer({
packageName,
purchaseToken,
productId: currentPurchase.productId,
});
}
// If validation successful, finish the transaction
await finishTransaction({purchase: currentPurchase});
} catch (error) {
console.error('Receipt validation failed:', error);
}
};
validateAndFinish();
}
}, [currentPurchase, finishTransaction]);
```
--------------------------------
### Clear Node Modules and Reinstall
Source: https://hyochan.github.io/expo-iap/docs/2.6/installation
Troubleshooting step to remove the 'node_modules' directory and reinstall dependencies. This can resolve issues caused by corrupted or outdated packages.
```bash
rm -rf node_modules
npm install
```
--------------------------------
### Enable Verbose Logging in Expo IAP
Source: https://hyochan.github.io/expo-iap/docs/2.6/guides/troubleshooting
Enables debug mode for the expo-iap library during development. This helps in getting more detailed logs for debugging purchase flows.
```javascript
import {setDebugMode} from 'expo-iap';
// Enable debug mode in development
if (__DEV__) {
setDebugMode(true);
}
```
--------------------------------
### Installing Dependencies with npm, yarn, or bun
Source: https://hyochan.github.io/expo-iap/docs/2.7/guides/support
Instructions for installing project dependencies using different package managers: npm, yarn, or bun.
```bash
npm install
# or
yarn install
# or
bun install
```
--------------------------------
### Verify Expo IAP Connection
Source: https://hyochan.github.io/expo-iap/docs/installation
A simple React Native component using the `useIAP` hook from `expo-iap` to check and log the connection status to the In-App Purchase service.
```javascript
import {useIAP} from 'expo-iap';
function TestComponent() {
const {connected} = useIAP();
console.log('IAP Connection status:', connected);
return null;
}
```
--------------------------------
### Basic App Navigation Setup
Source: https://hyochan.github.io/expo-iap/docs/2.6/examples/basic-store
Demonstrates the basic setup for a React Native application using Expo, including navigation setup with `@react-navigation/native` and rendering a `Store` component.
```javascript
import React from 'react';
import {NavigationContainer} from '@react-navigation/native';
import Store from './Store';
export default function App() {
return (
);
}
```