guru_sdk/guru_app/lib/guru_app.dart

345 lines
11 KiB
Dart

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<String, dynamic> 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<Locale> _mergeSupportedLocales() {
final Set<Locale> locales = supportedLocales.toSet();
for (var child in children) {
locales.addAll(child._mergeSupportedLocales());
}
return locales;
}
Iterable<LocalizationsDelegate<dynamic>> _mergeLocalizationsDelegates() {
final Set<LocalizationsDelegate<dynamic>> 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<String, dynamic> get defaultRemoteConfig => appSpec.defaultRemoteConfig;
Set<String> get conversionEvents => appSpec.deployment.conversionEvents;
GuruApp._({required this.appSpec, required this.rootPackage, ToastDelegate? toastDelegate}) {
GuruUtils.toastDelegate = toastDelegate;
AdsOverlay.bind(showBanner: GuruPopup.instance.showAdsBanner);
}
Iterable<Locale> get supportedLocales => rootPackage._mergeSupportedLocales();
Iterable<LocalizationsDelegate<dynamic>> 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<bool> _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<ProductId> offerProductIds(ProductId productId) {
return productProfile.offerProductIds(productId);
}
}
extension GuruRemoteConfigExt on GuruApp {
String getDefaultRemoteConfig(String key, {String defaultValue = ""}) {
return defaultRemoteConfig[key] ?? defaultValue;
}
}