|
@@ -1,5 +1,9 @@
|
|
|
import { native } from 'cc';
|
|
import { native } from 'cc';
|
|
|
-import { IAPImpl, IAPProductsResult, IAPResult } from './IAPImpl';
|
|
|
|
|
|
|
+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 {
|
|
export class IOSIAP extends IAPImpl {
|
|
|
private seed = 0;
|
|
private seed = 0;
|
|
@@ -23,21 +27,22 @@ export class IOSIAP extends IAPImpl {
|
|
|
clearTimeout(pending.timer);
|
|
clearTimeout(pending.timer);
|
|
|
this.pending.delete(response.requestId);
|
|
this.pending.delete(response.requestId);
|
|
|
if (response.success) pending.resolve(response.data);
|
|
if (response.success) pending.resolve(response.data);
|
|
|
- else pending.reject(new Error(response.error || 'IAP request failed'));
|
|
|
|
|
|
|
+ else pending.reject(new IAPRequestError('UNKNOWN', response.error || 'IAP request failed'));
|
|
|
});
|
|
});
|
|
|
this.listening = true;
|
|
this.listening = true;
|
|
|
}
|
|
}
|
|
|
private request<T>(method: string, params: object = {}): Promise<T> {
|
|
private request<T>(method: string, params: object = {}): Promise<T> {
|
|
|
- this.listen();
|
|
|
|
|
|
|
+ try { this.listen(); }
|
|
|
|
|
+ catch (error) { throw new IAPRequestError('BRIDGE_ERROR', String(error)); }
|
|
|
const requestId = `${Date.now()}-${++this.seed}`;
|
|
const requestId = `${Date.now()}-${++this.seed}`;
|
|
|
return new Promise<T>((resolve, reject) => {
|
|
return new Promise<T>((resolve, reject) => {
|
|
|
const timer = setTimeout(() => {
|
|
const timer = setTimeout(() => {
|
|
|
this.pending.delete(requestId);
|
|
this.pending.delete(requestId);
|
|
|
- reject(new Error('IAP 请求超时;不代表支付失败,请查询未完成交易,勿直接重复购买。'));
|
|
|
|
|
|
|
+ reject(new IAPRequestError('TIMEOUT', 'IAP 请求超时;不代表支付失败,请查询未完成交易,勿直接重复购买。'));
|
|
|
}, 180000);
|
|
}, 180000);
|
|
|
this.pending.set(requestId, { resolve, reject, timer });
|
|
this.pending.set(requestId, { resolve, reject, timer });
|
|
|
try { native.jsbBridgeWrapper.dispatchEventToNative('iap.request', JSON.stringify({ requestId, method, params })); }
|
|
try { native.jsbBridgeWrapper.dispatchEventToNative('iap.request', JSON.stringify({ requestId, method, params })); }
|
|
|
- catch (error) { clearTimeout(timer); this.pending.delete(requestId); reject(error); }
|
|
|
|
|
|
|
+ catch (error) { clearTimeout(timer); this.pending.delete(requestId); reject(new IAPRequestError('BRIDGE_ERROR', String(error))); }
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
|
init(productIds: string[]): Promise<IAPProductsResult> {
|
|
init(productIds: string[]): Promise<IAPProductsResult> {
|
|
@@ -46,7 +51,21 @@ export class IOSIAP extends IAPImpl {
|
|
|
}
|
|
}
|
|
|
return this.request('init', { productIds: [...new Set(productIds)] });
|
|
return this.request('init', { productIds: [...new Set(productIds)] });
|
|
|
}
|
|
}
|
|
|
- purchase(productId: string): Promise<IAPResult> { return this.request('purchase', { productId }); }
|
|
|
|
|
|
|
+ async purchase(productId: string): Promise<IAPResult> {
|
|
|
|
|
+ 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<IAPResult>('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<IAPResult[]> { return this.request('restore'); }
|
|
restore(): Promise<IAPResult[]> { return this.request('restore'); }
|
|
|
getPendingTransactions(): Promise<IAPResult[]> { return this.request('pending'); }
|
|
getPendingTransactions(): Promise<IAPResult[]> { return this.request('pending'); }
|
|
|
async finishTransaction(transactionId: string): Promise<void> {
|
|
async finishTransaction(transactionId: string): Promise<void> {
|