// // XSPhoneInfo.m // nochange // // Created by mac on 2024/10/15. // #import #import #import #import #import #import #import #import #import #import "XSPhoneInfo.h" @interface XSPhoneInfo() { } @property (nonatomic, strong) NSTimer *monitorTimer; @property (nonatomic, assign) BOOL isMonitoring; @property (nonatomic, copy) void (^memoryWarningHandler)(double availableMemory); @end @implementation XSPhoneInfo { dispatch_source_t _memoryPressureSource; natural_t mem_free; natural_t mem_total; } +(instancetype)sharedInstance { static XSPhoneInfo* _sharedInstance = nil; static dispatch_once_t oncePredicate; dispatch_once (&oncePredicate, ^{ _sharedInstance = [[XSPhoneInfo alloc] init]; }); return _sharedInstance; } -(instancetype)init { if (self = [super init]) { [self setupBatteryMonitoring]; _pageSize = vm_page_size; [self startMemoryMonitoring]; [self updateMemoryInfo]; self.remoteIp = @""; return self; } return nil; } - (void)setupBatteryMonitoring { // 允许电池监控 [[UIDevice currentDevice] setBatteryMonitoringEnabled:YES]; // 注册电池通知 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(batteryLevelDidChange:) name:UIDeviceBatteryLevelDidChangeNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(batteryStateDidChange:) name:UIDeviceBatteryStateDidChangeNotification object:nil]; } - (void)startBatteryMonitoring { if (!self.isMonitoring) { self.isMonitoring = YES; // 创建定时器定期更新电池信息 self.monitorTimer = [NSTimer scheduledTimerWithTimeInterval:60.0 target:self selector:@selector(updateBatteryInfo) userInfo:nil repeats:YES]; [self updateBatteryInfo]; } } - (void)updateBatteryInfo { // 更新基本电池信息 _batteryLevel = [[UIDevice currentDevice] batteryLevel]; _isCharging = [[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateCharging; _isFullyCharged = [[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateFull; // 获取详细电池信息 [self updateDetailedBatteryInfo]; //[self updateMemoryInfo]; } - (void)updateDetailedBatteryInfo { @try { // 使用IOKit获取电池详细信息 CFMutableDictionaryRef matching = IOServiceMatching("IOPMPowerSource"); io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, matching); if (service) { CFMutableDictionaryRef properties = NULL; kern_return_t kr = IORegistryEntryCreateCFProperties(service, &properties, kCFAllocatorDefault, 0); if (kr == KERN_SUCCESS) { NSDictionary *batteryProps = (__bridge_transfer NSDictionary *)properties; // 更新基本信息 _batteryLevel = [[batteryProps objectForKey:@"CurrentCapacity"] floatValue] / 100.0; _isCharging = [[batteryProps objectForKey:@"IsCharging"] boolValue]; _isFullyCharged = [[batteryProps objectForKey:@"FullyCharged"] boolValue]; // 获取电池容量信息 _designCapacity = [[batteryProps objectForKey:@"DesignCapacity"] floatValue]; _maxCapacity = [[batteryProps objectForKey:@"AppleRawMaxCapacity"] floatValue]; _currentCapacity = [[batteryProps objectForKey:@"CurrentCapacity"] floatValue]; // 获取电压信息 _batteryVoltage = [[batteryProps objectForKey:@"Voltage"] floatValue]; // 获取循环次数 _cycleCount = [[batteryProps objectForKey:@"CycleCount"] integerValue]; // 计算健康度 if (_designCapacity > 0 && _maxCapacity > 0) { _batteryHealth = (_maxCapacity / _designCapacity) * 100; } // 更新电池状态描述 [self updateBatteryStatus:batteryProps]; } IOObjectRelease(service); } } @catch (NSException *exception) { NSLog(@"Battery info update error: %@", exception); } } - (void)updateBatteryStatus:(NSDictionary *)batteryProps { NSMutableString *status = [NSMutableString string]; // 基本状态 if (_isCharging) { [status appendString:@"正在充电"]; } else { [status appendString:@"使用电池中"]; } // 健康状态 if (_batteryHealth > 0) { //[status appendFormat:@"\n健康度: %ld%%", (long)_batteryHealth]; /* if (_batteryHealth < 80) { [status appendString:@" (建议更换电池)"]; } else if (_batteryHealth < 90) { [status appendString:@" (性能可能降低)"]; } */ } // 循环次数 if (_cycleCount > 0) { //[status appendFormat:@"\n充电次数: %ld", (long)_cycleCount]; /* if (_cycleCount > 500) { [status appendString:@" (使用时间较长)"]; } */ } self.batteryStatus = [status copy]; } - (NSDictionary *)getBatteryInfo { return @{ @"level": @(self.batteryLevel), @"isCharging": @(self.isCharging), @"isFullyCharged": @(self.isFullyCharged), @"health": @(self.batteryHealth), @"cycleCount": @(self.cycleCount), @"temperature": @(self.temperature), @"voltage": @(self.voltage), @"status": self.batteryStatus ?: @"未知" }; } - (void)stopBatteryMonitoring { if (self.isMonitoring) { self.isMonitoring = NO; [self.monitorTimer invalidate]; self.monitorTimer = nil; } } - (void)batteryLevelDidChange:(NSNotification *)notification { [self updateBatteryInfo]; } - (void)batteryStateDidChange:(NSNotification *)notification { [self updateBatteryInfo]; } #pragma mark - Memory Info Methods - (void)updateMemoryInfo { mach_port_t host_port = mach_host_self(); mach_msg_type_number_t host_size = HOST_VM_INFO_COUNT; vm_statistics_data_t vm_stat; if (host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size) != KERN_SUCCESS) { NSLog(@"Failed to fetch vm statistics"); return; } // 计算内存信息 natural_t mem_used = (vm_stat.active_count + vm_stat.inactive_count + vm_stat.wire_count) * _pageSize; self->mem_free = vm_stat.free_count * _pageSize; self->mem_total = mem_used + mem_free; // 更新属性 _totalMemory = self->mem_total / (1024.0 * 1024.0 * 1024.0); // Convert to GB _availableMemory = self->mem_free / (1024.0 * 1024.0 * 1024.0); // Convert to GB _usedMemory = mem_used / (1024.0 * 1024.0 * 1024.0); // Convert to GB _memoryUsage = (mem_used * 100.0) / self->mem_total; // Calculate percentage } - (double)getMemoryUsageForPid:(pid_t)pid { task_vm_info_data_t vmInfo; mach_msg_type_number_t count = TASK_VM_INFO_COUNT; kern_return_t kernReturn = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t)&vmInfo, &count); if (kernReturn == KERN_SUCCESS) { return (double)vmInfo.phys_footprint / 1024.0 / 1024.0; // Convert to MB } return 0; } #pragma mark - Memory Monitoring - (void)handleCriticalMemoryPressure { // 发送通知 [[NSNotificationCenter defaultCenter] postNotificationName:@"MemoryCriticalNotification" object:nil userInfo:@{@"availableMemory": @(self.availableMemory)}]; } - (void)handleWarningMemoryPressure { // 发送警告通知 [[NSNotificationCenter defaultCenter] postNotificationName:@"MemoryWarningNotification" object:nil userInfo:@{@"availableMemory": @(self.availableMemory)}]; } - (void)startMemoryMonitoring { // 创建定时器定期检查内存 self.monitorTimer = [NSTimer scheduledTimerWithTimeInterval:30.0 target:self selector:@selector(checkMemoryStatus) userInfo:nil repeats:YES]; } - (void)stopMemoryMonitoring { [self.monitorTimer invalidate]; self.monitorTimer = nil; } - (void)checkMemoryStatus { [self updateMemoryInfo]; } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; [[UIDevice currentDevice] setBatteryMonitoringEnabled:NO]; [self stopBatteryMonitoring]; [self stopMemoryMonitoring]; if (_memoryPressureSource) { dispatch_source_cancel(_memoryPressureSource); } } - (NSString *)IPAddress { NSDictionary *addresses = [self getIPAddresses]; __block NSString *address; [addresses enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { address = obj; if(address) *stop = YES; }]; return address ? address : @"0.0.0.0"; } - (NSDictionary *)getIPAddresses { NSMutableDictionary *addresses = [NSMutableDictionary dictionaryWithCapacity:8]; // retrieve the current interfaces - returns 0 on success struct ifaddrs *interfaces; if(!getifaddrs(&interfaces)) { // Loop through linked list of interfaces struct ifaddrs *interface; for(interface=interfaces; interface; interface=interface->ifa_next) { if(!(interface->ifa_flags & IFF_UP) || (interface->ifa_flags & IFF_LOOPBACK)) { continue; // deeply nested code harder to read } const struct sockaddr_in *addr = (const struct sockaddr_in*)interface->ifa_addr; char addrBuf[ MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) ]; if(addr && (addr->sin_family==AF_INET)) { NSString *name = [NSString stringWithUTF8String:interface->ifa_name]; NSString *type; if(addr->sin_family == AF_INET) { if(inet_ntop(AF_INET, &addr->sin_addr, addrBuf, INET_ADDRSTRLEN)) { type = @"ipv4"; } } if(type) { NSString *key = [NSString stringWithFormat:@"%@/%@", name, type]; addresses[key] = [NSString stringWithUTF8String:addrBuf]; } } } // Free memory freeifaddrs(interfaces); } return [addresses count] ? addresses : nil; } - (NSString *)CurrentThermalState { NSProcessInfoThermalState state = [NSProcessInfo processInfo].thermalState; switch (state) { case NSProcessInfoThermalStateNominal: return @"Nominal"; case NSProcessInfoThermalStateFair: return @"Fair"; case NSProcessInfoThermalStateSerious: return @"Serious"; case NSProcessInfoThermalStateCritical: return @"Critical"; default: return @"Unknown"; } } - (NSString *)DiskSize { @try { // 磁盘 NSDictionary *info = [[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() error:nil]; NSLog(@"diskinfo: %@", info); int64_t size = [info[NSFileSystemSize] longLongValue]; // 总大小 int64_t space = [[info objectForKey:NSFileSystemFreeSize] longLongValue]; NSString *gb = [NSByteCountFormatter stringFromByteCount:size countStyle:NSByteCountFormatterCountStyleDecimal]; NSString *space_gb = [NSByteCountFormatter stringFromByteCount:space countStyle:NSByteCountFormatterCountStyleDecimal]; return [NSString stringWithFormat:@"%@/%@", space_gb,gb]; } @catch (NSException *exception) { return @""; } } - (NSString *)IPhoneStatus { [self updateBatteryInfo]; [self updateMemoryInfo]; NSString *gb = [NSByteCountFormatter stringFromByteCount: self->mem_total countStyle:NSByteCountFormatterCountStyleDecimal]; NSString *space_gb = [NSByteCountFormatter stringFromByteCount:self->mem_free countStyle:NSByteCountFormatterCountStyleDecimal]; NSString *mem = [NSString stringWithFormat:@"%@/%@", space_gb,gb]; NSString *res = [NSString stringWithFormat:@"电池%ld%%,%@;内存%@;磁盘%@",(long)(self.batteryLevel*100), self.batteryStatus, mem,self.DiskSize ]; return res; } @end