New file |
| | |
| | | // |
| | | // UIApplication+YYAdd.m |
| | | // YYCategories <https://github.com/ibireme/YYCategories> |
| | | // |
| | | // 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 "YYCategoriesMacro.h" |
| | | #import "UIDevice+YYAdd.h" |
| | | #import <sys/sysctl.h> |
| | | #import <mach/mach.h> |
| | | #import <objc/runtime.h> |
| | | |
| | | 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) { |
| | | [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 |