update: 修复自打点属性重复上报问题, 调整了 iOS 桥接 NULL 判定, 尽量对齐 Flutter 项目还原 Android 项目的上报事件逻辑

Signed-off-by: huyufei <yufei.hu@castbox.fm>
胡宇飞 2024-08-08 20:06:20 +08:00
parent b186489a54
commit cc5d36fea6
10 changed files with 261 additions and 159 deletions

View File

@ -451,7 +451,7 @@ namespace Guru.Editor
string strMon = nowDate.Month.ToString("00"); string strMon = nowDate.Month.ToString("00");
string strDay = nowDate.Day.ToString("00"); string strDay = nowDate.Day.ToString("00");
string strQuarter = ((nowDate.Hour * 60 + nowDate.Minute) / 15).ToString("00"); string strQuarter = ((nowDate.Hour * 60 + nowDate.Minute) / 15).ToString("00");
// 2024-08-01 08:00:00 to version string: 240801 // 2024-08-01 08:00:00 to version string: 24080130
string strBuildNumber = $"{strYear}{strMon}{strDay}{strQuarter}"; string strBuildNumber = $"{strYear}{strMon}{strDay}{strQuarter}";
return strBuildNumber; return strBuildNumber;
} }
@ -539,7 +539,7 @@ namespace Guru.Editor
string strMon = nowDate.Month.ToString("00"); string strMon = nowDate.Month.ToString("00");
string strDay = nowDate.Day.ToString("00"); string strDay = nowDate.Day.ToString("00");
string strQuarter = ((nowDate.Hour * 60 + nowDate.Minute) / 15).ToString("00"); string strQuarter = ((nowDate.Hour * 60 + nowDate.Minute) / 15).ToString("00");
// 2024-08-01 08:00:00 to version string: 240801 // 2024-08-01 00:00:00 to version string: 24080100
string strBuildNumber = $"{strYear}{strMon}{strDay}{strQuarter}"; string strBuildNumber = $"{strYear}{strMon}{strDay}{strQuarter}";
Debug.Log($"Get BuildVersion Code: {strBuildNumber}"); Debug.Log($"Get BuildVersion Code: {strBuildNumber}");
} }

View File

@ -1,7 +1,7 @@
// ============================================== // ==============================================
// U3DAnalytics 1.12.0 // U3DAnalytics 1.12.0
// Native Framework Version 0.3.6 // Native Framework Version 0.3.6
// update date: 2024-08-06 -- by HuYufei // update date: 2024-08-08 -- by HuYufei
// //
// Created by HuYufei on 2022/11/17. // Created by HuYufei on 2022/11/17.
// Copyright © 2022 guru. All rights reserved. // Copyright © 2022 guru. All rights reserved.
@ -68,11 +68,15 @@ NSString * const TchError = @"tch_error";
// 获取最终字符串 // 获取最终字符串
+(char*) finalChar: (NSString *) string +(char*) finalChar: (NSString *) string
{ {
if(string == NULL){
return NULL;
}
const char *tmpChar = [string cStringUsingEncoding:NSASCIIStringEncoding]; const char *tmpChar = [string cStringUsingEncoding:NSASCIIStringEncoding];
if (string == NULL) if(tmpChar == NULL){
return NULL; return NULL;
}
char* res = (char*)malloc(strlen(tmpChar) + 1); char* res = (char*)malloc(strlen(tmpChar) + 1);
strcpy(res, tmpChar); strcpy(res, tmpChar);
@ -86,15 +90,16 @@ NSString * const TchError = @"tch_error";
// 设置是否启用日志错误上报 // 设置是否启用日志错误上报
+(void) setEnableErrorLog: (bool) value{ +(void) setEnableErrorLog: (bool) value{
if(enableErrorLog == false && value){ if(value){
// 注册事件
enableErrorLog = value; enableErrorLog = true;
[GuruAnalytics registerInternalEventObserverWithReportCallback:^(NSInteger code, NSString * info){ [GuruAnalytics registerInternalEventObserverWithReportCallback:^(NSInteger code, NSString * info){
[U3DAnalytics onEventCallback:code andInfo:info]; [U3DAnalytics onEventCallback:code andInfo:info];
}]; }];
return;
} }
// 否则只赋值
enableErrorLog = value;
} }
@ -108,29 +113,33 @@ NSString * const TchError = @"tch_error";
}]; }];
} }
// 设置 BaseUrl // 设置 BaseUrl
+(void) setBaseUrl: (const char *) baseUrl{ +(void) setBaseUrl: (const char *) baseUrl{
if (baseUrl != nullptr && strlen(baseUrl) == 0) { if (baseUrl != nullptr && strlen(baseUrl) == 0) {
return; // baseUrl 为空 return; // baseUrl 为空
} }
[GuruAnalytics setEventsUploadEndPointWithHost:[U3DAnalytics charToString:baseUrl]]; [GuruAnalytics setEventsUploadEndPointWithHost:[U3DAnalytics charToString:baseUrl]];
} }
// 事件上报回调 // 事件上报回调
+(void) onEventCallback: (NSInteger)code andInfo:(NSString *) info{ +(void) onEventCallback: (NSInteger)code andInfo:(NSString *) info {
[U3DAnalytics sendMessage: [U3DAnalytics buildLogEventString: code andMessage:info]]; if(enableErrorLog == false) {
return; // 开关关闭不报
}
if(info == nil){
return; // 空字符串不报
}
NSString *msg = [U3DAnalytics buildLogEventString: code andMessage:info];
if(msg != NULL){
return;
}
[U3DAnalytics sendMessageToUnity: msg];
} }
// 构建数据 // 构建数据
+(NSString *) buildLogEventString: (NSInteger)status andMessage: (NSString *)msg{ +(NSString *) buildLogEventString: (NSInteger)status andMessage: (NSString *)msg{
NSString *jsonString = [NSString stringWithFormat: @"{\"action\":\"logger_error\",\"data\":{\"code\":%d,\"msg\":\"%@\"}}", (int)status, msg]; NSString *jsonString = [NSString stringWithFormat: @"{\"action\":\"logger_error\",\"data\":{\"code\":%d,\"msg\":\"%@\"}}", (int)status, msg];
NSLog(@"[ANI][Error]: %@", jsonString);
return jsonString; return jsonString;
} }
@ -158,7 +167,7 @@ NSString * const TchError = @"tch_error";
if([t isEqual: @"i"]){ if([t isEqual: @"i"]){
// int // int
[dict setValue:@([v integerValue]) forKey:k]; [dict setValue:@([v integerValue]) forKey:k];
}else if([t isEqual: @"d"]){ } else if ([t isEqual: @"d"]){
// double // double
[dict setValue:@([v doubleValue]) forKey:k]; [dict setValue:@([v doubleValue]) forKey:k];
} else { } else {
@ -211,26 +220,31 @@ NSString * const TchError = @"tch_error";
// 不存在 ad_paltform // 不存在 ad_paltform
[U3DAnalytics onTchErrorEvent:@"no_ad_platform" andRaw:json andOther:@""]; [U3DAnalytics onTchErrorEvent:@"no_ad_platform" andRaw:json andOther:@""];
} else { } else {
if(![[_platform stringValue] isEqual:@"appstore"]){
return;
}
// 非IAP订单 // 非IAP订单
if(![[_platform stringValue] isEqual:@"appstore"] ) if([U3DAnalytics isNullObject: _value] ){
{ [dict setValue: [NSNumber numberWithDouble: targetValue] forKey:@"value"];
if([U3DAnalytics isNullObject: _value] ){ [U3DAnalytics onTchErrorEvent:@"no_value" andRaw:json andOther:@""];
} else {
if([_value doubleValue] < targetValue){
[dict setValue: [NSNumber numberWithDouble: targetValue] forKey:@"value"]; [dict setValue: [NSNumber numberWithDouble: targetValue] forKey:@"value"];
[U3DAnalytics onTchErrorEvent:@"no_value" andRaw:json andOther:@""]; [U3DAnalytics onTchErrorEvent:@"value_error"
} else { andRaw:json andOther: [_value stringValue]];
if([_value doubleValue] < targetValue){
[dict setValue: [NSNumber numberWithDouble: targetValue] forKey:@"value"];
[U3DAnalytics onTchErrorEvent:@"value_error"
andRaw:json andOther: [_value stringValue]];
}
} }
} }
} }
} }
// 向Unity发送数据 // 向Unity发送数据
+(void) sendMessage: (NSString *)msg +(void) sendMessageToUnity: (NSString *)msg
{ {
if (msg == NULL) {
return;
}
// NSLog(@"--- unityInitSDK222: %@:%@", gameObjectName, callbackName); // NSLog(@"--- unityInitSDK222: %@:%@", gameObjectName, callbackName);
if(gameObjectName != nil && callbackName != nil){ if(gameObjectName != nil && callbackName != nil){
char *t1 = [U3DAnalytics finalChar: gameObjectName]; char *t1 = [U3DAnalytics finalChar: gameObjectName];
@ -277,7 +291,7 @@ NSString * const TchError = @"tch_error";
extern "C" { extern "C" {
// 请求GDPR // 初始化自打点
void unityInitAnalytics(const char *appId, const char *deviceInfo, bool isDebug, const char *baseUrl, const char *uploadIpAddressStr) void unityInitAnalytics(const char *appId, const char *deviceInfo, bool isDebug, const char *baseUrl, const char *uploadIpAddressStr)
{ {
// NSLog(@"--- [iOS] init Analytics libs"); // NSLog(@"--- [iOS] init Analytics libs");
@ -297,6 +311,7 @@ extern "C" {
// TODO: 当前的版本并不支持 uploadIpAddress, 后面的版本将 uploadIpAddressStr 转化为 Array<NSString> 传入接口 // TODO: 当前的版本并不支持 uploadIpAddress, 后面的版本将 uploadIpAddressStr 转化为 Array<NSString> 传入接口
} }
// 初始化回调对象和参数
void unityInitCallback(const char *gameObject, const char *method){ void unityInitCallback(const char *gameObject, const char *method){
// NSLog(@"--- unityInitSDK111: %s:%s", gameObject, method); // NSLog(@"--- unityInitSDK111: %s:%s", gameObject, method);
gameObjectName = [NSString stringWithUTF8String:gameObject]; gameObjectName = [NSString stringWithUTF8String:gameObject];
@ -308,7 +323,7 @@ extern "C" {
[GuruAnalytics setUserID:[U3DAnalytics charToString:uid]]; [GuruAnalytics setUserID:[U3DAnalytics charToString:uid]];
} }
// 设置用户ID // 设置Screen
void unitySetScreen(const char *screenName){ void unitySetScreen(const char *screenName){
[GuruAnalytics setScreen:[U3DAnalytics charToString:screenName]]; [GuruAnalytics setScreen:[U3DAnalytics charToString:screenName]];
} }
@ -349,7 +364,7 @@ extern "C" {
parameters:[U3DAnalytics buildDataWithJson:json andKey:evtName]]; // JSON转换 parameters:[U3DAnalytics buildDataWithJson:json andKey:evtName]]; // JSON转换
} }
// 上报事件 // 设置 Tch02 的上限值(即将废弃)
void unitySetTch02Value(const double value){ void unitySetTch02Value(const double value){
[U3DAnalytics setTch02MaxValue:value]; [U3DAnalytics setTch02MaxValue:value];
} }

View File

@ -1,3 +1,4 @@
// ReSharper disable ReplaceSubstringWithRangeIndexer
namespace Guru namespace Guru
{ {
using System; using System;
@ -78,14 +79,11 @@ namespace Guru
} }
} }
/// <summary>
/// 错误 code 表
/// </summary>
private readonly List<int> _errorCodeList = new List<int>();
private bool _enableErrorLog; private bool _enableErrorLog;
private string _experimentGroupId; private string _experimentGroupId;
public string ExperimentGroupId => _experimentGroupId; public string ExperimentGroupId => _experimentGroupId;
private DateTime _lastReportTime;
/// <summary> /// <summary>
/// 启动日志错误上报 /// 启动日志错误上报
@ -145,6 +143,7 @@ namespace Guru
// 初始化参数 // 初始化参数
Agent.Init(appId, deviceInfo, baseUrl, uploadIpAddress, onInitComplete, isDebug); Agent.Init(appId, deviceInfo, baseUrl, uploadIpAddress, onInitComplete, isDebug);
_lastReportTime = new DateTime(1970, 1, 1);
_isReady = true; _isReady = true;
Debug.Log($"{Tag} --- Guru Analytics [{Version}] initialized."); Debug.Log($"{Tag} --- Guru Analytics [{Version}] initialized.");
Debug.Log($"{Tag} --- GroupId: {groupId}"); Debug.Log($"{Tag} --- GroupId: {groupId}");
@ -403,7 +402,7 @@ namespace Guru
{ {
if (string.IsNullOrEmpty(raw)) return; if (string.IsNullOrEmpty(raw)) return;
if (!raw.Contains($"\"{ActionName}\"")) return; // 不对其他行为的日志进行过滤 if (!raw.Contains($"\"{ActionName}\"")) return; // 不对其他行为的日志进行过滤
ParseWithJson(raw); ParseJsonAndSendEvent(raw);
} }
/// <summary> /// <summary>
@ -411,72 +410,64 @@ namespace Guru
/// </summary> /// </summary>
/// <param name="code"></param> /// <param name="code"></param>
/// <param name="errorInfo"></param> /// <param name="errorInfo"></param>
private void OnLoggerErrorEvent(int code, string errorInfo = "") /// <param name="category"></param>
/// <param name="extra"></param>
private void ReportDevAuditEvent(int code, string errorInfo = "", string category = "", Dictionary<string, object> extra = null)
{ {
// Debug.Log($"{Tag} --- OnLoggerErrorEvent: code:{code}\t info:{errorInfo}"); // Debug.Log($"{Tag} --- OnLoggerErrorEvent: code:{code}\t info:{errorInfo}");
var codeString = ((AnalyticsCode)code).ToString(); var codeString = ((AnalyticsCode)code).ToString();
if (string.IsNullOrEmpty(codeString) || codeString == AnalyticsCode.Unknown.ToString()) codeString = $"ErrorCode:{code}"; if (string.IsNullOrEmpty(codeString)) codeString = $"ErrorCode:{code}";
if (string.IsNullOrEmpty(errorInfo)) errorInfo = "Empty";
Dictionary<string, dynamic> parameters = new Dictionary<string, dynamic>() var parameters = new Dictionary<string, dynamic>()
{ {
{"item_category", "error_event"},
{"item_name", codeString}, {"item_name", codeString},
{"country", IPMConfig.IPM_COUNTRY_CODE}, {"country", IPMConfig.IPM_COUNTRY_CODE},
{"network", Application.internetReachability.ToString()}, {"network", Application.internetReachability.ToString()},
{"exp", _experimentGroupId}
}; };
if (!string.IsNullOrEmpty(category))
{
parameters[Analytics.ParameterItemCategory] = category;
}
int len = 96;
if (errorInfo.Length > len)
errorInfo = errorInfo.TrimStart().Substring(0, len);
if (!string.IsNullOrEmpty(errorInfo)) if (!string.IsNullOrEmpty(errorInfo))
parameters["err"] = errorInfo;
if (extra != null)
{ {
// if (errorInfo.Contains("\"")) errorInfo = errorInfo.Replace("\"", "\\\""); foreach (var kvp in extra)
{
int len = 96; parameters[kvp.Key] = kvp.Value;
if (errorInfo.Length > len) errorInfo = errorInfo.TrimStart().Substring(0, len); }
} }
else
{
errorInfo = "empty error info";
}
parameters["err"] = errorInfo;
Debug.Log($"{Tag} ------ ErrorLogInfo:: code:{codeString}\tinfo:{errorInfo}");
// Only for firebase GA // Only for firebase GA
Analytics.TrackEvent("dev_audit", parameters, new Analytics.EventSetting() { EnableFirebaseAnalytics = true }); Analytics.TrackEvent("dev_audit", parameters, new Analytics.EventSetting() { EnableFirebaseAnalytics = true });
} }
private void ParseJsonAndSendEvent(string json)
private void ParseWithJson(string json)
{ {
Debug.Log($"{Tag} ------ ParseWithJson: json:\n{json}"); Debug.Log($"{Tag} ------ ParseWithJson: json:\n{json}");
int code = (int)AnalyticsCode.Unknown; int code = (int)AnalyticsCode.UNITY_INTERNAL_ERROR;
string info = json; string info = json;
try try
{ {
var dict = JsonConvert.DeserializeObject<JObject>(json); var dict = JsonConvert.DeserializeObject<JObject>(json);
if(dict != null && dict.TryGetValue("data", out var jData)) if (dict == null || !dict.TryGetValue("data", out var jData)) return;
{ var j = jData.Value<JObject>();
var j = jData.Value<JObject>(); if (j == null || !j.TryGetValue("code", out var jCode)) return;
if (j != null && j.TryGetValue("code", out var jCode)) code = jCode.Value<int>();
{ if (!j.TryGetValue("msg", out var jMsg)) return;
code = jCode.Value<int>(); info = jMsg.Value<string>();
ReportWithCodeAndInfo(code, info);
if (j.TryGetValue("msg", out var jMsg))
{
info = jMsg.Value<string>();
}
else
{
info = $"wrong msg format: {json}";
}
}
}
else
{
info = "no data property";
}
ReportCodeInfo(code, info);
} }
catch (Exception) catch (Exception)
{ {
@ -487,85 +478,141 @@ namespace Guru
// Debug.Log($"{Tag} --- {info}"); // Debug.Log($"{Tag} --- {info}");
Analytics.LogCrashlytics(json, false); Analytics.LogCrashlytics(json, false);
Analytics.LogCrashlytics(info); Analytics.LogCrashlytics(info);
ReportCodeInfo(code, info); ReportWithCodeAndInfo(code, info);
} }
} }
private void ReportCodeInfo(int code, string info) /// <summary>
/// 上报异常
/// 上报条件:上报总数 > 30 条, 上报成功率小于 0.7, 且间隔 5 分钟
/// Native 已经处理数量和成功率判断
/// </summary>
/// <param name="code"></param>
/// <param name="info"></param>
private void ReportWithCodeAndInfo(int code, string info)
{ {
if (Agent == null) return;
if (Application.internetReachability == NetworkReachability.NotReachable) return; // 网络不可用时不上报
ReportAnalyticsAudit(); // 上报
// 源码https://github.com/castbox/flutter_jigsort/blob/3.2.0V2/lib/data/jigsort_compliance_protocol.dart
var ac = (AnalyticsCode)code; var ac = (AnalyticsCode)code;
Debug.Log($"{Tag} ------ Get Code And Info: code:{code}[{ac}] \tinfo:{info}"); Debug.Log($"{Tag} ------ Get Code And Info: code:{code}[{ac}] \tinfo:{info}");
bool canCatch = false;
switch (ac) switch (ac)
{ {
case AnalyticsCode.Unknown: case AnalyticsCode.UNITY_INTERNAL_ERROR: // -1
case AnalyticsCode.DELETE_EXPIRED: ReportUnityErrorEvent(code, info);
case AnalyticsCode.UPLOAD_FAIL: break;
case AnalyticsCode.NETWORK_LOST: // case AnalyticsCode.DELETE_EXPIRED:
case AnalyticsCode.CRONET_INIT_FAIL: case AnalyticsCode.UPLOAD_FAIL: //14
case AnalyticsCode.CRONET_INIT_EXCEPTION: ReportUploadFailEvent(code, info);
case AnalyticsCode.ERROR_API: break;
case AnalyticsCode.ERROR_RESPONSE: // case AnalyticsCode.NETWORK_LOST:
case AnalyticsCode.ERROR_CACHE_CONTROL: // case AnalyticsCode.CRONET_INIT_FAIL:
case AnalyticsCode.ERROR_DELETE_EXPIRED: // case AnalyticsCode.CRONET_INIT_EXCEPTION:
case AnalyticsCode.ERROR_LOAD_MARK: // case AnalyticsCode.ERROR_API:
case AnalyticsCode.ERROR_DNS: // case AnalyticsCode.ERROR_RESPONSE:
case AnalyticsCode.ERROR_ZIP: // case AnalyticsCode.ERROR_CACHE_CONTROL:
case AnalyticsCode.ERROR_DNS_CACHE: // case AnalyticsCode.ERROR_DELETE_EXPIRED:
case AnalyticsCode.CRONET_INTERCEPTOR: case AnalyticsCode.ERROR_LOAD_MARK: // 105
case AnalyticsCode.EVENT_LOOKUP: ReportRuntimeErrorEvent(code, info);
case AnalyticsCode.EVENT_SESSION_ACTIVE: break;
canCatch = true; // case AnalyticsCode.ERROR_DNS:
// case AnalyticsCode.ERROR_ZIP:
// case AnalyticsCode.ERROR_DNS_CACHE:
// case AnalyticsCode.CRONET_INTERCEPTOR:
// case AnalyticsCode.ERROR_SESSION_START_ERROR:
case AnalyticsCode.EVENT_LOOKUP: // 1003
ReportDNSErrorEvent(code, info);
break;
case AnalyticsCode.EVENT_SESSION_ACTIVE: // 1004
ReportSessionActiveErrorEvent(code, info);
break; break;
} }
if (!canCatch && code is > 100 and <= 200) }
{
// 100 < code <= 200
canCatch = true;
}
if (_errorCodeList != null && _errorCodeList.Count > 0) private int _reportUploadFailCount = 0;
{ /// <summary>
if (_errorCodeList[0] == -1) /// 上报失败事件 (14)
{ /// </summary>
canCatch = true; /// <param name="code"></param>
} /// <param name="info"></param>
else private void ReportUploadFailEvent(int code, string info)
{ {
canCatch = _errorCodeList.Contains(code); if (Agent.GetEventCountTotal() < 50) return; // 数量太少不报
} if ((float)Agent.GetEventCountUploaded() / Agent.GetEventCountTotal() > 0.6f) return; // 成功率太高也不报
} if (_reportUploadFailCount >= 5) return; // N 次之后不再上报
ReportDevAuditEvent(code, info);
_reportUploadFailCount++;
}
if(canCatch) OnLoggerErrorEvent(code, info); private int _reportRuntimeExceptionTimes = 0;
// 105
private void ReportRuntimeErrorEvent(int code, string info)
{
if (_reportRuntimeExceptionTimes >= 5) return; // N 次之后不再上报
ReportDevAuditEvent(code, info);
_reportRuntimeExceptionTimes++;
}
// 1003
private void ReportDNSErrorEvent(int code, string info)
{
ReportDevAuditEvent(code, info, "ga_dns");
}
// 1004
private void ReportSessionActiveErrorEvent(int code, string info)
{
ReportDevAuditEvent(code, info, "session_active");
}
// -1
private void ReportUnityErrorEvent(int code, string info)
{
ReportDevAuditEvent(code, info, "unity");
}
// 上报 Snapshot 数据
private void ReportAnalyticsAudit()
{
if(DateTime.UtcNow - _lastReportTime < TimeSpan.FromMinutes(5)) // 5 分钟内只上报一次
return;
var snapshot = Agent.GetAuditSnapshot();
if (string.IsNullOrEmpty(snapshot)) return; // 空字段不报
var data = JsonParser.ToObject<Dictionary<string, object>>(snapshot);
if (data == null) return; // 解析失败不报
// 上报事件
ReportDevAuditEvent(0, "","analytics_audit", data);
_lastReportTime = DateTime.UtcNow;
} }
#endregion #endregion
#region UNIT_TEST #region UNIT_TEST
#if UNITY_EDITOR #if UNITY_EDITOR
public static void TestOnCallback(string msg) public static void TestOnCallback(string msg)
{ {
Instance.OnSDKCallback(msg); Instance.OnSDKCallback(msg);
} }
#endif #endif
#endregion #endregion
} }
/// <summary> /// <summary>
/// 网络状态枚举 /// 网络状态枚举
/// 详见 guru_analytics 库 guru.core.analytics.handler.AnalyticsCode 类
/// </summary> /// </summary>
public enum AnalyticsCode public enum AnalyticsCode
{ {
Unknown = -1, UNITY_INTERNAL_ERROR = -1, // unity 内部错误
DELETE_EXPIRED = 12, // 删除过期事件 DELETE_EXPIRED = 12, // 删除过期事件
UPLOAD_FAIL = 14, // 上报事件失败 UPLOAD_FAIL = 14, // 上报事件失败
@ -582,6 +629,7 @@ namespace Guru
ERROR_ZIP = 107, // zip 错误 ERROR_ZIP = 107, // zip 错误
ERROR_DNS_CACHE = 108, // zip 错误 ERROR_DNS_CACHE = 108, // zip 错误
CRONET_INTERCEPTOR = 109, // cronet拦截器 CRONET_INTERCEPTOR = 109, // cronet拦截器
ERROR_SESSION_START_ERROR = 110,
EVENT_LOOKUP = 1003, EVENT_LOOKUP = 1003,
EVENT_SESSION_ACTIVE = 1004, EVENT_SESSION_ACTIVE = 1004,

View File

@ -69,6 +69,7 @@ namespace Guru
/// <summary> /// <summary>
/// 默认的本地配置 /// 默认的本地配置
/// 2024-08-08 经后台确认,只保留 B 组C 组已经被废弃
/// </summary> /// </summary>
private const string DEFAULT_GURU_ANALYTICS_EXP = @"{ private const string DEFAULT_GURU_ANALYTICS_EXP = @"{
""enable"": true, ""enable"": true,
@ -76,12 +77,7 @@ namespace Guru
""groupId"": ""B"", ""groupId"": ""B"",
""baseUrl"": ""https://collect.saas.castbox.fm"", ""baseUrl"": ""https://collect.saas.castbox.fm"",
""uploadIpAddress"": [""13.248.248.135"", ""3.33.195.44""], ""uploadIpAddress"": [""13.248.248.135"", ""3.33.195.44""],
""enableErrorLog"": true ""enableErrorLog"": false
}, {
""groupId"": ""C"",
""baseUrl"": ""https://collect3.saas.castbox.fm"",
""uploadIpAddress"": [""34.107.185.54""],
""enableErrorLog"": true
}] }]
}"; }";

View File

@ -21,5 +21,8 @@ namespace Guru
void ReportEventSuccessRate(); // 上报任务成功率 void ReportEventSuccessRate(); // 上报任务成功率
void SetTch02Value(double value); // 设置太极02数值 void SetTch02Value(double value); // 设置太极02数值
void InitCallback(string objName, string method); // 设置回调对象参数 void InitCallback(string objName, string method); // 设置回调对象参数
int GetEventCountTotal(); // 获取事件总数
int GetEventCountUploaded(); // 获取成功上报的事件数量
string GetAuditSnapshot(); // 获取 AuditSnapshot 字段
} }
} }

View File

@ -14,7 +14,6 @@ namespace Guru
#endif #endif
private static bool _isDebug = false; private static bool _isDebug = false;
public static string BaseUrl = "";
#region 工具方法 #region 工具方法
@ -171,6 +170,11 @@ namespace Guru
CallStatic("setEnableErrorLog", _enableErrorLog); CallStatic("setEnableErrorLog", _enableErrorLog);
} }
} }
public int GetEventCountTotal() => CallStatic<int>("getEventCountAll");
public int GetEventCountUploaded() => CallStatic<int>("getEventCountUploaded");
public string GetAuditSnapshot() => CallStatic<string>("getAuditSnapshot");
#endregion #endregion
} }

View File

@ -29,6 +29,8 @@ namespace Guru
[DllImport(K_INTERNAL)] private static extern void unitySetTch02Value(double value); [DllImport(K_INTERNAL)] private static extern void unitySetTch02Value(double value);
[DllImport(K_INTERNAL)] private static extern void unitySetEnableErrorLog(bool value); [DllImport(K_INTERNAL)] private static extern void unitySetEnableErrorLog(bool value);
[DllImport(K_INTERNAL)] private static extern void unityInitCallback(string objName, string method); [DllImport(K_INTERNAL)] private static extern void unityInitCallback(string objName, string method);
[DllImport(K_INTERNAL)] private static extern int unityGetEventsCountAll();
[DllImport(K_INTERNAL)] private static extern int unityGetEventsCountUploaded();
#endif #endif
private static bool _isDebug = false; private static bool _isDebug = false;
@ -163,6 +165,29 @@ namespace Guru
public static void TestCrashEvent()=> unityTestUnrecognizedSelectorCrash(); public static void TestCrashEvent()=> unityTestUnrecognizedSelectorCrash();
#endif #endif
public int GetEventCountTotal()
{
#if UNITY_IOS
return unityGetEventsCountAll();
#endif
return 1;
}
public int GetEventCountUploaded()
{
#if UNITY_IOS
return unityGetEventsCountUploaded();
#endif
return 0;
}
public string GetAuditSnapshot()
{
// TODOiOS 原生类并未实现此接口
return "";
}
#endregion #endregion
} }

View File

@ -24,9 +24,12 @@ namespace Guru
Debug.Log($"{TAG} EnableErrorLog:<color=orange>{value}</color>"); Debug.Log($"{TAG} EnableErrorLog:<color=orange>{value}</color>");
_enableErrorLog = value; _enableErrorLog = value;
} }
} }
private int _eventTotalCount = 0;
private int _eventSuccessCount = 0;
public void Init(string appId, string deviceInfo, string baseUrl, string[] uploadIpAddress, Action onInitComplete, bool isDebug = false) public void Init(string appId, string deviceInfo, string baseUrl, string[] uploadIpAddress, Action onInitComplete, bool isDebug = false)
{ {
#if UNITY_EDITOR #if UNITY_EDITOR
@ -148,6 +151,12 @@ namespace Guru
Debug.Log($"{TAG} LogEvent: GuruAnalytics:<color=orange>{eventName} ({priority})</color> Properties:\n{sb.ToString()}"); Debug.Log($"{TAG} LogEvent: GuruAnalytics:<color=orange>{eventName} ({priority})</color> Properties:\n{sb.ToString()}");
} }
} }
_eventTotalCount++;
if (UnityEngine.Random.Range(0, 10) < 8)
{
_eventSuccessCount++;
}
} }
public void ReportEventSuccessRate() public void ReportEventSuccessRate()
@ -160,6 +169,9 @@ namespace Guru
Debug.Log($"{TAG} Tch02MaxValue: {value}"); Debug.Log($"{TAG} Tch02MaxValue: {value}");
} }
public int GetEventCountTotal() => _eventTotalCount;
public int GetEventCountUploaded() => _eventSuccessCount;
public string GetAuditSnapshot() => "";
#region Editor Test API #region Editor Test API

View File

@ -543,113 +543,112 @@ namespace Guru
//-------------------- 设置所有的属性 ----------------------- //-------------------- 设置所有的属性 -----------------------
public void ReportUid(string uid) public void ReportUid(string uid)
{ {
var prop = new MidWarePropertyUid(uid); var prop = new MidWarePropertyUid(uid);
_propertyMap.TryAdd(prop.key, prop); _propertyMap[prop.key] = prop;
prop.Report(); prop.Report();
} }
public void ReportBLevel(string bLevel) public void ReportBLevel(string bLevel)
{ {
var prop = new MidWarePropertyBLevel(bLevel); var prop = new MidWarePropertyBLevel(bLevel);
_propertyMap.TryAdd(prop.key, prop); _propertyMap[prop.key] = prop;
prop.Report(); prop.Report();
} }
public void ReportBPlay(string bPlay) public void ReportBPlay(string bPlay)
{ {
var prop = new MidWarePropertyBPlay(bPlay); var prop = new MidWarePropertyBPlay(bPlay);
_propertyMap.TryAdd(prop.key, prop); _propertyMap[prop.key] = prop;
prop.Report(); prop.Report();
} }
public void ReportAnalyticsExperimentGroup(string groupName) public void ReportAnalyticsExperimentGroup(string groupName)
{ {
var prop = new MidWarePropertyAnalyticsExperimentGroup(groupName); var prop = new MidWarePropertyAnalyticsExperimentGroup(groupName);
_propertyMap.TryAdd(prop.key, prop); _propertyMap[prop.key] = prop;
prop.Report(); prop.Report();
} }
public void ReportSignUpMethod(string methodName) public void ReportSignUpMethod(string methodName)
{ {
var prop = new MidWarePropertySignUpMethod(methodName); var prop = new MidWarePropertySignUpMethod(methodName);
_propertyMap.TryAdd(prop.key, prop); _propertyMap[prop.key] = prop;
prop.Report(); prop.Report();
} }
public void ReportDeviceId(string deviceId) public void ReportDeviceId(string deviceId)
{ {
var prop = new MidWarePropertyDeviceId(deviceId); var prop = new MidWarePropertyDeviceId(deviceId);
_propertyMap.TryAdd(prop.key, prop); _propertyMap[prop.key] = prop;
prop.Report(); prop.Report();
} }
public void ReportFirstOpenTime(string firstOpenTime) public void ReportFirstOpenTime(string firstOpenTime)
{ {
var prop = new MidWarePropertyFirstOpenTime(firstOpenTime); var prop = new MidWarePropertyFirstOpenTime(firstOpenTime);
_propertyMap.TryAdd(prop.key, prop); _propertyMap[prop.key] = prop;
prop.Report(); prop.Report();
} }
public void ReportIsIapUser(bool isIapUser) public void ReportIsIapUser(bool isIapUser)
{ {
var prop = new MidWarePropertyIsIapUser(isIapUser); var prop = new MidWarePropertyIsIapUser(isIapUser);
_propertyMap.TryAdd(prop.key, prop); _propertyMap[prop.key] = prop;
prop.Report(); prop.Report();
} }
public void ReportNetworkStatus(string networkStatus) public void ReportNetworkStatus(string networkStatus)
{ {
var prop = new MidWarePropertyNetwork(networkStatus); var prop = new MidWarePropertyNetwork(networkStatus);
_propertyMap.TryAdd(prop.key, prop); _propertyMap[prop.key] = prop;
prop.Report(); prop.Report();
} }
public void ReportAdjustId(string adjustId) public void ReportAdjustId(string adjustId)
{ {
var prop = new MidWarePropertyAdjustId(adjustId); var prop = new MidWarePropertyAdjustId(adjustId);
_propertyMap.TryAdd(prop.key, prop); _propertyMap[prop.key] = prop;
prop.Report(); prop.Report();
} }
public void ReportAttStatus(string attStatus) public void ReportAttStatus(string attStatus)
{ {
var prop = new MidWarePropertyAttStatus(attStatus); var prop = new MidWarePropertyAttStatus(attStatus);
_propertyMap.TryAdd(prop.key, prop); _propertyMap[prop.key] = prop;
prop.Report(); prop.Report();
} }
public void ReportNotiPerm(string notiPerm) public void ReportNotiPerm(string notiPerm)
{ {
var prop = new MidWarePropertyNotiPerm(notiPerm); var prop = new MidWarePropertyNotiPerm(notiPerm);
_propertyMap.TryAdd(prop.key, prop); _propertyMap[prop.key] = prop;
prop.Report(); prop.Report();
} }
public void ReportAndroidId(string androidId) public void ReportAndroidId(string androidId)
{ {
var prop = new MidWarePropertyAndroidId(androidId); var prop = new MidWarePropertyAndroidId(androidId);
_propertyMap.TryAdd(prop.key, prop); _propertyMap[prop.key] = prop;
prop.Report(); prop.Report();
} }
public void ReportGoogleAdId(string googleAdId) public void ReportGoogleAdId(string googleAdId)
{ {
var prop = new MidWarePropertyGoogleAdId(googleAdId); var prop = new MidWarePropertyGoogleAdId(googleAdId);
_propertyMap.TryAdd(prop.key, prop); _propertyMap[prop.key] = prop;
prop.Report(); prop.Report();
} }
public void ReportIDFV(string idfv) public void ReportIDFV(string idfv)
{ {
var prop = new MidWarePropertyIDFV(idfv); var prop = new MidWarePropertyIDFV(idfv);
_propertyMap.TryAdd(prop.key, prop); _propertyMap[prop.key] = prop;
prop.Report(); prop.Report();
} }
public void ReportIDFA(string idfa) public void ReportIDFA(string idfa)
{ {
var prop = new MidWarePropertyIDFA(idfa); var prop = new MidWarePropertyIDFA(idfa);
_propertyMap.TryAdd(prop.key, prop); _propertyMap[prop.key] = prop;
prop.Report(); prop.Report();
} }