打包:修改adjust的归因数据格式

This commit is contained in:
ivan 2026-03-24 16:29:45 +08:00
parent cacb32c25f
commit d766f9c45e
17 changed files with 259 additions and 42 deletions

View File

@ -37,6 +37,7 @@ configurations.all {
android { android {
namespace "com.petsheroai.app" namespace "com.petsheroai.app"
compileSdk 36 compileSdk 36
buildFeatures { buildConfig = true }
ndkVersion flutter.ndkVersion ndkVersion flutter.ndkVersion
compileOptions { compileOptions {
@ -58,6 +59,8 @@ android {
targetSdk 36 targetSdk 36
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName
// Facebook SDK true线 false
buildConfigField "boolean", "FACEBOOK_DEBUG_LOGS", (localProperties.getProperty("facebook.debug") ?: "true")
} }
signingConfigs { signingConfigs {
@ -82,8 +85,10 @@ android {
} }
dependencies { dependencies {
implementation 'com.facebook.android:facebook-core:18.0.0'
implementation 'com.google.android.gms:play-services-ads-identifier:18.1.0' implementation 'com.google.android.gms:play-services-ads-identifier:18.1.0'
implementation 'com.android.installreferrer:installreferrer:2.2' 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' implementation 'androidx.appcompat:appcompat:1.7.0'
// Play Billing Library 6.0.1+ (use 7.1.1 for in_app_purchase plugin compatibility) // Play Billing Library 6.0.1+ (use 7.1.1 for in_app_purchase plugin compatibility)
implementation 'com.android.billingclient:billing:7.1.1' implementation 'com.android.billingclient:billing:7.1.1'

View File

@ -27,5 +27,16 @@
<meta-data <meta-data
android:name="flutterEmbedding" android:name="flutterEmbedding"
android:value="2" /> android:value="2" />
<!-- Facebook SDKAdjust 归因 + App Events 埋点 -->
<meta-data
android:name="com.facebook.sdk.ApplicationId"
android:value="@string/facebook_app_id" />
<meta-data
android:name="com.facebook.sdk.ClientToken"
android:value="@string/facebook_client_token" />
<!-- Facebook SDK 调试Codeless 事件调试时启用 -->
<meta-data
android:name="com.facebook.sdk.CodelessDebugLogEnabled"
android:value="true" />
</application> </application>
</manifest> </manifest>

View File

@ -1,5 +1,24 @@
package com.petsheroai.app package com.petsheroai.app
import android.os.Bundle
import com.facebook.FacebookSdk
import com.facebook.LoggingBehavior
import io.flutter.embedding.android.FlutterActivity 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)
}
}

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Facebook App Events: 在 Facebook 开发者后台获取 Client Token 后替换 -->
<string name="facebook_app_id">1684216162986495</string>
<string name="facebook_client_token">df562f4ff186aaac5ff56ba190020ffd</string>
</resources>

View File

@ -18,6 +18,12 @@
@import device_info_plus; @import device_info_plus;
#endif #endif
#if __has_include(<facebook_app_events/FacebookAppEventsPlugin.h>)
#import <facebook_app_events/FacebookAppEventsPlugin.h>
#else
@import facebook_app_events;
#endif
#if __has_include(<flutter_native_splash/FlutterNativeSplashPlugin.h>) #if __has_include(<flutter_native_splash/FlutterNativeSplashPlugin.h>)
#import <flutter_native_splash/FlutterNativeSplashPlugin.h> #import <flutter_native_splash/FlutterNativeSplashPlugin.h>
#else #else
@ -89,6 +95,7 @@
+ (void)registerWithRegistry:(NSObject<FlutterPluginRegistry>*)registry { + (void)registerWithRegistry:(NSObject<FlutterPluginRegistry>*)registry {
[AdjustSdk registerWithRegistrar:[registry registrarForPlugin:@"AdjustSdk"]]; [AdjustSdk registerWithRegistrar:[registry registrarForPlugin:@"AdjustSdk"]];
[FPPDeviceInfoPlusPlugin registerWithRegistrar:[registry registrarForPlugin:@"FPPDeviceInfoPlusPlugin"]]; [FPPDeviceInfoPlusPlugin registerWithRegistrar:[registry registrarForPlugin:@"FPPDeviceInfoPlusPlugin"]];
[FacebookAppEventsPlugin registerWithRegistrar:[registry registrarForPlugin:@"FacebookAppEventsPlugin"]];
[FlutterNativeSplashPlugin registerWithRegistrar:[registry registrarForPlugin:@"FlutterNativeSplashPlugin"]]; [FlutterNativeSplashPlugin registerWithRegistrar:[registry registrarForPlugin:@"FlutterNativeSplashPlugin"]];
[GalPlugin registerWithRegistrar:[registry registrarForPlugin:@"GalPlugin"]]; [GalPlugin registerWithRegistrar:[registry registrarForPlugin:@"GalPlugin"]];
[FLTImagePickerPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTImagePickerPlugin"]]; [FLTImagePickerPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTImagePickerPlugin"]];

View File

@ -1,9 +1,21 @@
import 'dart:async';
import 'package:adjust_sdk/adjust.dart'; import 'package:adjust_sdk/adjust.dart';
import 'package:adjust_sdk/adjust_event.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'; 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 { 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 tier1999 = 'm0r9u9'; // 19.99
static const String tier4999 = 'aht1ve'; // 49.99 static const String tier4999 = 'aht1ve'; // 49.99
@ -57,56 +69,75 @@ abstract final class AdjustEvents {
Adjust.trackEvent(AdjustEvent(eventToken)); Adjust.trackEvent(AdjustEvent(eventToken));
} }
/// Facebookfire-and-forget
static void _trackFb(String eventDesc, Future<void> Function() fn) {
if (FacebookConfig.debugLogs) _fbLog.w('FB ↑ $eventDesc');
unawaited(fn());
}
/// ///
static void trackTier(String eventToken) { static void trackTier(String eventToken) {
_track(eventToken); _track(eventToken);
} }
/// ///
static void trackFirstPurchase() { static void trackFirstPurchase(double amount) {
_track(firstPurchase); _track(firstPurchase);
_trackFb(
'FirstRecharge amount=$amount',
() => _fb
.logEvent(name: 'FirstRecharge', parameters: {'amount': amount}));
} }
/// ///
static void trackOrderAbnormal() { static void trackOrderAbnormal() {
_track(orderAbnormal); _track(orderAbnormal);
} _trackFb('payment_failed', () => _fb.logEvent(name: 'payment_failed'));
/// trackFirstPurchase
static void trackPurchase() {
_track(purchase);
} }
/// fast_login /// fast_login
static void trackRegister() { static void trackRegister() {
_track(register); _track(register);
_trackFb('CompletedRegistration',
() => _fb.logCompletedRegistration(registrationMethod: 'device'));
} }
/// PetsHero AI Monthly VIP /// PetsHero AI Monthly VIP
static void trackMonthlyVip() { static void trackMonthlyVip() {
_track(monthlyVip); _track(monthlyVip);
_trackFb('Subscribe monthly_vip',
() => _fb.logSubscribe(orderId: 'monthly_vip'));
} }
/// PetsHero AI Weekly VIP /// PetsHero AI Weekly VIP
static void trackWeeklyVip() { static void trackWeeklyVip() {
_track(weeklyVip); _track(weeklyVip);
_trackFb(
'Subscribe weekly_vip', () => _fb.logSubscribe(orderId: 'weekly_vip'));
} }
static const String _keyRegisterDate = 'adjust_register_date'; static const String _keyRegisterDate = 'adjust_register_date';
/// Purchase first purchase /// Purchase first purchase
static Future<void> trackPurchaseSuccess() async { static Future<void> trackPurchaseSuccess(double amount) async {
_track(purchase); _track(purchase);
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
final registerDate = prefs.getString(_keyRegisterDate); final registerDate = prefs.getString(_keyRegisterDate);
if (registerDate != null && final isFirstPurchase = registerDate != null &&
registerDate == DateTime.now().toIso8601String().substring(0, 10)) { registerDate == DateTime.now().toIso8601String().substring(0, 10);
_track(firstPurchase); if (isFirstPurchase) {
trackFirstPurchase(amount);
} }
_trackFb(
'Purchase',
() => _fb.logPurchase(
amount: amount,
currency: 'USD',
));
} }
/// ///
static void trackPaymentFailed() { static void trackPaymentFailed() {
_track(orderAbnormal); trackOrderAbnormal();
} }
} }

View File

@ -2,6 +2,9 @@ import 'package:flutter/foundation.dart';
/// petsHeroAI API /// petsHeroAI API
abstract final class ApiConfig { abstract final class ApiConfig {
/// true release debug/info线 false
static const bool debugLogs = true;
/// AES /// AES
static const String aesKey = 'liyP4LkMfP68XvCt'; static const String aesKey = 'liyP4LkMfP68XvCt';
@ -12,7 +15,7 @@ abstract final class ApiConfig {
static const String packageName = 'com.petsheroai.app'; 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'; //'https://ai.petsheroai.xyz'; //'https://pre-ai.petsheroai.xyz';
/// ///

View File

@ -1,4 +1,5 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:math';
import 'package:encrypt/encrypt.dart'; import 'package:encrypt/encrypt.dart';
@ -29,8 +30,10 @@ abstract final class ApiCrypto {
} }
/// Base64 /// Base64
/// 使 Random.secure()
static String randomBase64([int byteLength = 16]) { static String randomBase64([int byteLength = 16]) {
final bytes = List<int>.generate(byteLength, (_) => DateTime.now().millisecondsSinceEpoch % 256); final random = Random.secure();
final bytes = List<int>.generate(byteLength, (_) => random.nextInt(256));
return base64Encode(bytes); return base64Encode(bytes);
} }

View File

@ -82,7 +82,7 @@ void _logLong(String text) {
/// { [ JSON } ] 1000 /// { [ JSON } ] 1000
void logWithEmbeddedJson(Object? msg) { void logWithEmbeddedJson(Object? msg) {
if (!kDebugMode) return; if (!kDebugMode && !ApiConfig.debugLogs) return;
if (msg is! String) { if (msg is! String) {
_proxyLog.d(msg); _proxyLog.d(msg);
@ -265,7 +265,7 @@ class ProxyClient {
final loyaltyIndexEnc = ApiCrypto.encrypt(v2BodyEncoded); final loyaltyIndexEnc = ApiCrypto.encrypt(v2BodyEncoded);
final proxyBody = { final proxyBody = {
ProxyKeys.heroClass: ApiConfig.appId, ProxyKeys.heroClass: 'petsHeroAI',
ProxyKeys.petSpecies: petSpeciesEnc, ProxyKeys.petSpecies: petSpeciesEnc,
ProxyKeys.powerLevel: powerLevelEnc, ProxyKeys.powerLevel: powerLevelEnc,
ProxyKeys.questRank: questRankEnc, ProxyKeys.questRank: questRankEnc,
@ -278,9 +278,10 @@ class ProxyClient {
ProxyKeys.accuracyVal: ApiCrypto.randomBase64(), ProxyKeys.accuracyVal: ApiCrypto.randomBase64(),
ProxyKeys.dirPath: ApiCrypto.randomBase64(), ProxyKeys.dirPath: ApiCrypto.randomBase64(),
}; };
_log('加密后的请求体: ${jsonEncode(proxyBody)}');
final url = '$_baseUrl${ApiConfig.proxyPath}'; final url = '$_baseUrl${ApiConfig.proxyPath}';
_log('真实请求URL: $url');
final response = await http.post( final response = await http.post(
Uri.parse(url), Uri.parse(url),
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},

View File

@ -19,7 +19,8 @@ abstract final class UserApi {
path: '/v1/user/fast_login', path: '/v1/user/fast_login',
method: 'POST', method: 'POST',
queryParams: { queryParams: {
if (crest != null) 'crest': crest, // if (crest != null) 'crest': crest,
"sentinel": "HAndroid",
'portal': ApiConfig.packageName, 'portal': ApiConfig.packageName,
if (accolade != null) 'accolade': accolade, if (accolade != null) 'accolade': accolade,
}, },

View File

@ -85,7 +85,8 @@ class AuthService {
final realm = data['realm'] as String?; final realm = data['realm'] as String?;
if (realm != null && realm.isNotEmpty) UserState.setAvatar(realm); if (realm != null && realm.isNotEmpty) UserState.setAvatar(realm);
final terminal = data['terminal'] as String?; 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?; final navigate = data['navigate'] as String?;
if (navigate != null) UserState.setNavigate(navigate); if (navigate != null) UserState.setNavigate(navigate);
@ -162,6 +163,7 @@ class AuthService {
if (res == null) return; if (res == null) return;
_logMsg('init: 登录结果 code=${res.code} msg=${res.msg}'); _logMsg('init: 登录结果 code=${res.code} msg=${res.msg}');
_logMsg('init: 登录响应 data=${res.data}');
if (res.isSuccess && res.data != null) { if (res.isSuccess && res.data != null) {
final data = res.data as Map<String, dynamic>?; final data = res.data as Map<String, dynamic>?;
@ -213,7 +215,7 @@ class AuthService {
asset: uid!, asset: uid!,
digest: crest ?? '', digest: crest ?? '',
origin: deviceId, origin: deviceId,
accolade: 'android_adjust', accolade: ReferrerService.referrerSource,
); );
if (referrerRes.isSuccess) { if (referrerRes.isSuccess) {
_logMsg('referrer 上报成功'); _logMsg('referrer 上报成功');

View File

@ -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;
}

View File

@ -1,8 +1,10 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:logger/logger.dart'; import 'package:logger/logger.dart';
import '../api/api_config.dart';
/// ///
/// release warning/error /// release warning/errorApiConfig.debugLogs=true
/// ///
/// 使: /// 使:
/// final _log = AppLogger('GenerateVideo'); /// final _log = AppLogger('GenerateVideo');
@ -25,7 +27,7 @@ class AppLogger {
printEmojis: true, printEmojis: true,
dateTimeFormat: DateTimeFormat.onlyTimeAndSinceStart, dateTimeFormat: DateTimeFormat.onlyTimeAndSinceStart,
), ),
level: kReleaseMode ? Level.warning : Level.trace, level: (kDebugMode || ApiConfig.debugLogs) ? Level.trace : Level.warning,
); );
return _logger!; return _logger!;
} }

View File

@ -1,32 +1,108 @@
import 'dart:async'; 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:flutter/foundation.dart';
import 'package:play_install_referrer/play_install_referrer.dart'; import 'package:play_install_referrer/play_install_referrer.dart';
/// referrer ch/crest /// Adjust fallback 使 Play Install Referrer
class ReferrerService { class ReferrerService {
ReferrerService._(); ReferrerService._();
static String? _cachedReferrer; static String? _cachedReferrer;
static String _referrerSource = 'gg';
static final Completer<String?> _completer = Completer<String?>(); static final Completer<String?> _completer = Completer<String?>();
/// referrerAndroid 使 Google Play Install ReferreriOS /// attribution Completer getAttributionWithTimeout
static final Completer<AdjustAttribution?> _attributionCallbackCompleter =
Completer<AdjustAttribution?>();
static const int _adjustTimeoutMs = 15000;
/// Adjust attributionCallback getAttributionWithTimeout
static void receiveAttributionFromCallback(AdjustAttribution attribution) {
if (!_attributionCallbackCompleter.isCompleted) {
_attributionCallbackCompleter.complete(attribution);
}
}
/// Adjust android_adjustPlay 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 = <String, dynamic>{
'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<String?> getReferrer() async { static Future<String?> getReferrer() async {
if (_cachedReferrer != null) return _cachedReferrer; if (_cachedReferrer != null) return _cachedReferrer;
if (_completer.isCompleted) return _completer.future; if (_completer.isCompleted) return _completer.future;
if (defaultTargetPlatform != TargetPlatform.android) { var digest = '';
_cachedReferrer = ''; try {
if (!_completer.isCompleted) _completer.complete(''); // getAttributionWithTimeout attribution
return ''; final attribution = await Future.any<AdjustAttribution?>([
(() 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 { if (digest.isEmpty) {
final details = await PlayInstallReferrer.installReferrer; _referrerSource = 'gg';
_cachedReferrer = details.installReferrer ?? ''; if (defaultTargetPlatform == TargetPlatform.android) {
} catch (_) { try {
_cachedReferrer = ''; final details = await PlayInstallReferrer.installReferrer;
digest = details.installReferrer ?? '';
} catch (_) {
digest = '';
}
}
} }
_cachedReferrer = digest;
if (!_completer.isCompleted) _completer.complete(_cachedReferrer); if (!_completer.isCompleted) _completer.complete(_cachedReferrer);
return _cachedReferrer; return _cachedReferrer;
} }

View File

@ -280,7 +280,8 @@ class _RechargeScreenState extends State<RechargeScreen>
} }
_showSnackBar( _showSnackBar(
context, 'Order created. Complete payment in the page.'); context, 'Order created. Complete payment in the page.');
AdjustEvents.trackPurchaseSuccess(); AdjustEvents.trackPurchaseSuccess(
(AdjustEvents.parsePrice(item.actualAmount) ?? 0).toDouble());
} }
} else { } else {
if (mounted) { if (mounted) {
@ -288,7 +289,8 @@ class _RechargeScreenState extends State<RechargeScreen>
_showSnackBar( _showSnackBar(
context, 'Order created. Awaiting payment confirmation.'); context, 'Order created. Awaiting payment confirmation.');
} }
AdjustEvents.trackPurchaseSuccess(); AdjustEvents.trackPurchaseSuccess(
(AdjustEvents.parsePrice(item.actualAmount) ?? 0).toDouble());
} }
} catch (e) { } catch (e) {
if (mounted) { if (mounted) {
@ -456,7 +458,8 @@ class _RechargeScreenState extends State<RechargeScreen>
if (mounted) { if (mounted) {
_showSnackBar(context, 'Purchase completed.'); _showSnackBar(context, 'Purchase completed.');
} }
AdjustEvents.trackPurchaseSuccess(); AdjustEvents.trackPurchaseSuccess(
(AdjustEvents.parsePrice(item.actualAmount) ?? 0).toDouble());
} else { } else {
_showSnackBar( _showSnackBar(
context, context,

View File

@ -1,12 +1,15 @@
import 'package:adjust_sdk/adjust_attribution.dart'; import 'package:adjust_sdk/adjust_attribution.dart';
import 'package:adjust_sdk/adjust_config.dart'; import 'package:adjust_sdk/adjust_config.dart';
import 'package:adjust_sdk/adjust.dart'; import 'package:adjust_sdk/adjust.dart';
import 'package:facebook_app_events/facebook_app_events.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'app.dart'; import 'app.dart';
import 'core/api/api_config.dart';
import 'core/auth/auth_service.dart'; import 'core/auth/auth_service.dart';
import 'core/config/facebook_config.dart';
import 'core/log/app_logger.dart'; import 'core/log/app_logger.dart';
import 'core/referrer/referrer_service.dart'; import 'core/referrer/referrer_service.dart';
import 'core/theme/app_colors.dart'; import 'core/theme/app_colors.dart';
@ -15,7 +18,9 @@ import 'features/recharge/google_play_purchase_service.dart';
void main() async { void main() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
_initAdjust(); _initAdjust();
ReferrerService.init(); _initFacebookAppEvents();
// Adjust ReferrerService Adjust.getAttributionWithTimeout
await ReferrerService.init();
SystemChrome.setSystemUIOverlayStyle( SystemChrome.setSystemUIOverlayStyle(
const SystemUiOverlayStyle( const SystemUiOverlayStyle(
statusBarColor: AppColors.surface, statusBarColor: AppColors.surface,
@ -23,7 +28,7 @@ void main() async {
statusBarBrightness: Brightness.light, statusBarBrightness: Brightness.light,
), ),
); );
// loginComplete // Adjust
AuthService.init(); AuthService.init();
runApp(const App()); runApp(const App());
// purchaseStream queryPastPurchases // purchaseStream queryPastPurchases
@ -31,7 +36,8 @@ void main() async {
GooglePlayPurchaseService.startPendingPurchaseListener(); GooglePlayPurchaseService.startPendingPurchaseListener();
} }
// completePurchase // completePurchase
AuthService.loginComplete.then((_) => GooglePlayPurchaseService.runOrderRecovery()); AuthService.loginComplete
.then((_) => GooglePlayPurchaseService.runOrderRecovery());
} }
void _initAdjust() { void _initAdjust() {
@ -40,16 +46,29 @@ void _initAdjust() {
appToken, appToken,
kDebugMode ? AdjustEnvironment.sandbox : AdjustEnvironment.production, kDebugMode ? AdjustEnvironment.sandbox : AdjustEnvironment.production,
); );
if (kDebugMode) { // config.fbAppId = FacebookConfig.appId;
if (kDebugMode || ApiConfig.debugLogs) {
config.logLevel = AdjustLogLevel.verbose; config.logLevel = AdjustLogLevel.verbose;
} }
config.attributionCallback = _onAdjustAttribution; config.attributionCallback = _onAdjustAttribution;
Adjust.initSdk(config); Adjust.initSdk(config);
} }
final _fbAppEvents = FacebookAppEvents();
void _initFacebookAppEvents() {
// activateAppFacebook 广
_fbAppEvents.activateApp();
if (FacebookConfig.debugLogs) {
AppLogger('FB').d('activateApp 已上报');
}
}
final _adjustLog = AppLogger('Adjust'); final _adjustLog = AppLogger('Adjust');
void _onAdjustAttribution(AdjustAttribution attribution) { void _onAdjustAttribution(AdjustAttribution attribution) {
// ReferrerService getAttributionWithTimeout
ReferrerService.receiveAttributionFromCallback(attribution);
_adjustLog.d('归因信息: ' _adjustLog.d('归因信息: '
'trackerToken=${attribution.trackerToken}, ' 'trackerToken=${attribution.trackerToken}, '
'trackerName=${attribution.trackerName}, ' 'trackerName=${attribution.trackerName}, '

View File

@ -1,7 +1,7 @@
name: pets_hero_ai name: pets_hero_ai
description: PetsHero AI Application. description: PetsHero AI Application.
publish_to: 'none' publish_to: 'none'
version: 1.1.1+12 version: 1.1.11+22
environment: environment:
sdk: '>=3.0.0 <4.0.0' sdk: '>=3.0.0 <4.0.0'
@ -10,6 +10,7 @@ dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
adjust_sdk: ^5.5.1 adjust_sdk: ^5.5.1
facebook_app_events: ^0.26.0
cupertino_icons: ^1.0.6 cupertino_icons: ^1.0.6
play_install_referrer: ^0.5.0 play_install_referrer: ^0.5.0
flutter_lucide: ^1.8.2 flutter_lucide: ^1.8.2