ios-hooks/AppRunMan/server/MyAdTask2.m
2025-12-01 10:07:51 +08:00

631 lines
20 KiB
Objective-C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "XUDPServer.h"
#import <Foundation/Foundation.h>
#import "IPhoneHertbeat.h"
#import "XSHackIos.h"
#import "XSHelper.h"
#import "XSPhoneInfo.h"
#import "XSPhoneConfig.h"
#import "MyAdServer.h"
#import "MyAdTask2.h"
#import "MyEventBus.h"
BOOL myadTaskManualStop = NO;
@interface MyAdTask2Mangger()
{
@private
BOOL running;
dispatch_source_t _timer;
NSDate *lastRun;
NSDate *lastGetCountry;
NSString *_lastIdfa;
NSString *taskId;
NSString *taskAppId;
int workType;
int screen_w;
int screen_h;
int adAfter;
NSString *linkId;
NSString *dataId;
NSString *remoteIp;
NSString *country;
dispatch_source_t _appendCheckTimer; // 新增定时器
}
@property (nonatomic, assign) NSTimeInterval lastAppSwitchTime; // 新增属性
@end
@implementation MyAdTask2Mangger
+(instancetype)sharedInstance {
static MyAdTask2Mangger* _sharedInstance = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedInstance = [[MyAdTask2Mangger alloc] init];
});
return _sharedInstance;
}
-(instancetype)init {
if (self = [super init]) {
self->running = NO;
self->_lastIdfa = @"";
self.manQueue = dispatch_queue_create("com.xyzshell.myadtask", DISPATCH_QUEUE_SERIAL);
CGFloat screen_scale = [[UIScreen mainScreen] scale];
CGFloat device_screen_width = [UIScreen mainScreen].bounds.size.width * screen_scale;
CGFloat device_screen_height = [UIScreen mainScreen].bounds.size.height * screen_scale;
self->screen_w = device_screen_width;
self->screen_h = device_screen_height;
self->adAfter = 1000;
self.lastAppSwitchTime = 0; // 初始化为0
return self;
}
return nil;
}
- (int)onShow:(NSDictionary *)dic {
if(dic == nil || [dic isEqual:[NSNull null]] || [dic count] <= 0) {
return 4000;
}
NSString *t_appid = [self getStr:@"appid" dic:dic];
NSString *t_idfa = [self getStr:@"idfa" dic:dic];
NSString *t_adId = [self getStr:@"id" dic:dic];
NSNumber *t_ecpm = [self getNum:@"ecpm" dic:dic];
BOOL ad = dic[@"ad"];
NSString *iphoneId = [[XSPhoneConfig sharedInstance] IPhoneName];
if(!ad) {
NSLog(@"XS- no ad show");
return 0;
}
int close = 4000;
AdLoadInfo adloadInfo = getAdLoadInfo(@{
@"idfa": t_idfa ?: @"",
@"adId": t_adId ?: @"",
@"ecpm": [NSString stringWithFormat:@"%@", t_ecpm],
@"appId": t_appid ?: @"",
@"deviceId":iphoneId ?: @""
});
close = [adloadInfo.adTime intValue];
int before = [adloadInfo.adTouchBeforeMs intValue];
if (before >= close) {
before = 1000;
}
int after = [adloadInfo.adTouchAfterMs intValue];
if(after > 1000) {
self->adAfter = after;
} else {
self->adAfter = 1000;
}
NSInteger random1 = arc4random_uniform(101);
NSInteger tr = [adloadInfo.touchRate intValue];
if (tr > random1) {
double beforeSec = before / 1000.0;
__weak typeof(self) weakSelf = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(beforeSec * NSEC_PER_SEC)),
self.manQueue, ^{
});
}
return close;
}
- (void)showStatus:(NSString *)data {
[[MyEventBus sharedInstance] postEvent:@"UpdateStatus" withObject:data];
}
- (void)setRemoteInfo {
if (self->country != nil && ![self->country isEqual:@""]) {
NSLog(@"Country info already set, skipping remote info update.");
return; // 如果国家信息已存在,则跳过更新
}
NSString *url = @"https://ipapi.co/json/";
if (!url) {
NSLog(@"Invalid URL for remote info");
return;
}
XSHttpHelper *http = [[XSHttpHelper alloc] init];
__weak typeof(self) weakSelf = self;
[http doGET:url withCallback:^(NSData *data) {
if(!data) {
NSLog(@"!setRemoteInfo 1data");
[weakSelf showStatus:@"!setRemoteInfo 1data"];
return;
}
NSDictionary *dic = [XSHelper jsonData2Dictionary:data];
if (!dic) {
NSLog(@"!setRemoteInfo dic");
[weakSelf showStatus:@"!setRemoteInfo dic"];
return;
}
NSString *isoCode = dic[@"country_code"];
NSString *ip = dic[@"ip"];
if (!isoCode || !ip) {
NSLog(@"Invalid data received for remote info");
return;
}
__strong typeof(weakSelf) strongSelf = weakSelf;
if (!strongSelf) return;
strongSelf->remoteIp = [ip copy];
strongSelf->country = [isoCode copy];
[XSPhoneInfo sharedInstance].remoteIp = [NSString stringWithFormat:@"%@:%@", isoCode, ip];
[weakSelf showStatus:[XSPhoneInfo sharedInstance].remoteIp];
} withError:^(NSError *err) {
NSLog(@"!setRemoteInfo err:%@",err);
[weakSelf showStatus:[NSString stringWithFormat:@"%@", err.description]];
}];
}
- (void)setRemoteInfo1 {
NSString *url = [[XSPhoneConfig sharedInstance] GetRemoteIPURL];
[self showStatus:url];
if (!url) {
NSLog(@"!setRemoteInfo url");
return;
}
__weak typeof(self) weakSelf = self;
XSHttpHelper *http = [[XSHttpHelper alloc] init];
[http doGET:url withCallback:^(NSData *data) {
if(!data) {
NSLog(@"!setRemoteInfo 1data");
[weakSelf showStatus:@"!setRemoteInfo 1data"];
return;
}
NSDictionary *dic = [XSHelper jsonData2Dictionary:data];
if (!dic) {
NSLog(@"!setRemoteInfo dic");
[weakSelf showStatus:@"!setRemoteInfo dic"];
return;
}
NSDictionary *_data = dic[@"data"];
if(!_data) {
NSLog(@"!setRemoteInfo data");
[weakSelf showStatus:@"!setRemoteInfo data"];
return;
}
NSString *isoCode = _data[@"isoCode"];
NSString *ip = _data[@"ip"];
NSLog(@"setRemoteInfo:%@", _data);
__strong typeof(weakSelf) strongSelf = weakSelf;
if (!strongSelf) return;
strongSelf->remoteIp = [ip copy];
strongSelf->country = [isoCode copy];
[XSPhoneInfo sharedInstance].remoteIp = [NSString stringWithFormat:@"%@:%@", isoCode, ip];
[weakSelf showStatus:[XSPhoneInfo sharedInstance].remoteIp];
} withError:^(NSError *err) {
NSLog(@"!setRemoteInfo err:%@",err);
[weakSelf showStatus:[NSString stringWithFormat:@"%@", err.description]];
}];
}
// 新增方法:检查并处理 append 文件
- (void)checkAppendFile {
NSString *appendDirPath = @"/var/mobile/Documents/ad/append";
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL isDir = NO;
if ([fileManager fileExistsAtPath:appendDirPath isDirectory:&isDir] && isDir) {
NSArray *files = [fileManager contentsOfDirectoryAtPath:appendDirPath error:nil];
if (files.count > 0) {
BOOL allDeleted = YES;
for (NSString *file in files) {
NSString *filePath = [appendDirPath stringByAppendingPathComponent:file];
NSError *error = nil;
[fileManager removeItemAtPath:filePath error:&error];
if (error) {
NSLog(@"Failed to delete file: %@, error: %@", filePath, error);
allDeleted = NO;
}
}
if (allDeleted) {
NSLog(@"append directory has files, deleted all, calling onEnd");
[self onEnd:nil];
}
}
}
}
- (BOOL)onEnd:(NSDictionary *)dic {
@autoreleasepool {
if (self->taskAppId) {
[self appKill:self->taskAppId];
}
[self startApp];
}
return NO;
}
- (void)startApp {
@autoreleasepool {
if (!self->running) {
return;
}
self->lastRun = [NSDate date];
NSDate *startTime = [NSDate date];
NSLog(@"getChangeInfo started at: %@", startTime);
__weak typeof(self) weakSelf = self;
getChangeInfo(self->_lastIdfa ?: @"", ^(NSDictionary *dic) {
if (!dic) {
NSLog(@"getChangeInfo returned nil dictionary");
return;
}
NSDate *endTime = [NSDate date];
NSTimeInterval duration = [endTime timeIntervalSinceDate:startTime];
NSLog(@"getChangeInfo completed at: %@, duration: %.2f seconds", endTime, duration);
dispatch_async(weakSelf.manQueue, ^{
[weakSelf onChangeInfo:dic];
});
}, ^(NSError *err) {
NSDate *endTime = [NSDate date];
NSTimeInterval duration = [endTime timeIntervalSinceDate:startTime];
NSLog(@"getChangeInfo completed at: %@, duration: %.2f seconds", endTime, duration);
NSLog(@"XS- startTask NSError is null, %@", err);
[weakSelf showStatus:[NSString stringWithFormat:@"getChangeInfo error after 5s restart: %@", err.description]];
// 延迟重新启动App
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), weakSelf.manQueue, ^{
__strong typeof(weakSelf) strongSelf = weakSelf;
if (strongSelf && strongSelf->running) { // 确保任务未被停止
[strongSelf startApp];
}
});
});
}
}
- (void)start {
self->running = YES;
myadTaskManualStop = NO;
[[IPhoneHertbeat sharedInstance] setStatus:@"运行中"];
[self startApp];
__weak typeof(self) weakSelf = self;
// 确保Timer在重新启动前被取消
if (_timer) {
dispatch_source_cancel(_timer);
_timer = nil;
}
// 使用 dispatch_source 创建timer
_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.manQueue);
dispatch_source_set_timer(_timer, dispatch_time(DISPATCH_TIME_NOW, 0), 10 * NSEC_PER_SEC, 1 * NSEC_PER_SEC);
dispatch_source_set_event_handler(_timer, ^{
@autoreleasepool {
[weakSelf proc];
// 检查心跳状态
if (![[IPhoneHertbeat sharedInstance] isHeartbeatActive]) {
NSLog(@"Heartbeat inactive, restarting...");
[[IPhoneHertbeat sharedInstance] restartHeartbeat];
}
}
});
dispatch_resume(_timer);
// 新增定时器,每秒检查 append 文件
if (_appendCheckTimer) {
dispatch_source_cancel(_appendCheckTimer);
_appendCheckTimer = nil;
}
_appendCheckTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.manQueue);
dispatch_source_set_timer(_appendCheckTimer, dispatch_time(DISPATCH_TIME_NOW, 0), 1 * NSEC_PER_SEC, 0);
dispatch_source_set_event_handler(_appendCheckTimer, ^{
[weakSelf checkAppendFile];
});
dispatch_resume(_appendCheckTimer);
[[MyEventBus sharedInstance] postEvent:@"UpdateRunStatus" withObject:@(YES)];
}
- (void)proc {
if (!self->running) {
return;
}
NSLog(@"XS- MyAdTaskManager proc");
NSDate* curRunTime = [NSDate date];
NSTimeInterval elapsed = [curRunTime timeIntervalSinceDate:self->lastRun];
BOOL washParam = [[XSPhoneConfig sharedInstance] WashParam];
if (elapsed >= 80) {
//[self onStop];
[self startApp];
}
if (!washParam) {
NSString* appId = [ self frontMostAppId];
if (![appId isEqual: self->taskAppId]) {
// 引入冷却时间,避免频繁切换应用
[self appKill:appId];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), self.manQueue, ^{
[self appRun:self->taskAppId];
self.lastAppSwitchTime = [NSDate timeIntervalSinceReferenceDate]; // 更新切换时间
});
}
}
}
- (NSString *)toggle {
if(self->running) {
[self stop];
} else {
[self start];
}
return [IPhoneHertbeat sharedInstance].status;
}
- (void)stop {
myadTaskManualStop = YES;
self->running = NO;
[IPhoneHertbeat sharedInstance].status = @"已停止";
if (_timer) {
dispatch_source_cancel(_timer);
_timer = nil;
}
// 停止 append 文件定时器
if (_appendCheckTimer) {
dispatch_source_cancel(_appendCheckTimer);
_appendCheckTimer = nil;
}
[[IPhoneHertbeat sharedInstance] stopHeartbeat]; // 确保心跳停止
[[MyEventBus sharedInstance] postEvent:@"UpdateRunStatus" withObject:@(NO)];
}
- (NSString *)getSystemInfo {
void *buffer = NULL;
NSString *result = nil;
// 设置 sysctl 的 mib 参数
// 0x100000006LL 拆分为两个 int: {6, 1}
// 高32位是1 (0x1), 低32位是6 (0x6)
int mib[2];
mib[0] = 6; // CTL_HW
mib[1] = 1; // HW_MACHINE
size_t size = 100;
// 第一次调用获取实际需要的缓冲区大小
// #import <sys/sysctl.h>
sysctl(mib, 2, NULL, &size, NULL, 0);
// 分配内存
buffer = malloc(size);
if (buffer != NULL) {
// 第二次调用获取实际数据
sysctl(mib, 2, buffer, &size, NULL, 0);
// 转换为 NSString
result = [NSString stringWithUTF8String:(const char *)buffer];
// 释放内存
free(buffer);
}
return result;
}
- (void)onChangeInfo:(NSDictionary *)dic {
NSString* t_idfa = [self getStr:@"idfa" dic:dic];
if (![XSHelper strIsEmpty:t_idfa]) {
self->_lastIdfa = [t_idfa copy];
} else {
NSLog(@"XS- startTask t_idfa is null");
return;
}
NSString *_linkId = [self getStr:@"linkId" dic:dic];
if (![XSHelper strIsEmpty:_linkId]) {
self->linkId = [_linkId copy];
}
NSString *_dataId = [self getStr:@"dataId" dic:dic];
if (![XSHelper strIsEmpty:_dataId]) {
self->dataId = [_dataId copy];
}
NSString* t_taskId = [self getStr:@"id" dic:dic];
if (![XSHelper strIsEmpty:t_taskId]) {
self->taskId = [t_taskId copy];
} else {
NSLog(@"XS- startTask t_taskId is null");
return;
}
NSString* t_taskAppId = [self getStr:@"appId" dic:dic];
if (![XSHelper strIsEmpty:t_taskAppId]) {
self->taskAppId = [t_taskAppId copy];
[IPhoneHertbeat sharedInstance].appId = self->taskAppId;
} else {
NSLog(@"XS- startTask t_taskAppId is null");
return;
}
__weak typeof(self) weakSelf = self;
[self restart:^{
__strong typeof(weakSelf) strongSelf = weakSelf;
if (!strongSelf) return;
// 重试逻辑最多重试3次每次延迟1秒
__block int retryCount = 0;
void (^saveBlock)(void) = ^{
if (saveChangeDataFile(dic)) {
// 成功,执行后续流程
strongSelf->running = YES;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC),
strongSelf.manQueue, ^{
__strong typeof(weakSelf) strongSelf2 = weakSelf;
if (!strongSelf2) return;
[strongSelf2 appRun:strongSelf2->taskAppId];
});
} else {
retryCount++;
if (retryCount < 3) {
// 延迟1秒重试
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), strongSelf.manQueue, saveBlock);
} else {
// 重试失败,记录日志
NSLog(@"saveChangeDataFile failed after 3 retries");
}
}
};
saveBlock();
}];
}
- (void)appKill:(NSString*)app {
NSLog(@"XS- appKill");
XSKillAppByName(app);
}
- (void)unlock {
NSLog(@"XS- unlock");
dispatch_async(dispatch_get_main_queue(), ^{
XSRemoteUnlock();
});
}
- (void)resetApp:(NSString*)appId callback:(OnEndCallback)callback {
NSLog(@"XS- JSApi resetApp");
NSString *appInfoPath = XSGetAppInfoPath(appId);
NSDictionary *appInfo = XSGetAppInfo(appInfoPath);
id bfaceDictKey = appInfo[@"bfaceDictKey"];
NSMutableDictionary *tempBfaceDictKey = nil;
if(bfaceDictKey) {
tempBfaceDictKey = [NSMutableDictionary dictionaryWithDictionary:bfaceDictKey];
} else {
tempBfaceDictKey = [[NSMutableDictionary alloc] init];
}
NSString *serverUrl = [[XSPhoneConfig sharedInstance] ServerURL];
BOOL washParam = [[XSPhoneConfig sharedInstance] WashParam];
[tempBfaceDictKey setValue:serverUrl forKey:@"adbrush_base_url"];
[tempBfaceDictKey setValue:@(washParam) forKey:@"washParam"];
// [tempBfaceDictKey setValue:lowEcpm forKey:@"adbrush_ecpm"];
if(self->linkId) {
[tempBfaceDictKey setValue:self->linkId forKey:@"linkId"];
} else {
NSString *linkId = [[NSUUID UUID] UUIDString];
[tempBfaceDictKey setValue:linkId forKey:@"linkId"];
}
if(self->dataId) {
[tempBfaceDictKey setValue:self->dataId forKey:@"dataId"];
} else {
[tempBfaceDictKey setValue:@"0" forKey:@"dataId"];
}
if(self->remoteIp) {
[tempBfaceDictKey setValue:self->remoteIp forKey:@"remoteIp"];
}
uint16_t udp_port = [XUDPServer sharedInstance].udp_port;
[tempBfaceDictKey setValue:@(udp_port) forKey:@"udp_port"];
[tempBfaceDictKey setValue:[self getSystemInfo] forKey:@"device_model"];
NSLog(@"XS- resetApp 1");
NSMutableDictionary *tempAppInfo = [[NSMutableDictionary alloc] init];
[tempAppInfo setValue:tempBfaceDictKey forKey:@"bfaceDictKey"];
XSClearAll(appId);
XSSaveAppInfo(tempAppInfo, appInfoPath);
callback();
}
- (NSString *)frontMostAppId {
return XSFrontMostAppId();
}
- (void)appRun:(NSString *)appId {
if ([XSHelper strIsEmpty:appId]) return;
dispatch_async(dispatch_get_main_queue(), ^{
@try {
bringAppToForeground(appId);
} @catch (NSException *exception) {
NSLog(@"Error bringing app to foreground: %@", exception);
}
});
}
- (void)restart:(OnEndCallback)callback {
@synchronized (self) {
__weak typeof(self) weakSelf = self;
dispatch_async(self.manQueue, ^{
@try {
__strong typeof(weakSelf) strongSelf = weakSelf;
if (!strongSelf) return;
[weakSelf appKill:@"com.apple.AppStore"];
[weakSelf appKill:@"com.apple.mobilesafari"];
if (strongSelf->taskAppId && ![strongSelf->taskAppId isEqual:[NSNull null]] && [strongSelf->taskAppId length] > 0) {
[weakSelf appKill:strongSelf->taskAppId];
[weakSelf unlock];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), strongSelf.manQueue, ^{
[weakSelf unlock];
[weakSelf resetApp:strongSelf->taskAppId callback:callback];
});
}
} @catch (NSException *exception) {
NSLog(@"Error in restart: %@", exception);
}
});
}
}
- (void)rndTouchApp {
int times = [XSHelper random:2 and:4];
}
- (NSString*)getStr:(NSString *)key dic:(NSDictionary*)dic {
NSLog(@"getStr: %@", key);
id t_idfa = dic[key];
if (t_idfa && ![t_idfa isEqual:[NSNull null]] && ![t_idfa isEqual:@""]) {
return [NSString stringWithFormat:@"%@", t_idfa];
} else {
NSLog(@"XS- dic %@ is null", key);
return @"";
}
}
- (NSNumber*)getNum:(NSString *)key dic:(NSDictionary*)dic {
NSLog(@"getNum: %@", key);
id t_idfa = dic[key];
NSString *ecpm_str = [NSString stringWithFormat:@"%@", t_idfa];
NSNumber *ecpm = @0.0;
if (ecpm_str && ![ecpm_str isEqual:[NSNull null]] && ![ecpm_str isEqual:@""]) {
ecpm = [XSHelper str2num:ecpm_str];
}
return ecpm;
}
- (int)getInt:(NSString *)key dic:(NSDictionary*)dic {
NSLog(@"getInt: %@", key);
id t_idfa = dic[key];
NSString *ecpm_str = [NSString stringWithFormat:@"%@", t_idfa];
NSNumber *ecpm = @(-99);
if (ecpm_str && ![ecpm_str isEqual:[NSNull null]] && ![ecpm_str isEqual:@""]) {
ecpm = [XSHelper str2num:ecpm_str];
}
return [ecpm intValue];
}
- (void)dealloc {
[self stop];
}
@end