com.guru.unity.sdk.core/Runtime/Keywords/Runtime/KeywordsManager.cs

429 lines
13 KiB
C#

using System;
using System.Collections.Generic;
using System.Globalization;
using Firebase.Crashlytics;
using UnityEngine;
namespace Guru
{
/// <summary>
/// MAX KeyWord管理器
/// </summary>
public class KeywordsManager
{
public const string Version = "0.4.0";
public static readonly string Tag = "[KWM]";
public static readonly DateTime BaseDate = new DateTime(1970, 1, 1).ToUniversalTime();
/// <summary>
/// 日期转时间戳 (Ticks)
/// </summary>
/// <param name="date"></param>
/// <returns></returns>
public static long DateToTicks(DateTime date) => (date.ToUniversalTime() - BaseDate).Ticks;
/// <summary>
/// 时间戳 (Ticks) 转日期
/// </summary>
/// <param name="stamp"></param>
/// <returns></returns>
public static DateTime TicksToDate(long stamp) => BaseDate.AddTicks(stamp);
/// <summary>
/// 首次安装时间
/// </summary>
public static DateTime FirstInstallDate
{
get
{
var key = nameof(FirstInstallDate);
if (PlayerPrefs.HasKey(key))
{
var value = PlayerPrefs.GetString(key, "");
if (!string.IsNullOrEmpty(value) && long.TryParse(value, out var ticks))
{
return TicksToDate(ticks);
}
}
Debug.Log($"{Tag} Can't find first install date, using NOW!!");
FirstInstallDate = UTCNow;
return UTCNow;
}
set => PlayerPrefs.SetString(nameof(FirstInstallDate), DateToTicks(value).ToString(new CultureInfo("en")));
}
public static DateTime UTCNow => DateTime.Now.ToUniversalTime();
/// <summary>
/// 当前的LT
/// </summary>
public static int CurrentLT => Instance?.GetLTValue() ?? -1;
private static KeywordsManager _instance;
public static KeywordsManager Instance {
get {
if(_instance == null) _instance = new KeywordsManager();
return _instance;
}
}
public static readonly List<int> ItDays = new List<int>()
{
0, 1, 2, 3, 4, 5, 6, 14, 30, 60, 90, 120, 180
};
private static string _badsWaterfallName = "null";
private static string _iadsWaterfallName = "null";
private static string _radsWaterfallName = "null";
// Banner 瀑布流名称
public static string BadsWaterfallName => _badsWaterfallName;
// Interstital 瀑布流名称
public static string IadsWaterfallName => _iadsWaterfallName;
// Reward 瀑布流名称
public static string RadsWaterfallName => _radsWaterfallName;
/// <summary>
/// 是否具有用户标签
/// </summary>
public static bool IsUserMarked
{
get
{
if(!PlayerPrefs.HasKey(nameof(IsUserMarked))) return false;
return !string.IsNullOrEmpty(PlayerPrefs.GetString(nameof(IsUserMarked), ""));
}
set => PlayerPrefs.SetString(nameof(IsUserMarked), value? "marked": "");
}
/// <summary>
/// 是否是付费用户
/// 在用户执行任何一次购买的时候需要更新该接口
/// </summary>
public static bool IsIapUser
{
get => PlayerPrefs.GetInt(nameof(IsIapUser), 0) == 1;
set => PlayerPrefs.SetInt(nameof(IsIapUser), value ? 1 : 0);
}
#region 初始化
/// <summary>
/// 安装服务
/// </summary>
/// <param name="isIAPUser">标记用户是否为付费用户</param>
/// <param name="finishedLevels">当前完成关卡数. 不做关卡过滤时. 默认赋值0即可</param>
public static void Install(bool isIAPUser = false, int finishedLevels = 0)
{
try
{
// 首先检查用户属性
if (finishedLevels > 0 && !CheckTargetUser(finishedLevels))
{
Debug.Log($"{Tag} User is not new installing. Skip user....");
return;
}
if (KeywordsConfig.Enabled()) // 云控开关, 如果不需要云控, 可注释此行
{
Instance.Init();
if (!IsIapUser && isIAPUser) IsIapUser = true; // 判断未赋值时, 更新此变量
}
}
catch (Exception e)
{
Crashlytics.LogException(e);
}
}
/// <summary>
/// 初始化
/// </summary>
private void Init()
{
var lt = GetLTValue(); // 初始化立即更新LT
Debug.Log($"{Tag} is inited. LT:{lt}"); // 显示启动日志
SetupMaxCallbacks();
}
private void SetupMaxCallbacks()
{
MaxSdkCallbacks.OnSdkInitializedEvent += OnMaxSdkInitializedCallBack;
MaxSdkCallbacks.Banner.OnAdLoadedEvent += OnBannerLoaded;
MaxSdkCallbacks.Banner.OnAdLoadFailedEvent += OnBannerLoadFailed;
MaxSdkCallbacks.Interstitial.OnAdLoadedEvent += OnInterstitialLoaded;
MaxSdkCallbacks.Interstitial.OnAdLoadFailedEvent += OnInterstitialLoadFailed;
MaxSdkCallbacks.Rewarded.OnAdLoadedEvent += OnRewardedLoaded;
MaxSdkCallbacks.Rewarded.OnAdLoadFailedEvent += OnRewardedLoadedFailed;
}
/// <summary>
/// 检查是否是目标用户
/// </summary>
/// <param name="finishedLevels"></param>
/// <returns></returns>
public static bool CheckTargetUser(int finishedLevels)
{
// 如果用户已经被标记, 则继续上报
if (IsUserMarked) return true;
// 用户未标记, 则根据完成的关卡判断用户是否是新用户
// 新用户则给标记
if (finishedLevels <= 2)
{
IsUserMarked = true;
Debug.Log($"{Tag} User is new installing. Mark user as target....");
return true;
}
// 用户未标记且已经开始过游戏了, 则视为老用户
return false;
}
#endregion
#region Keywords
/// <summary>
/// 上报关键字
/// </summary>
private void ReportKeyword()
{
var lt = GetLTValue();
bool paid = IsIapUser;
string version = Application.version;
var keywords = new [] { $"lt:{lt}", $"paid:{paid.ToString().ToLower()}", $"app_version:{version}" };
SetMaxKeywords(keywords);
}
/// <summary>
/// 获取LT值
/// </summary>
/// <returns></returns>
private int GetLTValue(int days = 0)
{
// Debug.Log($"{Tag} Get first install date: {FirstInstallDate}");
if(0 == days) days = (int)(UTCNow - FirstInstallDate).TotalDays;
if(days > ItDays[ItDays.Count-1]) return ItDays[ItDays.Count-1];
for (int i = 0; i < ItDays.Count; i++)
{
if (days < ItDays[i])
{
if (i > 0)
{
return ItDays[i - 1];
}
else
{
return ItDays[0];
}
}
}
return ItDays[0];
}
/// <summary>
/// 设置Keywords
/// </summary>
/// <param name="keywords"></param>
private void SetMaxKeywords(string[] keywords)
{
if ( null == keywords ) return;
Debug.Log($"{Tag} set keywords: [{string.Join(",", keywords)}]");
MaxSdk.TargetingData.ClearAll();
MaxSdk.TargetingData.Keywords = keywords;
}
#endregion
#region WaterfallName
/// <summary>
/// Banner WaterfallInfo
/// </summary>
/// <param name="waterfallInfo"></param>
private void OnGetBannerWaterInfo(MaxSdkBase.WaterfallInfo waterfallInfo)
{
_badsWaterfallName = waterfallInfo.Name;
}
/// <summary>
/// IV WaterfallInfo
/// </summary>
/// <param name="waterfallInfo"></param>
private void OnGetIVWaterInfo(MaxSdkBase.WaterfallInfo waterfallInfo)
{
_iadsWaterfallName = waterfallInfo.Name;
}
/// <summary>
/// RV WaterfallInfo
/// </summary>
/// <param name="waterfallInfo"></param>
private void OnGetRVWaterInfo(MaxSdkBase.WaterfallInfo waterfallInfo)
{
_radsWaterfallName = waterfallInfo.Name;
}
#endregion
#region Max 生命周期监控
private void OnMaxSdkInitializedCallBack(MaxSdkBase.SdkConfiguration obj)
{
ReportKeyword();
}
private void OnBannerLoaded(string adUnitId, MaxSdkBase.AdInfo adInfo)
{
OnGetBannerWaterInfo(adInfo.WaterfallInfo);
}
private void OnBannerLoadFailed(string adUnitId, MaxSdkBase.ErrorInfo errorInfo)
{
OnGetBannerWaterInfo(errorInfo.WaterfallInfo);
}
private void OnRewardedLoadedFailed(string adUnitId, MaxSdkBase.ErrorInfo errorInfo)
{
OnGetRVWaterInfo(errorInfo.WaterfallInfo);
}
private void OnRewardedLoaded(string adUnitId, MaxSdkBase.AdInfo adInfo)
{
OnGetRVWaterInfo(adInfo.WaterfallInfo);
}
private void OnInterstitialLoadFailed(string adUnitId, MaxSdkBase.ErrorInfo errorInfo)
{
OnGetIVWaterInfo(errorInfo.WaterfallInfo);
}
private void OnInterstitialLoaded(string adUnitId, MaxSdkBase.AdInfo adInfo)
{
OnGetIVWaterInfo(adInfo.WaterfallInfo);
}
#endregion
#region Unit Test
#if UNITY_EDITOR
public static void DebugKeywords(string[] kw) => Instance?.SetMaxKeywords(kw);
/// <summary>
/// LT取值测试
/// </summary>
[UnityEditor.MenuItem("Test/Test LT")]
public static void TestFetchLT()
{
var days = 0;
days = 0;
Debug.Log($"Days: {days} => TL: {Instance.GetLTValue(days)}");
days = 1;
Debug.Log($"Days: {days} => TL: {Instance.GetLTValue(days)}");
days = 2;
Debug.Log($"Days: {days} => TL: {Instance.GetLTValue(days)}");
days = 5;
Debug.Log($"Days: {days} => TL: {Instance.GetLTValue(days)}");
days = 12;
Debug.Log($"Days: {days} => TL: {Instance.GetLTValue(days)}");
days = 15;
Debug.Log($"Days: {days} => TL: {Instance.GetLTValue(days)}");
days = 55;
Debug.Log($"Days: {days} => TL: {Instance.GetLTValue(days)}");
days = 80;
Debug.Log($"Days: {days} => TL: {Instance.GetLTValue(days)}");
days = 179;
Debug.Log($"Days: {days} => TL: {Instance.GetLTValue(days)}");
days = 365;
Debug.Log($"Days: {days} => TL: {Instance.GetLTValue(days)}");
}
#endif
#endregion
}
#region 云控参数
[Serializable]
internal class KeywordsConfig
{
public const string KEY = "keywords_config";
public bool enable = false;
/// <summary>
/// 获取功能是否开启
/// </summary>
/// <returns></returns>
public static bool Enabled()
{
var cfg = Get();
return cfg?.enable ?? false;
}
public static KeywordsConfig Get()
{
try
{
string raw = GetRemoteValue(KEY);
if (!string.IsNullOrEmpty(raw))
{
return JsonUtility.FromJson<KeywordsConfig>(raw);
}
}
catch (Exception e)
{
Debug.LogError(e);
Crashlytics.LogException(e);
}
return new KeywordsConfig(); // 返回默认值
}
/// <summary>
/// 获取Online值
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
private static string GetRemoteValue(string key)
{
var remote = Firebase.RemoteConfig.FirebaseRemoteConfig.DefaultInstance;
if (remote != null)
{
try
{
return remote.GetValue(key).StringValue;
}
catch (Exception e)
{
Crashlytics.LogException(e);
}
}
return "";
}
}
#endregion
}