// ============================================== // U3DConsent.mm // UnityFramework // // Created by EricHu on 2022/11/17. // Copyright © 2022 guru. All rights reserved. // ============================================== #import #import "UnityAppController+UnityInterface.h" #import @interface U3DAnalytics : NSObject //+ (void)requestGDPR: (NSString *)deviceId :(int) debugGeo; //+ (UIViewController *) getUnityViewController; @end static NSString *gameobjectName; static NSString *callbackName; static GuruAnalytics *_analytics; @implementation U3DAnalytics // Const value define NSString * const Version = @"1.8.1"; static const double kUploadPeriodInSecond = 60.0; static const int kBatchLimit = 15; static const double kEventExpiredSeconds = 7 * 24 * 60 * 60; static const double kInitializeTimeout = 5.0; static double tch001MaxValue = 0.01; static double tch02MaxValue = 0.2; NSString * const TchAdRevRoas001 = @"tch_ad_rev_roas_001"; NSString * const TchAdRevRoas02 = @"tch_ad_rev_roas_02"; NSString * const TchError = @"tch_error"; +(UnityAppController *)GetAppController { return (UnityAppController*)[UIApplication sharedApplication].delegate; } +(UIViewController *) getUnityViewController { return UnityGetGLViewController(); } // 字符串转换 +(const char*) stringToChar: (NSString *) str{ return [str cStringUsingEncoding:NSASCIIStringEncoding]; } +(NSString *) charToString: (const char *) c{ return [[NSString alloc] initWithUTF8String:c]; } // 获取最终字符串 +(char*) finalChar: (NSString *) string { const char *tmpChar = [string cStringUsingEncoding:NSASCIIStringEncoding]; if (string == NULL) return NULL; char* res = (char*)malloc(strlen(tmpChar) + 1); strcpy(res, tmpChar); return res; } // 设置太极02的预设值 +(void) setTch02MaxValue: (const double) value{ tch02MaxValue = value; } // 构建数据 //+(NSString *) buildDataString: (int)status andMessage: (NSString *)msg{ // // NSString *jsonString = [NSString stringWithFormat: @"{\"action\":\"gdpr\",\"data\":{\"status\":%d,\"msg\":\"%@\"}}", status, msg]; // return jsonString; //} // 构建数据字典 +(NSDictionary *) buildDataDict: (NSString *) str{ NSArray *raw = [str componentsSeparatedByString:@","]; if( raw == nil || raw.count == 0) return nil; NSMutableDictionary* dict = [[NSMutableDictionary alloc] init]; //must init before using for(NSString *s in raw ){ NSArray *kvp = [s componentsSeparatedByString:@":"]; if(kvp == nil || kvp.count < 2){ continue; } NSString *k = kvp[0]; NSString *t = [kvp[1] substringToIndex:1]; NSString *v = [kvp[1] substringFromIndex:1]; // NSLog(@"---[iOS] parse kvp key:%@ type:%@ value:%@", k, t, v); //TODO 解析字符值 if([t isEqual: @"i"]){ // int [dict setValue:@([v integerValue]) forKey:k]; }else if([t isEqual: @"d"]){ // double [dict setValue:@([v doubleValue]) forKey:k]; } else { // String [dict setValue:v forKey:k]; } } return dict; } // 构建Json格式的数据字典 +(NSMutableDictionary *) buildDataWithJson: (NSString *) json andKey: (NSString *) key{ if( json == nil || json.length == 0) return nil; NSData *jsonData = [json dataUsingEncoding:NSUTF8StringEncoding]; NSError *err; NSMutableDictionary *dict = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&err]; if(err || dict == nil) { NSLog(@"json解析失败:%@",err); [U3DAnalytics onTchErrorEvent:@"json_error" andRaw:json andOther:@""]; return nil; } // ---------- 太极数据校验 ------------- if(key == TchAdRevRoas001){ // tch 001 参数修复 [U3DAnalytics fixTchParams: dict andJson:json andMaxValue:tch001MaxValue]; } else if(key == TchAdRevRoas02){ // tch 02 参数修复 [U3DAnalytics fixTchParams: dict andJson:json andMaxValue:tch02MaxValue]; } return dict; } // 修复自打点数据 +(void) fixTchParams: (NSMutableDictionary *)dict andJson: (NSString *)json andMaxValue: (double) targetValue { // --- 保存 raw数据 --- [dict setValue: json forKey:@"raw"]; id _platform = [dict objectForKey:@"ad_platform"]; id _value = [dict objectForKey:@"value"]; if([U3DAnalytics isNullObject: _platform]) { // 不存在 ad_paltform [U3DAnalytics onTchErrorEvent:@"no_ad_platform" andRaw:json andOther:@""]; } else { // 非IAP订单 if(![[_platform stringValue] isEqual:@"appstore"] ) { 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:@"value_error" andRaw:json andOther: [_value stringValue]]; } } } } } // 上报 tch_error 事件 +(void) onTchErrorEvent:(NSString *) evtName andRaw: (NSString *)raw andOther: (NSString *) other{ NSString *json = [NSString stringWithFormat:@"{\"event\":\"%@\", \"raw\":\"%@\", \"other\":\"%@\"}", evtName, raw, other]; [GuruAnalytics logEvent:TchError parameters:[U3DAnalytics buildDataWithJson:json andKey:evtName]]; } // 对象判空 + (BOOL)isNullObject:(__kindof id) obj{ if(!obj){ return YES; } if(obj == NULL){ return YES; } if([obj isEqual:[NSNull null]]){ return YES; } return NO; } @end //============================ UNITY PUBLIC API ============================ extern "C" { // 请求GDPR void unityInitAnalytics(const char *appId, const char *deviceInfo, bool isDebug) { // NSLog(@"--- [iOS] init Analytics libs"); [GuruAnalytics initializeLibWithUploadPeriodInSecond:kUploadPeriodInSecond batchLimit:kBatchLimit eventExpiredSeconds:kEventExpiredSeconds initializeTimeout:kInitializeTimeout saasXAPPID:[U3DAnalytics charToString:appId] saasXDEVICEINFO:[U3DAnalytics charToString:deviceInfo] loggerDebug:isDebug]; } // 设置用户ID void unitySetUserID(const char *uid){ [GuruAnalytics setUserID:[U3DAnalytics charToString:uid]]; } // 设置用户ID void unitySetScreen(const char *screenName){ [GuruAnalytics setScreen:[U3DAnalytics charToString:screenName]]; } // 设置用户ADID void unitySetAdId(const char *adId){ [GuruAnalytics setAdId:[U3DAnalytics charToString:adId]]; } // 设置用户AdjustID void unitySetAdjustID(const char *adjustId){ [GuruAnalytics setAdjustId:[U3DAnalytics charToString:adjustId]]; } // 设置用户FirebaseID void unitySetFirebaseId(const char *firebaseId){ [GuruAnalytics setFirebaseId:[U3DAnalytics charToString:firebaseId]]; } // 设置用户设备ID void unitySetDeviceId(const char *did){ [GuruAnalytics setDeviceId:[U3DAnalytics charToString:did]]; } // 设置用户属性 void unitySetUserProperty(const char *key, const char *value){ [GuruAnalytics setUserProperty:[U3DAnalytics charToString:value] forName:[U3DAnalytics charToString:key]]; } // 上报事件 void unityLogEvent(const char *key, const char *data){ NSString *evtName = [U3DAnalytics charToString:key]; NSString *json = [U3DAnalytics charToString:data]; [GuruAnalytics logEvent: evtName parameters:[U3DAnalytics buildDataWithJson:json andKey:evtName]]; // JSON转换 } // 上报事件 void unitySetTch02Value(const double value){ [U3DAnalytics setTch02MaxValue:value]; } // 打点事件成功率 void unityReportEventRate(void){ [GuruAnalytics debug_eventsStatistics:^(NSInteger uploadedEventsCount, NSInteger loggedEventsCount) { // 上报事件总量 [GuruAnalytics setUserProperty:[NSString stringWithFormat:@"%ld", loggedEventsCount] forName:@"lgd"]; // 上报成功数量 [GuruAnalytics setUserProperty:[NSString stringWithFormat:@"%ld", uploadedEventsCount] forName:@"uld"]; }]; } }