ios-hooks/AppRunMan/server/MyAdTask2.m
2025-12-01 17:42:45 +08:00

622 lines
20 KiB
Objective-C

#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;
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 {
NSLog(@"XS- saveChangeDataFile failed");
}
};
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