import 'dart:io'; import 'dart:io'; import 'package:adjust_sdk/adjust_event.dart'; import 'package:firebase_analytics/firebase_analytics.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; import 'package:guru_app/account/account_data_store.dart'; import 'package:guru_app/account/account_manager.dart'; import 'package:guru_app/ads/ads_manager.dart'; import 'package:guru_app/analytics/guru_analytics.dart'; import 'package:guru_app/app/app_models.dart'; import 'package:guru_app/database/guru_db.dart'; import 'package:guru_app/financial/financial_manager.dart'; import 'package:guru_app/financial/iap/iap_manager.dart'; import 'package:guru_app/financial/manifest/manifest.dart'; import 'package:guru_app/financial/manifest/manifest_manager.dart'; import 'package:guru_app/financial/product/product_model.dart'; import 'package:guru_app/financial/reward/reward_manager.dart'; import 'package:guru_app/firebase/dxlinks/dxlink_manager.dart'; import 'package:guru_applovin_flutter/guru_applovin_flutter.dart'; import 'package:guru_utils/collection/collectionutils.dart'; import 'package:guru_utils/controller/aware/ads/overlay/ads_overlay.dart'; import 'package:guru_utils/datetime/datetime_utils.dart'; import 'package:guru_utils/lifecycle/lifecycle_manager.dart'; import 'package:guru_utils/network/network_utils.dart'; import 'package:guru_utils/property/app_property.dart'; import 'package:guru_app/property/settings/guru_settings.dart'; import 'package:guru_app/firebase/firebase.dart'; import 'package:guru_utils/http/http_ex.dart'; import 'package:guru_utils/log/log.dart'; import 'package:guru_utils/packages/guru_package.dart'; import 'package:guru_utils/ads/ads.dart'; import 'package:guru_utils/guru_utils.dart'; import 'package:logger/logger.dart' as Logger; import 'package:guru_utils/aigc/bi/ai_bi.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:guru_popup/guru_popup.dart'; export 'package:firebase_core/firebase_core.dart'; export 'package:guru_app/app/app_models.dart'; export 'package:guru_utils/log/log.dart'; export 'package:guru_spec/guru_spec.dart'; export 'package:guru_app/analytics/guru_analytics.dart'; export 'package:guru_app/financial/product/product_model.dart'; export 'package:adjust_sdk/adjust_event.dart'; export 'package:guru_utils/ads/ads.dart'; export 'package:guru_utils/guru_utils.dart'; export 'dart:io'; export 'dart:math'; export 'package:guru_app/financial/manifest/manifest.dart'; export 'package:guru_app/firebase/messaging/remote_messaging_manager.dart'; /// Created by Haoyi on 2022/8/25 abstract class AppSpec { String get appName; String get flavor; AppDetails get details; AdsProfile get adsProfile; ProductProfile get productProfile; AdjustProfile get adjustProfile; Deployment get deployment; Map get defaultRemoteConfig; } class NotImplementationAppSpecCreatorException implements Exception { NotImplementationAppSpecCreatorException(); @override String toString() { return 'NotImplementationAppSpecCreatorException'; } } class AppEnv { final AppSpec spec; final RootPackage package; final BackgroundMessageHandler? backgroundMessageHandler; final ToastDelegate? toastDelegate; AppEnv( {required this.spec, required this.package, this.backgroundMessageHandler, this.toastDelegate}); } extension _GuruPackageExtension on GuruPackage { Iterable _mergeSupportedLocales() { final Set locales = supportedLocales.toSet(); for (var child in children) { locales.addAll(child._mergeSupportedLocales()); } return locales; } Iterable> _mergeLocalizationsDelegates() { final Set> delegates = localizationsDelegates.toSet(); for (var child in children) { delegates.addAll(child._mergeLocalizationsDelegates()); } return delegates; } Future _dispatchInitialize() async { await initialize(); children.sort((p1, p2) { return p2.priority.compareTo(p1.priority); }); for (var child in children) { if (flattenChildrenAsyncInit) { child._dispatchInitialize(); } else { await child._dispatchInitialize(); } } } Future _dispatchInitializeAsync() async { initializeAsync(); for (var child in children) { child._dispatchInitializeAsync(); } } } class GuruApp { static late GuruApp _instance; static GuruApp get instance => _instance; final RootPackage rootPackage; final AppSpec appSpec; String get appName => appSpec.appName; String get flavor => appSpec.flavor; AppDetails get details => appSpec.details; AdsProfile get adsProfile => appSpec.adsProfile; AdjustProfile get adjustProfile => appSpec.adjustProfile; ProductProfile get productProfile => appSpec.productProfile; Map get defaultRemoteConfig => appSpec.defaultRemoteConfig; Set get conversionEvents => appSpec.deployment.conversionEvents; GuruApp._({required this.appSpec, required this.rootPackage, ToastDelegate? toastDelegate}) { GuruUtils.toastDelegate = toastDelegate; AdsOverlay.bind(showBanner: GuruPopup.instance.showAdsBanner); } Iterable get supportedLocales => rootPackage._mergeSupportedLocales(); Iterable> get localizationsDelegates => rootPackage._mergeLocalizationsDelegates(); bool? _check; Future _initialize() async { try { await GuruDB.instance.initDatabase(); AppProperty.initialize(GuruDB.instance, cacheSize: appSpec.deployment.propertyCacheSize); await GuruSettings.instance.refresh(); Paint.enableDithering = appSpec.deployment.enableDithering; // 3.16 default enabled await _dispatchInitializeSync(); _dispatchInitializeAsync(); } catch (error, stacktrace) { Log.w("initialize error:$error, $stacktrace"); } } Future _checkApp() async { try { final pkgName = (await PackageInfo.fromPlatform()).appName; final result = _check ??= (pkgName != GuruApp.instance.details.appId); GuruAnalytics.instance.logGuruEvent( "dev_audit", CollectionUtils.filterOutNulls({ "item_category": "pkg", "result": result == true ? 1 : 0, "err_info": result != true ? pkgName : null, })); return result == true; } catch (error, stacktrace) { Log.w("checkApp error:$error, $stacktrace"); GuruAnalytics.instance.logException(error, stacktrace: stacktrace); GuruAnalytics.instance.logGuruEvent( "dev_audit", CollectionUtils.filterOutNulls({ "item_category": "pkg", "result": 0, "err_info": error.runtimeType.toString(), })); return false; } } Future _dispatchInitializeSync() async { await RemoteConfigManager.instance.init(appSpec.defaultRemoteConfig); await rootPackage._dispatchInitialize(); try { GuruUtils.isTablet = (await GuruApplovinFlutter.instance.isTablet()) ?? false; Log.d("isTablet: ${GuruUtils.isTablet}"); } catch (error, stacktrace) { Log.w("invoke isTablet error:$error, $stacktrace"); } } Future _dispatchInitializeAsync() async { _initCommon(); _initRemoteConfig(); _initRemoteMessaging(); _initAnalytics(); if (appSpec.adsProfile != AdsProfile.invalid) { _initAds(); } _initFinancial(); _initAccount(); _initDxLink(); rootPackage._dispatchInitializeAsync(); Future.delayed(const Duration(seconds: 15), () async { await _checkApp(); }); } static Future initialize({required AppEnv appEnv}) async { final backgroundMessageHandler = appEnv.backgroundMessageHandler; if (backgroundMessageHandler != null) { FirebaseMessaging.onBackgroundMessage(backgroundMessageHandler); } WidgetsFlutterBinding.ensureInitialized(); try { await Firebase.initializeApp(); } catch (error, stacktrace) { Log.e("Firebase.initializeApp() error!", error: error, stackTrace: stacktrace); } GuruUtils.flavor = appEnv.spec.flavor; try { _instance = GuruApp._( appSpec: appEnv.spec, rootPackage: appEnv.package, toastDelegate: appEnv.toastDelegate); Log.init(_instance.appName, persistentLogFileSize: appEnv.spec.deployment.logFileSizeLimit, persistentLogCount: appEnv.spec.deployment.logFileCount, persistentLevel: appEnv.spec.deployment.persistentLogLevel); AiBi.instance.init(); AdsManager.instance.ensureInitialize(); await _instance._initialize(); LifecycleManager.instance.init(); } catch (error, stacktrace) { Log.e("GuruApp initialize error!", error: error, stackTrace: stacktrace); rethrow; } } void showToast(String message, {Duration duration = const Duration(seconds: 3)}) { GuruUtils.showToast(message, duration: duration); } } extension GuruAppInitializerExt on GuruApp { Future _initCommon() async { await NetworkUtils.init(); } Future _initRemoteConfig() async { await RemoteConfigManager.instance.fetchAndActivate(); final cdnConfig = RemoteConfigManager.instance.getCdnConfig(); HttpEx.init(cdnConfig, GuruApp.instance.appSpec.details.storagePrefix); final remoteDeployment = RemoteConfigManager.instance.getRemoteDeployment(); Settings.get() .keepOnScreenDuration .set(remoteDeployment.keepScreenOnDuration * DateTimeUtils.minuteInMillis); } void _initAnalytics() { GuruAnalytics.instance.init(); } void _initRemoteMessaging() async { RemoteMessagingManager.instance.init(); } void _initDxLink() { Future.delayed(const Duration(seconds: 2), () { DxLinkManager.instance.init(); }); } void _initAds() async { try { await AccountDataStore.instance.observableSaasUser .firstWhere((saasUser) => saasUser?.isValid == true) .timeout(const Duration(seconds: 3)); } catch (error, stacktrace) { Log.w("wait account error! $error", stackTrace: stacktrace); } finally { await AdsManager.instance.initialize(saasUser: AccountDataStore.instance.user); } } Future _initFinancial() async { ManifestManager.instance.addBuilders(GuruApp.instance.productProfile.manifestBuilders); FinancialManager.instance.init(); } Future _initAccount() async { await AccountManager.instance.init(); } } extension GuruAppFinancialExt on GuruApp { ProductId defineProductId(String sku, int attr, TransactionMethod method) { return productProfile.define(sku, attr, method); } ProductId? findProductId({String? sku, int? attr}) { return productProfile.find(sku: sku, attr: attr); } Set offerProductIds(ProductId productId) { return productProfile.offerProductIds(productId); } } extension GuruRemoteConfigExt on GuruApp { String getDefaultRemoteConfig(String key, {String defaultValue = ""}) { return defaultRemoteConfig[key] ?? defaultValue; } }