429 lines
13 KiB
C#
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
|
|
|
|
} |