expo-duooomi-app/hooks/use-ios-purchase.ts

114 lines
2.9 KiB
TypeScript

import { ErrorCode, useIAP } from 'expo-iap'
import { useEffect } from 'react'
import { Platform } from 'react-native'
import { Toast } from '@/@share/components'
type UseIOSPurchaseOptions = {
skus: string[]
onPurchaseSuccess?: (purchase: any) => Promise<void>
onPurchaseError?: (error: any) => void
onProductsFetched?: (products: any[]) => void
}
/**
* iOS 专用的 IAP Hook
* 在非 iOS 平台返回空实现,避免不必要的初始化
*/
export function useIOSPurchase(options: UseIOSPurchaseOptions) {
const { skus, onPurchaseSuccess, onPurchaseError, onProductsFetched } = options
const isIOS = Platform.OS === 'ios'
// iOS 平台使用真实的 IAP
const { connected, products, fetchProducts, requestPurchase, finishTransaction } = useIAP({
onPurchaseSuccess: async (purchase) => {
if (!isIOS) return
console.log('✅ Purchase successful:', purchase)
// 执行自定义成功回调
if (onPurchaseSuccess) {
await onPurchaseSuccess(purchase)
}
// 完成交易(消耗型商品)
await finishTransaction({ purchase, isConsumable: true })
},
onPurchaseError: (error) => {
if (!isIOS) return
// 用户取消不显示错误
if (error.code !== ErrorCode.UserCancelled) {
console.error('❌ Purchase failed:', error)
if (onPurchaseError) {
onPurchaseError(error)
} else {
Toast.show({ title: '购买失败,请稍后重试' })
}
}
},
onError: (error) => {
console.log('❌ IAP Error:', error)
},
})
// 连接后自动获取商品
useEffect(() => {
if (!isIOS || !connected) return
console.log('🔗 IAP connected, fetching products...', connected)
console.log('📦 SKUs:', skus)
fetchProducts({ skus, type: 'in-app' })
.then((result) => {
if (!result?.products?.length) {
console.warn('⚠️ No products returned. Check App Store Connect configuration.')
}
if (onProductsFetched && result?.products) {
onProductsFetched(result.products)
}
})
.catch((error) => {
console.error('❌ Failed to fetch products:', error)
Toast.show({ title: '获取商品信息失败' })
})
}, [isIOS, connected, skus])
// 非 iOS 平台返回空实现
if (!isIOS) {
return {
connected: false,
products: [],
requestPurchase: async () => {
console.warn('IAP is only supported on iOS')
},
}
}
return {
connected,
products,
requestPurchase: async (productId: string) => {
if (!connected) {
Toast.show({ title: 'App Store 未连接' })
return
}
if (!products?.length) {
Toast.show({ title: '商品信息加载中,请稍后' })
return
}
await requestPurchase({
request: {
apple: { sku: productId },
},
type: 'in-app',
})
},
}
}