342 lines
10 KiB
Plaintext
342 lines
10 KiB
Plaintext
|
|
// ==============================================
|
|||
|
|
// U3DConsent.mm
|
|||
|
|
// UnityFramework
|
|||
|
|
//
|
|||
|
|
// Created by EricHu on 2022/11/17.
|
|||
|
|
// Copyright © 2022 guru. All rights reserved.
|
|||
|
|
// ==============================================
|
|||
|
|
|
|||
|
|
#import <Foundation/Foundation.h>
|
|||
|
|
#import "UnityAppController+UnityInterface.h"
|
|||
|
|
#import <GuruAnalyticsLib/GuruAnalyticsLib-Swift.h>
|
|||
|
|
|
|||
|
|
@interface U3DAnalytics : NSObject
|
|||
|
|
|
|||
|
|
//+ (void)requestGDPR: (NSString *)deviceId :(int) debugGeo;
|
|||
|
|
//+ (UIViewController *) getUnityViewController;
|
|||
|
|
|
|||
|
|
@end
|
|||
|
|
|
|||
|
|
static NSString *gameobjectName = @"GuruCallback";
|
|||
|
|
static NSString *callbackName =@"OnCallback";
|
|||
|
|
|
|||
|
|
static GuruAnalytics *_analytics;
|
|||
|
|
|
|||
|
|
|
|||
|
|
@implementation U3DAnalytics
|
|||
|
|
|
|||
|
|
// Const value define
|
|||
|
|
NSString * const Version = @"1.9.0";
|
|||
|
|
|
|||
|
|
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;
|
|||
|
|
static bool enableErrorLog = false;
|
|||
|
|
|
|||
|
|
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;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 设置是否启用日志错误上报
|
|||
|
|
+(void) setEnableErrorLog: (bool) value{
|
|||
|
|
if(enableErrorLog == false && value){
|
|||
|
|
|
|||
|
|
enableErrorLog = value;
|
|||
|
|
|
|||
|
|
[GuruAnalytics registerInternalEventObserverWithReportCallback:^(NSInteger code, NSString * info){
|
|||
|
|
[U3DAnalytics onEventCallback:code andInfo:info];
|
|||
|
|
}];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 事件上报回调
|
|||
|
|
+(void) onEventCallback: (NSInteger)code andInfo:(NSString *) info{
|
|||
|
|
[U3DAnalytics sendMessage: [U3DAnalytics buildLogEventString: code andMessage:info]];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
// 构建数据
|
|||
|
|
+(NSString *) buildLogEventString: (NSInteger)status andMessage: (NSString *)msg{
|
|||
|
|
NSString *jsonString = [NSString stringWithFormat: @"{\"action\":\"logger_error\",\"data\":{\"code\":%d,\"msg\":\"%@\"}}", (int)status, msg];
|
|||
|
|
return jsonString;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 构建数据字典
|
|||
|
|
+(NSDictionary<NSString*, id> *) 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]];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 向Unity发送数据
|
|||
|
|
+(void) sendMessage: (NSString *)msg
|
|||
|
|
{
|
|||
|
|
// NSLog(@"--- unityInitSDK222: %@:%@", gameobjectName, callbackName);
|
|||
|
|
if(gameobjectName != nil && callbackName != nil){
|
|||
|
|
char *t1 = [U3DAnalytics finalChar: gameobjectName];
|
|||
|
|
char *t2 = [U3DAnalytics finalChar: callbackName];
|
|||
|
|
char *t3 = [U3DAnalytics finalChar: msg];
|
|||
|
|
|
|||
|
|
UnitySendMessage(t1, t2, t3);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
// 上报 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];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void unityInitCallback(const char *gameobject, const char *method){
|
|||
|
|
// NSLog(@"--- unityInitSDK111: %s:%s", gameobject, method);
|
|||
|
|
gameobjectName = [NSString stringWithUTF8String:gameobject];
|
|||
|
|
callbackName = [NSString stringWithUTF8String:method];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 设置用户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"];
|
|||
|
|
}];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 注册内部日志 Error 监听
|
|||
|
|
void unitySetEnableErrorLog(bool value){
|
|||
|
|
[U3DAnalytics setEnableErrorLog:value];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
|