114 lines
2.9 KiB
TypeScript
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',
|
|
})
|
|
},
|
|
}
|
|
}
|