diff --git a/android/app/build.gradle b/android/app/build.gradle index 169edc2..5424e86 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -37,6 +37,7 @@ configurations.all { android { namespace "com.petsheroai.app" compileSdk 36 + buildFeatures { buildConfig = true } ndkVersion flutter.ndkVersion compileOptions { @@ -58,6 +59,8 @@ android { targetSdk 36 versionCode flutterVersionCode.toInteger() versionName flutterVersionName + // Facebook SDK 调试:正式包调试时设为 true,上线前改回 false + buildConfigField "boolean", "FACEBOOK_DEBUG_LOGS", (localProperties.getProperty("facebook.debug") ?: "true") } signingConfigs { @@ -82,8 +85,10 @@ android { } dependencies { + implementation 'com.facebook.android:facebook-core:18.0.0' implementation 'com.google.android.gms:play-services-ads-identifier:18.1.0' implementation 'com.android.installreferrer:installreferrer:2.2' + implementation 'com.adjust.sdk:adjust-android-meta-referrer:5.5.1' implementation 'androidx.appcompat:appcompat:1.7.0' // Play Billing Library 6.0.1+ (use 7.1.1 for in_app_purchase plugin compatibility) implementation 'com.android.billingclient:billing:7.1.1' diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index b0586f2..e827b43 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -27,5 +27,16 @@ + + + + + diff --git a/android/app/src/main/kotlin/com/petsheroai/app/MainActivity.kt b/android/app/src/main/kotlin/com/petsheroai/app/MainActivity.kt index c3c9841..b4ea52a 100644 --- a/android/app/src/main/kotlin/com/petsheroai/app/MainActivity.kt +++ b/android/app/src/main/kotlin/com/petsheroai/app/MainActivity.kt @@ -1,5 +1,24 @@ package com.petsheroai.app +import android.os.Bundle +import com.facebook.FacebookSdk +import com.facebook.LoggingBehavior import io.flutter.embedding.android.FlutterActivity -class MainActivity: FlutterActivity() +class MainActivity : FlutterActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + // 必须在 super.onCreate 之前初始化,否则 facebook_app_events 插件注册时会因 SDK 未初始化而崩溃 + FacebookSdk.sdkInitialize(applicationContext) + // Facebook SDK 调试日志:需 buildConfigField FACEBOOK_DEBUG_LOGS=true + if (BuildConfig.FACEBOOK_DEBUG_LOGS) { + try { + FacebookSdk.setIsDebugEnabled(true) + FacebookSdk.addLoggingBehavior(LoggingBehavior.APP_EVENTS) + FacebookSdk.addLoggingBehavior(LoggingBehavior.REQUESTS) + FacebookSdk.addLoggingBehavior(LoggingBehavior.DEVELOPER_ERRORS) + } catch (_: Exception) { /* ignore */ } + } + super.onCreate(savedInstanceState) + } +} diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..b4c992e --- /dev/null +++ b/android/app/src/main/res/values/strings.xml @@ -0,0 +1,6 @@ + + + + 1684216162986495 + df562f4ff186aaac5ff56ba190020ffd + diff --git a/ios/Runner/GeneratedPluginRegistrant.m b/ios/Runner/GeneratedPluginRegistrant.m index 13f20ce..9fc859c 100644 --- a/ios/Runner/GeneratedPluginRegistrant.m +++ b/ios/Runner/GeneratedPluginRegistrant.m @@ -18,6 +18,12 @@ @import device_info_plus; #endif +#if __has_include() +#import +#else +@import facebook_app_events; +#endif + #if __has_include() #import #else @@ -89,6 +95,7 @@ + (void)registerWithRegistry:(NSObject*)registry { [AdjustSdk registerWithRegistrar:[registry registrarForPlugin:@"AdjustSdk"]]; [FPPDeviceInfoPlusPlugin registerWithRegistrar:[registry registrarForPlugin:@"FPPDeviceInfoPlusPlugin"]]; + [FacebookAppEventsPlugin registerWithRegistrar:[registry registrarForPlugin:@"FacebookAppEventsPlugin"]]; [FlutterNativeSplashPlugin registerWithRegistrar:[registry registrarForPlugin:@"FlutterNativeSplashPlugin"]]; [GalPlugin registerWithRegistrar:[registry registrarForPlugin:@"GalPlugin"]]; [FLTImagePickerPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTImagePickerPlugin"]]; diff --git a/lib/core/adjust/adjust_events.dart b/lib/core/adjust/adjust_events.dart index 8c74582..bb1aefe 100644 --- a/lib/core/adjust/adjust_events.dart +++ b/lib/core/adjust/adjust_events.dart @@ -1,9 +1,21 @@ +import 'dart:async'; + import 'package:adjust_sdk/adjust.dart'; import 'package:adjust_sdk/adjust_event.dart'; +import 'package:facebook_app_events/facebook_app_events.dart'; +import 'package:logger/logger.dart'; import 'package:shared_preferences/shared_preferences.dart'; -/// Adjust 事件埋点(识别码见 docs/adjuest.md) +import '../config/facebook_config.dart'; + +/// 事件埋点:Adjust + Facebook App Events 双通道上报 +/// Adjust 识别码见 docs/adjuest.md abstract final class AdjustEvents { + static final _fb = FacebookAppEvents(); + static final _fbLog = Logger( + printer: PrettyPrinter(methodCount: 0, lineLength: 120), + level: FacebookConfig.debugLogs ? Level.trace : Level.off, + ); // 购买档位(充值页选择档位时上报) static const String tier1999 = 'm0r9u9'; // 19.99 static const String tier4999 = 'aht1ve'; // 49.99 @@ -57,56 +69,75 @@ abstract final class AdjustEvents { Adjust.trackEvent(AdjustEvent(eventToken)); } + /// 上报 Facebook(fire-and-forget,不阻塞主流程) + static void _trackFb(String eventDesc, Future Function() fn) { + if (FacebookConfig.debugLogs) _fbLog.w('FB ↑ $eventDesc'); + unawaited(fn()); + } + /// 购买档位(用户点击某档位购买时) static void trackTier(String eventToken) { _track(eventToken); } /// 首日充值 - static void trackFirstPurchase() { + static void trackFirstPurchase(double amount) { _track(firstPurchase); + _trackFb( + 'FirstRecharge amount=$amount', + () => _fb + .logEvent(name: 'FirstRecharge', parameters: {'amount': amount})); } /// 支付失败 static void trackOrderAbnormal() { _track(orderAbnormal); - } - - /// 支付成功(若为首日充值需额外调用 trackFirstPurchase) - static void trackPurchase() { - _track(purchase); + _trackFb('payment_failed', () => _fb.logEvent(name: 'payment_failed')); } /// 注册(首次 fast_login 成功) static void trackRegister() { _track(register); + _trackFb('CompletedRegistration', + () => _fb.logCompletedRegistration(registrationMethod: 'device')); } /// PetsHero AI Monthly VIP static void trackMonthlyVip() { _track(monthlyVip); + _trackFb('Subscribe monthly_vip', + () => _fb.logSubscribe(orderId: 'monthly_vip')); } /// PetsHero AI Weekly VIP static void trackWeeklyVip() { _track(weeklyVip); + _trackFb( + 'Subscribe weekly_vip', () => _fb.logSubscribe(orderId: 'weekly_vip')); } static const String _keyRegisterDate = 'adjust_register_date'; /// 支付成功时调用:上报 Purchase,若为首日充值则同时上报 first purchase - static Future trackPurchaseSuccess() async { + static Future trackPurchaseSuccess(double amount) async { _track(purchase); final prefs = await SharedPreferences.getInstance(); final registerDate = prefs.getString(_keyRegisterDate); - if (registerDate != null && - registerDate == DateTime.now().toIso8601String().substring(0, 10)) { - _track(firstPurchase); + final isFirstPurchase = registerDate != null && + registerDate == DateTime.now().toIso8601String().substring(0, 10); + if (isFirstPurchase) { + trackFirstPurchase(amount); } + _trackFb( + 'Purchase', + () => _fb.logPurchase( + amount: amount, + currency: 'USD', + )); } /// 支付失败时调用 static void trackPaymentFailed() { - _track(orderAbnormal); + trackOrderAbnormal(); } } diff --git a/lib/core/api/api_config.dart b/lib/core/api/api_config.dart index a1b8376..d278dba 100644 --- a/lib/core/api/api_config.dart +++ b/lib/core/api/api_config.dart @@ -2,6 +2,9 @@ import 'package:flutter/foundation.dart'; /// petsHeroAI API 配置 abstract final class ApiConfig { + /// 调试日志:true 时 release 包也输出 debug/info(正式包调试用,上线前改 false) + static const bool debugLogs = true; + /// AES 密钥 static const String aesKey = 'liyP4LkMfP68XvCt'; @@ -12,7 +15,7 @@ abstract final class ApiConfig { static const String packageName = 'com.petsheroai.app'; /// 预发环境域名 - static const String preBaseUrl = 'https://pre-ai.petsheroai.xyz'; + static const String preBaseUrl = 'https://ai.petsheroai.xyz'; //'https://ai.petsheroai.xyz'; //'https://pre-ai.petsheroai.xyz'; /// 生产环境域名 diff --git a/lib/core/api/api_crypto.dart b/lib/core/api/api_crypto.dart index dc12c3c..0c05443 100644 --- a/lib/core/api/api_crypto.dart +++ b/lib/core/api/api_crypto.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:math'; import 'package:encrypt/encrypt.dart'; @@ -29,8 +30,10 @@ abstract final class ApiCrypto { } /// 生成随机 Base64 字符串(用于噪音字段) + /// 使用 Random.secure() 保证密码学安全随机性 static String randomBase64([int byteLength = 16]) { - final bytes = List.generate(byteLength, (_) => DateTime.now().millisecondsSinceEpoch % 256); + final random = Random.secure(); + final bytes = List.generate(byteLength, (_) => random.nextInt(256)); return base64Encode(bytes); } diff --git a/lib/core/api/proxy_client.dart b/lib/core/api/proxy_client.dart index 49a7678..dbca292 100644 --- a/lib/core/api/proxy_client.dart +++ b/lib/core/api/proxy_client.dart @@ -82,7 +82,7 @@ void _logLong(String text) { /// 遇到 { 或 [ 视为 JSON 开始,直到与之匹配的 } 或 ] 结束;格式化后单条不超过 1000 字,分条时按行切分保持对齐。 void logWithEmbeddedJson(Object? msg) { - if (!kDebugMode) return; + if (!kDebugMode && !ApiConfig.debugLogs) return; if (msg is! String) { _proxyLog.d(msg); @@ -265,7 +265,7 @@ class ProxyClient { final loyaltyIndexEnc = ApiCrypto.encrypt(v2BodyEncoded); final proxyBody = { - ProxyKeys.heroClass: ApiConfig.appId, + ProxyKeys.heroClass: 'petsHeroAI', ProxyKeys.petSpecies: petSpeciesEnc, ProxyKeys.powerLevel: powerLevelEnc, ProxyKeys.questRank: questRankEnc, @@ -278,9 +278,10 @@ class ProxyClient { ProxyKeys.accuracyVal: ApiCrypto.randomBase64(), ProxyKeys.dirPath: ApiCrypto.randomBase64(), }; + _log('加密后的请求体: ${jsonEncode(proxyBody)}'); final url = '$_baseUrl${ApiConfig.proxyPath}'; - + _log('真实请求URL: $url'); final response = await http.post( Uri.parse(url), headers: {'Content-Type': 'application/json'}, diff --git a/lib/core/api/services/user_api.dart b/lib/core/api/services/user_api.dart index c5be95c..e3a040b 100644 --- a/lib/core/api/services/user_api.dart +++ b/lib/core/api/services/user_api.dart @@ -19,7 +19,8 @@ abstract final class UserApi { path: '/v1/user/fast_login', method: 'POST', queryParams: { - if (crest != null) 'crest': crest, + // if (crest != null) 'crest': crest, + "sentinel": "HAndroid", 'portal': ApiConfig.packageName, if (accolade != null) 'accolade': accolade, }, diff --git a/lib/core/auth/auth_service.dart b/lib/core/auth/auth_service.dart index 72b57a1..c6895c0 100644 --- a/lib/core/auth/auth_service.dart +++ b/lib/core/auth/auth_service.dart @@ -85,7 +85,8 @@ class AuthService { final realm = data['realm'] as String?; if (realm != null && realm.isNotEmpty) UserState.setAvatar(realm); final terminal = data['terminal'] as String?; - if (terminal != null && terminal.isNotEmpty) UserState.setUserName(terminal); + if (terminal != null && terminal.isNotEmpty) + UserState.setUserName(terminal); final navigate = data['navigate'] as String?; if (navigate != null) UserState.setNavigate(navigate); @@ -162,6 +163,7 @@ class AuthService { if (res == null) return; _logMsg('init: 登录结果 code=${res.code} msg=${res.msg}'); + _logMsg('init: 登录响应 data=${res.data}'); if (res.isSuccess && res.data != null) { final data = res.data as Map?; @@ -213,7 +215,7 @@ class AuthService { asset: uid!, digest: crest ?? '', origin: deviceId, - accolade: 'android_adjust', + accolade: ReferrerService.referrerSource, ); if (referrerRes.isSuccess) { _logMsg('referrer 上报成功'); diff --git a/lib/core/config/facebook_config.dart b/lib/core/config/facebook_config.dart new file mode 100644 index 0000000..c2c3045 --- /dev/null +++ b/lib/core/config/facebook_config.dart @@ -0,0 +1,27 @@ +/// Facebook SDK 配置 +/// +/// 用于 Adjust Meta Install Referrer 归因与 Facebook App Events 埋点。 +abstract final class FacebookConfig { + /// Facebook 调试日志:true 时 Dart 层会打印所有 FB 事件(正式包调试用,上线前改 false) + static const bool debugLogs = true; + + /// Facebook 应用 ID(应用编号) + static const String appId = '1684216162986495'; + + /// Facebook Client Token(客户端口令) + /// + /// 在 Facebook 开发者后台获取:应用 → 设置 → 高级 → 客户端口令 + static const String clientToken = ''; + + /// 安装引荐来源解密密钥 + /// + /// 用于解密 Facebook App Install Ads 的加密 referrer。 + /// 请在 Adjust 控制台填写此密钥以启用解密 + /// (路径:App Settings → Partner setup → Meta/Facebook)。 + static const String installReferrerDecryptionKey = + '068aff9bac7e8846b94e9fc73d51c7a5ab7c8ac39fe9a2b16d0ff8b74f98f'; + + /// 应用密钥(App Secret)仅用于服务端,勿放入客户端。 + static bool get hasClientToken => clientToken.isNotEmpty; +} + diff --git a/lib/core/log/app_logger.dart b/lib/core/log/app_logger.dart index c29d58d..9535863 100644 --- a/lib/core/log/app_logger.dart +++ b/lib/core/log/app_logger.dart @@ -1,8 +1,10 @@ import 'package:flutter/foundation.dart'; import 'package:logger/logger.dart'; +import '../api/api_config.dart'; + /// 统一应用日志,提升可读性:时间戳、级别、标签、格式化输出。 -/// 在 release 下仅输出 warning/error,避免泄露信息。 +/// release 下默认仅输出 warning/error;ApiConfig.debugLogs=true 时放开全部级别。 /// /// 使用示例: /// final _log = AppLogger('GenerateVideo'); @@ -25,7 +27,7 @@ class AppLogger { printEmojis: true, dateTimeFormat: DateTimeFormat.onlyTimeAndSinceStart, ), - level: kReleaseMode ? Level.warning : Level.trace, + level: (kDebugMode || ApiConfig.debugLogs) ? Level.trace : Level.warning, ); return _logger!; } diff --git a/lib/core/referrer/referrer_service.dart b/lib/core/referrer/referrer_service.dart index 2e7631f..aa079fc 100644 --- a/lib/core/referrer/referrer_service.dart +++ b/lib/core/referrer/referrer_service.dart @@ -1,32 +1,108 @@ import 'dart:async'; +import 'dart:convert'; +import 'package:adjust_sdk/adjust_attribution.dart'; +import 'package:adjust_sdk/adjust.dart'; import 'package:flutter/foundation.dart'; import 'package:play_install_referrer/play_install_referrer.dart'; -/// 安装来源 referrer 服务(用于 ch/crest 渠道参数) +/// 归因信息服务(优先从 Adjust 获取,fallback 使用 Play Install Referrer) class ReferrerService { ReferrerService._(); static String? _cachedReferrer; + static String _referrerSource = 'gg'; static final Completer _completer = Completer(); - /// 获取 referrer,Android 使用 Google Play Install Referrer,iOS 返回空 + /// attribution 回调的 Completer,与 getAttributionWithTimeout 竞速,谁先返回用谁 + static final Completer _attributionCallbackCompleter = + Completer(); + + static const int _adjustTimeoutMs = 15000; + + /// 由 Adjust attributionCallback 调用,首次安装时归因往往通过此回调返回(晚于 getAttributionWithTimeout) + static void receiveAttributionFromCallback(AdjustAttribution attribution) { + if (!_attributionCallbackCompleter.isCompleted) { + _attributionCallbackCompleter.complete(attribution); + } + } + + /// 归因来源:Adjust 为 android_adjust,Play Install Referrer 为 gg + static String get referrerSource => _referrerSource; + + /// JSON 可编码的 costAmount:保留字段,非有限数字用字符串避免 encode 抛错 + static Object? _jsonEncodableCostAmount(num? v) { + if (v == null) return null; + if (v is double && !v.isFinite) return v.toString(); + return v; + } + + /// 将完整 AdjustAttribution 序列化为 JSON(供 digest / Base64),不省略任何键 + static String _attributionToDigest(AdjustAttribution attr) { + final map = { + 'trackerToken': attr.trackerToken, + 'trackerName': attr.trackerName, + 'network': attr.network, + 'campaign': attr.campaign, + 'adgroup': attr.adgroup, + 'creative': attr.creative, + 'clickLabel': attr.clickLabel, + 'costType': attr.costType, + 'costAmount': _jsonEncodableCostAmount(attr.costAmount), + 'costCurrency': attr.costCurrency, + 'jsonResponse': attr.jsonResponse, + 'fbInstallReferrer': attr.fbInstallReferrer, + }; + try { + return jsonEncode(map); + } catch (_) { + return ''; + } + } + + /// 获取 referrer/digest,优先从 Adjust 归因获取,fallback 使用 Play Install Referrer + /// 同时监听 attributionCallback,首次安装时归因往往通过回调返回(可能晚于 getAttributionWithTimeout) static Future getReferrer() async { if (_cachedReferrer != null) return _cachedReferrer; if (_completer.isCompleted) return _completer.future; - if (defaultTargetPlatform != TargetPlatform.android) { - _cachedReferrer = ''; - if (!_completer.isCompleted) _completer.complete(''); - return ''; + var digest = ''; + try { + // 竞速:getAttributionWithTimeout 与 attribution 回调,谁先返回用谁 + final attribution = await Future.any([ + (() async { + try { + return await Adjust.getAttributionWithTimeout(_adjustTimeoutMs); + } catch (_) { + return null; + } + })(), + _attributionCallbackCompleter.future, + ]); + if (attribution != null) { + final raw = _attributionToDigest(attribution); + if (raw.isNotEmpty) { + _referrerSource = 'android_adjust'; + digest = base64Encode(utf8.encode(raw)); + } + } + } catch (_) { + digest = ''; } - try { - final details = await PlayInstallReferrer.installReferrer; - _cachedReferrer = details.installReferrer ?? ''; - } catch (_) { - _cachedReferrer = ''; + if (digest.isEmpty) { + _referrerSource = 'gg'; + if (defaultTargetPlatform == TargetPlatform.android) { + try { + final details = await PlayInstallReferrer.installReferrer; + digest = details.installReferrer ?? ''; + } catch (_) { + digest = ''; + } + } } + + _cachedReferrer = digest; if (!_completer.isCompleted) _completer.complete(_cachedReferrer); return _cachedReferrer; } diff --git a/lib/features/recharge/recharge_screen.dart b/lib/features/recharge/recharge_screen.dart index e122d0c..4ffc77c 100644 --- a/lib/features/recharge/recharge_screen.dart +++ b/lib/features/recharge/recharge_screen.dart @@ -280,7 +280,8 @@ class _RechargeScreenState extends State } _showSnackBar( context, 'Order created. Complete payment in the page.'); - AdjustEvents.trackPurchaseSuccess(); + AdjustEvents.trackPurchaseSuccess( + (AdjustEvents.parsePrice(item.actualAmount) ?? 0).toDouble()); } } else { if (mounted) { @@ -288,7 +289,8 @@ class _RechargeScreenState extends State _showSnackBar( context, 'Order created. Awaiting payment confirmation.'); } - AdjustEvents.trackPurchaseSuccess(); + AdjustEvents.trackPurchaseSuccess( + (AdjustEvents.parsePrice(item.actualAmount) ?? 0).toDouble()); } } catch (e) { if (mounted) { @@ -456,7 +458,8 @@ class _RechargeScreenState extends State if (mounted) { _showSnackBar(context, 'Purchase completed.'); } - AdjustEvents.trackPurchaseSuccess(); + AdjustEvents.trackPurchaseSuccess( + (AdjustEvents.parsePrice(item.actualAmount) ?? 0).toDouble()); } else { _showSnackBar( context, diff --git a/lib/main.dart b/lib/main.dart index 3c58ab9..2a270ba 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,12 +1,15 @@ import 'package:adjust_sdk/adjust_attribution.dart'; import 'package:adjust_sdk/adjust_config.dart'; import 'package:adjust_sdk/adjust.dart'; +import 'package:facebook_app_events/facebook_app_events.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'app.dart'; +import 'core/api/api_config.dart'; import 'core/auth/auth_service.dart'; +import 'core/config/facebook_config.dart'; import 'core/log/app_logger.dart'; import 'core/referrer/referrer_service.dart'; import 'core/theme/app_colors.dart'; @@ -15,7 +18,9 @@ import 'features/recharge/google_play_purchase_service.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); _initAdjust(); - ReferrerService.init(); + _initFacebookAppEvents(); + // 等待 Adjust 归因(ReferrerService 会调用 Adjust.getAttributionWithTimeout) + await ReferrerService.init(); SystemChrome.setSystemUIOverlayStyle( const SystemUiOverlayStyle( statusBarColor: AppColors.surface, @@ -23,7 +28,7 @@ void main() async { statusBarBrightness: Brightness.light, ), ); - // 先启动登录,确保首次构建时 loginComplete 可被监听 + // Adjust 初始化后执行登录,确保登录时归因数据已就绪 AuthService.init(); runApp(const App()); // 尽早订阅 purchaseStream,否则未确认订单不会出现在 queryPastPurchases 中,补单会为空 @@ -31,7 +36,8 @@ void main() async { GooglePlayPurchaseService.startPendingPurchaseListener(); } // 登录完成后执行谷歌支付补单(未核销订单上报服务端并 completePurchase) - AuthService.loginComplete.then((_) => GooglePlayPurchaseService.runOrderRecovery()); + AuthService.loginComplete + .then((_) => GooglePlayPurchaseService.runOrderRecovery()); } void _initAdjust() { @@ -40,16 +46,29 @@ void _initAdjust() { appToken, kDebugMode ? AdjustEnvironment.sandbox : AdjustEnvironment.production, ); - if (kDebugMode) { + // config.fbAppId = FacebookConfig.appId; + if (kDebugMode || ApiConfig.debugLogs) { config.logLevel = AdjustLogLevel.verbose; } config.attributionCallback = _onAdjustAttribution; Adjust.initSdk(config); } +final _fbAppEvents = FacebookAppEvents(); + +void _initFacebookAppEvents() { + // activateApp:应用启动事件,Facebook 用于统计与广告归因 + _fbAppEvents.activateApp(); + if (FacebookConfig.debugLogs) { + AppLogger('FB').d('activateApp 已上报'); + } +} + final _adjustLog = AppLogger('Adjust'); void _onAdjustAttribution(AdjustAttribution attribution) { + // 注入 ReferrerService,与 getAttributionWithTimeout 竞速,首次安装时归因多由此回调返回 + ReferrerService.receiveAttributionFromCallback(attribution); _adjustLog.d('归因信息: ' 'trackerToken=${attribution.trackerToken}, ' 'trackerName=${attribution.trackerName}, ' diff --git a/pubspec.yaml b/pubspec.yaml index 833e110..b962d6c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: pets_hero_ai description: PetsHero AI Application. publish_to: 'none' -version: 1.1.1+12 +version: 1.1.11+22 environment: sdk: '>=3.0.0 <4.0.0' @@ -10,6 +10,7 @@ dependencies: flutter: sdk: flutter adjust_sdk: ^5.5.1 + facebook_app_events: ^0.26.0 cupertino_icons: ^1.0.6 play_install_referrer: ^0.5.0 flutter_lucide: ^1.8.2