import { native } from "cc"; import { FacebookImpl, IFBEventParams, IFBLoginRes, IFBShareOptions, IFBShareRes, } from "./FacebookImpl"; const REQUEST_EVENT = "facebook.request"; const RESPONSE_EVENT = "facebook.response"; const DEFAULT_TIMEOUT_MS = 15_000; const USER_OPERATION_TIMEOUT_MS = 180_000; interface NativeError { code?: string; message?: string; } interface NativeResponse> { requestId: string; method: string; success: boolean; cancelled?: boolean; data?: T; error?: NativeError; } interface LoginData { accessToken?: string; userId?: string; } interface ShareData { postId?: string; } interface EventData { accepted?: boolean; } interface PendingRequest { method: string; resolve: (response: NativeResponse) => void; reject: (error: Error) => void; timer: ReturnType; } export class FBAndroidImpl extends FacebookImpl { private _requestSeed = 0; private _pendingRequests = new Map(); private _initPromise: Promise | null = null; private readonly _responseListener = (payload: string) => this.onNativeResponse(payload); init(): void { if (this._initPromise) return; native.jsbBridgeWrapper.addNativeEventListener(RESPONSE_EVENT, this._responseListener); this._initPromise = this.request("init") .then(() => { this.onInited(); return true; }) .catch((error) => { console.error("[Facebook][Android] 初始化失败:", error); return false; }); } protected async onLogin(): Promise { if (!(await this.ensureInitialized())) { return this.loginFailure("Facebook Android SDK 尚未初始化。"); } try { const response = await this.request( "login", { permissions: ["public_profile", "email"] }, USER_OPERATION_TIMEOUT_MS, ); if (response.cancelled) { return { accessToken: "", isCancel: true, status: "cancelled", }; } const accessToken = response.data?.accessToken || ""; if (!accessToken) { return this.loginFailure("Facebook 登录未返回 Access Token。"); } return { accessToken, isCancel: false, status: "connected", }; } catch (error) { return this.loginFailure(this.errorMessage(error)); } } async logOut(): Promise { if (!(await this.ensureInitialized())) return false; try { await this.request("logout"); return true; } catch (error) { console.error("[Facebook][Android] 登出失败:", error); return false; } } async share(options: IFBShareOptions): Promise { if (!(await this.ensureInitialized())) { return { success: false, isCancel: false, reason: "Facebook Android SDK 尚未初始化。", }; } try { const response = await this.request( "share", { url: options?.url || "", hashtag: options?.hashtag || "", quote: options?.quote || "", }, USER_OPERATION_TIMEOUT_MS, ); return { success: !response.cancelled, isCancel: Boolean(response.cancelled), postId: response.data?.postId, }; } catch (error) { return { success: false, isCancel: false, reason: this.errorMessage(error), }; } } async logEvent( eventName: string, parameters: IFBEventParams = {}, valueToSum?: number, ): Promise { if (!(await this.ensureInitialized())) return false; try { const params: Record = { eventName, parameters }; if (valueToSum !== undefined) params.valueToSum = valueToSum; const response = await this.request("logEvent", params); return response.data?.accepted === true; } catch (error) { console.error(`[Facebook][Android] 事件 ${eventName} 记录失败:`, error); return false; } } async logPurchase( amount: number, currency: string, parameters: IFBEventParams = {}, ): Promise { if (!(await this.ensureInitialized())) return false; try { const response = await this.request("logPurchase", { amount, currency, parameters, }); return response.data?.accepted === true; } catch (error) { console.error("[Facebook][Android] 购买事件记录失败:", error); return false; } } async flushEvents(): Promise { if (!(await this.ensureInitialized())) return false; try { const response = await this.request("flushEvents"); return response.data?.accepted === true; } catch (error) { console.error("[Facebook][Android] App Events 刷新失败:", error); return false; } } private async ensureInitialized(): Promise { if (!this._initPromise) this.init(); return this._initPromise!; } private request>( method: string, params: Record = {}, timeoutMs = DEFAULT_TIMEOUT_MS, ): Promise> { const requestId = `${Date.now()}-${++this._requestSeed}`; return new Promise>((resolve, reject) => { const timer = setTimeout(() => { this._pendingRequests.delete(requestId); reject(new Error(`Facebook ${method} 请求超时。`)); }, timeoutMs); this._pendingRequests.set(requestId, { method, resolve, reject, timer, }); try { native.jsbBridgeWrapper.dispatchEventToNative( REQUEST_EVENT, JSON.stringify({ requestId, method, params }), ); } catch (error) { clearTimeout(timer); this._pendingRequests.delete(requestId); reject(error instanceof Error ? error : new Error(String(error))); } }); } private onNativeResponse(payload: string): void { let response: NativeResponse; try { response = JSON.parse(payload) as NativeResponse; } catch (error) { console.error("[Facebook][Android] 无法解析原生响应:", error); return; } const pending = this._pendingRequests.get(response.requestId); if (!pending) return; clearTimeout(pending.timer); this._pendingRequests.delete(response.requestId); if (response.success) { pending.resolve(response); return; } const code = response.error?.code ? `[${response.error.code}] ` : ""; pending.reject(new Error(`${code}${response.error?.message || `${pending.method} 执行失败。`}`)); } private loginFailure(reason: string): IFBLoginRes { return { accessToken: "", isCancel: false, status: "error", reason, }; } private errorMessage(error: unknown): string { return error instanceof Error ? error.message : String(error); } }