diff --git a/Runtime/GuruAnalytics/Runtime/Script/Experiment.meta b/Runtime/GuruAnalytics/Runtime/Script/Experiment.meta deleted file mode 100644 index 9b07101..0000000 --- a/Runtime/GuruAnalytics/Runtime/Script/Experiment.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: f6d79ccb59bc4a5791121a696d6695b0 -timeCreated: 1721722422 \ No newline at end of file diff --git a/Runtime/GuruAnalytics/Runtime/Script/GuruAnalytics.cs b/Runtime/GuruAnalytics/Runtime/Script/GuruAnalytics.cs index 930b53e..2a1866d 100644 --- a/Runtime/GuruAnalytics/Runtime/Script/GuruAnalytics.cs +++ b/Runtime/GuruAnalytics/Runtime/Script/GuruAnalytics.cs @@ -8,20 +8,6 @@ namespace Guru using UnityEngine; using System.Diagnostics.CodeAnalysis; - - /// - /// 自打点初始化配置 - /// - public class GuruAnalyticsInitConfig - { - public bool usingExtraSettings = false; - public string baseUrl = ""; - public string[] uploadIpAddress = null; - public bool enableErrorLog = false; - public bool isDebug = false; - } - - public class GuruAnalytics { // Plugin Version @@ -96,6 +82,9 @@ namespace Guru /// private readonly List _errorCodeList = new List(); private bool _enableErrorLog; + + private string _experimentGroupId; + public string ExperimentGroupId => _experimentGroupId; /// /// 启动日志错误上报 @@ -116,33 +105,42 @@ namespace Guru /// /// 初始化接口 /// - public static void Init(string appId, string deviceInfo, GuruAnalyticsInitConfig initConfig, Action onInitComplete) + public static void Init(string appId, string deviceInfo, Action onInitComplete, bool isDebug = false) { Debug.Log($"{Tag} --- Guru Analytics [{Version}] initialing..."); if (_instance == null) { _instance = new GuruAnalytics(); - + bool enableErrorLog = false; + string groupId = "not_set"; #if UNITY_ANDROID - if (initConfig.usingExtraSettings && Instance.Agent is AnalyticsAgentAndroid androidAgent) + enableErrorLog = true; + // 获取云控参数 + // TODO: 针对 GuruSDK 整体的云控值做一个分组的解决方案 + var guruInitParams = GuruAnalyticsConfigManager.GetInitParams(); + // 记录分组数据 + groupId = guruInitParams.groupId; + + if (guruInitParams.enabled && Instance.Agent is AnalyticsAgentAndroid androidAgent) { // 强制转换为 Android 的自打点初始化接口 androidAgent.InitAndroidConfig(appId, deviceInfo, - initConfig.baseUrl, initConfig.uploadIpAddress, // <--- Android 附加参数 - onInitComplete,initConfig.isDebug); + guruInitParams.baseUrl, guruInitParams.uploadIpAddress, // <--- Android 附加参数 + onInitComplete, isDebug); } else { // 外部(云控)如果关闭使用 Android 自打点附加参数, 则使用正常的启动接口 - _instance.Agent.Init(appId, deviceInfo, onInitComplete, initConfig.isDebug); + _instance.Agent.Init(appId, deviceInfo, onInitComplete, isDebug); } #else // iOS 使用正常的启动接口 - _instance.Agent.Init(appId, deviceInfo, onInitComplete, initConfig.isDebug); + _instance.Agent.Init(appId, deviceInfo, onInitComplete, isDebug); #endif - _instance.EnableErrorLog = initConfig.enableErrorLog; + _instance.EnableErrorLog = enableErrorLog; _instance._isReady = true; + _instance._experimentGroupId = groupId; } } diff --git a/Runtime/GuruAnalytics/Runtime/Script/GuruAnalyticsConfigManager.cs b/Runtime/GuruAnalytics/Runtime/Script/GuruAnalyticsConfigManager.cs new file mode 100644 index 0000000..891a2df --- /dev/null +++ b/Runtime/GuruAnalytics/Runtime/Script/GuruAnalyticsConfigManager.cs @@ -0,0 +1,274 @@ +namespace Guru +{ + using System; + using UnityEngine; + using Random = UnityEngine.Random; + using Firebase.RemoteConfig; + using System.Linq; + + public class GuruAnalyticsConfigManager + { + + private const string Tag = "[SDK][ANU][EXP]"; + + private static bool IsDebug + { + get + { +#if UNITY_EDITOR || DEBUG + return true; +#endif + return false; + } + } + + + private static string _localExperimentGroupId = ""; + private static string LocalExperimentGroupId + { + get + { + if (string.IsNullOrEmpty(_localExperimentGroupId)) + { + _localExperimentGroupId = PlayerPrefs.GetString(nameof(LocalExperimentGroupId), ""); + } + return _localExperimentGroupId; + } + set + { + _localExperimentGroupId = value; + PlayerPrefs.SetString(nameof(LocalExperimentGroupId), value); + PlayerPrefs.Save(); + } + } + + /** + * 原始数据 + private const string JSON_GROUP_B = + "{\"cap\":\"firebase|facebook|guru\",\"init_delay_s\":10,\"experiment\":\"B\",\"guru_upload_ip_address\":[\"13.248.248.135\", \"3.33.195.44\"]}"; + + private const string JSON_GROUP_C = + "{\"cap\":\"firebase|facebook|guru\",\"init_delay_s\":10,\"experiment\":\"C\",\"guru_upload_ip_address\":[\"34.107.185.54\"],\"guru_event_url\":\"https://collect3.saas.castbox.fm\"}"; + **/ + + /// + /// 解析 JSON 字符串 + /// + /// + /// + private static GuruAnalyticsExperimentData Parse(string json) + { + if (string.IsNullOrEmpty(json)) return null; + return JsonParser.ToObject(json); + } + + /// + /// 云控数据参数 + /// + public const string KEY_GURU_ANALYTICS_EXP = "guru_analytics_exp"; + + /// + /// 默认的本地配置 + /// + private const string DEFAULT_GURU_ANALYTICS_EXP = @"{ + ""enable"": true, + ""exps"": [{ + ""groupId"": ""B"", + ""baseUrl"": ""https://collect.saas.castbox.fm"", + ""uploadIpAddress"": [""13.248.248.135"", ""3.33.195.44""] + }, { + ""groupId"": ""C"", + ""baseUrl"": ""https://collect3.saas.castbox.fm"", + ""uploadIpAddress"": [""34.107.185.54""] + }] +}"; + + /// + /// 获取默认数据 + /// + private static GuruAnalyticsExperimentData DefaultData => Parse(DEFAULT_GURU_ANALYTICS_EXP); + + + /// + /// 在当前版本中,随机获取线上配置的值 + /// 若无法获取线上配置,则默认是 B 分组 + /// + /// + /// + /// + /// + internal static GuruInitParams GetInitParams() + { + var groupId = ""; + var baseUrl = ""; + string[] uploadIpAddress = null; + var isEnabled = true; + GuruAnalyticsExperimentConfig config; + + if(IsDebug) Debug.LogWarning($"{Tag} --- #0 Analytics EXP saved groupId :{LocalExperimentGroupId}"); + + // 拉取云控数据 + var json = ""; + if(FirebaseUtil.IsFirebaseInitialized && FirebaseRemoteConfig.DefaultInstance.Keys.Contains(KEY_GURU_ANALYTICS_EXP)) + json = FirebaseRemoteConfig.DefaultInstance.GetValue(GuruAnalyticsConfigManager.KEY_GURU_ANALYTICS_EXP).StringValue; + + if (string.IsNullOrEmpty(json)) + { + // 没有云控值,走本地的数据配置,随机取值 + if(IsDebug) Debug.LogWarning($"{Tag} --- #1 Analytics EXP json is Null -> using DefaultData"); + config = GetDefaultGuruAnalyticsExpConfig(); + } + else + { + // 有云控值,则直接使用云控的数据 + if(IsDebug) Debug.LogWarning($"{Tag} --- #2 Analytics EXP Try to get remote json -> {json}"); + var expData = Parse(json); + if (expData == null) + { + // 如果云控值为空,则使用本地分组 + if(IsDebug) Debug.LogWarning($"{Tag} --- #2.1 Analytics EXP Parse failed -> using DefaultData"); + config = GetDefaultGuruAnalyticsExpConfig(); + } + else + { + // 如果云控值不为空,但不可用,则直接使用默认分组 + if (!expData.enable) + { + Debug.LogWarning($"{Tag} --- #2.2 Analytics EXP Disabled -> using DefaultData"); + expData = DefaultData; + } + config = expData.GetFirstConfig(); + } + } + + // 最后取不到的话只能默认分组了 + if (config == null) { + config = DefaultData.GetFirstConfig(); // 默认是 B 组 + if(IsDebug) Debug.LogWarning($"{Tag} --- #3 Try get config is Null -> using Default config"); + } + + if (config != null) + { + baseUrl = config.baseUrl; + groupId = config.groupId; + uploadIpAddress = config.uploadIpAddress; + LocalExperimentGroupId = groupId; + } + else + { + isEnabled = false; + } + Debug.Log($"{Tag} --- Analytics EXP params:: groupId:{groupId} baseUrl:{baseUrl} uploadIpAddress:[{ (uploadIpAddress != null ? string.Join(",", uploadIpAddress) : "null")}]"); + + return new GuruInitParams() + { + groupId = groupId, + baseUrl = baseUrl, + uploadIpAddress = uploadIpAddress, + enabled = isEnabled + }; + } + + + + + private static GuruAnalyticsExperimentConfig GetDefaultGuruAnalyticsExpConfig() + { + GuruAnalyticsExperimentConfig config = null; + if (!string.IsNullOrEmpty(LocalExperimentGroupId)) + { + config = DefaultData.GetConfig(LocalExperimentGroupId); // 非空则取值 + } + else + { + config = DefaultData.GetRandomConfig(); // 随机获取本地的 Config + } + if(IsDebug) Debug.LogWarning($"{Tag} --- #1.1 using Default GroupId: {config.groupId}"); + return config; + } + } + + + /// + /// 实验数据主题 + /// + [Serializable] + internal class GuruAnalyticsExperimentData + { + public readonly bool enable = true; // 默认是打开的状态 + public GuruAnalyticsExperimentConfig[] experiments; // 实验列表 + public string ToJson() => JsonParser.ToJson(this); // 转换成 JSON 字符串 + + /// + /// 获取随机分组 + /// + /// + public GuruAnalyticsExperimentConfig GetRandomConfig() + { + if (experiments == null || experiments.Length == 0) return null; + return experiments[Random.Range(0, experiments.Length)]; + } + + /// + /// 根据分组名称获取分组 + /// + /// + /// + public GuruAnalyticsExperimentConfig GetConfig(string groupId) + { + foreach (var g in experiments) + { + if (g.groupId == groupId) return g; + } + + return null; + } + + /// + /// 获取首个配置 + /// + /// + public GuruAnalyticsExperimentConfig GetFirstConfig() + { + if (experiments != null && experiments.Length > 0) return experiments[0]; + return null; + } + + + /// + /// 分组是否存在 + /// + /// + /// + public bool IsGroupExists(string groupId) + { + foreach (var g in experiments) + { + if (g.groupId == groupId) return true; + } + return false; + } + + } + + /// + /// 实验配置 + /// + [Serializable] + internal class GuruAnalyticsExperimentConfig + { + public string groupId; + public string baseUrl; + public string[] uploadIpAddress; + } + + [Serializable] + internal class GuruInitParams + { + public string groupId; + public string baseUrl; + public string[] uploadIpAddress; + public bool enabled; + } + +} \ No newline at end of file diff --git a/Runtime/GuruAnalytics/Runtime/Script/GuruAnalyticsConfigManager.cs.meta b/Runtime/GuruAnalytics/Runtime/Script/GuruAnalyticsConfigManager.cs.meta new file mode 100644 index 0000000..971b1b9 --- /dev/null +++ b/Runtime/GuruAnalytics/Runtime/Script/GuruAnalyticsConfigManager.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a840d9218d324971b528c639ddfea270 +timeCreated: 1721722549 \ No newline at end of file diff --git a/Runtime/GuruAnalytics/Runtime/Script/Impl/AnalyticsAgentAndroid.cs b/Runtime/GuruAnalytics/Runtime/Script/Impl/AnalyticsAgentAndroid.cs index 4740d3d..9a4001e 100644 --- a/Runtime/GuruAnalytics/Runtime/Script/Impl/AnalyticsAgentAndroid.cs +++ b/Runtime/GuruAnalytics/Runtime/Script/Impl/AnalyticsAgentAndroid.cs @@ -1,19 +1,14 @@ - - -using System.Threading.Tasks; - namespace Guru { using System; using UnityEngine; - using System.Collections.Generic; public class AnalyticsAgentAndroid: IAnalyticsAgent { #if UNITY_ANDROID - public static readonly string AnalyticsClassName = "com.guru.unity.analytics.Analytics"; + private static readonly string AnalyticsClassName = "com.guru.unity.analytics.Analytics"; private static AndroidJavaClass _classAnalytics; private static AndroidJavaClass ClassAnalytics => _classAnalytics ??= new AndroidJavaClass(AnalyticsClassName); @@ -61,7 +56,7 @@ namespace Guru { if (ClassAnalytics != null) { - if(_isDebug) Debug.Log($"{GuruAnalytics.Tag} Android call static <{typeof(T).ToString()}> :: {methodName}"); + if(_isDebug) Debug.Log($"{GuruAnalytics.Tag} Android call static <{typeof(T)}> :: {methodName}"); return ClassAnalytics.CallStatic(methodName, args); } } @@ -86,14 +81,7 @@ namespace Guru /// public void Init(string appId, string deviceInfo, Action onInitComplete, bool isDebug = false) { - _isDebug = isDebug; - string bundleId = Application.identifier; - bool useWorker = true; - bool useCronet = false; - string baseUrl = ""; - string[] uploadIpAddress = null; - CallSDKInit(appId, deviceInfo, bundleId, baseUrl, uploadIpAddress , useWorker, useCronet, isDebug); // 调用接口 - onInitComplete?.Invoke(); + InitAndroidConfig(appId, deviceInfo, "", null, onInitComplete, isDebug); // 调用接口 } @@ -110,9 +98,7 @@ namespace Guru { _isDebug = isDebug; string bundleId = Application.identifier; - bool useWorker = true; - bool useCronet = false; - CallSDKInit(appId, deviceInfo, bundleId, baseUrl, uploadIpAddress , useWorker, useCronet, _isDebug); // 调用接口 + CallSDKInit(appId, deviceInfo, bundleId, baseUrl, uploadIpAddress , true, false, _isDebug); // 调用接口 onInitComplete?.Invoke(); } @@ -137,7 +123,7 @@ namespace Guru bool useCronet = false, bool isDebug = false) { - CallStatic("init", appId, deviceInfo, bundleId, isDebug, useWorker, useCronet, baseUrl, string.Join(",", uploadIpAddress)); // 调用接口 + CallStatic("init", appId, deviceInfo, bundleId, isDebug, useWorker, useCronet, baseUrl, string.Join(",", uploadIpAddress ?? Array.Empty())); // 调用接口 } diff --git a/Runtime/GuruCore/Runtime/Analytics/Analytics.Custom.cs b/Runtime/GuruCore/Runtime/Analytics/Analytics.Custom.cs index 29fe950..29c9f77 100644 --- a/Runtime/GuruCore/Runtime/Analytics/Analytics.Custom.cs +++ b/Runtime/GuruCore/Runtime/Analytics/Analytics.Custom.cs @@ -1,7 +1,6 @@ namespace Guru { using System; - using System.Collections.Generic; using Firebase.Analytics; using Firebase.Crashlytics; using Firebase.Extensions; @@ -21,18 +20,17 @@ namespace Guru private static DateTime _lastReportRateDate; //上次上报信息的日期 private static double _reportSuccessInterval; // 上报频率 - private const string VALUE_NOT_FOR_IOS = "not_support_for_ios"; - private const string VALUE_ONLY_FOR_IOS = "idfa_only_for_ios"; + // private const string VALUE_NOT_FOR_IOS = "not_support_for_ios"; + // private const string VALUE_ONLY_FOR_IOS = "idfa_only_for_ios"; - public static bool IsDebug { get; set; } = false; - private static readonly bool _isGuruAnalyticInitOnce = false; + private static bool IsDebug { get; set; } = false; + private static bool _isGuruAnalyticInitOnce = false; - public static void InitGuruAnalyticService(GuruAnalyticsInitConfig initConfig, string firebaseId) + public static void InitGuruAnalyticService(string firebaseId) { if (_isGuruAnalyticInitOnce) return; - - Debug.Log($"{TAG} --- InstallGuruAnalytics baseUrl: {initConfig.baseUrl} enableErrorLog: {initConfig.enableErrorLog} firebaseId:{firebaseId}"); - + _isGuruAnalyticInitOnce = true; + try { #if UNITY_EDITOR @@ -54,7 +52,11 @@ namespace Guru if(!string.IsNullOrEmpty(firebaseId)) GuruAnalytics.Instance.SetFirebaseId(firebaseId); // 在自打点初始化之前, 需要调用一下设置 FirebaseId - GuruAnalytics.Init(appId, deviceInfo, initConfig, OnGuruAnalyticsInitComplete); // Android 初始化 + GuruAnalytics.Init(appId, deviceInfo, () => + { + SetUserProperty(GuruAnalyticsConfig.KEY_GURU_ANALYTICS_EXP, GuruAnalytics.Instance.ExpGroupId); + OnGuruAnalyticsInitComplete(); + }, IsDebug); // Android 初始化 UpdateAllUserProperties(); } catch (Exception ex) diff --git a/Runtime/GuruCore/Runtime/Analytics/Analytics.cs b/Runtime/GuruCore/Runtime/Analytics/Analytics.cs index c89921e..b4bbcd0 100644 --- a/Runtime/GuruCore/Runtime/Analytics/Analytics.cs +++ b/Runtime/GuruCore/Runtime/Analytics/Analytics.cs @@ -59,12 +59,7 @@ namespace Guru /// /// 初始化打点模块 /// - /// - /// - /// - /// - /// - public static void Init(string baseUrl = "", string[] uploadIpAddress = null, bool isEnable = false, bool enableErrorLog = false, string firebaseId = "") + public static void Init() { if (_isInitOnce) return; _isInitOnce = true; diff --git a/Runtime/GuruCore/Runtime/Data.meta b/Runtime/GuruCore/Runtime/Data.meta deleted file mode 100644 index 57145eb..0000000 --- a/Runtime/GuruCore/Runtime/Data.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 005347f128bb460f9312778f93e39a9b -timeCreated: 1679986193 \ No newline at end of file diff --git a/Runtime/GuruCore/Runtime/Data/StandardProperties.cs b/Runtime/GuruCore/Runtime/Data/StandardProperties.cs deleted file mode 100644 index 787d04b..0000000 --- a/Runtime/GuruCore/Runtime/Data/StandardProperties.cs +++ /dev/null @@ -1,206 +0,0 @@ - -namespace Guru -{ - using System; - using System.Globalization; - using UnityEngine; - using System.IO; - - /// - /// 应用的全局标准属性 - /// - public static class StandardProperties - { - - #region 初始化 - - /// - /// 全局属性初始化 需要在应用启动时调用一次 - /// - public static void Init() - { - // 首次安装初始化各种参数 - if (IsFirstInstall) - { - string key = ""; - FirstInstallDate = DateTime.Now; - - key = nameof(SoundEffectEnabled); - if (!HasKey(key)) SoundEffectEnabled = true; - - key = nameof(VibrationEnabled); - if (!HasKey(key)) VibrationEnabled = true; - - key = nameof(FirstInstallVersion); - if (!HasKey(key)) FirstInstallVersion = FullVersion; - - Save(); - } - } - - private static bool IsFirstInstall => HasKey(nameof(FirstInstallDate)); - - private static bool HasKey(string key) => PlayerPrefs.HasKey(key); - - private static void Save() => PlayerPrefs.Save(); - - #endregion - - #region 标准属性值 - - /// - /// FirebaseId - /// - public static string FirebaseId - { - get => PlayerPrefs.GetString(nameof(FirebaseId), ""); - set { - if (!string.IsNullOrEmpty(value)) - { - PlayerPrefs.SetString(nameof(FirebaseId), value); - GuruAnalytics.Instance.SetFirebaseId(value); - } - } - } - - /// - /// Adjust ADID - /// - public static string AdjustId - { - get => PlayerPrefs.GetString(nameof(AdjustId), ""); - set { - if (!string.IsNullOrEmpty(value)) - { - PlayerPrefs.SetString(nameof(AdjustId), value); - GuruAnalytics.Instance.SetAdjustId(value); - } - } - } - - /// - /// Google ADID - /// - public static string GoogleAdId - { - get => PlayerPrefs.GetString(nameof(GoogleAdId), ""); - set { - if (!string.IsNullOrEmpty(value)) - { - PlayerPrefs.SetString(nameof(GoogleAdId), value); - GuruAnalytics.Instance.SetAdId(value); - } - } - } - - /// - /// 免费金币资源 - /// - public static int Coin - { - get => PlayerPrefs.GetInt(nameof(Coin), 0); - set => PlayerPrefs.SetInt(nameof(Coin), value); - } - - /// - /// 付费金币资源 - /// - public static int IAPCoin - { - get => PlayerPrefs.GetInt(nameof(IAPCoin), 0); - set => PlayerPrefs.SetInt(nameof(IAPCoin), value); - } - - /// - /// 用户累计购买次数 - /// - public static int PurchaseCount - { - get => PlayerPrefs.GetInt(nameof(PurchaseCount), 0); - set => PlayerPrefs.SetInt(nameof(PurchaseCount), value); - } - - /// - /// 首次安装日期 - /// - public static DateTime FirstInstallDate - { - get - { - var key = nameof(FirstInstallDate); - if (PlayerPrefs.HasKey(key)) - { - var value = PlayerPrefs.GetString(key, ""); - if (!string.IsNullOrEmpty(value)) return DateTime.Parse(value); - } - var now = DateTime.Now.ToUniversalTime(); - FirstInstallDate = now; - return now; - } - - set => PlayerPrefs.SetString(nameof(FirstInstallDate), - value.ToUniversalTime().ToString(CultureInfo.InvariantCulture)); - } - - /// - /// 首次安装版本号 - /// - public static string FirstInstallVersion - { - get => PlayerPrefs.GetString(nameof(FirstInstallVersion), ""); - set => PlayerPrefs.SetString(nameof(FirstInstallVersion), value); - } - - /// - /// 当前应用的版本 - /// - public static string AppVersion => Application.version; - - /// - /// 当前应用的版本Code - /// - public static string VersionCode - { - get - { - var path = $"{Application.streamingAssetsPath}/{GuruCore.VERSION_CODE_FILE}"; - if (File.Exists(path)) return File.ReadAllText(path); - return ""; - } - } - - /// - /// 完整版本号 - /// - public static string FullVersion - { - get - { - var code = VersionCode; - if (string.IsNullOrEmpty(code)) code = "unknown"; - return $"{AppVersion}-{code}"; - } - } - - /// - /// 音效开关 - /// - public static bool SoundEffectEnabled - { - get => PlayerPrefs.GetInt(nameof(SoundEffectEnabled), 0) == 1; - set => PlayerPrefs.SetInt(nameof(SoundEffectEnabled), value? 1: 0); - } - - /// - /// 震动开关 - /// - public static bool VibrationEnabled - { - get => PlayerPrefs.GetInt(nameof(VibrationEnabled), 0) == 1; - set => PlayerPrefs.SetInt(nameof(VibrationEnabled), value? 1: 0); - } - - #endregion - - } -} \ No newline at end of file diff --git a/Runtime/GuruCore/Runtime/Data/StandardProperties.cs.meta b/Runtime/GuruCore/Runtime/Data/StandardProperties.cs.meta deleted file mode 100644 index 66dffaf..0000000 --- a/Runtime/GuruCore/Runtime/Data/StandardProperties.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 2b2215a925974a3593ff2c6db2cf02fc -timeCreated: 1679986312 \ No newline at end of file