update: 修复自打点属性重复上报问题, 调整了 iOS 桥接 NULL 判定, 尽量对齐 Flutter 项目还原 Android 项目的上报事件逻辑
Signed-off-by: huyufei <yufei.hu@castbox.fm>
							parent
							
								
									b186489a54
								
							
						
					
					
						commit
						cc5d36fea6
					
				|  | @ -451,7 +451,7 @@ namespace Guru.Editor | |||
| 		    string strMon = nowDate.Month.ToString("00"); | ||||
| 		    string strDay = nowDate.Day.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}"; | ||||
| 		    return strBuildNumber; | ||||
| 	    } | ||||
|  | @ -539,7 +539,7 @@ namespace Guru.Editor | |||
| 		    string strMon = nowDate.Month.ToString("00"); | ||||
| 		    string strDay = nowDate.Day.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}"; | ||||
| 		    Debug.Log($"Get BuildVersion Code: {strBuildNumber}"); | ||||
| 	    } | ||||
|  |  | |||
										
											Binary file not shown.
										
									
								
							|  | @ -1,7 +1,7 @@ | |||
| // ============================================== | ||||
| //  U3DAnalytics 1.12.0 | ||||
| //  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. | ||||
| //  Copyright © 2022 guru. All rights reserved. | ||||
|  | @ -68,11 +68,15 @@ NSString * const TchError = @"tch_error"; | |||
| // 获取最终字符串 | ||||
| +(char*) finalChar: (NSString *) string | ||||
| { | ||||
|     const char *tmpChar = [string cStringUsingEncoding:NSASCIIStringEncoding]; | ||||
|         | ||||
|     if (string == NULL) | ||||
|     if(string == NULL){ | ||||
|         return NULL; | ||||
|     } | ||||
|      | ||||
|     const char *tmpChar = [string cStringUsingEncoding:NSASCIIStringEncoding]; | ||||
|      | ||||
|     if(tmpChar == NULL){ | ||||
|         return NULL; | ||||
|     } | ||||
|     char* res = (char*)malloc(strlen(tmpChar) + 1); | ||||
|     strcpy(res, tmpChar); | ||||
|      | ||||
|  | @ -86,15 +90,16 @@ NSString * const TchError = @"tch_error"; | |||
| 
 | ||||
| // 设置是否启用日志错误上报 | ||||
| +(void) setEnableErrorLog: (bool) value{ | ||||
|     if(enableErrorLog == false && value){ | ||||
|          | ||||
|         enableErrorLog = value; | ||||
|          | ||||
|     if(value){ | ||||
|         // 注册事件 | ||||
|         enableErrorLog = true; | ||||
|         [GuruAnalytics registerInternalEventObserverWithReportCallback:^(NSInteger code, NSString * info){ | ||||
|             [U3DAnalytics onEventCallback:code andInfo:info]; | ||||
|         }]; | ||||
|          | ||||
|         return; | ||||
|     } | ||||
|     // 否则只赋值 | ||||
|     enableErrorLog = value; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -108,29 +113,33 @@ NSString * const TchError = @"tch_error"; | |||
|             }]; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| // 设置 BaseUrl | ||||
| +(void) setBaseUrl: (const char *) baseUrl{ | ||||
|      | ||||
|     if (baseUrl != nullptr && strlen(baseUrl) == 0) { | ||||
|         return; // baseUrl 为空 | ||||
|     } | ||||
|      | ||||
|     [GuruAnalytics setEventsUploadEndPointWithHost:[U3DAnalytics charToString:baseUrl]]; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| // 事件上报回调 | ||||
| +(void) onEventCallback: (NSInteger)code  andInfo:(NSString *) info{ | ||||
|     [U3DAnalytics sendMessage:  [U3DAnalytics buildLogEventString: code  andMessage:info]]; | ||||
| +(void) onEventCallback: (NSInteger)code  andInfo:(NSString *) 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 *jsonString = [NSString stringWithFormat: @"{\"action\":\"logger_error\",\"data\":{\"code\":%d,\"msg\":\"%@\"}}", (int)status, msg]; | ||||
|     NSLog(@"[ANI][Error]: %@", jsonString); | ||||
|     return jsonString; | ||||
| } | ||||
| 
 | ||||
|  | @ -158,7 +167,7 @@ NSString * const TchError = @"tch_error"; | |||
|         if([t isEqual: @"i"]){ | ||||
|             // int | ||||
|             [dict setValue:@([v integerValue]) forKey:k]; | ||||
|         }else if([t isEqual: @"d"]){ | ||||
|         } else if ([t isEqual: @"d"]){ | ||||
|             // double | ||||
|             [dict setValue:@([v doubleValue]) forKey:k]; | ||||
|         } else { | ||||
|  | @ -211,26 +220,31 @@ NSString * const TchError = @"tch_error"; | |||
|         // 不存在 ad_paltform | ||||
|         [U3DAnalytics onTchErrorEvent:@"no_ad_platform" andRaw:json andOther:@""]; | ||||
|     } else { | ||||
|         if(![[_platform stringValue] isEqual:@"appstore"]){ | ||||
|             return; | ||||
|         } | ||||
|          | ||||
|         // 非IAP订单 | ||||
|         if(![[_platform stringValue] isEqual:@"appstore"] ) | ||||
|         { | ||||
|             if([U3DAnalytics isNullObject: _value] ){ | ||||
|         if([U3DAnalytics isNullObject: _value] ){ | ||||
|             [dict setValue: [NSNumber numberWithDouble: targetValue] forKey:@"value"]; | ||||
|             [U3DAnalytics onTchErrorEvent:@"no_value" andRaw:json andOther:@""]; | ||||
|         } else { | ||||
|             if([_value doubleValue] < targetValue){ | ||||
|                 [dict setValue: [NSNumber numberWithDouble: targetValue] forKey:@"value"]; | ||||
|                 [U3DAnalytics onTchErrorEvent:@"no_value" andRaw:json andOther:@""]; | ||||
|             } else { | ||||
|                 if([_value doubleValue] < targetValue){ | ||||
|                     [dict setValue: [NSNumber numberWithDouble: targetValue] forKey:@"value"]; | ||||
|                     [U3DAnalytics onTchErrorEvent:@"value_error" | ||||
|                                            andRaw:json andOther: [_value stringValue]]; | ||||
|                 } | ||||
|                 [U3DAnalytics onTchErrorEvent:@"value_error" | ||||
|                                        andRaw:json andOther: [_value stringValue]]; | ||||
|             } | ||||
|         } | ||||
|          | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // 向Unity发送数据 | ||||
| +(void) sendMessage: (NSString *)msg | ||||
| +(void) sendMessageToUnity: (NSString *)msg | ||||
| { | ||||
|     if (msg == NULL) { | ||||
|         return; | ||||
|     } | ||||
|     // NSLog(@"--- unityInitSDK222: %@:%@", gameObjectName, callbackName); | ||||
|     if(gameObjectName != nil && callbackName != nil){ | ||||
|         char *t1 = [U3DAnalytics finalChar: gameObjectName]; | ||||
|  | @ -277,7 +291,7 @@ NSString * const TchError = @"tch_error"; | |||
| 
 | ||||
| extern "C" { | ||||
|   | ||||
|     // 请求GDPR | ||||
|     // 初始化自打点 | ||||
|     void unityInitAnalytics(const char *appId, const char *deviceInfo, bool isDebug, const char *baseUrl, const char *uploadIpAddressStr) | ||||
|     { | ||||
| //        NSLog(@"--- [iOS] init Analytics libs"); | ||||
|  | @ -296,7 +310,8 @@ extern "C" { | |||
|         // 设置 uploadIpAddress | ||||
|         // TODO: 当前的版本并不支持 uploadIpAddress, 后面的版本将 uploadIpAddressStr 转化为 Array<NSString> 传入接口 | ||||
|     } | ||||
| 
 | ||||
|      | ||||
|     // 初始化回调对象和参数 | ||||
|     void unityInitCallback(const char *gameObject, const char *method){ | ||||
|         // NSLog(@"--- unityInitSDK111: %s:%s", gameObject, method); | ||||
|         gameObjectName = [NSString stringWithUTF8String:gameObject]; | ||||
|  | @ -308,7 +323,7 @@ extern "C" { | |||
|         [GuruAnalytics setUserID:[U3DAnalytics charToString:uid]]; | ||||
|     } | ||||
| 
 | ||||
|     // 设置用户ID | ||||
|     // 设置Screen | ||||
|     void unitySetScreen(const char *screenName){ | ||||
|         [GuruAnalytics setScreen:[U3DAnalytics charToString:screenName]]; | ||||
|     } | ||||
|  | @ -349,7 +364,7 @@ extern "C" { | |||
|                      parameters:[U3DAnalytics buildDataWithJson:json andKey:evtName]]; // JSON转换 | ||||
|     } | ||||
|      | ||||
|     // 上报事件 | ||||
|     // 设置 Tch02 的上限值(即将废弃) | ||||
|     void unitySetTch02Value(const double value){ | ||||
|         [U3DAnalytics setTch02MaxValue:value]; | ||||
|     } | ||||
|  |  | |||
|  | @ -1,3 +1,4 @@ | |||
| // ReSharper disable ReplaceSubstringWithRangeIndexer | ||||
| namespace Guru | ||||
| { | ||||
|     using System; | ||||
|  | @ -78,14 +79,11 @@ namespace Guru | |||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 错误 code 表 | ||||
|         /// </summary> | ||||
|         private readonly List<int> _errorCodeList = new List<int>(); | ||||
|         private bool _enableErrorLog; | ||||
| 
 | ||||
|         private string _experimentGroupId; | ||||
|         public string ExperimentGroupId => _experimentGroupId; | ||||
|         private DateTime _lastReportTime; | ||||
|          | ||||
|         /// <summary> | ||||
|         /// 启动日志错误上报 | ||||
|  | @ -144,7 +142,8 @@ namespace Guru | |||
|              | ||||
|             // 初始化参数 | ||||
|             Agent.Init(appId, deviceInfo, baseUrl, uploadIpAddress, onInitComplete, isDebug); | ||||
|              | ||||
| 
 | ||||
|             _lastReportTime = new DateTime(1970, 1, 1); | ||||
|             _isReady = true; | ||||
|             Debug.Log($"{Tag} --- Guru Analytics [{Version}] initialized."); | ||||
|             Debug.Log($"{Tag} --- GroupId: {groupId}"); | ||||
|  | @ -403,7 +402,7 @@ namespace Guru | |||
|         { | ||||
|             if (string.IsNullOrEmpty(raw)) return; | ||||
|             if (!raw.Contains($"\"{ActionName}\"")) return; // 不对其他行为的日志进行过滤 | ||||
|             ParseWithJson(raw); | ||||
|             ParseJsonAndSendEvent(raw); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|  | @ -411,72 +410,64 @@ namespace Guru | |||
|         /// </summary> | ||||
|         /// <param name="code"></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}"); | ||||
|              | ||||
|             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}, | ||||
|                 {"country", IPMConfig.IPM_COUNTRY_CODE}, | ||||
|                 {"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)) | ||||
|                 parameters["err"] = errorInfo; | ||||
| 
 | ||||
|             if (extra != null) | ||||
|             { | ||||
|                 // if (errorInfo.Contains("\"")) errorInfo = errorInfo.Replace("\"", "\\\""); | ||||
|                  | ||||
|                 int len = 96; | ||||
|                 if (errorInfo.Length > len) errorInfo = errorInfo.TrimStart().Substring(0, len); | ||||
|                 foreach (var kvp in extra) | ||||
|                 { | ||||
|                     parameters[kvp.Key] = kvp.Value; | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 errorInfo = "empty error info"; | ||||
|             } | ||||
|              | ||||
|             parameters["err"] = errorInfo; | ||||
|              | ||||
|             Debug.Log($"{Tag} ------ ErrorLogInfo:: code:{codeString}\tinfo:{errorInfo}"); | ||||
|              | ||||
|             // Only for firebase GA | ||||
|             Analytics.TrackEvent("dev_audit", parameters, new Analytics.EventSetting() { EnableFirebaseAnalytics = true }); | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         private void ParseWithJson(string json) | ||||
|          | ||||
|         private void ParseJsonAndSendEvent(string json) | ||||
|         { | ||||
|             Debug.Log($"{Tag} ------ ParseWithJson: json:\n{json}"); | ||||
|              | ||||
|             int code = (int)AnalyticsCode.Unknown; | ||||
|             int code = (int)AnalyticsCode.UNITY_INTERNAL_ERROR; | ||||
|             string info = json; | ||||
|             try | ||||
|             { | ||||
|                 var dict = JsonConvert.DeserializeObject<JObject>(json); | ||||
|                 if(dict != null && dict.TryGetValue("data", out var jData)) | ||||
|                 { | ||||
|                     var j = jData.Value<JObject>(); | ||||
|                     if (j != null && j.TryGetValue("code", out var jCode)) | ||||
|                     { | ||||
|                         code = jCode.Value<int>(); | ||||
|                          | ||||
|                         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); | ||||
|                 if (dict == null || !dict.TryGetValue("data", out var jData)) return; | ||||
|                 var j = jData.Value<JObject>(); | ||||
|                 if (j == null || !j.TryGetValue("code", out var jCode)) return; | ||||
|                 code = jCode.Value<int>(); | ||||
|                 if (!j.TryGetValue("msg", out var jMsg)) return; | ||||
|                 info = jMsg.Value<string>(); | ||||
|                 ReportWithCodeAndInfo(code, info); | ||||
|             } | ||||
|             catch (Exception) | ||||
|             { | ||||
|  | @ -487,85 +478,141 @@ namespace Guru | |||
|                 // Debug.Log($"{Tag} --- {info}"); | ||||
|                 Analytics.LogCrashlytics(json, false); | ||||
|                 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; | ||||
|             Debug.Log($"{Tag} ------ Get Code And Info: code:{code}[{ac}]  \tinfo:{info}"); | ||||
|             bool canCatch = false; | ||||
|             switch (ac) | ||||
|             { | ||||
|                 case AnalyticsCode.Unknown: | ||||
|                 case AnalyticsCode.DELETE_EXPIRED: | ||||
|                 case AnalyticsCode.UPLOAD_FAIL: | ||||
|                 case AnalyticsCode.NETWORK_LOST: | ||||
|                 case AnalyticsCode.CRONET_INIT_FAIL: | ||||
|                 case AnalyticsCode.CRONET_INIT_EXCEPTION: | ||||
|                 case AnalyticsCode.ERROR_API: | ||||
|                 case AnalyticsCode.ERROR_RESPONSE: | ||||
|                 case AnalyticsCode.ERROR_CACHE_CONTROL: | ||||
|                 case AnalyticsCode.ERROR_DELETE_EXPIRED: | ||||
|                 case AnalyticsCode.ERROR_LOAD_MARK: | ||||
|                 case AnalyticsCode.ERROR_DNS: | ||||
|                 case AnalyticsCode.ERROR_ZIP: | ||||
|                 case AnalyticsCode.ERROR_DNS_CACHE: | ||||
|                 case AnalyticsCode.CRONET_INTERCEPTOR: | ||||
|                 case AnalyticsCode.EVENT_LOOKUP: | ||||
|                 case AnalyticsCode.EVENT_SESSION_ACTIVE:     | ||||
|                     canCatch = true; | ||||
|                 case AnalyticsCode.UNITY_INTERNAL_ERROR:        // -1 | ||||
|                     ReportUnityErrorEvent(code, info); | ||||
|                     break; | ||||
|                 // case AnalyticsCode.DELETE_EXPIRED: | ||||
|                 case AnalyticsCode.UPLOAD_FAIL:                 //14 | ||||
|                     ReportUploadFailEvent(code, info); | ||||
|                     break; | ||||
|                 // case AnalyticsCode.NETWORK_LOST: | ||||
|                 // case AnalyticsCode.CRONET_INIT_FAIL: | ||||
|                 // case AnalyticsCode.CRONET_INIT_EXCEPTION: | ||||
|                 // case AnalyticsCode.ERROR_API: | ||||
|                 // case AnalyticsCode.ERROR_RESPONSE: | ||||
|                 // case AnalyticsCode.ERROR_CACHE_CONTROL: | ||||
|                 // case AnalyticsCode.ERROR_DELETE_EXPIRED: | ||||
|                 case AnalyticsCode.ERROR_LOAD_MARK:             // 105 | ||||
|                     ReportRuntimeErrorEvent(code, info); | ||||
|                     break; | ||||
|                 // 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; | ||||
|             } | ||||
| 
 | ||||
|             if (!canCatch && code is > 100 and <= 200) | ||||
|             { | ||||
|                 // 100 < code <= 200 | ||||
|                 canCatch = true; | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         private int _reportUploadFailCount = 0; | ||||
|         /// <summary> | ||||
|         /// 上报失败事件 (14) | ||||
|         /// </summary> | ||||
|         /// <param name="code"></param> | ||||
|         /// <param name="info"></param> | ||||
|         private void ReportUploadFailEvent(int code, string info) | ||||
|         { | ||||
|             if (Agent.GetEventCountTotal() < 50) return; // 数量太少不报 | ||||
|             if ((float)Agent.GetEventCountUploaded() / Agent.GetEventCountTotal() > 0.6f) return; // 成功率太高也不报 | ||||
|             if (_reportUploadFailCount >= 5) return; // N 次之后不再上报 | ||||
|             ReportDevAuditEvent(code, info); | ||||
|             _reportUploadFailCount++; | ||||
|         } | ||||
| 
 | ||||
|             if (_errorCodeList != null && _errorCodeList.Count > 0) | ||||
|             { | ||||
|                 if (_errorCodeList[0] == -1) | ||||
|                 { | ||||
|                     canCatch = true; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     canCatch = _errorCodeList.Contains(code); | ||||
|                 } | ||||
|             } | ||||
|         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"); | ||||
|         } | ||||
| 
 | ||||
|             if(canCatch) OnLoggerErrorEvent(code, info); | ||||
|         // 上报 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 | ||||
| 
 | ||||
|         #region UNIT_TEST | ||||
| 
 | ||||
| 
 | ||||
|          | ||||
| #if UNITY_EDITOR | ||||
| 
 | ||||
|         public static void TestOnCallback(string msg) | ||||
|         { | ||||
|             Instance.OnSDKCallback(msg); | ||||
|         } | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
|         #endregion | ||||
|          | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|      | ||||
|     /// <summary> | ||||
|     /// 网络状态枚举 | ||||
|     /// 详见 guru_analytics 库 guru.core.analytics.handler.AnalyticsCode 类 | ||||
|     /// </summary> | ||||
|     public enum AnalyticsCode | ||||
|     { | ||||
|         Unknown = -1, | ||||
|         UNITY_INTERNAL_ERROR = -1,     // unity 内部错误 | ||||
|          | ||||
|         DELETE_EXPIRED = 12,            // 删除过期事件 | ||||
|         UPLOAD_FAIL = 14,               // 上报事件失败 | ||||
|  | @ -582,6 +629,7 @@ namespace Guru | |||
|         ERROR_ZIP = 107,                // zip 错误 | ||||
|         ERROR_DNS_CACHE = 108,          // zip 错误 | ||||
|         CRONET_INTERCEPTOR = 109,       // cronet拦截器 | ||||
|         ERROR_SESSION_START_ERROR = 110,  | ||||
|          | ||||
|         EVENT_LOOKUP = 1003, | ||||
|         EVENT_SESSION_ACTIVE = 1004, | ||||
|  |  | |||
|  | @ -69,6 +69,7 @@ namespace Guru | |||
|          | ||||
|         /// <summary> | ||||
|         /// 默认的本地配置 | ||||
|         /// 2024-08-08 经后台确认,只保留 B 组,C 组已经被废弃  | ||||
|         /// </summary> | ||||
|         private const string DEFAULT_GURU_ANALYTICS_EXP = @"{
 | ||||
| 	""enable"": true, | ||||
|  | @ -76,12 +77,7 @@ namespace Guru | |||
| 		""groupId"": ""B"", | ||||
| 		""baseUrl"": ""https://collect.saas.castbox.fm"", | ||||
| 		""uploadIpAddress"": [""13.248.248.135"", ""3.33.195.44""], | ||||
|         ""enableErrorLog"": true | ||||
| 	}, { | ||||
| 		""groupId"": ""C"", | ||||
| 		""baseUrl"": ""https://collect3.saas.castbox.fm"", | ||||
| 		""uploadIpAddress"": [""34.107.185.54""], | ||||
|         ""enableErrorLog"": true | ||||
|         ""enableErrorLog"": false | ||||
| 	}] | ||||
| }";
 | ||||
|          | ||||
|  |  | |||
|  | @ -21,5 +21,8 @@ namespace Guru | |||
|         void ReportEventSuccessRate(); // 上报任务成功率 | ||||
|         void SetTch02Value(double value); // 设置太极02数值 | ||||
|         void InitCallback(string objName, string method); // 设置回调对象参数 | ||||
|         int GetEventCountTotal(); // 获取事件总数 | ||||
|         int GetEventCountUploaded(); // 获取成功上报的事件数量 | ||||
|         string GetAuditSnapshot(); // 获取 AuditSnapshot 字段 | ||||
|     } | ||||
| } | ||||
|  | @ -14,7 +14,6 @@ namespace Guru | |||
| 
 | ||||
| #endif | ||||
|         private static bool _isDebug = false; | ||||
|         public static string BaseUrl = ""; | ||||
|              | ||||
|         #region 工具方法 | ||||
|          | ||||
|  | @ -171,6 +170,11 @@ namespace Guru | |||
|                 CallStatic("setEnableErrorLog", _enableErrorLog);   | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         public int GetEventCountTotal() => CallStatic<int>("getEventCountAll"); | ||||
|         public int GetEventCountUploaded() => CallStatic<int>("getEventCountUploaded"); | ||||
|         public string GetAuditSnapshot() => CallStatic<string>("getAuditSnapshot"); | ||||
|          | ||||
|         #endregion | ||||
|          | ||||
|     } | ||||
|  |  | |||
|  | @ -29,6 +29,8 @@ namespace Guru | |||
|         [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 unityInitCallback(string objName, string method); | ||||
|         [DllImport(K_INTERNAL)] private static extern int unityGetEventsCountAll(); | ||||
|         [DllImport(K_INTERNAL)] private static extern int unityGetEventsCountUploaded(); | ||||
| #endif | ||||
|          | ||||
|         private static bool _isDebug = false;     | ||||
|  | @ -162,7 +164,30 @@ namespace Guru | |||
|         // iOS 测试用事件 | ||||
|         public static void TestCrashEvent()=> unityTestUnrecognizedSelectorCrash(); | ||||
| #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() | ||||
|         { | ||||
|             // TODO:iOS 原生类并未实现此接口 | ||||
|             return ""; | ||||
|         } | ||||
| 
 | ||||
|         #endregion | ||||
|          | ||||
|     } | ||||
|  |  | |||
|  | @ -24,9 +24,12 @@ namespace Guru | |||
|                 Debug.Log($"{TAG} EnableErrorLog:<color=orange>{value}</color>"); | ||||
|                 _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) | ||||
|         { | ||||
| #if UNITY_EDITOR | ||||
|  | @ -148,6 +151,12 @@ namespace Guru | |||
|                     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() | ||||
|  | @ -160,13 +169,16 @@ namespace Guru | |||
|             Debug.Log($"{TAG} Tch02MaxValue: {value}"); | ||||
|         } | ||||
| 
 | ||||
|         public int GetEventCountTotal() => _eventTotalCount; | ||||
|         public int GetEventCountUploaded() => _eventSuccessCount; | ||||
|         public string GetAuditSnapshot() => ""; | ||||
| 
 | ||||
|         #region Editor Test API | ||||
|          | ||||
|          | ||||
|           | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|         #endregion | ||||
|          | ||||
| 
 | ||||
|     } | ||||
| } | ||||
|  | @ -542,114 +542,113 @@ namespace Guru | |||
| 		*/ | ||||
| 	         | ||||
| 			//-------------------- 设置所有的属性 ----------------------- | ||||
|          | ||||
| 	         | ||||
| 	        public void ReportUid(string uid) | ||||
| 	        { | ||||
| 		        var prop = new MidWarePropertyUid(uid); | ||||
| 		        _propertyMap.TryAdd(prop.key, prop); | ||||
| 		        _propertyMap[prop.key] = prop; | ||||
| 		        prop.Report(); | ||||
| 	        } | ||||
| 	        public void ReportBLevel(string bLevel) | ||||
| 	        { | ||||
| 		        var prop = new MidWarePropertyBLevel(bLevel); | ||||
| 		        _propertyMap.TryAdd(prop.key, prop); | ||||
| 		        _propertyMap[prop.key] = prop; | ||||
| 		        prop.Report(); | ||||
| 	        } | ||||
| 	        public void ReportBPlay(string bPlay) | ||||
| 	        { | ||||
| 		        var prop = new MidWarePropertyBPlay(bPlay); | ||||
| 		        _propertyMap.TryAdd(prop.key, prop); | ||||
| 		        _propertyMap[prop.key] = prop; | ||||
| 		        prop.Report(); | ||||
| 	        } | ||||
| 
 | ||||
| 	        public void ReportAnalyticsExperimentGroup(string groupName) | ||||
| 	        { | ||||
| 		        var prop = new MidWarePropertyAnalyticsExperimentGroup(groupName); | ||||
| 		        _propertyMap.TryAdd(prop.key, prop); | ||||
| 		        _propertyMap[prop.key] = prop; | ||||
| 		        prop.Report(); | ||||
| 	        } | ||||
| 	         | ||||
| 	        public void ReportSignUpMethod(string methodName) | ||||
| 	        { | ||||
| 		        var prop = new MidWarePropertySignUpMethod(methodName); | ||||
| 		        _propertyMap.TryAdd(prop.key, prop); | ||||
| 		        _propertyMap[prop.key] = prop; | ||||
| 		        prop.Report(); | ||||
| 	        } | ||||
| 	         | ||||
| 	        public void ReportDeviceId(string deviceId) | ||||
| 	        { | ||||
| 		        var prop = new MidWarePropertyDeviceId(deviceId); | ||||
| 		        _propertyMap.TryAdd(prop.key, prop); | ||||
| 		        _propertyMap[prop.key] = prop; | ||||
| 		        prop.Report(); | ||||
| 	        } | ||||
| 	         | ||||
| 	        public void ReportFirstOpenTime(string firstOpenTime) | ||||
| 	        { | ||||
| 		        var prop = new MidWarePropertyFirstOpenTime(firstOpenTime); | ||||
| 		        _propertyMap.TryAdd(prop.key, prop); | ||||
| 		        _propertyMap[prop.key] = prop; | ||||
| 		        prop.Report(); | ||||
| 	        } | ||||
| 
 | ||||
| 	        public void ReportIsIapUser(bool isIapUser) | ||||
| 	        { | ||||
| 		        var prop = new MidWarePropertyIsIapUser(isIapUser); | ||||
| 		        _propertyMap.TryAdd(prop.key, prop); | ||||
| 		        _propertyMap[prop.key] = prop; | ||||
| 		        prop.Report(); | ||||
| 	        } | ||||
| 	         | ||||
| 	        public void ReportNetworkStatus(string networkStatus) | ||||
| 	        { | ||||
| 		        var prop = new MidWarePropertyNetwork(networkStatus); | ||||
| 		        _propertyMap.TryAdd(prop.key, prop); | ||||
| 		        _propertyMap[prop.key] = prop; | ||||
| 		        prop.Report(); | ||||
| 	        } | ||||
| 	         | ||||
| 	        public void ReportAdjustId(string adjustId) | ||||
| 	        { | ||||
| 		        var prop = new MidWarePropertyAdjustId(adjustId); | ||||
| 		        _propertyMap.TryAdd(prop.key, prop); | ||||
| 		        _propertyMap[prop.key] = prop; | ||||
| 		        prop.Report(); | ||||
| 	        } | ||||
| 	         | ||||
| 	        public void ReportAttStatus(string attStatus) | ||||
| 	        { | ||||
| 		        var prop = new MidWarePropertyAttStatus(attStatus); | ||||
| 		        _propertyMap.TryAdd(prop.key, prop); | ||||
| 		        _propertyMap[prop.key] = prop; | ||||
| 		        prop.Report(); | ||||
| 	        } | ||||
| 	         | ||||
| 	        public void ReportNotiPerm(string notiPerm) | ||||
| 	        { | ||||
| 		        var prop = new MidWarePropertyNotiPerm(notiPerm); | ||||
| 		        _propertyMap.TryAdd(prop.key, prop); | ||||
| 		        _propertyMap[prop.key] = prop; | ||||
| 		        prop.Report(); | ||||
| 	        } | ||||
| 	         | ||||
| 	        public void ReportAndroidId(string androidId) | ||||
| 	        { | ||||
| 		        var prop = new MidWarePropertyAndroidId(androidId); | ||||
| 		        _propertyMap.TryAdd(prop.key, prop); | ||||
| 		        _propertyMap[prop.key] = prop; | ||||
| 		        prop.Report(); | ||||
| 	        } | ||||
| 	         | ||||
| 	        public void ReportGoogleAdId(string googleAdId) | ||||
| 	        { | ||||
| 		        var prop = new MidWarePropertyGoogleAdId(googleAdId); | ||||
| 		        _propertyMap.TryAdd(prop.key, prop); | ||||
| 		        _propertyMap[prop.key] = prop; | ||||
| 		        prop.Report(); | ||||
| 	        } | ||||
| 	         | ||||
| 	        public void ReportIDFV(string idfv) | ||||
| 	        { | ||||
| 		        var prop = new MidWarePropertyIDFV(idfv); | ||||
| 		        _propertyMap.TryAdd(prop.key, prop); | ||||
| 		        _propertyMap[prop.key] = prop; | ||||
| 		        prop.Report(); | ||||
| 	        } | ||||
| 	        public void ReportIDFA(string idfa) | ||||
| 	        { | ||||
| 		        var prop = new MidWarePropertyIDFA(idfa); | ||||
| 		        _propertyMap.TryAdd(prop.key, prop); | ||||
| 		        _propertyMap[prop.key] = prop; | ||||
| 		        prop.Report(); | ||||
| 	        } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue