// // UIApplication+YYAdd.m // YYKit // // Created by ibireme on 13/4/4. // Copyright (c) 2015 ibireme. // // This source code is licensed under the MIT-style license found in the // LICENSE file in the root directory of this source tree. // #import "UIApplication+YYAdd.h" #import "NSArray+YYAdd.h" #import "NSObject+YYAdd.h" #import "YYKitMacro.h" #import "UIDevice+YYAdd.h" #import #import #import YYSYNTH_DUMMY_CLASS(UIApplication_YYAdd) #define kNetworkIndicatorDelay (1/30.0) @interface _YYUIApplicationNetworkIndicatorInfo : NSObject @property (nonatomic, assign) NSInteger count; @property (nonatomic, strong) NSTimer *timer; @end @implementation _YYUIApplicationNetworkIndicatorInfo @end @implementation UIApplication (YYAdd) - (NSURL *)documentsURL { return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; } - (NSString *)documentsPath { return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; } - (NSURL *)cachesURL { return [[[NSFileManager defaultManager] URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask] lastObject]; } - (NSString *)cachesPath { return [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject]; } - (NSURL *)libraryURL { return [[[NSFileManager defaultManager] URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] lastObject]; } - (NSString *)libraryPath { return [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) firstObject]; } - (BOOL)isPirated { if ([[UIDevice currentDevice] isSimulator]) return YES; // Simulator is not from appstore if (getgid() <= 10) return YES; // process ID shouldn't be root if ([[[NSBundle mainBundle] infoDictionary] objectForKey:@"SignerIdentity"]) { return YES; } if (![self _yy_fileExistInMainBundle:@"_CodeSignature"]) { return YES; } if (![self _yy_fileExistInMainBundle:@"SC_Info"]) { return YES; } //if someone really want to crack your app, this method is useless.. //you may change this method's name, encrypt the code and do more check.. return NO; } - (BOOL)_yy_fileExistInMainBundle:(NSString *)name { NSString *bundlePath = [[NSBundle mainBundle] bundlePath]; NSString *path = [NSString stringWithFormat:@"%@/%@", bundlePath, name]; return [[NSFileManager defaultManager] fileExistsAtPath:path]; } - (NSString *)appBundleName { return [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"]; } - (NSString *)appBundleID { return [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"]; } - (NSString *)appVersion { return [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; } - (NSString *)appBuildVersion { return [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]; } - (BOOL)isBeingDebugged { size_t size = sizeof(struct kinfo_proc); struct kinfo_proc info; int ret = 0, name[4]; memset(&info, 0, sizeof(struct kinfo_proc)); name[0] = CTL_KERN; name[1] = KERN_PROC; name[2] = KERN_PROC_PID; name[3] = getpid(); if (ret == (sysctl(name, 4, &info, &size, NULL, 0))) { return ret != 0; } return (info.kp_proc.p_flag & P_TRACED) ? YES : NO; } - (int64_t)memoryUsage { struct task_basic_info info; mach_msg_type_number_t size = sizeof(info); kern_return_t kern = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &size); if (kern != KERN_SUCCESS) return -1; return info.resident_size; } - (float)cpuUsage { kern_return_t kr; task_info_data_t tinfo; mach_msg_type_number_t task_info_count; task_info_count = TASK_INFO_MAX; kr = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)tinfo, &task_info_count); if (kr != KERN_SUCCESS) { return -1; } thread_array_t thread_list; mach_msg_type_number_t thread_count; thread_info_data_t thinfo; mach_msg_type_number_t thread_info_count; thread_basic_info_t basic_info_th; kr = task_threads(mach_task_self(), &thread_list, &thread_count); if (kr != KERN_SUCCESS) { return -1; } long tot_sec = 0; long tot_usec = 0; float tot_cpu = 0; int j; for (j = 0; j < thread_count; j++) { thread_info_count = THREAD_INFO_MAX; kr = thread_info(thread_list[j], THREAD_BASIC_INFO, (thread_info_t)thinfo, &thread_info_count); if (kr != KERN_SUCCESS) { return -1; } basic_info_th = (thread_basic_info_t)thinfo; if (!(basic_info_th->flags & TH_FLAGS_IDLE)) { tot_sec = tot_sec + basic_info_th->user_time.seconds + basic_info_th->system_time.seconds; tot_usec = tot_usec + basic_info_th->system_time.microseconds + basic_info_th->system_time.microseconds; tot_cpu = tot_cpu + basic_info_th->cpu_usage / (float)TH_USAGE_SCALE; } } kr = vm_deallocate(mach_task_self(), (vm_offset_t)thread_list, thread_count * sizeof(thread_t)); assert(kr == KERN_SUCCESS); return tot_cpu; } YYSYNTH_DYNAMIC_PROPERTY_OBJECT(networkActivityInfo, setNetworkActivityInfo, RETAIN_NONATOMIC, _YYUIApplicationNetworkIndicatorInfo *); - (void)_delaySetActivity:(NSTimer *)timer { NSNumber *visiable = timer.userInfo; if (self.networkActivityIndicatorVisible != visiable.boolValue) { //modify by leo [self setNetworkActivityIndicatorVisible:visiable.boolValue]; } [timer invalidate]; } - (void)_changeNetworkActivityCount:(NSInteger)delta { @synchronized(self){ dispatch_async_on_main_queue(^{ _YYUIApplicationNetworkIndicatorInfo *info = [self networkActivityInfo]; if (!info) { info = [_YYUIApplicationNetworkIndicatorInfo new]; [self setNetworkActivityInfo:info]; } NSInteger count = info.count; count += delta; info.count = count; [info.timer invalidate]; info.timer = [NSTimer timerWithTimeInterval:kNetworkIndicatorDelay target:self selector:@selector(_delaySetActivity:) userInfo:@(info.count > 0) repeats:NO]; [[NSRunLoop mainRunLoop] addTimer:info.timer forMode:NSRunLoopCommonModes]; }); } } - (void)incrementNetworkActivityCount { [self _changeNetworkActivityCount:1]; } - (void)decrementNetworkActivityCount { [self _changeNetworkActivityCount:-1]; } + (BOOL)isAppExtension { static BOOL isAppExtension = NO; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ Class cls = NSClassFromString(@"UIApplication"); if(!cls || ![cls respondsToSelector:@selector(sharedApplication)]) isAppExtension = YES; if ([[[NSBundle mainBundle] bundlePath] hasSuffix:@".appex"]) isAppExtension = YES; }); return isAppExtension; } + (UIApplication *)sharedExtensionApplication { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wundeclared-selector" return [self isAppExtension] ? nil : [UIApplication performSelector:@selector(sharedApplication)]; #pragma clang diagnostic pop } @end