ios-hooks/AppRunMan/server/MyAdServer.m
2025-11-13 14:29:24 +08:00

385 lines
14 KiB
Objective-C

//
// MyAdServer.m
// nochange
//
// Created by mac on 2024/7/26.
//
#import <Foundation/Foundation.h>
#import <signal.h>
#import <execinfo.h>
#import "XSHelper.h"
#import "MyAdServer.h"
#import "XSPhoneConfig.h"
#import "XSPhoneInfo.h"
void pushAdTaskLog(AdTaskLogData *data) {
NSDictionary *dic = @{
@"taskId": data->taskId,
@"title": data->title,
@"message": data->message,
@"idfa": data->idfa,
@"appid": data->appid,
@"adid": data->adid,
@"level": @(data->level),
@"ecpm": data->ecpm ? : @0.0,
@"iphoneId": data->iphoneId,
@"ipAddr": data->ipAddr
};
saveAdTaskLog(dic);
}
void saveAdTaskLog(NSDictionary *dic) {
XSPhoneConfig *config = [XSPhoneConfig sharedInstance];
NSString *url = [config GetFullServerURL:@"ios/top_selection/push_ad_task_log"];
NSString *json = [XSHelper dic2Json:dic];
XSHttpHelper *http = [[XSHttpHelper alloc] init];
[http doPOST:url json:json withCallback:^(NSData *res) {
NSLog(@"-ad log- push:\n %@", [XSHelper data2str:res]);
} withError:^(NSError *err) {
NSLog(@"XS- %@", err);
}];
}
void getLowEcpm(LowEcpmCallback callback) {
XSPhoneConfig *config = [XSPhoneConfig sharedInstance];
NSString *url = [NSString stringWithFormat:@"ios/top_selection/low_ecpm?iphoneId=%@", config.IPhoneName];
NSLog(@"XS- getLowEcpm url %@", url);
NSString *fullurl = [config GetFullServerURL:url];
XSHttpHelper *http = [[XSHttpHelper alloc] init];
[http doGET:fullurl withCallback:^(NSData *data) {
if(data && ![data isEqual:[NSNull null]]) {
NSDictionary *dic = [XSHelper jsonData2Dictionary:data];
NSLog(@"XS- getLowEcpm data %@", dic);
NSNumber *ecpm = dic[@"data"];
if (ecpm) {
callback(ecpm);
} else {
callback(ecpm);
}
} else {
callback(@(0.0001));
}
} withError:^(NSError *err) {
callback(@(0.0001));
}];
}
BOOL needAdContinue(NSString *appid, NSString *idfa, NSNumber *maxEcpm) {
XSPhoneConfig *config = [XSPhoneConfig sharedInstance];
NSString *fullurl = [config GetFullServerURL: @"ios/top_selection/get_need_continue"];
NSDictionary *postData = @{
@"id": config.IPhoneName,
@"appid": appid,
@"idfa": idfa,
@"maxEcpm": maxEcpm
};
XSHttpHelper *http = [[XSHttpHelper alloc] init];
NSData *data = [http doPOST:fullurl json:[XSHelper dic2Json:postData]];
if(data == nil || [data isEqual:[NSNull null]]) {
return NO;
}
NSDictionary *dic = [XSHelper jsonData2Dictionary:data];
NSLog(@"XS- needAdContinue data %@", dic);
return [dic[@"data"] isEqual:@(true)];
}
void getChangeInfo(NSString *idfa, ChangeDataSaveCallback callback, error_callback errorCallback) {
XSPhoneConfig *config = [XSPhoneConfig sharedInstance];
NSString *url = [config GetFullServerURL:@"/ios/top_selection/get_change_data_json"];
XSHttpHelper *http = [[XSHttpHelper alloc] init];
NSDictionary *dic = @{
@"packageName": [config PackageName],
@"washParam": @([config WashParam]),
};
NSString *json = [XSHelper dic2Json:dic];
[http doPOST:url json:json withCallback:^(NSData *jsonData) {
NSDictionary *data = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
if (data && [data objectForKey:@"data"]) {
NSDictionary *_data = data[@"data"];
if(_data && ![_data isEqual:[NSNull null]]) {
callback(_data);
}
} else {
if(errorCallback) {
errorCallback(nil);
}
}
} withError:^(NSError *err) {
NSLog(@"XS- log- get data: %@", err);
if(errorCallback) {
errorCallback(err);
}
}];
}
void _newgetChangeInfo(NSString *idfa, ChangeDataSaveCallback callback, error_callback errorCallback) {
XSPhoneConfig *config = [XSPhoneConfig sharedInstance];
NSString *url = [config GetFullServerURL:[NSString stringWithFormat:@"ios/top_selection/change_data?id=%@&idfa=%@", [config IPhoneName], idfa ?: @""]];
XSHttpHelper *http = [[XSHttpHelper alloc] init];
[http doGET:url withCallback:^(NSData *jsonData) {
NSDictionary *data = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
if (data && [data objectForKey:@"data"]) {
NSString *aesData = data[@"data"];
NSString *decData = @"";
if(aesData && ![aesData isEqual:[NSNull null]] && ![aesData isEqual:@""]) {
decData = [aesData aesDecrypt:AES_KEY iv:AES_IV];
}
// NSString *decData = [aesData aesDecrypt:AES_KEY iv:AES_IV];
NSLog(@"XS- changeData: %@", decData);
NSDictionary *dt = [XSHelper json2Dictionary:decData];
callback(dt);
} else {
if(errorCallback) {
errorCallback(nil);
}
}
} withError:^(NSError *err) {
NSLog(@"XS- log- get data: %@", err);
if(errorCallback) {
errorCallback(err);
}
}];
}
BOOL saveChangeDataFile(NSDictionary *data) {
if (!data || ![data isKindOfClass:[NSDictionary class]]) {
NSLog(@"Invalid data input");
return NO;
}
@try {
NSString *bundleId = @"org.xyzshell.NotNil";
NSString *plistPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleId];
// 使用同步锁保证线程安全
@synchronized(NSFileManager.defaultManager) {
NSMutableDictionary *tempDic = [NSMutableDictionary new];
// 安全地遍历字典
[data enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
if (![key isKindOfClass:[NSString class]]) return;
if (obj == [NSNull null]) {
tempDic[key] = nil;
} else if ([obj isKindOfClass:[NSDictionary class]]) {
NSMutableDictionary *newDic = [NSMutableDictionary new];
[(NSDictionary *)obj enumerateKeysAndObjectsUsingBlock:^(id key1, id obj1, BOOL *stop1) {
if (![key1 isKindOfClass:[NSString class]]) return;
newDic[key1] = (obj1 == [NSNull null]) ? nil : obj1;
}];
tempDic[key] = [newDic copy];
} else {
tempDic[key] = obj;
}
}];
// 创建目录
NSError *error;
NSString *dirPath = [plistPath stringByDeletingLastPathComponent];
if (![NSFileManager.defaultManager fileExistsAtPath:dirPath]) {
if (![NSFileManager.defaultManager createDirectoryAtPath:dirPath
withIntermediateDirectories:YES
attributes:nil
error:&error]) {
NSLog(@"Failed to create directory: %@", error);
return NO;
}
}
// 写入文件
BOOL y = [tempDic writeToFile:plistPath atomically:YES];
NSLog(@"XS- save change file: %@", @(y));
return y;
}
} @catch (NSException *exception) {
NSLog(@"Error saving change data: %@", exception);
return NO;
}
}
AdLoadInfo getAdLoadInfo(NSDictionary *request) {
AdLoadInfo info = {0}; // 初始化所有字段为0
if (!request || ![request isKindOfClass:[NSDictionary class]]) {
NSLog(@"Invalid request");
return info;
}
@try {
NSString *apiUrl = [[XSPhoneConfig sharedInstance] GetFullServerURL:@"ios/top_selection/ad_can_show"];
if (!apiUrl.length) {
NSLog(@"Invalid API URL");
return info;
}
XSHttpHelper *http = [[XSHttpHelper alloc] init];
NSData *data = [http doPOST:apiUrl json:[XSHelper dic2Json:request]];
if (!data) {
NSLog(@"No response data");
return info;
}
NSError *jsonError;
NSDictionary *res = [NSJSONSerialization JSONObjectWithData:data
options:0
error:&jsonError];
if (jsonError || ![res isKindOfClass:[NSDictionary class]]) {
NSLog(@"JSON parsing error: %@", jsonError);
return info;
}
NSDictionary *resData = res[@"data"];
if (![resData isKindOfClass:[NSDictionary class]]) {
NSLog(@"Invalid response data format");
return info;
}
// 安全地获取值
info.loads = [resData[@"loads"] isKindOfClass:[NSNumber class]] ? resData[@"loads"] : @0;
info.adTime = [resData[@"adTime"] isKindOfClass:[NSNumber class]] ? resData[@"adTime"] : @0;
info.adTimeout = [resData[@"adTimeout"] isKindOfClass:[NSNumber class]] ? resData[@"adTimeout"] : @0;
info.adTouchAfterMs = [resData[@"adTouchAfterMs"] isKindOfClass:[NSNumber class]] ? resData[@"adTouchAfterMs"] : @0;
info.adTouchBeforeMs = [resData[@"adTouchBeforeMs"] isKindOfClass:[NSNumber class]] ? resData[@"adTouchBeforeMs"] : @0;
info.touchRate = [resData[@"touchRate"] isKindOfClass:[NSNumber class]] ? resData[@"touchRate"] : @0;
} @catch (NSException *exception) {
NSLog(@"Error getting ad load info: %@", exception);
}
return info;
}
void pushInfo(int type, NSString *data, rt_str_callback callback,error_callback errorCallback) {
XSPhoneConfig *config = [XSPhoneConfig sharedInstance];
NSString *url = [config GetMainServerURL:@"ios/top_selection/_putinfo"];
NSString *aesData = [data aesEncrypt:AES_KEY iv:AES_IV];
NSDictionary *dic = @{
@"data": aesData,
@"type": @(type)
};
XSHttpHelper *http = [[XSHttpHelper alloc] init];
[http doPOST:url json:[XSHelper dic2Json:dic] withCallback:^(NSData *data) {
NSDictionary *dic = [XSHelper jsonData2Dictionary:data];
if (dic && dic[@"data"]) {
NSString *strData = dic[@"data"];
NSLog(@"XS- aes data:%@", strData);
NSString *json = @"";
if(strData && ![strData isEqual:[NSNull null]]) {
json = [strData aesDecrypt:AES_KEY iv:AES_IV];
}
callback(json);
}
} withError:errorCallback];
}
void pushIphoneLog(NSString *data) {
/*
logs.ipAddr = log.ipAddr;
logs.created = log.created;
logs.data = log.decryptData();
logs.type = log.type;
logs.pkgName = log.pkgName;
logs.version = log.version;
*/
NSString *aesData = [data aesEncrypt:AES_KEY iv:AES_IV];
NSString *ipAddr = [[XSPhoneInfo sharedInstance] IPAddress];
NSString *pkgName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"];
NSString *version = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
NSDictionary *dic = @{
@"ipAddr": ipAddr,
@"data": aesData,
@"type": @(2),
@"pkgName": pkgName,
@"version": version
};
XSPhoneConfig *config = [XSPhoneConfig sharedInstance];
NSString *url = [config GetMainServerURL:@"ios/top_selection/save_iphone_logs"];
XSHttpHelper *http = [[XSHttpHelper alloc] init];
[http doPOST:url json:[XSHelper dic2Json:dic] withCallback:^(NSData *data) {
NSString *log = [XSHelper data2str:data];
NSLog(@"pushIphoneLog %@", log);
} withError:^(NSError *err) {
NSLog(@"pushIphoneLog %@", err);
}];
}
void logMessage(NSString *message) {
NSString *documentsDirectory = @"/var/logs/";
NSString *logFilePath = [documentsDirectory stringByAppendingPathComponent:@"app_log.txt"];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSString *timestamp = [dateFormatter stringFromDate:[NSDate date]];
NSString *logEntry = [NSString stringWithFormat:@"%@: %@\n", timestamp, message];
if (![[NSFileManager defaultManager] fileExistsAtPath:logFilePath]) {
[logEntry writeToFile:logFilePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
} else {
NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingAtPath:logFilePath];
[fileHandle seekToEndOfFile];
[fileHandle writeData:[logEntry dataUsingEncoding:NSUTF8StringEncoding]];
[fileHandle closeFile];
}
}
void uncaughtExceptionHandler(NSException *exception) {
NSArray *callStack = [exception callStackSymbols];
NSString *reason = [exception reason];
NSString *name = [exception name];
NSString *urlString = [NSString stringWithFormat:@"crash://%@", name];
NSString *userInfo = [NSString stringWithFormat:@"%@\nreason:\n%@\ncallStackSymbols:\n%@",
urlString, reason, [callStack componentsJoinedByString:@"\n"]];
NSLog(@"Crash: %@", userInfo);
logMessage(userInfo);
// 这里你可以将崩溃信息保存到文件或发送到服务器
pushIphoneLog(userInfo);
}
void signalHandler(int signal) {
NSMutableString *crashLog = [NSMutableString string];
[crashLog appendFormat:@"Signal %d was raised.\n", signal];
void* callstack[128];
int frames = backtrace(callstack, 128);
char **strs = backtrace_symbols(callstack, frames);
for (int i = 0; i < frames; ++i) {
[crashLog appendFormat:@"%s\n", strs[i]];
}
free(strs);
NSLog(@"Crash: %@", crashLog);
logMessage(crashLog);
// 这里你可以将崩溃信息保存到文件或发送到服务器
pushIphoneLog(crashLog);
}
void registerSignalHandler(void) {
signal(SIGABRT, signalHandler);
signal(SIGILL, signalHandler);
signal(SIGSEGV, signalHandler);
signal(SIGFPE, signalHandler);
signal(SIGBUS, signalHandler);
signal(SIGPIPE, signalHandler);
NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
}