import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../bootstrap/client_bootstrap.dart'; import '../config/skin_config.dart'; import '../entities/payment_entities.dart'; import 'analytics_service.dart'; import 'facebook_service.dart'; import 'payment_flow/payment_flow_models.dart'; /// 宿主侧业务埋点(Adjust token 来自 `skin_config.json` 的 `adjustEvents` + Facebook App Events)。 /// /// 须在 [ClientBootstrap.initFromAsset] / [ClientBootstrap.initFromJson] 与 [ClientBootstrap.initAnalytics] 之后调用。 /// 行为对齐常见 app 线(如 app_client [AdjustEvents]):档位价、首日充值标记、支付成功/失败。 abstract final class AnalyticsEvents { AnalyticsEvents._(); static const _prefsRegisterDayKey = 'client_proxy_framework_skin_analytics_register_day'; /// 历史宿主键(FunyMee 曾用),仅用于读取兼容。 static const _prefsLegacyRegisterDayKey = 'funymee_analytics_register_date'; static SkinConfig get _skin => ClientBootstrap.skin; /// 从金额文案解析数字(如 `"¥19.99"` / `"\$9.99"`)。 static num? parsePrice(String? amount) { if (amount == null || amount.trim().isEmpty) return null; final m = RegExp(r'[\d.]+').firstMatch(amount); if (m == null) return null; return num.tryParse(m.group(0)!); } static String? _tierLogicalNameForPrice(num price) { final s = price.toStringAsFixed(2); switch (s) { case '5.99': return 'price_599'; case '9.99': return 'price_999'; case '19.99': return 'price_1999'; case '49.99': return 'price_4999'; case '99.99': return 'price_9999'; default: return null; } } /// 用户点击某档位发起支付前(按价格匹配 `adjustEvents.price_*`,否则 `purchase`)。 static void trackTierSelection(PaymentProductItem item) { final p = parsePrice(item.actualAmount); if (p == null) return; final name = _tierLogicalNameForPrice(p); if (name != null) { _skin.trackAdjustEvent(name); } else { _skin.trackAdjustEvent('purchase'); } } /// [FastLoginResponse.firstRegister] 为 true 时调用。 static Future trackRegisterIfNeeded({required bool firstRegister}) async { if (!firstRegister) return; _skin.trackAdjustEvent('register'); AnalyticsService.trackRegister(); final prefs = await SharedPreferences.getInstance(); await prefs.setString( _prefsRegisterDayKey, DateTime.now().toIso8601String().substring(0, 10), ); if (kDebugMode) { debugPrint('[AnalyticsEvents] register + first-day marker set'); } } /// 支付成功:Adjust `purchase`;若注册当日则 `firstPurchase` + Facebook `FirstRecharge`(与 app_client [AdjustEvents.trackFirstPurchase] 一致);Facebook 标准购买见 [AnalyticsService.trackPurchase]。 static Future trackPurchaseSuccess(double amount) async { _skin.trackAdjustEvent('purchase'); final prefs = await SharedPreferences.getInstance(); final regDate = prefs.getString(_prefsRegisterDayKey) ?? prefs.getString(_prefsLegacyRegisterDayKey); final today = DateTime.now().toIso8601String().substring(0, 10); if (regDate != null && regDate == today) { _skin.trackAdjustEvent('firstPurchase'); FacebookService.logEvent( 'FirstRecharge', parameters: {'amount': amount}, ); } if (amount > 0) { AnalyticsService.trackPurchase(amount: amount, currency: 'USD'); } } /// 使用 [PaymentProductItem.actualAmount] 解析金额后 [trackPurchaseSuccess]。 static Future trackPurchaseSuccessForProduct( PaymentProductItem? item) async { final raw = parsePrice(item?.actualAmount); final amount = raw?.toDouble() ?? 0.0; await trackPurchaseSuccess(amount); } /// 支付失败 / 下单失败(Adjust `paymentFailed` + FB `payment_failed`)。 static void trackPaymentFailed() { _skin.trackAdjustEvent('paymentFailed'); FacebookService.logEvent('payment_failed'); } /// 根据支付编排结果 [PaymentSettlement] 自动埋点(成功 → [trackPurchaseSuccessForProduct];失败 → [trackPaymentFailed])。 /// /// 取消、超时、[PaymentFlowOutcomeType.nativePendingHostVerification] 不打点。 static void trackPaymentSettlement( PaymentSettlement settlement, { PaymentProductItem? product, }) { switch (settlement.type) { case PaymentFlowOutcomeType.success: unawaited(trackPurchaseSuccessForProduct(product)); break; case PaymentFlowOutcomeType.failure: trackPaymentFailed(); break; case PaymentFlowOutcomeType.cancelled: case PaymentFlowOutcomeType.timeout: case PaymentFlowOutcomeType.nativePendingHostVerification: break; } } /// Facebook 自定义事件。 static void trackCustomEvent(String name, {Map? parameters}) { FacebookService.logEvent(name, parameters: parameters); } }