1307 lines
		
	
	
		
			53 KiB
		
	
	
	
		
			C#
		
	
	
			
		
		
	
	
			1307 lines
		
	
	
		
			53 KiB
		
	
	
	
		
			C#
		
	
	
 | 
						||
 | 
						||
 | 
						||
namespace Guru
 | 
						||
{
 | 
						||
    using System;
 | 
						||
    using System.Collections.Generic;
 | 
						||
    using UnityEngine;
 | 
						||
    
 | 
						||
    /// <summary>
 | 
						||
    /// 打点管理
 | 
						||
    /// </summary>
 | 
						||
    public partial class GuruSDK
 | 
						||
    {
 | 
						||
        /// <summary>
 | 
						||
        /// 主线关卡类型
 | 
						||
        /// 只有传入此类型时才会进行 Blevel 的累加
 | 
						||
        /// </summary>
 | 
						||
        public const string LevelTypeMain = "main";
 | 
						||
        
 | 
						||
        //----------------- 关卡开始类型 ---------------------
 | 
						||
        public const string EventLevelStartModePlay = "play";
 | 
						||
        public const string EventLevelStartModeReplay = "replay";
 | 
						||
        public const string EventLevelStartModeContinue= "continue";
 | 
						||
        
 | 
						||
        //----------------- 关卡结束类型 ---------------------
 | 
						||
        public const string EventLevelEndSuccess = "success";
 | 
						||
        public const string EventLevelEndFail = "fail";
 | 
						||
        public const string EventLevelEndExit = "exit";
 | 
						||
        public const string EventLevelEndTimeout = "timeout";
 | 
						||
 | 
						||
        #region 通用接口
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 自定义事件打点
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="eventName"></param>
 | 
						||
        /// <param name="data"></param>
 | 
						||
        /// <param name="priority"></param>
 | 
						||
        public static void LogEvent(string eventName, Dictionary<string, dynamic> data = null, int priority = -1)
 | 
						||
        {
 | 
						||
            if (!IsInitialSuccess)
 | 
						||
            {
 | 
						||
                UnityEngine.Debug.LogError($"{Tag} :: LogEvent {eventName} :: Please call <GuruSDK.Start()> first, before you call <LogEvent>.");
 | 
						||
                return;
 | 
						||
            }
 | 
						||
            
 | 
						||
            if(priority < 0) priority = GetEventPriorityInt(eventName);
 | 
						||
            
 | 
						||
            Analytics.Track(eventName, data, null, priority);
 | 
						||
        }
 | 
						||
 | 
						||
        public static void SetScreen(string screen, string extra = "")
 | 
						||
        {
 | 
						||
            if (!IsInitialSuccess)
 | 
						||
            {
 | 
						||
                UnityEngine.Debug.LogError($"{Tag} :: SetScreen {screen} :: Please call <GuruSDK.Start()> first, before you call <SetScreen>.");
 | 
						||
                return;
 | 
						||
            }
 | 
						||
            Analytics.SetCurrentScreen(screen, extra);
 | 
						||
        }
 | 
						||
 | 
						||
        #endregion
 | 
						||
        
 | 
						||
        #region 游戏打点
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 游戏启动打点 (level_start)
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="levelId">关卡Id</param>
 | 
						||
        /// <param name="levelName">关卡名称: main_01_9001,  daily_challenge_81011</param>
 | 
						||
        /// <param name="levelType">关卡类型: 主线:main</param>
 | 
						||
        /// <param name="itemId">配置/谜题/图片/自定义Id: 101120</param>
 | 
						||
        /// <param name="startType">关卡开始类型: play:开始游戏;replay:重玩;continue:继续游戏</param>
 | 
						||
        /// <param name="isReplay">是否重新开始: true/false</param>
 | 
						||
        /// <param name="extra">扩展数据</param>
 | 
						||
        public static void LogLevelStart(int levelId, string startType = EventLevelStartModePlay, 
 | 
						||
            string levelType = LevelTypeMain, string levelName = "", string itemId = "",
 | 
						||
            bool isReplay = false, Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            if (!IsInitialSuccess)
 | 
						||
            {
 | 
						||
                UnityEngine.Debug.LogError($"{Tag} :: LogLevelStart {levelId} :: Please call <GuruSDK.Start()> first, before you call <LogLevelStart>.");
 | 
						||
                return;
 | 
						||
            }
 | 
						||
 | 
						||
            Analytics.LogLevelStart(levelId, levelName, levelType, itemId, startType, isReplay, extra);
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 游戏点击 Continue 继续游戏 (level_start) (continue)
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="levelId"></param>
 | 
						||
        /// <param name="levelType"></param>
 | 
						||
        /// <param name="levelName"></param>
 | 
						||
        /// <param name="itemId"></param>
 | 
						||
        /// <param name="extra"></param>
 | 
						||
        public static void LogLevelContinue(int levelId, string levelType = LevelTypeMain,
 | 
						||
            string levelName = "", string itemId = "", Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            LogLevelStart(levelId, EventLevelStartModeContinue, levelType, levelName, itemId,  true, extra:extra);
 | 
						||
        }
 | 
						||
        
 | 
						||
        /// <summary>
 | 
						||
        /// 游戏点击 Replay 重玩关卡 (level_start) (replay)
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="levelId"></param>
 | 
						||
        /// <param name="levelType"></param>
 | 
						||
        /// <param name="levelName"></param>
 | 
						||
        /// <param name="itemId"></param>
 | 
						||
        public static void LogLevelReplay(int levelId, string levelType = LevelTypeMain,
 | 
						||
            string levelName = "", string itemId = "", Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            LogLevelStart(levelId, EventLevelStartModeReplay,levelType, levelName, itemId,  true, extra:extra);
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 关卡结束打点 (level_end)
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="levelId">关卡Id</param>
 | 
						||
        /// <param name="result">success:成功;fail:失败;exit:退出;timeout:超时;replay:重玩...</param>
 | 
						||
        /// <param name="levelType">关卡类型: 主线:main</param>
 | 
						||
        /// <param name="levelName">关卡名称: main_01_9001,  daily_challenge_81011</param>
 | 
						||
        /// <param name="itemId">配置/谜题/图片/自定义Id: 101120</param>
 | 
						||
        /// <param name="duration">关卡完成时长(单位:毫秒)</param>
 | 
						||
        /// <param name="step">步数(有则上报)</param>
 | 
						||
        /// <param name="score">分数(有则上报)</param>
 | 
						||
        /// <param name="extra">扩展数据</param>
 | 
						||
        public static void LogLevelEnd(int levelId, string result = EventLevelEndSuccess,
 | 
						||
            string levelType = LevelTypeMain, string levelName = "", string itemId = "",
 | 
						||
            int duration = 0, int? step = null, int? score = null, Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            if (!IsInitialSuccess)
 | 
						||
            {
 | 
						||
                UnityEngine.Debug.LogError(
 | 
						||
                    $"{Tag} :: LogLevelEnd {levelId} :: Please call <GuruSDK.Start()> first, before you call <LogLevelEnd>.");
 | 
						||
                return;
 | 
						||
            }
 | 
						||
            // 优先打 level_end 事件
 | 
						||
            Analytics.LogLevelEnd(levelId, result, levelName, levelType, itemId, duration, step, score, extra);
 | 
						||
            
 | 
						||
            // 自动记录关卡属性
 | 
						||
            if (InitConfig.AutoRecordFinishedLevels)
 | 
						||
            {
 | 
						||
                if (result == EventLevelEndSuccess)
 | 
						||
                {
 | 
						||
                    if (levelType == LevelTypeMain)
 | 
						||
                    {
 | 
						||
                        if (levelId > Model.SuccessLevelId) Model.SuccessLevelId = levelId; // 自动记录关卡完成次数
 | 
						||
                    }
 | 
						||
 | 
						||
                    Model.TotalPlayedCount++; // 自动记录关卡总次数
 | 
						||
 | 
						||
                    Analytics.LevelEndSuccess(Model.TotalPlayedCount); // 自动 level_end_success
 | 
						||
                }
 | 
						||
                
 | 
						||
                Analytics.BLevel = Model.SuccessLevelId; // 记录 BLevel
 | 
						||
                Analytics.BPlay = Model.TotalPlayedCount; // 记录 BPlay
 | 
						||
            }
 | 
						||
           
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 关卡首次通关
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="levelType"></param>
 | 
						||
        /// <param name="levelName"></param>
 | 
						||
        /// <param name="level"></param>
 | 
						||
        /// <param name="result"></param>
 | 
						||
        /// <param name="duration"></param>
 | 
						||
        /// <param name="extra"></param>
 | 
						||
        public static void LogLevelFirstEnd(string levelType, string levelName, int level,
 | 
						||
            string result = EventLevelEndSuccess, int duration = 0, Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            Analytics.LevelFirstEnd(levelType, levelName, level, result, duration, extra);
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 关卡总胜利次数打点 (level_end_success_{num})
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="bPlay">完成总关数累计值</param>
 | 
						||
        /// /// <param name="extra">扩展参数</param>
 | 
						||
        public static void LogLevelEndSuccess(int bPlay, Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            if (InitConfig.AutoRecordFinishedLevels) return;
 | 
						||
            Analytics.LevelEndSuccess(bPlay, extra);
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 游戏失败打点 (level_end) (fail)
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="levelId"></param>
 | 
						||
        /// <param name="levelType"></param>
 | 
						||
        /// <param name="levelName"></param>
 | 
						||
        /// <param name="itemId"></param>
 | 
						||
        /// <param name="duration"></param>
 | 
						||
        /// <param name="step"></param>
 | 
						||
        /// <param name="score"></param>
 | 
						||
        /// <param name="extra"></param>
 | 
						||
        public static void LogLevelFail(int levelId,
 | 
						||
            string levelType = LevelTypeMain, string levelName = "", string itemId = "",
 | 
						||
            int duration = 0, int? step = null, int? score = null , Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            LogLevelEnd(levelId, EventLevelEndFail, levelType, levelName, itemId, duration, step, score, extra);
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 游戏失败退出 (level_end) (exit) 
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="levelId"></param>
 | 
						||
        /// <param name="levelType"></param>
 | 
						||
        /// <param name="levelName"></param>
 | 
						||
        /// <param name="itemId"></param>
 | 
						||
        /// <param name="duration"></param>
 | 
						||
        /// <param name="step"></param>
 | 
						||
        /// <param name="score"></param>
 | 
						||
        /// <param name="extra"></param>
 | 
						||
        public static void LogLevelFailExit(int levelId,
 | 
						||
            string levelType = LevelTypeMain, string levelName = "", string itemId = "",
 | 
						||
            int duration = 0, int? step = null, int? score = null, Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            LogLevelEnd(levelId, EventLevelEndExit, levelType, levelName, itemId, duration, step, score, extra);
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 关卡超时失败 (level_end) (timeout) 
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="levelId"></param>
 | 
						||
        /// <param name="levelType"></param>
 | 
						||
        /// <param name="levelName"></param>
 | 
						||
        /// <param name="itemId"></param>
 | 
						||
        /// <param name="duration"></param>
 | 
						||
        /// <param name="step"></param>
 | 
						||
        /// <param name="score"></param>
 | 
						||
        /// <param name="extra"></param>
 | 
						||
        public static void LogLevelFailTimeout(int levelId,
 | 
						||
            string levelType = LevelTypeMain, string levelName = "", string itemId = "",
 | 
						||
            int duration = 0, int? step = null, int? score = null, Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            LogLevelEnd(levelId, EventLevelEndTimeout, levelType, levelName, itemId, duration, step, score, extra);
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 玩家(角色)升级事件 (level_up)
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="playerLevel"></param>
 | 
						||
        /// <param name="characterName"></param>
 | 
						||
        /// <param name="extra">扩展数据</param>
 | 
						||
        public static void LogLevelUp(int playerLevel, string characterName, Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            if (!IsInitialSuccess)
 | 
						||
            {
 | 
						||
                UnityEngine.Debug.LogError($"{Tag} :: LogLevelUp {playerLevel} :: Please call <GuruSDK.Start()> first, before you call <LogLevelUp>.");
 | 
						||
                return;
 | 
						||
            }
 | 
						||
            Analytics.LevelUp(playerLevel, characterName, extra);
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 玩家解锁成就 (unlock_achievement)
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="achievementId"></param>
 | 
						||
        /// <param name="extra">扩展数据</param>
 | 
						||
        public static void LogAchievement(string achievementId, Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            if (!IsInitialSuccess)
 | 
						||
            {
 | 
						||
                UnityEngine.Debug.LogError($"{Tag} :: LogAchievement {achievementId} :: Please call <GuruSDK.Start()> first, before you call <LogAchievement>.");
 | 
						||
                return;
 | 
						||
            }
 | 
						||
            Analytics.UnlockAchievement(achievementId, extra);
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 玩家体力变化 (hp_points)
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="scene">场景</param>
 | 
						||
        /// <param name="hp">HP 增量值</param>
 | 
						||
        /// <param name="hpBefore">HP 初始值</param>
 | 
						||
        /// <param name="hpAfter">HP 结算值</param>
 | 
						||
        /// <param name="extra">额外数据</param>
 | 
						||
        public static void LogHpPoints(string scene, int hp, int hpBefore, int hpAfter,
 | 
						||
            Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            if (!IsInitialSuccess)
 | 
						||
            {
 | 
						||
                UnityEngine.Debug.LogError(
 | 
						||
                    $"{Tag} :: LogHpPoints {hp} :: Please call <GuruSDK.Start()> first, before you call <LogHpChanged>.");
 | 
						||
                return;
 | 
						||
            }
 | 
						||
 | 
						||
            var dict = new Dictionary<string, object>()
 | 
						||
            {
 | 
						||
                [Consts.ParameterItemCategory] = scene,
 | 
						||
                ["hp"] = hp,
 | 
						||
                ["hp_before"] = hpBefore,
 | 
						||
                ["hp_after"] = hpAfter,
 | 
						||
            };
 | 
						||
 | 
						||
            if (extra != null)
 | 
						||
            {
 | 
						||
                foreach (var k in extra.Keys)
 | 
						||
                {
 | 
						||
                    dict[k] = extra[k];
 | 
						||
                }
 | 
						||
            }
 | 
						||
 | 
						||
            LogEvent(Consts.EventHpPoints, dict);
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
        #endregion
 | 
						||
 | 
						||
        #region 用户属性
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 提前调用用户属性
 | 
						||
        /// </summary>
 | 
						||
        private static void InitUserProperties()
 | 
						||
        {
 | 
						||
            if (!IsInitialSuccess)
 | 
						||
            {
 | 
						||
                UnityEngine.Debug.LogError($"{Tag} :: InitUserProperties :: Please call <GuruSDK.Start()> first, before you call <InitUserProperties>.");
 | 
						||
                return;
 | 
						||
            }
 | 
						||
            
 | 
						||
            Debug.Log($"[SDK] --- PurchasedCount:{Model.PurchasedCount}");
 | 
						||
            Debug.Log($"[SDK] --- IsIapUser:{Model.IsIapUser}");
 | 
						||
            
 | 
						||
            SetUserIsIAP(Model.IsIapUser); // 预先设置用户的 IAP User 属性
 | 
						||
            SetUserBLevel(Model.SuccessLevelId); // 预先设置用户的 BLevel 属性
 | 
						||
            SetUserBPlay(Model.TotalPlayedCount);  // 预先设置用户的 BPlay 属性
 | 
						||
            if (Model.IsNoAds) SetBuyNoAds(true); // 设置用户已经购买了去广告
 | 
						||
        }
 | 
						||
 | 
						||
        private static HashSet<string> _userPropertyExistKeys = new HashSet<string>();
 | 
						||
 | 
						||
        private static void RecordUserPropertyKey(string key)
 | 
						||
        {
 | 
						||
            if(_userPropertyExistKeys == null)
 | 
						||
                _userPropertyExistKeys = new HashSet<string>();
 | 
						||
            
 | 
						||
            if(!HasUserPropertyKey(key)) _userPropertyExistKeys.Add(key);
 | 
						||
        }
 | 
						||
        
 | 
						||
        private static bool HasUserPropertyKey(string key)
 | 
						||
        {
 | 
						||
            return _userPropertyExistKeys?.Contains(key) ?? false;
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 设置用户属性
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="key"></param>
 | 
						||
        /// <param name="value"></param>
 | 
						||
        public static void SetUserProperty(string key, string value)
 | 
						||
        {
 | 
						||
            if (!IsInitialSuccess)
 | 
						||
            {
 | 
						||
                UnityEngine.Debug.LogError($"{Tag} :: SetUserProperty {key}:{value} ::Please call <GuruSDK.Start()> first, before you call <SetUserProperty>.");
 | 
						||
                return;
 | 
						||
            }
 | 
						||
            RecordUserPropertyKey(key);
 | 
						||
            Analytics.SetUserProperty(key, value);
 | 
						||
        }
 | 
						||
 | 
						||
        public static void SetUID(string uid)
 | 
						||
        {
 | 
						||
            SetUserProperty(Consts.PropertyUserID, uid);
 | 
						||
        }
 | 
						||
 | 
						||
        public static void SetUserBLevel(int blevel)
 | 
						||
        {
 | 
						||
            if (!InitConfig.AutoRecordFinishedLevels)
 | 
						||
            {
 | 
						||
                Model.SetBLevelValue(blevel);
 | 
						||
                Analytics.BLevel = blevel;
 | 
						||
            }
 | 
						||
            SetUserProperty(Consts.PropertyLevel, $"{blevel}");
 | 
						||
        }
 | 
						||
        
 | 
						||
        public static void SetUserBPlay(int bplay)
 | 
						||
        {
 | 
						||
            if (!InitConfig.AutoRecordFinishedLevels)
 | 
						||
            {
 | 
						||
                Model.SetBPlayValue(bplay);
 | 
						||
                Analytics.BPlay = bplay;
 | 
						||
            }
 | 
						||
            SetUserProperty(Consts.PropertyPlay, $"{bplay}");
 | 
						||
        }
 | 
						||
        
 | 
						||
        /// <summary>
 | 
						||
        /// 上报用户全部的 Coin (当前值)
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="coins"></param>
 | 
						||
        public static void SetUserCoin(int coins)
 | 
						||
        {
 | 
						||
            SetUserProperty(Consts.PropertyCoin, $"{coins}");        
 | 
						||
        }
 | 
						||
        
 | 
						||
        /// <summary>
 | 
						||
        /// 上报用户免费金币的 数量 (累加值)
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="freeCoins"></param>
 | 
						||
        public static void SetUserNonIapCoin(int freeCoins)
 | 
						||
        {
 | 
						||
            SetUserProperty(Consts.PropertyNonIAPCoin, $"{freeCoins}");        
 | 
						||
        }
 | 
						||
        
 | 
						||
        /// <summary>
 | 
						||
        /// 上报用户付费金币的 数量 (累加值)
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="freeCoins"></param>
 | 
						||
        public static void SetUserIapCoin(int paidCoins)
 | 
						||
        {
 | 
						||
            SetUserProperty(Consts.PropertyIAPCoin, $"{paidCoins}");        
 | 
						||
        }
 | 
						||
        
 | 
						||
        public static void SetUserExp(int exp)
 | 
						||
        {
 | 
						||
            SetUserProperty(Consts.PropertyExp, $"{exp}");        
 | 
						||
        }
 | 
						||
        
 | 
						||
        public static void SetUserHp(int hp)
 | 
						||
        {
 | 
						||
            SetUserProperty(Consts.PropertyHp, $"{hp}");        
 | 
						||
        }
 | 
						||
 | 
						||
        public static void SetUserGrade(int grade)
 | 
						||
        {
 | 
						||
            SetUserProperty(Consts.PropertyGrade, $"{grade}");        
 | 
						||
        }
 | 
						||
 | 
						||
        public static void SetUserIsIAP(bool isIapUser)
 | 
						||
        {
 | 
						||
            SetUserProperty(Consts.PropertyIsIAPUser, isIapUser? "true" : "false");
 | 
						||
        }
 | 
						||
 | 
						||
        public static void SetFirstOpenTime(string timestamp)
 | 
						||
        {
 | 
						||
            SetUserProperty(Analytics.PropertyFirstOpenTime, timestamp);
 | 
						||
        }
 | 
						||
        
 | 
						||
        public static void SetNotiPerm(string status)
 | 
						||
        {
 | 
						||
            SetUserProperty(Consts.PropertyNotiPerm, status);
 | 
						||
        }
 | 
						||
        
 | 
						||
        public static void SetATTStatus(string status)
 | 
						||
        {
 | 
						||
            SetUserProperty(Consts.PropertyATTStatus, status);
 | 
						||
        }
 | 
						||
        
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 初始化时调用一下所有的属性打点 </br>
 | 
						||
        /// <a href="https://docs.google.com/spreadsheets/d/1N47rXgjatRHFvzWWx0Hqv5C1D9NHHGbggi6pQ65c-zQ/edit#gid=1858695240">用户属性文档</a>
 | 
						||
        /// </summary>
 | 
						||
        private static void UpdateAllUserProperties()
 | 
						||
        {
 | 
						||
            if(!HasUserPropertyKey(Consts.PropertyFirstOpenTime)) 
 | 
						||
                SetFirstOpenTime(TimeUtil.GetCurrentTimeStamp().ToString());    //  first_open_time 
 | 
						||
            
 | 
						||
            if(!HasUserPropertyKey(Consts.PropertyIsIAPUser)) 
 | 
						||
                SetUserIsIAP(Model?.IsIapUser ?? false);    // is_iap_user
 | 
						||
 | 
						||
            if (!HasUserPropertyKey(Consts.PropertyLevel))
 | 
						||
                SetUserBLevel(Model?.SuccessLevelId ?? 0);  // b_level
 | 
						||
            
 | 
						||
            if (!HasUserPropertyKey(Consts.PropertyPlay))
 | 
						||
                SetUserBLevel(Model?.TotalPlayedCount ?? 0); // b_play
 | 
						||
            
 | 
						||
            if(!HasUserPropertyKey(Consts.PropertyUserID)) 
 | 
						||
                SetUserProperty(Consts.PropertyUserID, UID); // user_id
 | 
						||
            
 | 
						||
            if(!HasUserPropertyKey(Consts.PropertyDeviceID)) 
 | 
						||
                SetUserProperty(Consts.PropertyDeviceID, DeviceId); // device_id
 | 
						||
            
 | 
						||
            if(!HasUserPropertyKey(Consts.PropertyIAPCoin)) 
 | 
						||
                SetUserIapCoin(0); // iap_coin
 | 
						||
            
 | 
						||
            if(!HasUserPropertyKey(Consts.PropertyNonIAPCoin)) 
 | 
						||
                SetUserNonIapCoin(0); // non_iap_coin
 | 
						||
            
 | 
						||
            if(!HasUserPropertyKey(Consts.PropertyCoin)) 
 | 
						||
                SetUserCoin(0);// coin
 | 
						||
 | 
						||
            if (!HasUserPropertyKey(Consts.PropertyGrade))
 | 
						||
                SetUserGrade(0); // grade
 | 
						||
            
 | 
						||
            if(!HasUserPropertyKey(Consts.PropertyExp))
 | 
						||
                SetUserExp(0); // exp
 | 
						||
            
 | 
						||
            if(!HasUserPropertyKey(Consts.PropertyHp))
 | 
						||
                SetUserHp(0); // hp
 | 
						||
 | 
						||
#if UNITY_IOS
 | 
						||
            if(!HasUserPropertyKey(Consts.PropertyATTStatus))
 | 
						||
                SetATTStatus("notDetermined"); // att_status
 | 
						||
#endif
 | 
						||
 | 
						||
            if(!HasUserPropertyKey(Consts.PropertyNotiPerm))
 | 
						||
                SetNotiPerm("not_determined"); // noti_perm
 | 
						||
            
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
        #endregion
 | 
						||
 | 
						||
        #region SDK 打点
 | 
						||
        
 | 
						||
        /// <summary>
 | 
						||
        /// Log SDK boost time
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="time"></param>
 | 
						||
        private static void LogSDKInitTime(double time)
 | 
						||
        {
 | 
						||
            Analytics.Track(Consts.EventSDKInfo, new Dictionary<string, dynamic>()
 | 
						||
            {
 | 
						||
                { "boost_time", time.ToString("F6") },
 | 
						||
                { Consts.PropertyDeviceID, DeviceId },
 | 
						||
                { "version", Version}
 | 
						||
            }, new Analytics.EventSetting()
 | 
						||
            {
 | 
						||
                EnableFirebaseAnalytics = true,
 | 
						||
            });
 | 
						||
            
 | 
						||
            SetUserProperty("sdk_version", Version);
 | 
						||
        }
 | 
						||
        
 | 
						||
        #endregion
 | 
						||
 | 
						||
        #region IAP 打点
 | 
						||
 | 
						||
        private static string TryGetFirstProductId()
 | 
						||
        {
 | 
						||
            if (GuruSettings.Instance != null && (GuruSettings.Instance.Products?.Length ?? 0) > 0)
 | 
						||
            {
 | 
						||
                return GuruSettings.Instance.Products[0]?.ProductId ?? "";
 | 
						||
            }
 | 
						||
 | 
						||
            return "";
 | 
						||
        }
 | 
						||
        
 | 
						||
        private static string TryGetCurrentProductId()
 | 
						||
        {
 | 
						||
            if (GuruIAP.Instance != null && IsIAPReady)
 | 
						||
            {
 | 
						||
                return GuruIAP.Instance.CurrentBuyingProductId;
 | 
						||
            }
 | 
						||
            return "";
 | 
						||
        }
 | 
						||
        
 | 
						||
        
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 当付费页面打开时调用 (iap_imp)
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="scene">付费页场景名称</param>
 | 
						||
        /// <param name="productId">列表中首个商品的 ProductId </param>
 | 
						||
        public static void LogIAPImp(string scene, Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            Analytics.IAPImp(scene, extra);
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 当付费页面关闭时调用 (iap_close)
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="scene"></param>
 | 
						||
        /// <param name="productId"></param>
 | 
						||
        public static void LogIAPClose(string scene, Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            Analytics.IAPClose(scene, extra);
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 当点击 IAP 商品按钮的时候调用 (iap_clk)
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="scene"></param>
 | 
						||
        /// <param name="productId"></param>
 | 
						||
        /// <param name="offerId"></param>
 | 
						||
        public static void LogIAPClick(string scene, string productId, string basePlan = "", string offerId = "", Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            Analytics.IAPClick(scene, productId, basePlan, offerId, extra);
 | 
						||
        }
 | 
						||
        
 | 
						||
        #endregion
 | 
						||
 | 
						||
        #region 经济打点
 | 
						||
        
 | 
						||
        // ************************************************************************************************
 | 
						||
        // *
 | 
						||
        // *                                        经济打点
 | 
						||
        // * 内容详参: https://docs.google.com/spreadsheets/d/1xYSsAjbrwqeJm7panoVzHO0PeGRQVDCR4e2CU9OPEzk/edit#gid=0
 | 
						||
        // *
 | 
						||
        // ************************************************************************************************
 | 
						||
        
 | 
						||
        //---------------------------------------- EARN ---------------------------------------- 
 | 
						||
        /// <summary>
 | 
						||
        /// 基础收入接口 (earn_virtual_currency)
 | 
						||
        /// 可直接调用此接口上报相关参数
 | 
						||
        /// 获取虚拟货币/道具. 
 | 
						||
        /// 基础接口, 不推荐项目组直接调用
 | 
						||
        /// 请直接调用其他对应场景的统计接口
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="currencyName">货币名称</param>
 | 
						||
        /// <param name="value">货币增加值 10</param>
 | 
						||
        /// <param name="balance">结算后货币总量 20 -> 30</param>
 | 
						||
        /// <param name="category">消耗类型, 默认值请赋 reward</param>
 | 
						||
        /// <param name="levelName">当前关卡或者人物等级名称</param>
 | 
						||
        /// <param name="itemName">购买道具名称</param>
 | 
						||
        /// <param name="scene">购买场景如 Store, Workbench, Sign, Ads....</param>
 | 
						||
        public static void LogEarnVirtualCurrency(string currencyName, 
 | 
						||
            int value, int balance, 
 | 
						||
            string category = "", string itemName = "",
 | 
						||
            string levelName = "", string scene = "", Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            Analytics.EarnVirtualCurrency(currencyName, value, balance, category, itemName,levelName, scene, extra);
 | 
						||
        }
 | 
						||
        
 | 
						||
        
 | 
						||
        
 | 
						||
        /// <summary>
 | 
						||
        /// 赚取组合: 货币+道具 (earn_virtual_currency) (props)
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="currencyName"></param>
 | 
						||
        /// <param name="value"></param>
 | 
						||
        /// <param name="balance"></param>
 | 
						||
        /// <param name="category"></param>
 | 
						||
        /// <param name="itemName"></param>
 | 
						||
        /// <param name="props"></param>
 | 
						||
        /// <param name="levelName"></param>
 | 
						||
        /// <param name="scene"></param>
 | 
						||
        private static void LogEarnVirtualCurrencyAndProps(string currencyName, 
 | 
						||
            int value = 0, int balance = 0,
 | 
						||
            string category = "", string itemName = "",
 | 
						||
            string levelName = "", string scene = Consts.ParameterDefaultScene,  
 | 
						||
            string[] props = null, Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            //---- Currency -----
 | 
						||
            if (value > 0)
 | 
						||
            {
 | 
						||
                LogEarnVirtualCurrency(currencyName, value, balance, category, itemName, levelName, scene, extra);
 | 
						||
            }
 | 
						||
            //---- Props --------
 | 
						||
            if (null != props)
 | 
						||
            {
 | 
						||
                int i = 0;
 | 
						||
                while (i < props.Length)
 | 
						||
                {
 | 
						||
                    LogEarnVirtualCurrency(props[i], 1, 0, category, itemName, levelName, scene, extra);
 | 
						||
                    i++;
 | 
						||
                }
 | 
						||
            }
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 签到奖励. 获得货币/道具 (earn_virtual_currency) (reward:sign)
 | 
						||
        /// <li>通常类型: Coin 收入 </li>
 | 
						||
        /// <li>特殊类型: Coin + Props (道具列表) </li>
 | 
						||
        /// <li>特殊类型: Props (道具列表) </li>
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="currencyName">货币名称</param>
 | 
						||
        /// <param name="value">赚取金额</param>
 | 
						||
        /// <param name="balance">货币总量(累加后)</param>
 | 
						||
        /// <param name="levelName">当前关卡名称</param>
 | 
						||
        /// <param name="scene">应用场景</param>
 | 
						||
        /// <param name="props">获取的道具名称列表</param>
 | 
						||
        public static void LogEarnVirtualCurrencyBySign(string currencyName, 
 | 
						||
            int value = 0, int balance = 0, string levelName = "", 
 | 
						||
            string scene = "home_page", string[] props = null, Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            string category = Consts.CurrencyCategoryReward;
 | 
						||
            string itemName = "sign";
 | 
						||
 | 
						||
            LogEarnVirtualCurrencyAndProps(currencyName, value, balance, category, itemName, levelName, scene, props, extra);
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// IAP 付费购买. 获得货币/道具 (earn_virtual_currency) (iap_buy:sku)
 | 
						||
        /// <li>通常类型: Coin 收入 </li>
 | 
						||
        /// <li>特殊类型: Coin + Props (道具列表) </li>
 | 
						||
        /// <li>特殊类型: Props (道具列表) </li> 
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="currencyName">IAP 道具名称</param>
 | 
						||
        /// <param name="value">赚取金额</param>
 | 
						||
        /// <param name="balance">货币总量(累加后)</param>
 | 
						||
        /// <param name="levelName">当前关卡名称</param>
 | 
						||
        /// <param name="scene">应用场景</param>
 | 
						||
        /// <param name="props">获取的道具名称列表</param>
 | 
						||
        public static void LogEarnVirtualCurrencyByIAP(string currencyName,
 | 
						||
            int value = 0, int balance = 0, string levelName = "", 
 | 
						||
            string scene = "store", string[] props = null, Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            string category = Consts.CurrencyCategoryIAP;
 | 
						||
            // string itemName = productId;
 | 
						||
            string itemName = "sku";
 | 
						||
            LogEarnVirtualCurrencyAndProps(currencyName, value, balance, category, itemName, levelName, scene, props, extra);
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 看广告获取到货币/道具 (earn_virtual_currency) (reward:ads)
 | 
						||
        /// <li>通常类型: Coin 收入 </li>
 | 
						||
        /// <li>特殊类型: Coin + Props (道具列表) </li>
 | 
						||
        /// <li>特殊类型: Props (道具列表) </li> 
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="currencyName">货币名称</param>
 | 
						||
        /// <param name="value">赚取金额</param>
 | 
						||
        /// <param name="balance">货币总量(累加后)</param>
 | 
						||
        /// <param name="levelName">当前关卡名称</param>
 | 
						||
        /// <param name="scene">应用场景</param>
 | 
						||
        /// <param name="props">获取的道具名称列表</param>
 | 
						||
        public static void LogEarnVirtualCurrencyByAds(string currencyName, 
 | 
						||
            int value = 0, int balance = 0, string levelName = "", 
 | 
						||
            string scene = "store", string[] props = null, Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            string category = Consts.CurrencyCategoryReward;
 | 
						||
            string itemName = "ads";
 | 
						||
            LogEarnVirtualCurrencyAndProps(currencyName, value, balance, category, itemName, levelName, scene, props, extra);
 | 
						||
        }
 | 
						||
        
 | 
						||
        /// <summary>
 | 
						||
        /// 使用了金币半价 + 看广告获取到货币/道具 (earn_virtual_currency) (bonus:ads)
 | 
						||
        /// <li>通常类型: Coin 收入 </li>
 | 
						||
        /// <li>特殊类型: Coin + Props (道具列表) </li>
 | 
						||
        /// <li>特殊类型: Props (道具列表) </li> 
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="currencyName">货币名称</param>
 | 
						||
        /// <param name="value">赚取金额</param>
 | 
						||
        /// <param name="balance">货币总量(累加后)</param>
 | 
						||
        /// <param name="levelName">当前关卡名称</param>
 | 
						||
        /// <param name="scene">应用场景</param>
 | 
						||
        /// <param name="props">获取的道具名称列表</param>
 | 
						||
        public static void LogEarnVirtualCurrencyByPaidAds(string currencyName, 
 | 
						||
            int value = 0, int balance = 0, string levelName = "", 
 | 
						||
            string scene = Consts.ParameterDefaultScene, string[] props = null, Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            string category = Consts.CurrencyCategoryBonus;
 | 
						||
            string itemName = "ads";
 | 
						||
            LogEarnVirtualCurrencyAndProps(currencyName, value, balance, category, itemName, levelName, scene, props, extra);
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 过关奖励获取到货币/道具 (earn_virtual_currency) (reward:level) 
 | 
						||
        /// <li>通常类型: Coin 收入 </li>
 | 
						||
        /// <li>特殊类型: Coin + Props (道具列表) </li>
 | 
						||
        /// <li>特殊类型: Props (道具列表) </li> 
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="currencyName">货币名称</param>
 | 
						||
        /// <param name="value">赚取金额</param>
 | 
						||
        /// <param name="balance">货币总量(累加后)</param>
 | 
						||
        /// <param name="levelName">当前关卡名称</param>
 | 
						||
        /// <param name="scene">应用场景</param>
 | 
						||
        /// <param name="props">获取的道具名称列表</param>
 | 
						||
        public static void LogEarnVirtualCurrencyByLevelComplete(string currencyName, 
 | 
						||
            int value = 0, int balance = 0, string levelName = "", 
 | 
						||
            string scene = "store", string[] props = null, Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            string category = Consts.CurrencyCategoryReward;
 | 
						||
            string itemName = "level";
 | 
						||
            LogEarnVirtualCurrencyAndProps(currencyName, value, balance, category, itemName, levelName, scene, props, extra);
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 通过使用 Currency 购买获得 Prop (earn_virtual_currency) (reward:level) 
 | 
						||
        /// 记录 Prop 增加的打点, 消费游戏内货币
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="currencyName">货币名称</param>
 | 
						||
        /// <param name="props">获取的道具名称列表</param>
 | 
						||
        /// <param name="scene">应用场景</param>
 | 
						||
        /// <param name="value">赚取金额</param>
 | 
						||
        /// <param name="balance">货币总量(累加后)</param>
 | 
						||
        /// <param name="levelName">当前关卡名称</param>
 | 
						||
        public static void LogEarnPropsByVirtualCurrency(string currencyName, string[] props,
 | 
						||
            string scene = Consts.ParameterDefaultScene,
 | 
						||
            int value = 1, int balance = 0, string levelName = "", Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            string category = Consts.CurrencyCategoryIGC;
 | 
						||
            string itemName = currencyName;
 | 
						||
            LogEarnVirtualCurrencyAndProps(currencyName, value, balance, category, itemName, levelName, scene, props, extra);
 | 
						||
        }
 | 
						||
        
 | 
						||
        /// <summary>
 | 
						||
        /// 通过道具交换/合成或得了其他道具 (earn_virtual_currency) (igb:coin) 
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="propName"></param>
 | 
						||
        /// <param name="otherName"></param>
 | 
						||
        /// <param name="scene"></param>
 | 
						||
        /// <param name="value"></param>
 | 
						||
        /// <param name="balance"></param>
 | 
						||
        /// <param name="levelName"></param>
 | 
						||
        public static void LogEarnPropByProp(string propName, string otherName,
 | 
						||
            string scene = Consts.ParameterDefaultScene,
 | 
						||
            int value = 1, int balance = 0, string levelName = "", Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            string category = Consts.CurrencyCategoryIGB;
 | 
						||
            LogEarnVirtualCurrency(propName, value, balance, category, otherName, levelName, scene, extra);
 | 
						||
        }
 | 
						||
        
 | 
						||
        
 | 
						||
        /// <summary>
 | 
						||
        /// 通过转盘或者抽奖, 获取货币/道具 (earn_virtual_currency) (igb:lottery) 
 | 
						||
        /// <li>通常类型: Coin 收入 </li>
 | 
						||
        /// <li>特殊类型: Coin + Props (道具列表) </li>
 | 
						||
        /// <li>特殊类型: Props (道具列表) </li> 
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="currencyName">货币名称</param>
 | 
						||
        /// <param name="value">赚取金额</param>
 | 
						||
        /// <param name="balance">货币总量(累加后)</param>
 | 
						||
        /// <param name="levelName">当前关卡名称</param>
 | 
						||
        /// <param name="scene">应用场景</param>
 | 
						||
        /// <param name="props">获取的道具名称列表</param>
 | 
						||
        public static void LogEarnVirtualCurrencyByLottery(string currencyName, 
 | 
						||
            int value = 0, int balance = 0, string levelName = "", 
 | 
						||
            string scene = "store", string[] props = null, Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            string category = Consts.CurrencyCategoryIGB;
 | 
						||
            string itemName = "lottery";
 | 
						||
            LogEarnVirtualCurrencyAndProps(currencyName, value, balance, category, itemName, levelName, scene, props, extra);
 | 
						||
        }
 | 
						||
        
 | 
						||
        
 | 
						||
        //---------------------------------------- SPEND ---------------------------------------- 
 | 
						||
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 基础花费虚拟货币/道具 (spend_virtual_currency)
 | 
						||
        /// 基础接口, 不推荐项目组直接调用
 | 
						||
        /// 请直接调用其他对应场景的统计接口
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="currencyName">货币名称</param>
 | 
						||
        /// <param name="value">货币消耗值 10</param>
 | 
						||
        /// <param name="balance">结算后货币总量 30 -> 20</param>
 | 
						||
        /// <param name="category">消耗类型, 默认值请赋 reward</param>
 | 
						||
        /// <param name="levelName">当前关卡或者人物等级名称</param>
 | 
						||
        /// <param name="itemName">购买道具名称</param>
 | 
						||
        /// <param name="scene">购买场景如 Store, Workbench, Sign, Ads....</param>
 | 
						||
        public static void LogSpendVirtualCurrency(string currencyName, int value, int balance, string category = "", string itemName = "",
 | 
						||
            string levelName = "", string scene = "", Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            Analytics.SpendVirtualCurrency(currencyName, value, balance, category, itemName, levelName, scene, extra);
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 消耗货币购买道具 (spend_virtual_currency) (props)
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="currencyName"></param>
 | 
						||
        /// <param name="prop"></param>
 | 
						||
        /// <param name="value"></param>
 | 
						||
        /// <param name="balance"></param>
 | 
						||
        /// <param name="levelName"></param>
 | 
						||
        /// <param name="scene"></param>
 | 
						||
        public static void LogSpendVirtualCurrencyWithProp(string currencyName, string prop,
 | 
						||
            int value, int balance,
 | 
						||
            string levelName = "", string scene = "", Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            LogSpendVirtualCurrencyWithProps(currencyName, new string[] {prop}, value, balance, levelName, scene, extra);
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 消耗货币购买道具 (含多个) (spend_virtual_currency) (props)
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="currencyName"></param>
 | 
						||
        /// <param name="props"></param>
 | 
						||
        /// <param name="value"></param>
 | 
						||
        /// <param name="balance"></param>
 | 
						||
        /// <param name="levelName"></param>
 | 
						||
        /// <param name="scene"></param>
 | 
						||
        public static void LogSpendVirtualCurrencyWithProps(string currencyName, string[] props,
 | 
						||
            int value, int balance, 
 | 
						||
            string levelName = "", string scene = "", Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            string category = Consts.CurrencyCategoryProps;
 | 
						||
            if (props != null && props.Length > 0)
 | 
						||
            {
 | 
						||
                int i = 0;
 | 
						||
                while (i < props.Length)
 | 
						||
                {
 | 
						||
                    LogSpendVirtualCurrency(currencyName, value, balance, category, props[i], levelName, scene, extra); 
 | 
						||
                    i++;
 | 
						||
                }
 | 
						||
            }
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 消耗货币购买礼包或组合 (spend_virtual_currency) (bundle)
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="currencyName"></param>
 | 
						||
        /// <param name="bundle"></param>
 | 
						||
        /// <param name="value"></param>
 | 
						||
        /// <param name="balance"></param>
 | 
						||
        /// <param name="levelName"></param>
 | 
						||
        /// <param name="scene"></param>
 | 
						||
        public static void LogSpendVirtualCurrencyWithBundle(string currencyName, string bundle,
 | 
						||
            int value, int balance,
 | 
						||
            string levelName = "", string scene = "", Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            LogSpendVirtualCurrencyWithBundles(currencyName, new string[] {bundle}, value, balance, levelName, scene, extra);
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 消耗货币购买礼包或组合 (复数) (spend_virtual_currency) (bundle)
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="currencyName"></param>
 | 
						||
        /// <param name="bundles"></param>
 | 
						||
        /// <param name="value"></param>
 | 
						||
        /// <param name="balance"></param>
 | 
						||
        /// <param name="levelName"></param>
 | 
						||
        /// <param name="scene"></param>
 | 
						||
        public static void LogSpendVirtualCurrencyWithBundles(string currencyName, string[] bundles,
 | 
						||
            int value, int balance, 
 | 
						||
            string levelName = "", string scene = "", Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            string category = Consts.CurrencyCategoryBundle;
 | 
						||
            if (bundles != null && bundles.Length > 0)
 | 
						||
            {
 | 
						||
                int i = 0;
 | 
						||
                while (i < bundles.Length)
 | 
						||
                {
 | 
						||
                    LogSpendVirtualCurrency(currencyName, value, balance, category, bundles[i], levelName, scene, extra); 
 | 
						||
                    i++;
 | 
						||
                }
 | 
						||
            }
 | 
						||
        }
 | 
						||
        
 | 
						||
        /// <summary>
 | 
						||
        /// 消耗物品, 交换其他物品 (spend_virtual_currency) (prop)
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="currencyName"></param>
 | 
						||
        /// <param name="bundles"></param>
 | 
						||
        /// <param name="value"></param>
 | 
						||
        /// <param name="balance"></param>
 | 
						||
        /// <param name="levelName"></param>
 | 
						||
        /// <param name="scene"></param>
 | 
						||
        public static void LogSpendPropWithProp(string propName, string otherName,
 | 
						||
            int value, int balance, 
 | 
						||
            string levelName = "", string scene = "", string extraCategory = "", Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            string category = string.IsNullOrEmpty(extraCategory) ? Consts.CurrencyCategoryProp : extraCategory;
 | 
						||
            LogSpendVirtualCurrency(propName, value, balance, category, otherName, levelName, scene, extra); 
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
        #endregion
 | 
						||
 | 
						||
        #region ATT 二次引导弹窗
 | 
						||
        
 | 
						||
        /// <summary>
 | 
						||
        /// ATT 二次引导弹窗展示 (att_reguide_imp)
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="type">引导样式名称</param>
 | 
						||
        /// <param name="showTimes">第几次展示</param>
 | 
						||
        /// <param name="installDays">举例安装日期的天数</param>
 | 
						||
        /// <param name="extra">扩展数据</param>
 | 
						||
        public static void LogAttReguideImp(string type, 
 | 
						||
            int showTimes = 1, int installDays = 0, Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            var dict = new Dictionary<string, object>()
 | 
						||
            {
 | 
						||
                ["type"] = type,
 | 
						||
                ["show_times"] = showTimes,
 | 
						||
                ["install_days"] = installDays,
 | 
						||
            };
 | 
						||
 | 
						||
            if (extra != null) dict = GuruSDKUtils.MergeDictionary(dict, extra);
 | 
						||
            LogEvent(Consts.EventAttReguideImp, dict);
 | 
						||
        }
 | 
						||
        
 | 
						||
        /// <summary>
 | 
						||
        /// ATT 二次引导弹窗点击 (att_reguide_clk)
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="type">引导样式名称</param>
 | 
						||
        /// <param name="showTimes">第几次展示</param>
 | 
						||
        /// <param name="installDays">举例安装日期的天数</param>
 | 
						||
        /// <param name="action">点击引导页的动作:dissmiss/go</param>
 | 
						||
        /// <param name="extra">扩展数据</param>
 | 
						||
        public static void LogAttReguideClick(string type, string action, 
 | 
						||
            int showTimes = 1, int installDays = 0, Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            var dict = new Dictionary<string, object>()
 | 
						||
            {
 | 
						||
                ["type"] = type,
 | 
						||
                ["show_times"] = showTimes,
 | 
						||
                ["install_days"] = installDays,
 | 
						||
                ["action"] = action,
 | 
						||
            };
 | 
						||
 | 
						||
            if (extra != null) dict = GuruSDKUtils.MergeDictionary(dict, extra);
 | 
						||
            LogEvent(Consts.EventAttReguideClk, dict);
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// ATT 二次引导弹窗展示结果 (att_reguide_result)
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="type">引导样式名称</param>
 | 
						||
        /// <param name="showTimes">第几次展示</param>
 | 
						||
        /// <param name="installDays">举例安装日期的天数</param>
 | 
						||
        /// <param name="action">点击引导页的动作:dissmiss/go</param>
 | 
						||
        /// <param name="result">结果字段:authorized, denied, restricted, notDetermined</param>
 | 
						||
        /// <param name="extra">扩展数据</param>
 | 
						||
        public static void LogAttReguideResult(string type, string action, string result, 
 | 
						||
            int showTimes = 1, int installDays = 0, Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            var dict = new Dictionary<string, object>()
 | 
						||
            {
 | 
						||
                ["type"] = type,
 | 
						||
                ["show_times"] = showTimes,
 | 
						||
                ["install_days"] = installDays,
 | 
						||
                ["action"] = action,
 | 
						||
                [Consts.ParameterItemCategory] = result,
 | 
						||
            };
 | 
						||
 | 
						||
            if (extra != null) dict = GuruSDKUtils.MergeDictionary(dict, extra);
 | 
						||
            LogEvent(Consts.EventAttReguideResult, dict);
 | 
						||
        }
 | 
						||
        
 | 
						||
 | 
						||
        #endregion
 | 
						||
        
 | 
						||
        #region 教程引导
 | 
						||
        
 | 
						||
        /// <summary>
 | 
						||
        /// 教程开始
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="extra">扩展数据</param>
 | 
						||
        public static void LogTutorialBegin(Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            LogEvent(Consts.EventTutorialBegin, extra);
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 教程开始
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="step">教程步骤</param>
 | 
						||
        /// <param name="extra">扩展数据</param>
 | 
						||
        public static void LogTutorialImp(int step, Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            string key = Consts.EventTutorialImp.Replace("{0}", step.ToString());
 | 
						||
            LogEvent(key, extra);
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 教程开始
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="step">教程步骤</param>
 | 
						||
        /// <param name="extra">扩展数据</param>
 | 
						||
        public static void LogTutorialNextClick(int step, Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            string key = Consts.EventTutorialNextClick.Replace("{0}", step.ToString());
 | 
						||
            LogEvent(key, extra);
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 教程结束
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="extra">扩展数据</param>
 | 
						||
        public static void LogTutorialComplete(Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            LogEvent(Consts.EventTutorialComplete, extra);
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 教程页面关闭
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="extra">扩展数据</param>
 | 
						||
        public static void LogTutorialClose(Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            LogEvent(Consts.EventTutorialClose, extra);
 | 
						||
        }
 | 
						||
        #endregion
 | 
						||
 | 
						||
        #region 消息权限弹窗打点
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 通知栏请求权限展示时触发 (noti_perm_imp)
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="style">弹窗样式</param>
 | 
						||
        /// <param name="requestTimes">请求弹窗的次数</param>
 | 
						||
        /// <param name="showTimes">展现弹窗的次数</param>
 | 
						||
        /// <param name="deniedTimes">点击 deny 的次数</param>
 | 
						||
        /// <param name="promptTrigger">弹窗触发来源</param>
 | 
						||
        /// <param name="scene">弹窗场景</param>
 | 
						||
        /// <param name="extra">扩展参数</param>
 | 
						||
        public static void LogNotiPermImp(int requestTimes,  int showTimes, int deniedTimes, string promptTrigger,string style = "default",  string scene = "", Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            var dict = new Dictionary<string, object>()
 | 
						||
            {
 | 
						||
                [Consts.ParameterItemCategory] = style,
 | 
						||
                ["request_times"] = requestTimes,
 | 
						||
                ["show_times"] = showTimes,
 | 
						||
                ["denied_times"] = deniedTimes,
 | 
						||
                ["prompt_trigger"] = promptTrigger,
 | 
						||
            };
 | 
						||
 | 
						||
            if (!string.IsNullOrEmpty(scene))
 | 
						||
                dict[Consts.ParameterItemName] = scene;
 | 
						||
 | 
						||
            if (extra != null) dict = GuruSDKUtils.MergeDictionary(dict, extra);
 | 
						||
            LogEvent(Consts.EventNotiPermImp, dict);
 | 
						||
        }
 | 
						||
        
 | 
						||
        /// <summary>
 | 
						||
        /// 得到权限结果时触发 (noti_perm_result)
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="requestTimes"></param>
 | 
						||
        /// <param name="showTimes"></param>
 | 
						||
        /// <param name="deniedTimes"></param>
 | 
						||
        /// <param name="result"></param>
 | 
						||
        /// <param name="promptTrigger"></param>
 | 
						||
        /// <param name="style"></param>
 | 
						||
        /// <param name="scene"></param>
 | 
						||
        /// <param name="extra"></param>
 | 
						||
        public static void LogNotiPermResult( int requestTimes,  int showTimes, int deniedTimes, string result, string promptTrigger, string style = "default", string scene = "", Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            var dict = new Dictionary<string, object>()
 | 
						||
            {
 | 
						||
                ["request_times"] = requestTimes,
 | 
						||
                ["show_times"] = showTimes,
 | 
						||
                ["denied_times"] = deniedTimes,
 | 
						||
                ["prompt_trigger"] = promptTrigger,
 | 
						||
                ["result"] = result,
 | 
						||
                [Consts.ParameterItemCategory] = style,
 | 
						||
            };
 | 
						||
 | 
						||
            if (!string.IsNullOrEmpty(scene))
 | 
						||
                dict[Consts.ParameterItemName] = scene;
 | 
						||
 | 
						||
            if (extra != null) dict = GuruSDKUtils.MergeDictionary(dict, extra);
 | 
						||
            LogEvent(Consts.EventNotiPermResult, dict);
 | 
						||
        }
 | 
						||
        
 | 
						||
        /// <summary>
 | 
						||
        /// 说明性通知栏权限引导展示时触发 (noti_perm_rationale_imp)
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="pageName">引导页的名称,自定义</param>
 | 
						||
        /// <param name="scene"></param>
 | 
						||
        /// <param name="extra"></param>
 | 
						||
        public static void LogNotiPermRationaleImp(string pageName, string scene = "", Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            var dict = new Dictionary<string, object>()
 | 
						||
            {
 | 
						||
                [Consts.ParameterItemCategory] = pageName,
 | 
						||
            };
 | 
						||
 | 
						||
            if (!string.IsNullOrEmpty(scene))
 | 
						||
                dict[Consts.ParameterItemName] = scene;
 | 
						||
 | 
						||
            if (extra != null) dict = GuruSDKUtils.MergeDictionary(dict, extra);
 | 
						||
            LogEvent(Consts.EventNotiPermRationaleImp, dict);
 | 
						||
        }
 | 
						||
        
 | 
						||
        /// <summary>
 | 
						||
        /// 说明性通知栏权限引导结果时触发 (noti_perm_rationale_result)
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="result"></param>
 | 
						||
        /// <param name="pageName"></param>
 | 
						||
        /// <param name="scene"></param>
 | 
						||
        /// <param name="extra"></param>
 | 
						||
        public static void LogNotiPermRationaleResult(string result, string pageName, string scene = "", Dictionary<string, object> extra = null)
 | 
						||
        {
 | 
						||
            var dict = new Dictionary<string, object>()
 | 
						||
            {
 | 
						||
                ["result"] = result,
 | 
						||
                [Consts.ParameterItemCategory] = pageName,
 | 
						||
            };
 | 
						||
 | 
						||
            if (!string.IsNullOrEmpty(scene))
 | 
						||
                dict[Consts.ParameterItemName] = scene;
 | 
						||
 | 
						||
            if (extra != null) dict = GuruSDKUtils.MergeDictionary(dict, extra);
 | 
						||
            LogEvent(Consts.EventNotiPermRationaleResult, dict);
 | 
						||
        }
 | 
						||
 | 
						||
        #endregion
 | 
						||
 | 
						||
        #region 错误时间上报
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 上报错误事件
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="errorCode"></param>
 | 
						||
        /// <param name="err"></param>
 | 
						||
        /// <param name="country"></param>
 | 
						||
        /// <param name="network"></param>
 | 
						||
        public static void LogDevAudit(string errorCode, string err, string country = "", string network = "")
 | 
						||
        {
 | 
						||
            var dict = new Dictionary<string, object>()
 | 
						||
            {
 | 
						||
                [Consts.ParameterItemCategory] = "error_event",
 | 
						||
                [Consts.ParameterItemName] = errorCode,
 | 
						||
                ["err"] = err,
 | 
						||
                ["country"] = country,
 | 
						||
                ["network"] = network,
 | 
						||
            };
 | 
						||
            LogEvent(Consts.EventDevAudit, dict);
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
        #endregion
 | 
						||
        
 | 
						||
        #region Crashlytics 接口
 | 
						||
 | 
						||
        public static void CrashLog(string message)
 | 
						||
        {
 | 
						||
            if (!IsFirebaseReady) return;
 | 
						||
            CrashlyticsAgent.Log(message);
 | 
						||
        }
 | 
						||
        
 | 
						||
        public static void CrashException(string message)
 | 
						||
        {
 | 
						||
            if (!IsFirebaseReady) return;
 | 
						||
            CrashlyticsAgent.LogException(message);
 | 
						||
        }
 | 
						||
 | 
						||
        public static void CrashException(Exception ex)
 | 
						||
        {
 | 
						||
            if (!IsFirebaseReady) return;
 | 
						||
            CrashlyticsAgent.LogException(ex);
 | 
						||
        }
 | 
						||
 | 
						||
        public static void CrashCustomKeys(string key, string value)
 | 
						||
        {
 | 
						||
            if (!IsFirebaseReady) return;
 | 
						||
            CrashlyticsAgent.SetCustomKey(key, value);
 | 
						||
        }
 | 
						||
        #endregion
 | 
						||
 | 
						||
        #region 优先级设置
 | 
						||
        
 | 
						||
        
 | 
						||
        /// <summary>
 | 
						||
        /// 设置
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="priority"></param>
 | 
						||
        /// <param name="eventNames"></param>
 | 
						||
        public static void SetEventPriority(EventPriority priority, string[] eventNames)
 | 
						||
        {
 | 
						||
            if (!IsInitialSuccess)
 | 
						||
            {
 | 
						||
                UnityEngine.Debug.LogError($"{Tag} :: LogEvent {priority} :: Please call <GuruSDK.Start()> first, before you call <LogEvent>.");
 | 
						||
                return;
 | 
						||
            }
 | 
						||
 | 
						||
            if (Model.event_priorities == null) Model.event_priorities = new Dictionary<string, int>(10);
 | 
						||
 | 
						||
            int i = 0;
 | 
						||
            string evt = "";
 | 
						||
            while (i < eventNames.Length)
 | 
						||
            {
 | 
						||
                evt = eventNames[i];
 | 
						||
                if (!string.IsNullOrEmpty(evt))
 | 
						||
                {
 | 
						||
                    Model.event_priorities[evt] = (int)priority;
 | 
						||
                }
 | 
						||
                i++;
 | 
						||
            }
 | 
						||
        }
 | 
						||
 | 
						||
        public static void SetEventPriority(EventPriority priority, string eventName)
 | 
						||
        {
 | 
						||
            if (!IsInitialSuccess)
 | 
						||
            {
 | 
						||
                UnityEngine.Debug.LogError($"{Tag} :: LogEvent {priority} :: Please call <GuruSDK.Start()> first, before you call <LogEvent>.");
 | 
						||
                return;
 | 
						||
            }
 | 
						||
            
 | 
						||
            SetEventPriority(priority, new string[]{eventName});
 | 
						||
        }
 | 
						||
 | 
						||
        public static EventPriority GetEventPriority(string eventName)
 | 
						||
        {
 | 
						||
            if (Model.event_priorities != null 
 | 
						||
                && Model.event_priorities.TryGetValue(eventName, out int p))
 | 
						||
            {
 | 
						||
                return (EventPriority)p;
 | 
						||
            }
 | 
						||
            return EventPriority.Default;
 | 
						||
        }
 | 
						||
        
 | 
						||
        internal static int GetEventPriorityInt(string eventName)
 | 
						||
        {
 | 
						||
            return (int)GetEventPriority(eventName);
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// set all events as 'Emergence' event, which will be triggered immediately
 | 
						||
        /// </summary>
 | 
						||
        internal void SetSDKEventPriority()
 | 
						||
        {
 | 
						||
            SetEventPriority(EventPriority.Emergence, new []
 | 
						||
            {
 | 
						||
                Consts.EventTchAdRev001Impression,
 | 
						||
                Consts.EventTchAdRev02Impression,
 | 
						||
                Consts.EventLevelStart,
 | 
						||
                Consts.EventLevelEnd,
 | 
						||
            });
 | 
						||
        }
 | 
						||
 | 
						||
        #endregion
 | 
						||
    }
 | 
						||
} |