import { native } from 'cc'; import { IAPImpl, IAPProductsResult, IAPResult, IAPErrorCode } from './IAPImpl'; class IAPRequestError extends Error { constructor(public readonly code: IAPErrorCode, message: string) { super(message); } } export class IOSIAP extends IAPImpl { private seed = 0; private listening = false; private pending = new Map void; reject: (error: Error) => void; timer: ReturnType }>(); private listeners = new Set<(transaction: IAPResult) => void>(); private listen(): void { if (this.listening) return; native.jsbBridgeWrapper.addNativeEventListener('iap.response', payload => { let response: any; try { response = JSON.parse(payload); } catch { return; } if (response.method === 'transaction') { for (const listener of this.listeners) { try { listener(response.data); } catch (error) { console.error('[IAP] Transaction listener failed', error); } } return; } const pending = this.pending.get(response.requestId); if (!pending) return; clearTimeout(pending.timer); this.pending.delete(response.requestId); if (response.success) pending.resolve(response.data); else pending.reject(new IAPRequestError('UNKNOWN', response.error || 'IAP request failed')); }); this.listening = true; } private request(method: string, params: object = {}): Promise { try { this.listen(); } catch (error) { throw new IAPRequestError('BRIDGE_ERROR', String(error)); } const requestId = `${Date.now()}-${++this.seed}`; return new Promise((resolve, reject) => { const timer = setTimeout(() => { this.pending.delete(requestId); reject(new IAPRequestError('TIMEOUT', 'IAP 请求超时;不代表支付失败,请查询未完成交易,勿直接重复购买。')); }, 180000); this.pending.set(requestId, { resolve, reject, timer }); try { native.jsbBridgeWrapper.dispatchEventToNative('iap.request', JSON.stringify({ requestId, method, params })); } catch (error) { clearTimeout(timer); this.pending.delete(requestId); reject(new IAPRequestError('BRIDGE_ERROR', String(error))); } }); } init(productIds: string[]): Promise { if (!productIds.length || productIds.some(id => typeof id !== 'string' || !id.trim())) { return Promise.reject(new Error('商品 ID 不能为空。')); } return this.request('init', { productIds: [...new Set(productIds)] }); } async purchase(productId: string): Promise { if (typeof productId !== 'string' || !productId.trim()) { return { status: 'error', productId: typeof productId === 'string' ? productId : '', errorCode: 'INVALID_PRODUCT_ID', reason: '商品 ID 不能为空。' }; } try { return await this.request('purchase', { productId }); } catch (error) { return { status: 'error', errorCode: error instanceof IAPRequestError ? error.code : 'UNKNOWN', productId, reason: error instanceof Error ? error.message : String(error), }; } } restore(): Promise { return this.request('restore'); } getPendingTransactions(): Promise { return this.request('pending'); } async finishTransaction(transactionId: string): Promise { if (!transactionId) throw new Error('交易 ID 不能为空。'); await this.request('finish', { transactionId }); } onTransaction(listener: (transaction: IAPResult) => void): () => void { this.listen(); this.listeners.add(listener); return () => { this.listeners.delete(listener); }; } }