763 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			C#
		
	
	
			
		
		
	
	
			763 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			C#
		
	
	
namespace Guru
 | 
						||
{
 | 
						||
    using UnityEngine;
 | 
						||
    using System;
 | 
						||
    using System.Collections;
 | 
						||
    using System.Collections.Generic;
 | 
						||
    using System.IO;
 | 
						||
    using Debug = UnityEngine.Debug;
 | 
						||
    
 | 
						||
    public partial class GuruSDK: MonoBehaviour
 | 
						||
    {
 | 
						||
        // SDK_VERSION
 | 
						||
        public const string Version = "1.0.14"; 
 | 
						||
        
 | 
						||
        // Const
 | 
						||
        public const string Tag = "[Guru]";
 | 
						||
        public const string ServicesConfigKey = "guru_services";
 | 
						||
        
 | 
						||
        private static GuruSDK _instance;
 | 
						||
        /// <summary>
 | 
						||
        /// 单利引用
 | 
						||
        /// </summary>
 | 
						||
        public static GuruSDK Instance
 | 
						||
        {
 | 
						||
            get
 | 
						||
            {
 | 
						||
                if(null == _instance)
 | 
						||
                {
 | 
						||
                    _instance = CreateInstance();
 | 
						||
                }
 | 
						||
                return _instance;
 | 
						||
            }
 | 
						||
            
 | 
						||
        }
 | 
						||
 | 
						||
        private GuruSDKInitConfig _initConfig;
 | 
						||
        private Action<bool> _onCompleteCallback;
 | 
						||
 | 
						||
        internal static GuruSDKInitConfig InitConfig => Instance._initConfig;
 | 
						||
        internal static GuruSDKModel Model => GuruSDKModel.Instance;
 | 
						||
        private static GuruServicesConfig _appServicesConfig;
 | 
						||
        private static GuruSettings _guruSettings;
 | 
						||
        private static GuruSettings GuruSettings
 | 
						||
        {
 | 
						||
            get
 | 
						||
            {
 | 
						||
                if (_guruSettings == null) _guruSettings = GuruSettings.Instance;
 | 
						||
                return _guruSettings;
 | 
						||
            }
 | 
						||
        }
 | 
						||
        
 | 
						||
        private static DateTime _initTime;
 | 
						||
        private static bool _isDebugEnabled = false;
 | 
						||
        /// <summary>
 | 
						||
        /// Debug Mode
 | 
						||
        /// </summary>
 | 
						||
        public static bool IsDebugMode
 | 
						||
        {
 | 
						||
            get
 | 
						||
            {
 | 
						||
#if UNITY_EDITOR || DEBUG
 | 
						||
                return true;
 | 
						||
#endif
 | 
						||
                return _isDebugEnabled;
 | 
						||
            }
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 初始化成功标志位
 | 
						||
        /// </summary>
 | 
						||
        public static bool IsInitialSuccess { get; private set; } = false;
 | 
						||
        /// <summary>
 | 
						||
        /// Firebase 就绪标志位
 | 
						||
        /// </summary>
 | 
						||
        public static bool IsFirebaseReady { get; private set; } = false;
 | 
						||
        /// <summary>
 | 
						||
        /// 服务就绪标志位
 | 
						||
        /// </summary>
 | 
						||
        public static bool IsServiceReady { get; private set; } = false;
 | 
						||
 | 
						||
        #region 初始化
 | 
						||
        
 | 
						||
        private static GuruSDK CreateInstance()
 | 
						||
        {
 | 
						||
            var go = new GameObject(nameof(GuruSDK));
 | 
						||
            DontDestroyOnLoad(go);
 | 
						||
            _instance = go.AddComponent<GuruSDK>();
 | 
						||
            return _instance;
 | 
						||
        }
 | 
						||
 | 
						||
        public static GuruSDKInitConfig BuildConfig(
 | 
						||
            bool useCustomConsent = false, 
 | 
						||
            bool autoLoadAds = true, 
 | 
						||
            bool iapEnabled = true, 
 | 
						||
            bool autoRecordFinishedLevels = true, 
 | 
						||
            bool debugMode = false,
 | 
						||
            bool isBuyNoAds = false,
 | 
						||
            string bannerColor = "#00000000",
 | 
						||
            Dictionary<string, object> defaultRemoteData = null,
 | 
						||
            byte[] googleKeys = null,
 | 
						||
            byte[] appleRootCerts = null)
 | 
						||
        {
 | 
						||
            var config = GuruSDKInitConfig.Build(useCustomConsent, autoLoadAds, iapEnabled, 
 | 
						||
                autoRecordFinishedLevels, isBuyNoAds, bannerColor,
 | 
						||
                debugMode, defaultRemoteData, googleKeys, appleRootCerts);
 | 
						||
            return config;
 | 
						||
        }
 | 
						||
 | 
						||
        public static void Init(Action<bool> onComplete)
 | 
						||
        {
 | 
						||
            Init(GuruSDKInitConfig.Build(), onComplete);
 | 
						||
        }
 | 
						||
        
 | 
						||
        public static void Init(GuruSDKInitConfig config, Action<bool> onComplete)
 | 
						||
        {
 | 
						||
            _initTime = DateTime.Now.ToUniversalTime();
 | 
						||
            // ----- First Open Time -----
 | 
						||
            // SetFirstOpenTime(GetFirstOpenTime());  // FirstOpenTime 
 | 
						||
            LogI($"#1 ---- Guru SDK [{Version}] ----\n{config.ToString()}");
 | 
						||
            Instance.StartWithConfig(config, onComplete);
 | 
						||
        }
 | 
						||
        private static string GetFirstOpenTime()
 | 
						||
        {
 | 
						||
            string firstOpenTime = IPMConfig.FirstOpenTime;
 | 
						||
            if (string.IsNullOrEmpty(firstOpenTime))
 | 
						||
            {
 | 
						||
                firstOpenTime = TimeUtil.GetCurrentTimeStamp().ToString();
 | 
						||
                IPMConfig.FirstOpenTime = firstOpenTime;
 | 
						||
            }
 | 
						||
 | 
						||
            return firstOpenTime;
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 启动SDK
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="config"></param>
 | 
						||
        /// <param name="onComplete"></param>
 | 
						||
        private void StartWithConfig(GuruSDKInitConfig config, Action<bool> onComplete)
 | 
						||
        {
 | 
						||
            Model.PropBLevel.OnValueChanged += OnBLevelChanged;
 | 
						||
            Model.PropBPlay.OnValueChanged += OnBPlayChanged;
 | 
						||
            
 | 
						||
            IsInitialSuccess = false;
 | 
						||
            _initConfig = config;
 | 
						||
            _onCompleteCallback = onComplete;
 | 
						||
            _isDebugEnabled = config.DebugMode;
 | 
						||
 | 
						||
            InitAssets();
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
        private void InitAssets()
 | 
						||
        {
 | 
						||
            InitUpdaters(); // Updaters
 | 
						||
            InitThreadHandler(); // 初始化线程处理器
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
        void Start()
 | 
						||
        {
 | 
						||
            //---- Start All tools ----
 | 
						||
            LogI($"#2 --- InitFirebase ---");
 | 
						||
            //---------- Start Firebase ------------
 | 
						||
            FirebaseUtil.onInitComplete += OnFirebaseReady;
 | 
						||
            FirebaseUtil.OnUserAuthResult += OnUserAuthResult;
 | 
						||
            FirebaseUtil.OnFirebaseAuthResult += OnFirebaseAuthResult;
 | 
						||
            FirebaseUtil.InitFirebase(null); // 确保所有的逻辑提前被调用到 + Analytics.Init TODO:之后需要改为事件驱动
 | 
						||
            
 | 
						||
            LogI($"#2.1 --- InitFacebook ---");
 | 
						||
            //---------- Start Facebook ------------
 | 
						||
            FBService.Instance.StartService();
 | 
						||
            
 | 
						||
            LogI($"#2.2 --- Call SDK init complete  ->  callback: { (_onCompleteCallback == null ? "Null" : _onCompleteCallback.ToString()) } ---");
 | 
						||
            IsInitialSuccess = true;
 | 
						||
            _onCompleteCallback?.Invoke(true);
 | 
						||
        }
 | 
						||
 | 
						||
        
 | 
						||
 | 
						||
        private void OnUserAuthResult(bool success)
 | 
						||
        {
 | 
						||
            
 | 
						||
            if (success && string.IsNullOrEmpty(IPMConfig.IPM_UID))
 | 
						||
            {
 | 
						||
                success = false;
 | 
						||
            }
 | 
						||
            Callbacks.SDK._onUserAuthResult?.Invoke(success);
 | 
						||
 | 
						||
            if (success)
 | 
						||
            {
 | 
						||
                Model.UserId = IPMConfig.IPM_UID;
 | 
						||
                if (GuruIAP.Instance != null)
 | 
						||
                {
 | 
						||
                    GuruIAP.Instance.SetUID(UID);
 | 
						||
                    GuruIAP.Instance.SetUUID(UUID);
 | 
						||
                }
 | 
						||
                
 | 
						||
                UpdateAllUserProperties(); // 同步所有用户属性打点
 | 
						||
            }
 | 
						||
        }
 | 
						||
        
 | 
						||
        private void OnFirebaseAuthResult(bool success)
 | 
						||
        {
 | 
						||
            Callbacks.SDK._onFirebaseAuthResult?.Invoke(success);
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 开始各种组件初始化
 | 
						||
        /// </summary>
 | 
						||
        private void OnFirebaseReady(bool success)
 | 
						||
        {
 | 
						||
            FirebaseUtil.onInitComplete -= OnFirebaseReady;
 | 
						||
            LogI($"#3 --- On FirebaseDeps: {success} ---");
 | 
						||
            IsFirebaseReady = success;
 | 
						||
            Callbacks.SDK._onFirebaseReady?.Invoke(success);
 | 
						||
            // LogFirebaseDeps(success);
 | 
						||
 | 
						||
            LogI($"#3.5 --- Call InitRemoteConfig ---");
 | 
						||
            // 开始Remote Manager初始化 
 | 
						||
            RemoteConfigManager.Init(BuildDefaultRemoteData(_initConfig.DefaultRemoteData));
 | 
						||
            RemoteConfigManager.OnFetchCompleted += OnFetchRemoteCallback;
 | 
						||
 | 
						||
            LogI($"#4 --- Apply remote services config ---");
 | 
						||
            // 根据缓存的云控配置来初始化参数
 | 
						||
            InitAllServices();
 | 
						||
            
 | 
						||
            LogI($"#5 --- sync sdk time ---");
 | 
						||
            var sp = DateTime.Now.ToUniversalTime() - _initTime;
 | 
						||
            LogSDKInitTime(sp.TotalSeconds);
 | 
						||
            
 | 
						||
            // 上报所有初始化用户属性
 | 
						||
            UpdateAllUserProperties();
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 注入云控参数基础数据
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="dict"></param>
 | 
						||
        /// <returns></returns>
 | 
						||
        private Dictionary<string, object> BuildDefaultRemoteData(Dictionary<string, object> dict)
 | 
						||
        {
 | 
						||
            if (dict == null) dict = new Dictionary<string, object>(3);
 | 
						||
            
 | 
						||
            // 注入默认的 Services 配置值
 | 
						||
            string json = Model.LoadDefaltServicesConfigJson(); 
 | 
						||
            if (!string.IsNullOrEmpty(json)) dict[ServicesConfigKey] = json;
 | 
						||
       
 | 
						||
            return dict;
 | 
						||
        }
 | 
						||
        
 | 
						||
        /// <summary>
 | 
						||
        /// 拉取云控参数完成
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="success"></param>
 | 
						||
        private void OnFetchRemoteCallback(bool success)
 | 
						||
        {
 | 
						||
            LogI($"#6 --- Remote fetch complete: {success} ---");
 | 
						||
            ABTestManager.Init(); // 启动AB测试解析器
 | 
						||
            Callbacks.Remote._onRemoteFetchComplete?.Invoke(success);
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
        private void Update()
 | 
						||
        {
 | 
						||
            UpdateAllUpdates(); // 驱动所有的更新器
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
        #endregion
 | 
						||
 | 
						||
        #region App Remote Update
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// Apply Cloud guru-service configs for sdk assets
 | 
						||
        /// </summary>
 | 
						||
        private void InitAllServices()
 | 
						||
        {
 | 
						||
            // -------- Init Analytics ---------
 | 
						||
            InitUserProperties();
 | 
						||
            SetSDKEventPriority();
 | 
						||
            // -------- Init Noti -----------
 | 
						||
            InitNotiPermission();
 | 
						||
            
 | 
						||
            bool useKeywords = false;
 | 
						||
            bool useIAP = _initConfig.IAPEnabled;
 | 
						||
            bool appleReview = false;
 | 
						||
            bool enableAnaErrorLog = false;
 | 
						||
            
 | 
						||
            //----------- Set GuruServices ----------------
 | 
						||
            var services = GetRemoteServicesConfig();
 | 
						||
            if (services != null)
 | 
						||
            {
 | 
						||
                _appServicesConfig = services;
 | 
						||
                useKeywords = _appServicesConfig.KeywordsEnabled();
 | 
						||
                // 使用初始化配置中的 IAPEnable来联合限定, 如果本地写死关闭则不走云控开启
 | 
						||
                useIAP = _initConfig.IAPEnabled && _appServicesConfig.IsIAPEnabled(); 
 | 
						||
                enableAnaErrorLog = _appServicesConfig.EnableAnaErrorLog();
 | 
						||
                
 | 
						||
                Try(() =>
 | 
						||
                {
 | 
						||
                    LogI($"#4.1 --- Start apply services ---");
 | 
						||
                    //----------------------------------------------------------------
 | 
						||
 | 
						||
                    // 自打点设置错误上报
 | 
						||
                    if(enableAnaErrorLog) GuruAnalytics.EnableErrorLog = true;
 | 
						||
                    
 | 
						||
                    // adjust 事件设置
 | 
						||
                    if (null != _appServicesConfig.adjust_settings && null != GuruSettings)
 | 
						||
                    {
 | 
						||
                        // 更新 Adjust Tokens
 | 
						||
                        GuruSettings.UpdateAdjustTokens(
 | 
						||
                            _appServicesConfig.adjust_settings.AndroidToken(),
 | 
						||
                            _appServicesConfig.adjust_settings.iOSToken());
 | 
						||
                        // 更新 Adjust Events
 | 
						||
                        GuruSettings.UpdateAdjustEvents(_appServicesConfig.adjust_settings.events);
 | 
						||
                    }
 | 
						||
                
 | 
						||
                    LogI($"#4.2 --- Start GuruSttings ---");
 | 
						||
                    // GuruSettings 设置
 | 
						||
                    if (null != _appServicesConfig.app_settings)
 | 
						||
                    {
 | 
						||
                        if (_appServicesConfig.Tch02Value() > 0)
 | 
						||
                        {
 | 
						||
                            Analytics.EnableTch02Event = true;
 | 
						||
                            Analytics.SetTch02TargetValue(_appServicesConfig.Tch02Value());
 | 
						||
                        }
 | 
						||
                     
 | 
						||
                        // 设置获取设备 UUID 的方法
 | 
						||
                        if (_appServicesConfig.UseUUID())
 | 
						||
                        {
 | 
						||
                            IPMConfig.UsingUUID = true; // 开始使用 UUID 作为 DeviceID 标识
 | 
						||
                        }
 | 
						||
 | 
						||
#if UNITY_IOS 
 | 
						||
                        // 苹果审核标志位
 | 
						||
                        appleReview = _appServicesConfig.IsAppReview();
 | 
						||
#endif
 | 
						||
                    
 | 
						||
                        if (null !=  GuruSettings)
 | 
						||
                        {
 | 
						||
                            // 更新和升级 GuruSettings 对应的值
 | 
						||
                            GuruSettings.UpdateAppSettings(
 | 
						||
                                _appServicesConfig.app_settings.bundle_id,
 | 
						||
                                _appServicesConfig.fb_settings?.fb_app_id ?? "",
 | 
						||
                                _appServicesConfig.app_settings.support_email,
 | 
						||
                                _appServicesConfig.app_settings.privacy_url,
 | 
						||
                                _appServicesConfig.app_settings.terms_url,
 | 
						||
                                _appServicesConfig.app_settings.android_store,
 | 
						||
                                _appServicesConfig.app_settings.ios_store, 
 | 
						||
                                _appServicesConfig.parameters?.using_uuid ?? false,
 | 
						||
                                _appServicesConfig.parameters?.cdn_host ?? "");
 | 
						||
                            
 | 
						||
                            _appBundleId = _appServicesConfig.app_settings.bundle_id; // 配置预设的 BundleId
 | 
						||
                        }
 | 
						||
                    }
 | 
						||
                    //---------------------------------
 | 
						||
                }, ex =>
 | 
						||
                {
 | 
						||
                    UnityEngine.Debug.LogError($"--- ERROR on apply services: {ex.Message}");
 | 
						||
                });
 | 
						||
          
 | 
						||
                
 | 
						||
            }
 | 
						||
            //----------- Set IAP ----------------
 | 
						||
            if (useIAP)
 | 
						||
            {
 | 
						||
                // InitIAP(_initConfig.GoogleKeys, _initConfig.AppleRootCerts); // 初始化IAP
 | 
						||
                Try(() =>
 | 
						||
                {
 | 
						||
                    LogI($"#4.3 --- Start IAP ---");
 | 
						||
                    if (_initConfig.GoogleKeys == null || _initConfig.AppleRootCerts == null)
 | 
						||
                    {
 | 
						||
                        LogException("[IAP] GoogleKeys is null when using IAPService! Integration failed. App will Exit");
 | 
						||
                    }
 | 
						||
 | 
						||
 | 
						||
                    InitIAP(UID, _initConfig.GoogleKeys, _initConfig.AppleRootCerts); // 初始化IAP
 | 
						||
                }, ex =>
 | 
						||
                {
 | 
						||
                    UnityEngine.Debug.LogError($"--- ERROR on useIAP: {ex.Message}");
 | 
						||
                });
 | 
						||
            }
 | 
						||
            //----------- Set Keywords ----------------
 | 
						||
            if (useKeywords)
 | 
						||
            {
 | 
						||
                // KeywordsManager.Install(Model.IsIAPUser, Model.SuccessLevelId); // 启动Keyword管理器
 | 
						||
                Try(() =>
 | 
						||
                {
 | 
						||
                    LogI($"#4.4 --- Start Keywords ---");
 | 
						||
                    KeywordsManager.Install(Model.IsIapUser, Model.SuccessLevelId); // 启动Keyword管理器
 | 
						||
                }, ex =>
 | 
						||
                {
 | 
						||
                    UnityEngine.Debug.LogError($"--- ERROR on Keywords: {ex.Message}");
 | 
						||
                });
 | 
						||
            }
 | 
						||
 | 
						||
#if UNITY_IOS
 | 
						||
            if (appleReview)
 | 
						||
            {
 | 
						||
                // StartAppleReviewFlow(); // 直接显示 ATT 弹窗, 跳过 Consent 流程
 | 
						||
                Try(() =>
 | 
						||
                {
 | 
						||
                    LogI($"#4.5.0 ---  StartAppleReviewFlow ---");
 | 
						||
                    StartAppleReviewFlow(); // 直接显示 ATT 弹窗, 跳过 Consent 流程
 | 
						||
                }, ex =>
 | 
						||
                {
 | 
						||
                    Debug.LogError($"--- ERROR on StartAppleReviewFlow: {ex.Message}");
 | 
						||
                });
 | 
						||
                return;
 | 
						||
            }
 | 
						||
#endif
 | 
						||
            //----------- Set Consent ----------------
 | 
						||
            if (!InitConfig.UseCustomConsent && !appleReview)
 | 
						||
            {
 | 
						||
                // LogI($"--- #3 Start Consent Flow ---");
 | 
						||
                // StartConsentFlow();
 | 
						||
                Try(() =>
 | 
						||
                {
 | 
						||
                    StartConsentFlow();
 | 
						||
                }, ex =>
 | 
						||
                {
 | 
						||
                    UnityEngine.Debug.LogError($"--- ERROR on StartConsentFlow: {ex.Message}");
 | 
						||
                });
 | 
						||
            }
 | 
						||
 | 
						||
            IsServiceReady = true;
 | 
						||
            
 | 
						||
            // 中台服务初始化结束
 | 
						||
            Callbacks.SDK._onGuruServiceReady?.Invoke();
 | 
						||
            
 | 
						||
#if UNITY_ANDROID
 | 
						||
            // Android 命令行调试
 | 
						||
            StartAndroidDebugCmds();           
 | 
						||
#endif
 | 
						||
        }
 | 
						||
        
 | 
						||
        /// <summary>
 | 
						||
        /// Get the guru-service cloud config value;
 | 
						||
        /// User can fetch the cloud guru-service config by using Custom Service Key
 | 
						||
        /// </summary>
 | 
						||
        /// <returns></returns>
 | 
						||
        private GuruServicesConfig GetRemoteServicesConfig()
 | 
						||
        {
 | 
						||
 | 
						||
            string defaultJson = GetRemoteString(ServicesConfigKey);
 | 
						||
            
 | 
						||
            bool useCustomKey = false;
 | 
						||
            string key = ServicesConfigKey;
 | 
						||
            if (!string.IsNullOrEmpty(_initConfig.CustomServiceKey))
 | 
						||
            {
 | 
						||
                key = _initConfig.CustomServiceKey;
 | 
						||
                useCustomKey = true;
 | 
						||
            }
 | 
						||
            var json = GetRemoteString(key); // Cloud cached data
 | 
						||
 | 
						||
            if (string.IsNullOrEmpty(json) && useCustomKey && !string.IsNullOrEmpty(defaultJson))
 | 
						||
            {
 | 
						||
                // No remote data fetched from cloud, should use default values
 | 
						||
                json = defaultJson;
 | 
						||
                UnityEngine.Debug.Log($"{Tag} --- No remote data found with: {key}  -> Using default key {ServicesConfigKey} and local data!!!");
 | 
						||
            }
 | 
						||
 | 
						||
            if (!string.IsNullOrEmpty(json))
 | 
						||
            {
 | 
						||
                return JsonParser.ToObject<GuruServicesConfig>(json);
 | 
						||
            }
 | 
						||
            
 | 
						||
            return null;
 | 
						||
        }
 | 
						||
 | 
						||
        private void Try(Action method, Action<Exception> onException = null, Action onFinal = null)
 | 
						||
        {
 | 
						||
            if (method == null) return;
 | 
						||
 | 
						||
            try
 | 
						||
            {
 | 
						||
                method.Invoke();
 | 
						||
            }
 | 
						||
            catch (Exception ex)
 | 
						||
            {
 | 
						||
                LogException(ex);
 | 
						||
                // ignored
 | 
						||
                onException?.Invoke(ex);
 | 
						||
            }
 | 
						||
            finally
 | 
						||
            {
 | 
						||
                // Finally
 | 
						||
                onFinal?.Invoke();
 | 
						||
            }
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
        #endregion
 | 
						||
 | 
						||
        #region Apple 审核流程逻辑
 | 
						||
 | 
						||
#if UNITY_IOS
 | 
						||
        private void StartAppleReviewFlow()
 | 
						||
        {
 | 
						||
            CheckAttStatus();
 | 
						||
        }
 | 
						||
#endif
 | 
						||
        #endregion
 | 
						||
        
 | 
						||
        #region 数据
 | 
						||
 | 
						||
        private void OnBLevelChanged(int blevel)
 | 
						||
        {
 | 
						||
            SetUserBLevel(blevel);
 | 
						||
        }
 | 
						||
 | 
						||
        private void OnBPlayChanged(int bplay)
 | 
						||
        {
 | 
						||
            SetUserBPlay(bplay);
 | 
						||
        }
 | 
						||
        
 | 
						||
        #endregion
 | 
						||
        
 | 
						||
        #region Logging
 | 
						||
        
 | 
						||
        internal static void LogI(object message)
 | 
						||
        {
 | 
						||
            UnityEngine.Debug.Log($"{Tag} {message}");
 | 
						||
        }
 | 
						||
        
 | 
						||
        internal static void LogW(object message)
 | 
						||
        {
 | 
						||
            UnityEngine.Debug.LogWarning($"{Tag} {message}");
 | 
						||
        }
 | 
						||
        
 | 
						||
        internal static void LogE(object message)
 | 
						||
        {
 | 
						||
            UnityEngine.Debug.LogError($"{Tag} {message}");
 | 
						||
        }
 | 
						||
 | 
						||
        
 | 
						||
        internal static void LogException(string message)
 | 
						||
        {
 | 
						||
            LogException( new Exception($"{Tag} {message}"));
 | 
						||
        }
 | 
						||
        
 | 
						||
        internal static void LogException(Exception e)
 | 
						||
        {
 | 
						||
            UnityEngine.Debug.LogException(e);
 | 
						||
        }
 | 
						||
        
 | 
						||
        /// <summary>
 | 
						||
        /// 上报崩溃信息
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="message"></param>
 | 
						||
        public static void Report(string message)
 | 
						||
        {
 | 
						||
            Analytics.LogCrashlytics(message, false);
 | 
						||
        }
 | 
						||
        
 | 
						||
        /// <summary>
 | 
						||
        /// 上报异常
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="message"></param>
 | 
						||
        public static void ReportException(string message)
 | 
						||
        {
 | 
						||
            Analytics.LogCrashlytics(message);
 | 
						||
        }
 | 
						||
        
 | 
						||
        /// <summary>
 | 
						||
        /// 上报异常 Exception
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="ex"></param>
 | 
						||
        public static void ReportException(Exception ex)
 | 
						||
        {
 | 
						||
            Analytics.LogCrashlytics(ex);
 | 
						||
        }
 | 
						||
 | 
						||
        #endregion
 | 
						||
 | 
						||
        #region 生命周期
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 暂停时处理
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="paused"></param>
 | 
						||
        private void OnAppPauseHandler(bool paused)
 | 
						||
        {
 | 
						||
            if(paused) Model.Save(true); // 强制保存数据
 | 
						||
            Callbacks.App._onAppPaused?.Invoke(paused);
 | 
						||
        }
 | 
						||
        
 | 
						||
        private void OnApplicationPause(bool paused)
 | 
						||
        {
 | 
						||
            OnAppPauseHandler(paused);
 | 
						||
        }
 | 
						||
 | 
						||
        private void OnApplicationFocus(bool hasFocus)
 | 
						||
        {
 | 
						||
            OnAppPauseHandler(!hasFocus);
 | 
						||
        }
 | 
						||
 | 
						||
        private void OnApplicationQuit()
 | 
						||
        {
 | 
						||
            Model.Save(true);
 | 
						||
            Callbacks.App._onAppQuit?.Invoke();
 | 
						||
        }
 | 
						||
 | 
						||
        #endregion
 | 
						||
 | 
						||
        #region 延迟处理
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 启动协程
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="enumerator"></param>
 | 
						||
        /// <returns></returns>
 | 
						||
        public static Coroutine DoCoroutine(IEnumerator enumerator)
 | 
						||
        {
 | 
						||
            return Instance != null ? Instance.StartCoroutine(enumerator) : null;
 | 
						||
        }
 | 
						||
 | 
						||
        public static void KillCoroutine(Coroutine coroutine)
 | 
						||
        {
 | 
						||
            if(coroutine != null)
 | 
						||
                Instance.StopCoroutine(coroutine);
 | 
						||
        }
 | 
						||
        
 | 
						||
        /// <summary>
 | 
						||
        /// 延时执行
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="seconds"></param>
 | 
						||
        /// <param name="callback"></param>
 | 
						||
        public static Coroutine Delay(float seconds, Action callback)
 | 
						||
        {
 | 
						||
            return DoCoroutine(Instance.OnDelayCall(seconds, callback));
 | 
						||
        }
 | 
						||
 | 
						||
        private IEnumerator OnDelayCall(float delay, Action callback)
 | 
						||
        {
 | 
						||
            if (delay > 0)
 | 
						||
            {
 | 
						||
                yield return new WaitForSeconds(delay);
 | 
						||
            }
 | 
						||
            else
 | 
						||
            {
 | 
						||
                yield return null;
 | 
						||
            }
 | 
						||
            callback?.Invoke();
 | 
						||
        }
 | 
						||
        
 | 
						||
        #endregion
 | 
						||
 | 
						||
        #region 帧更新 Updater
 | 
						||
 | 
						||
        
 | 
						||
        private List<IUpdater> _updaterRunningList;
 | 
						||
        private List<IUpdater> _updaterRemoveList;
 | 
						||
 | 
						||
        private void InitUpdaters()
 | 
						||
        {
 | 
						||
            _updaterRunningList = new List<IUpdater>(20);
 | 
						||
            _updaterRemoveList = new List<IUpdater>(20);
 | 
						||
        }
 | 
						||
 | 
						||
        private void UpdateAllUpdates()
 | 
						||
        {
 | 
						||
            int i = 0;
 | 
						||
            IUpdater updater;
 | 
						||
            // ---- Updater Trigger ----
 | 
						||
            if (_updaterRunningList.Count > 0)
 | 
						||
            {
 | 
						||
                i = 0;
 | 
						||
                while (i < _updaterRunningList.Count)
 | 
						||
                {
 | 
						||
                    updater = _updaterRunningList[i];
 | 
						||
                    if (updater != null) 
 | 
						||
                    {
 | 
						||
                        if (updater.State == UpdaterState.Running)
 | 
						||
                        {
 | 
						||
                            updater.OnUpdate();
 | 
						||
                        }
 | 
						||
                        else if(updater.State == UpdaterState.Kill)
 | 
						||
                        {
 | 
						||
                            _updaterRemoveList.Add(updater);
 | 
						||
                        }
 | 
						||
                    }
 | 
						||
                    else
 | 
						||
                    {
 | 
						||
                        _updaterRunningList.RemoveAt(i);
 | 
						||
                        i--;
 | 
						||
                    }
 | 
						||
                    i++;
 | 
						||
                }
 | 
						||
 | 
						||
            }
 | 
						||
 | 
						||
            if (_updaterRemoveList.Count > 0)
 | 
						||
            {
 | 
						||
                i = 0;
 | 
						||
                while (i < _updaterRemoveList.Count)
 | 
						||
                {
 | 
						||
                    RemoveUpdater(_updaterRemoveList[i]);
 | 
						||
                    i++;
 | 
						||
                }
 | 
						||
                _updaterRemoveList.Clear();
 | 
						||
            }
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 注册帧更新器
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="updater"></param>
 | 
						||
        public static void RegisterUpdater(IUpdater updater)
 | 
						||
        {
 | 
						||
            Instance.AddUpdater(updater);
 | 
						||
            updater.Start();
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
        private void AddUpdater(IUpdater updater)
 | 
						||
        {
 | 
						||
            if (_updaterRunningList == null) _updaterRunningList = new List<IUpdater>(20);
 | 
						||
            _updaterRunningList.Add(updater);
 | 
						||
        }
 | 
						||
 | 
						||
        private void RemoveUpdater(IUpdater updater)
 | 
						||
        {
 | 
						||
            if (_updaterRunningList != null && updater != null)
 | 
						||
            {
 | 
						||
                _updaterRunningList.Remove(updater);
 | 
						||
            }
 | 
						||
        }
 | 
						||
 | 
						||
        #endregion
 | 
						||
 | 
						||
        #region 推送管理
 | 
						||
 | 
						||
        private static int _messageRetry = 0;
 | 
						||
        public static void SetPushNotificationEnabled(bool enabled)
 | 
						||
        {
 | 
						||
            DeviceInfoUploadRequest request = new DeviceInfoUploadRequest()
 | 
						||
                .SetRetryTimes(1)
 | 
						||
                .SetSuccessCallBack(() =>
 | 
						||
                {
 | 
						||
                    _messageRetry = 0;
 | 
						||
                    Debug.Log($"[SDK] --- Set Push Enabled: {enabled} success");
 | 
						||
                })
 | 
						||
                .SetFailCallBack(() =>
 | 
						||
                {
 | 
						||
                    double retryDelay = Math.Pow(2, _messageRetry);
 | 
						||
                    _messageRetry++;
 | 
						||
                    CoroutineHelper.Instance.StartDelayed((float)retryDelay, ()=> SetPushNotificationEnabled(enabled));
 | 
						||
                }) as DeviceInfoUploadRequest;
 | 
						||
 | 
						||
            if (request != null)
 | 
						||
            {
 | 
						||
                request.SetPushEnabled(enabled);
 | 
						||
                request.Send();
 | 
						||
            }
 | 
						||
        }
 | 
						||
        
 | 
						||
        #endregion
 | 
						||
    }
 | 
						||
} |