import 'dart:async'; import 'dart:convert'; import 'package:flutter/foundation.dart'; import '../api/api_client.dart'; import '../api/proxy_client.dart'; import '../config/attribution_config.dart'; import '../entities/user_entities.dart'; import 'adjust_service.dart'; import 'user_api.dart'; /// 认证服务回调 /// 用于在认证流程各阶段通知调用方 abstract class AuthServiceCallbacks { /// 获取设备 ID(由调用方实现) Future getDeviceId(); /// 计算签名(由调用方实现) String computeSign(String deviceId); /// 登录成功后回调 void onLoginSuccess(FastLoginResponse data) {} /// 通用信息获取后回调 void onCommonInfoLoaded(CommonInfoResponse data) {} /// 登录失败回调 void onLoginFailed(String msg) {} } /// APP 启动认证服务 /// 封装完整的启动登录流程,包括: /// 1. 快速登录 /// 2. 归因上报 /// 3. 获取通用信息 abstract class FrameworkAuthService { static AuthServiceCallbacks? _callbacks; static Future? _loginFuture; static bool _isInitialized = false; /// 登录是否已完成 static final ValueNotifier isLoginComplete = ValueNotifier(false); /// 登录完成后的 Future,需鉴权接口应 await 此 Future 再请求 static Future get loginComplete => _loginFuture ?? Future.value(); /// 初始化认证服务 static void init(AuthServiceCallbacks callbacks) { _callbacks = callbacks; _isInitialized = true; } /// 启动登录流程 /// [delaySeconds] 启动延迟秒数,默认 2 秒 /// [maxRetries] 最大重试次数,默认 3 次 /// [retryDelaySeconds] 重试延迟秒数,默认 2 秒 static Future start({ int delaySeconds = 2, int maxRetries = 3, int retryDelaySeconds = 2, }) async { if (!_isInitialized || _callbacks == null) { throw StateError( 'AuthService not initialized. Call AuthService.init(callbacks) first.'); } if (_loginFuture != null) return _loginFuture!; final completer = Completer(); _loginFuture = completer.future; if (kDebugMode) { debugPrint('[AuthService] start: 开始登录流程'); } try { await Future.delayed(Duration(seconds: delaySeconds)); final deviceId = await _callbacks!.getDeviceId(); if (kDebugMode) { debugPrint('[AuthService] start: deviceId=$deviceId'); } final sign = _callbacks!.computeSign(deviceId); if (kDebugMode) { debugPrint('[AuthService] start: sign=$sign'); } final referer = await AttributionService.getReferrer(); if (kDebugMode && referer != null) { debugPrint('[AuthService] start: referer=$referer'); } // 尝试快速登录 EntityResponse? res; for (var i = 0; i < maxRetries; i++) { if (i > 0) { if (kDebugMode) { debugPrint('[AuthService] start: 第 ${i + 1} 次重试...'); } await Future.delayed(Duration(seconds: retryDelaySeconds)); } try { res = await UserApi.fastLogin( deviceId: deviceId, sign: sign, referer: referer ?? '', ); break; } catch (e) { if (kDebugMode) { debugPrint('[AuthService] start: 第 ${i + 1} 次请求失败: $e'); } if (i == maxRetries - 1) rethrow; } } if (res == null) { completer.complete(); return; } if (kDebugMode) { debugPrint('[AuthService] start: 登录结果 code=${res.code} msg=${res.msg}'); } if (res.isSuccess && res.data != null) { final loginData = res.data!; // 设置 Token if (loginData.userToken != null && loginData.userToken!.isNotEmpty) { ApiClient.instance.setUserToken(loginData.userToken!); if (kDebugMode) { debugPrint('[AuthService] start: 已设置 userToken'); } } // 回调登录成功 _callbacks!.onLoginSuccess(loginData); // 上报归因并获取通用信息 await _reportReferrersAndLoadCommonInfo( uid: loginData.userId ?? '', deviceId: deviceId, ); } else { _callbacks!.onLoginFailed(res.msg); } } catch (e, st) { if (kDebugMode) { debugPrint('[AuthService] start: 异常 $e\n$st'); } _callbacks!.onLoginFailed(e.toString()); } finally { if (!completer.isCompleted) { completer.complete(); isLoginComplete.value = true; } } } /// 上报归因并获取通用信息 static Future _reportReferrersAndLoadCommonInfo({ required String uid, required String deviceId, }) async { if (uid.isEmpty) return; final config = ApiClient.instance.config; // 上报 Adjust 归因 final adjustReferer = await AttributionService.getAdjustReferrer(); if (adjustReferer != null && adjustReferer.isNotEmpty) { try { final rAdjust = await UserApi.referrer( app: config.appId, userId: uid, referer: adjustReferer, deviceId: deviceId, type: 'android_adjust', ); if (kDebugMode) { debugPrint( '[AuthService] referrer(android_adjust): ${rAdjust.isSuccess ? "成功" : "失败"}'); } } catch (e) { if (kDebugMode) { debugPrint('[AuthService] referrer(android_adjust): 异常 $e'); } } } // 上报 Google Play 归因(从 AdjustService 获取缓存的 referrer) final playReferrer = AdjustService.cachedPlayReferrer; if (playReferrer != null && playReferrer.isNotEmpty) { try { final rGg = await UserApi.referrer( app: config.appId, userId: uid, referer: playReferrer, deviceId: deviceId, type: 'gg', ); if (kDebugMode) { debugPrint( '[AuthService] referrer(gg): ${rGg.isSuccess ? "成功" : "失败"}'); } } catch (e) { if (kDebugMode) { debugPrint('[AuthService] referrer(gg): 异常 $e'); } } } // 获取通用信息 try { final commonRes = await UserApi.getCommonInfo( app: config.appId, userId: uid, ); if (commonRes.isSuccess && commonRes.data != null) { _callbacks?.onCommonInfoLoaded(commonRes.data!); if (kDebugMode) { debugPrint('[AuthService] common_info: 获取成功'); } } else if (kDebugMode) { debugPrint( '[AuthService] common_info: 失败 code=${commonRes.code} msg=${commonRes.msg}'); } } catch (e) { if (kDebugMode) { debugPrint('[AuthService] common_info: 异常 $e'); } } } /// 解析 extConfig JSON 字符串 static Map? parseExtConfig(String? extConfigStr) { if (extConfigStr == null || extConfigStr.isEmpty) return null; try { return json.decode(extConfigStr) as Map?; } catch (_) { return null; } } }