├── README.md ├── VKSniffer ├── VKSniffer.h ├── VKSniffer.m ├── VKSnifferProtocol.h └── VKSnifferProtocol.m ├── VKSnifferDemo ├── Podfile ├── VKSnifferDemo.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcuserdata │ │ └── Awhisper.xcuserdatad │ │ └── xcschemes │ │ └── VKSnifferDemo.xcscheme └── VKSnifferDemo │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Info.plist │ ├── ViewController.h │ ├── ViewController.m │ └── main.m └── VKSnifferUI ├── VKSniffer+UI.h ├── VKSniffer+UI.m ├── VKSnifferCell.h ├── VKSnifferCell.m ├── VKSnifferResult+UI.h ├── VKSnifferResult+UI.m ├── VKSnifferViewController.h ├── VKSnifferViewController.m ├── VKSnifferWindow.h └── VKSnifferWindow.m /README.md: -------------------------------------------------------------------------------- 1 | # 简介: 2 | 3 | 无侵入式将所有App发起的网络请求,独立记录管理起来,支持界面形式进行查看 4 | 5 | - 支持`URLConnection` `URLSession` 6 | - 支持进行域名过滤嗅探,只截获记录符合过滤规则的网络请求 7 | - 支持界面形式实时查看网络请求记录 8 | - 支持网络请求记录的顺序,倒序查看 9 | - 查看复制网络请求信息到剪切板 10 | 11 | # 使用 12 | 13 | ## VKSniffer 14 | 15 | VKSniffer目录是嗅探器的主体逻辑代码,只导入VKSniffer目录,即可让嗅探器正常工作 16 | 17 | ```objectivec 18 | //基本用法 19 | [VKSniffer setupSnifferHandler:^(VKSnifferResult *result) { 20 | NSLog(@"%@",result); 21 | }]; 22 | [VKSniffer startSniffer]; 23 | ``` 24 | 25 | - `+ startSniffer` 26 | 27 | Require方法,一行代码即可开启监听和嗅探。 28 | 29 | - `+ setupSnifferHandler:` 30 | 31 | Option方法,嗅探到的每一条网络请求结果,会通过Handler回调,传给使用者,如果不设置,网络请求会保存在单例的netResultArray里 32 | 33 | - `+ setupHostFilter:` 34 | 35 | Option方法,可以让嗅探器有选择的拦截指定域名的网络请求并记录,如果不设置,默认全体拦截 36 | 37 | - `+ setupConfiguration:` 38 | 39 | Option方法,嗅探器默认支持`NSURLConnection`与系统的`[NSURLSession sharedSession]`,如果需要支持`defaultSessionConfiguration`生成的`NSURLSession`需要调用此函数来进行额外配置(例如:AfNetworking3.0) 40 | 41 | ```objectiveC 42 | //初始化AfNetworking3.0 配置VKSniffer 43 | NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; 44 | 45 | //在创建manager前,调用setupConfiguration 46 | [VKSniffer setupConfiguration:configuration]; 47 | 48 | //创建manager 49 | AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration]; 50 | self.manager = manager; 51 | ``` 52 | 53 | 54 | ## VKSnifferUI 55 | 56 | VKSnifferUI目录是界面列表功能,同时导入`VKSnifferUI`与`VKSniffer`目录即可让所有的网络请求日志,通过列表界面进行查看 57 | 58 | - `+ showSnifferView` 59 | - `+ hideSnifferView` 60 | 61 | 一行代码,打开网络请求日志界面 62 | 63 | __Menu功能包含__ 64 | 65 | - 暂停/启动 UrlProtocol拦截 66 | - 移除列表中所有内容 67 | - 列表逆序/顺序排列 68 | - 重新设定域名过滤器 69 | - 查看复制网络请求信息到剪切板 70 | 71 | __推荐配合VKShakeCommands使用__ 72 | 73 | 74 | VKShakeCommands是工具 [VKKeyCommands](https://github.com/Awhisper/VKKeyCommands) 下的摇一摇组件,可以捕捉真机的摇一摇事件 75 | 76 | - 触发VKShakeCommands 77 | - 调用showSnifferView 78 | 79 | 在真机黑盒调试代码的时候,为了方便的不链接Xcode,也不必charles挂代理,就能看到所有网络日志,可以轻轻摇一摇手机,打开嗅探器界面,实现快速查看网络日志 80 | 81 | 82 | 83 | # 背景 84 | 85 | VKSniffer其实是 [VKDevTool](https://github.com/Awhisper/VKDevTool) 的子功能发展而来。VKDevTool内部包含着网络请求日志查看功能。 86 | 87 | 当初开发VKDevTool的时候,贪心大而全,并且求快,网络请求日志功能,大体逻辑都已经实现,但是界面很糙,功能特别不细致(支持列表查看复制,支持暂停/开启,支持域名过滤) 88 | 89 | 后来看到了 [Xniffer](https://github.com/xmartlabs/Xniffer) 一款用Swift语言写的针对NSURLSession的嗅探器,他的大体功能VKDevTool的网络日志模块都已实现,他的好处是网络请求日志更加精细,细致记录了很多网络请求细节 90 | 91 | - 请求耗时 92 | - 请求状态码 93 | - 请求数据 94 | - 请求Error信息 95 | 96 | 97 | 因此萌生了重写`VKSniffer`的想法,取人之长,补己之短,并且把这个模块从VKDevTool中独立出来,可以独立运作。 98 | 99 | PS: VKDevTool逐个模块打算一一重新整理,当初写的太糙了 100 | 101 | PPS: 感谢 [Xniffer](https://github.com/xmartlabs/Xniffer) 的精致细节 102 | -------------------------------------------------------------------------------- /VKSniffer/VKSniffer.h: -------------------------------------------------------------------------------- 1 | // 2 | // VKSniffer.h 3 | // VKSnifferDemo 4 | // 5 | // Created by Awhisper on 2017/3/6. 6 | // Copyright © 2017年 baidu. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | 13 | #define VKNetSnifferReqLogNotification @"VKNetSnifferReqLogNotification" 14 | 15 | @interface VKSnifferRequestItem : NSObject 16 | 17 | @property (nonatomic,assign) NSInteger identifier; 18 | 19 | @property (nonatomic,assign) NSTimeInterval timeStamp; 20 | 21 | @property (nonatomic,strong) NSURLRequest *request; 22 | 23 | 24 | @end 25 | 26 | @interface VKSnifferResponseItem : NSObject 27 | 28 | @property (nonatomic,assign) NSUInteger identifier; 29 | 30 | @property (nonatomic,assign) NSTimeInterval timeStamp; 31 | 32 | @property (nonatomic,strong) NSHTTPURLResponse *response; 33 | 34 | @property (nonatomic,strong) NSURLSession *session; 35 | 36 | @property (nonatomic,strong) NSData *data; 37 | 38 | @end 39 | 40 | @interface VKSnifferErrorItem : NSObject 41 | 42 | @property (nonatomic,assign) NSInteger identifier; 43 | 44 | @property (nonatomic,assign) NSTimeInterval timeStamp; 45 | 46 | @property (nonatomic,strong) NSHTTPURLResponse *response; 47 | 48 | @property (nonatomic,strong) NSURLSession *session; 49 | 50 | @property (nonatomic,strong) NSError *error; 51 | 52 | @end 53 | 54 | @interface VKSnifferResult : NSObject 55 | 56 | @property (nonatomic,strong) NSURLRequest *request; 57 | 58 | @property (nonatomic,strong) NSHTTPURLResponse *response; 59 | 60 | @property (nonatomic,strong) NSError *error; 61 | 62 | @property (nonatomic,strong) NSURLSession *session; 63 | 64 | @property (nonatomic,assign) NSTimeInterval duration; 65 | 66 | @property (nonatomic,strong) NSData *data; 67 | 68 | -(NSString *)detailInfo; 69 | 70 | @end 71 | 72 | typedef void(^VKSnifferHandler)(VKSnifferResult *result); 73 | 74 | @interface VKSniffer : NSObject 75 | 76 | @property (nonatomic,assign) BOOL enableSniffer; 77 | 78 | @property(nonatomic,strong) NSString* hostFilter; 79 | 80 | @property(atomic,strong) NSMutableArray* netResultArray; 81 | 82 | - (instancetype)sharedInstance; 83 | 84 | + (instancetype)singleton; 85 | 86 | + (void)startSniffer; 87 | 88 | //Use this for custom Session such as Afnetworking 3.0 89 | + (void)setupConfiguration:(NSURLSessionConfiguration *)config; 90 | //option 91 | + (void)setupSnifferHandler:(VKSnifferHandler)callback; 92 | //option 93 | + (void)setupHostFilter:(NSString *)host; 94 | 95 | @end 96 | -------------------------------------------------------------------------------- /VKSniffer/VKSniffer.m: -------------------------------------------------------------------------------- 1 | // 2 | // VKSniffer.m 3 | // VKSnifferDemo 4 | // 5 | // Created by Awhisper on 2017/3/6. 6 | // Copyright © 2017年 baidu. All rights reserved. 7 | // 8 | 9 | #import "VKSniffer.h" 10 | #import "VKSnifferProtocol.h" 11 | #import "VKSnifferWindow.h" 12 | 13 | #define VKMAXSNIFFERPRECORD 50 14 | 15 | @implementation VKSnifferRequestItem 16 | 17 | 18 | @end 19 | 20 | @implementation VKSnifferResponseItem 21 | 22 | 23 | @end 24 | 25 | @implementation VKSnifferErrorItem 26 | 27 | 28 | @end 29 | 30 | @implementation VKSnifferResult 31 | 32 | -(NSString *)description 33 | { 34 | NSMutableString *pstr = [[NSMutableString alloc]initWithString:@""]; 35 | [pstr appendString:@"URL: - "]; 36 | [pstr appendString:self.request.URL.absoluteString]; 37 | [pstr appendString:@"\r\n"]; 38 | 39 | NSString * statusStr = (self.response.statusCode >= 200 && self.response.statusCode < 300) ? @"Success" : @"Error"; 40 | statusStr = [NSString stringWithFormat:@"%@ Code: %@",statusStr,@(self.response.statusCode)]; 41 | [pstr appendString:statusStr]; 42 | [pstr appendString:@"\r\n"]; 43 | 44 | NSTimeInterval ms = self.duration * 1000.0f; 45 | NSString *timeStr = [NSString stringWithFormat:@"Time: %.2f ms",ms]; 46 | [pstr appendString:timeStr]; 47 | [pstr appendString:@"\r\n"]; 48 | 49 | if (self.data) { 50 | NSString *dataStr = [[NSJSONSerialization JSONObjectWithData:self.data options:kNilOptions error:nil] description]; 51 | [pstr appendString:@"responeData:"]; 52 | [pstr appendString:@"\r\n"]; 53 | [pstr appendString:dataStr]; 54 | [pstr appendString:@"\r\n"]; 55 | } 56 | 57 | 58 | return [pstr copy]; 59 | } 60 | 61 | -(NSString *)detailInfo{ 62 | return self.description; 63 | } 64 | @end 65 | 66 | 67 | @interface VKSniffer () 68 | 69 | @property (nonatomic,strong) VKSnifferHandler Snifferhandler; 70 | 71 | @property(atomic,strong) NSMutableArray * netRequestArray; 72 | 73 | @end 74 | 75 | @implementation VKSniffer 76 | 77 | #pragma mark singleton 78 | 79 | - (instancetype)sharedInstance 80 | { 81 | return [[self class] singleton]; 82 | } 83 | 84 | static id __singleton__; 85 | 86 | + (instancetype)singleton 87 | { 88 | static dispatch_once_t once; 89 | dispatch_once( &once, ^{ __singleton__ = [[self alloc] init]; } ); 90 | return __singleton__; 91 | } 92 | 93 | #pragma mark init 94 | -(instancetype)init{ 95 | self = [super init]; 96 | if (self) { 97 | self.enableSniffer = NO; 98 | self.netResultArray = [[NSMutableArray alloc]init]; 99 | self.netRequestArray = [[NSMutableArray alloc]init]; 100 | } 101 | return self; 102 | } 103 | 104 | +(void)setupConfiguration:(NSURLSessionConfiguration *)config 105 | { 106 | if (config) { 107 | NSMutableArray *mProtocolClasses = [[NSMutableArray alloc]initWithArray:config.protocolClasses]; 108 | [mProtocolClasses insertObject:[VKSnifferProtocol class] atIndex:0]; 109 | config.protocolClasses = [NSArray arrayWithArray:mProtocolClasses]; 110 | } 111 | 112 | } 113 | 114 | +(void)setupSnifferHandler:(VKSnifferHandler)callback{ 115 | if (callback) { 116 | [VKSniffer singleton].Snifferhandler = callback; 117 | } 118 | } 119 | 120 | +(void)setupHostFilter:(NSString *)host{ 121 | if (host) { 122 | [VKSniffer singleton].hostFilter = host; 123 | } 124 | } 125 | 126 | +(void)startSniffer{ 127 | [VKSniffer singleton].enableSniffer = YES; 128 | [NSURLProtocol registerClass:[VKSnifferProtocol class]]; 129 | } 130 | 131 | #pragma mark logic 132 | 133 | -(void)sniffRequestEnqueue:(VKSnifferRequestItem *)request 134 | { 135 | if (request) { 136 | [self.netRequestArray addObject:request]; 137 | } 138 | } 139 | 140 | -(VKSnifferRequestItem *)sniffRequestDequeue:(NSInteger)requestId 141 | { 142 | VKSnifferRequestItem *request; 143 | for (VKSnifferRequestItem* item in self.netRequestArray) { 144 | if (item.identifier == requestId) { 145 | request = item; 146 | break; 147 | } 148 | } 149 | return request; 150 | } 151 | 152 | -(void)sniffRequestResponse:(VKSnifferResponseItem *)response{ 153 | VKSnifferRequestItem *request = [self sniffRequestDequeue:response.identifier]; 154 | NSTimeInterval timeInterval = response.timeStamp - request.timeStamp; 155 | VKSnifferResult *result = [[VKSnifferResult alloc]init]; 156 | result.request = request.request; 157 | result.response = response.response; 158 | result.error = nil; 159 | result.data = response.data; 160 | result.session = response.session; 161 | result.duration = timeInterval; 162 | [self postSnifferResult:result]; 163 | } 164 | 165 | -(void)sniffRequestError:(VKSnifferErrorItem *)error{ 166 | VKSnifferRequestItem *request = [self sniffRequestDequeue:error.identifier]; 167 | NSTimeInterval timeInterval = error.timeStamp - request.timeStamp; 168 | VKSnifferResult *result = [[VKSnifferResult alloc]init]; 169 | result.request = request.request; 170 | result.response = error.response; 171 | result.error = error.error; 172 | result.session = error.session; 173 | result.duration = timeInterval; 174 | [self postSnifferResult:result]; 175 | } 176 | 177 | -(void)postSnifferResult:(VKSnifferResult *)result{ 178 | 179 | 180 | @synchronized([VKSniffer singleton]) { 181 | if (result) { 182 | 183 | [[VKSniffer singleton].netResultArray addObject:result]; 184 | 185 | if ([[VKSniffer singleton].netResultArray count] > VKMAXSNIFFERPRECORD) { 186 | NSInteger nowCount = [VKSniffer singleton].netResultArray.count; 187 | [[VKSniffer singleton].netResultArray removeObjectsInRange:NSMakeRange(0, nowCount - VKMAXSNIFFERPRECORD)]; 188 | } 189 | if ([NSThread isMainThread]) { 190 | [[NSNotificationCenter defaultCenter]postNotificationName:VKNetSnifferReqLogNotification object:result]; 191 | if (self.Snifferhandler) { 192 | self.Snifferhandler(result); 193 | } 194 | }else { 195 | dispatch_async(dispatch_get_main_queue(), ^{ 196 | [[NSNotificationCenter defaultCenter]postNotificationName:VKNetSnifferReqLogNotification object:result]; 197 | if (self.Snifferhandler) { 198 | self.Snifferhandler(result); 199 | } 200 | }); 201 | } 202 | } 203 | 204 | } 205 | 206 | 207 | } 208 | 209 | @end 210 | -------------------------------------------------------------------------------- /VKSniffer/VKSnifferProtocol.h: -------------------------------------------------------------------------------- 1 | // 2 | // VKSnifferProtocol.h 3 | // VKSnifferDemo 4 | // 5 | // Created by Awhisper on 2017/3/6. 6 | // Copyright © 2017年 baidu. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "VKSniffer.h" 11 | @interface VKSniffer (NSURLProtocol) 12 | 13 | -(void)sniffRequestEnqueue:(VKSnifferRequestItem *)request; 14 | 15 | -(void)sniffRequestResponse:(VKSnifferResponseItem *)response; 16 | 17 | -(void)sniffRequestError:(VKSnifferErrorItem *)error; 18 | 19 | -(VKSnifferRequestItem *)sniffRequestDequeue:(NSInteger)requestId; 20 | 21 | @end 22 | 23 | @interface VKSnifferProtocol : NSURLProtocol 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /VKSniffer/VKSnifferProtocol.m: -------------------------------------------------------------------------------- 1 | // 2 | // VKSnifferProtocol.m 3 | // VKSnifferDemo 4 | // 5 | // Created by Awhisper on 2017/3/6. 6 | // Copyright © 2017年 baidu. All rights reserved. 7 | // 8 | 9 | #import "VKSnifferProtocol.h" 10 | 11 | static NSString * const VKSnifferProtocolKey = @"VKSnifferProtocolKey"; 12 | 13 | @interface VKSnifferProtocol () 14 | 15 | @property (nonatomic,strong) NSURLSession *internalSession; 16 | @property (nonatomic,strong) NSURLSessionDataTask *internalTask; 17 | @property (nonatomic,strong) NSHTTPURLResponse *internalResponse; 18 | @property (nonatomic,strong) NSMutableData *internalResponseData; 19 | 20 | @end 21 | 22 | @implementation VKSnifferProtocol 23 | 24 | #pragma mark NSURLProtocol 25 | 26 | +(BOOL)canInitWithRequest:(NSURLRequest *)request{ 27 | if (![VKSniffer singleton].enableSniffer) { 28 | return NO; 29 | } 30 | 31 | //Post请求 body 会有问题因此抛弃 32 | if ([request.HTTPMethod isEqualToString:@"POST"]) { 33 | return NO; 34 | } 35 | 36 | //只处理http和https请求 37 | NSString *scheme = [[request URL] scheme]; 38 | if ( ([scheme rangeOfString:@"http"].location != NSNotFound) || 39 | ([scheme rangeOfString:@"https"].location != NSNotFound)) 40 | { 41 | if ([VKSniffer singleton].hostFilter && [VKSniffer singleton].hostFilter.length > 0) { 42 | 43 | NSString *url = [[request URL] absoluteString]; 44 | if ([url rangeOfString:[VKSniffer singleton].hostFilter].location != NSNotFound) { 45 | //看看是否已经处理过了,防止无限循环 46 | if ([NSURLProtocol propertyForKey:VKSnifferProtocolKey inRequest:request]) { 47 | return NO; 48 | } 49 | }else{ 50 | return NO; 51 | } 52 | }else{ 53 | //看看是否已经处理过了,防止无限循环 54 | if ([NSURLProtocol propertyForKey:VKSnifferProtocolKey inRequest:request]) { 55 | return NO; 56 | } 57 | } 58 | return YES; 59 | } 60 | 61 | return NO; 62 | } 63 | 64 | -(instancetype)initWithRequest:(NSURLRequest *)request cachedResponse:(NSCachedURLResponse *)cachedResponse client:(id)client{ 65 | self = [super initWithRequest:request cachedResponse:cachedResponse client:client]; 66 | if (self) { 67 | self.internalSession = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil]; 68 | self.internalTask = [self.internalSession dataTaskWithRequest:request]; 69 | } 70 | return self; 71 | } 72 | 73 | + (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request { 74 | return request; 75 | } 76 | 77 | -(void)startLoading{ 78 | [self hookRequest:self.request]; 79 | [self.internalTask resume]; 80 | } 81 | 82 | - (void)stopLoading{ 83 | [[VKSniffer singleton] sniffRequestDequeue:[self requestIdentifier]]; 84 | [self.internalSession invalidateAndCancel]; 85 | } 86 | 87 | #pragma mark logic 88 | 89 | -(NSMutableData *)internalResponseData{ 90 | if (!_internalResponseData) { 91 | _internalResponseData = [[NSMutableData alloc]init]; 92 | } 93 | return _internalResponseData; 94 | } 95 | 96 | -(NSUInteger)requestIdentifier{ 97 | if (self.internalTask && self.internalTask.originalRequest) { 98 | return self.hash; 99 | } 100 | return 0; 101 | } 102 | 103 | -(void)hookRequest:(NSURLRequest *)request{ 104 | NSTimeInterval startStamp = [[NSDate date] timeIntervalSince1970]; 105 | VKSnifferRequestItem *reqItem = [[VKSnifferRequestItem alloc]init]; 106 | reqItem.identifier = [self requestIdentifier]; 107 | reqItem.timeStamp = startStamp; 108 | reqItem.request = request; 109 | [[VKSniffer singleton]sniffRequestEnqueue:reqItem]; 110 | } 111 | 112 | -(void)hookResponse:(NSHTTPURLResponse *)response Data:(NSData *)data Session:(NSURLSession *)session{ 113 | NSTimeInterval endStamp = [[NSDate date] timeIntervalSince1970]; 114 | VKSnifferResponseItem * responseItem = [[VKSnifferResponseItem alloc]init]; 115 | responseItem.identifier = [self requestIdentifier]; 116 | responseItem.timeStamp = endStamp; 117 | responseItem.response = response; 118 | responseItem.session = session; 119 | responseItem.data = data; 120 | [[VKSniffer singleton]sniffRequestResponse:responseItem]; 121 | } 122 | 123 | -(void)hookError:(NSError *)error Response:(NSHTTPURLResponse *)response Data:(NSData *)data Session:(NSURLSession *)session{ 124 | NSTimeInterval endStamp = [[NSDate date] timeIntervalSince1970]; 125 | VKSnifferErrorItem * errorItem = [[VKSnifferErrorItem alloc]init]; 126 | errorItem.identifier = [self requestIdentifier]; 127 | errorItem.timeStamp = endStamp; 128 | errorItem.response = response; 129 | errorItem.session = session; 130 | errorItem.error = error; 131 | [[VKSniffer singleton]sniffRequestError:errorItem]; 132 | } 133 | 134 | #pragma mark URLSessionTaskDelegate 135 | 136 | -(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{ 137 | if (error) { 138 | [self hookError:error Response:self.internalResponse Data:self.internalResponseData Session:session]; 139 | [self.client URLProtocol:self didFailWithError:error]; 140 | }else if(self.internalResponse){ 141 | [self hookResponse:self.internalResponse Data:self.internalResponseData Session:session]; 142 | [self.client URLProtocolDidFinishLoading:self]; 143 | } 144 | } 145 | 146 | #pragma mark URLSessionDataDelegate 147 | 148 | -(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(nonnull NSURLResponse *)response completionHandler:(nonnull void (^)(NSURLSessionResponseDisposition))completionHandler{ 149 | if ([response isKindOfClass:[NSHTTPURLResponse class]]) { 150 | self.internalResponse = (NSHTTPURLResponse *)response; 151 | completionHandler(NSURLSessionResponseAllow); 152 | [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageAllowed]; 153 | } 154 | } 155 | 156 | -(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{ 157 | [self.internalResponseData appendData:data]; 158 | [self.client URLProtocol:self didLoadData:data]; 159 | } 160 | 161 | 162 | @end 163 | -------------------------------------------------------------------------------- /VKSnifferDemo/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | platform :ios, '8.0' 3 | 4 | target 'VKSnifferDemo' do 5 | # Uncomment the next line if you're using Swift or would like to use dynamic frameworks 6 | # use_frameworks! 7 | 8 | # Pods for VKSnifferDemo 9 | pod 'AFNetworking', '~> 3.0' 10 | end 11 | -------------------------------------------------------------------------------- /VKSnifferDemo/VKSnifferDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 3BD17D08734CC27D32B7325B /* libPods-VKSnifferDemo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DE2D964D7340892D1C836BED /* libPods-VKSnifferDemo.a */; }; 11 | 6CA85A6D1E6D538B00FD9EDF /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CA85A6C1E6D538B00FD9EDF /* main.m */; }; 12 | 6CA85A701E6D538B00FD9EDF /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CA85A6F1E6D538B00FD9EDF /* AppDelegate.m */; }; 13 | 6CA85A731E6D538B00FD9EDF /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CA85A721E6D538B00FD9EDF /* ViewController.m */; }; 14 | 6CA85A761E6D538B00FD9EDF /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6CA85A741E6D538B00FD9EDF /* Main.storyboard */; }; 15 | 6CA85A781E6D538B00FD9EDF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6CA85A771E6D538B00FD9EDF /* Assets.xcassets */; }; 16 | 6CA85A7B1E6D538B00FD9EDF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6CA85A791E6D538B00FD9EDF /* LaunchScreen.storyboard */; }; 17 | 6CA85A851E6D53F800FD9EDF /* VKSniffer.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CA85A841E6D53F800FD9EDF /* VKSniffer.m */; }; 18 | 6CA85A881E6D541200FD9EDF /* VKSnifferProtocol.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CA85A871E6D541200FD9EDF /* VKSnifferProtocol.m */; }; 19 | 6CA85A951E7296D100FD9EDF /* VKSnifferWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CA85A941E7296D100FD9EDF /* VKSnifferWindow.m */; }; 20 | 6CA85A981E7296E200FD9EDF /* VKSnifferViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CA85A971E7296E200FD9EDF /* VKSnifferViewController.m */; }; 21 | 6CA85A9B1E72C3BA00FD9EDF /* VKSniffer+UI.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CA85A9A1E72C3BA00FD9EDF /* VKSniffer+UI.m */; }; 22 | 6CA85AA21E73A47900FD9EDF /* VKSnifferCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CA85AA11E73A47900FD9EDF /* VKSnifferCell.m */; }; 23 | 6CA85AA51E73A88000FD9EDF /* VKSnifferResult+UI.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CA85AA41E73A88000FD9EDF /* VKSnifferResult+UI.m */; }; 24 | /* End PBXBuildFile section */ 25 | 26 | /* Begin PBXFileReference section */ 27 | 6CA85A681E6D538B00FD9EDF /* VKSnifferDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = VKSnifferDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 28 | 6CA85A6C1E6D538B00FD9EDF /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 29 | 6CA85A6E1E6D538B00FD9EDF /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 30 | 6CA85A6F1E6D538B00FD9EDF /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 31 | 6CA85A711E6D538B00FD9EDF /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 32 | 6CA85A721E6D538B00FD9EDF /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 33 | 6CA85A751E6D538B00FD9EDF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 34 | 6CA85A771E6D538B00FD9EDF /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 35 | 6CA85A7A1E6D538B00FD9EDF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 36 | 6CA85A7C1E6D538B00FD9EDF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 37 | 6CA85A831E6D53F800FD9EDF /* VKSniffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VKSniffer.h; sourceTree = ""; }; 38 | 6CA85A841E6D53F800FD9EDF /* VKSniffer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VKSniffer.m; sourceTree = ""; }; 39 | 6CA85A861E6D541200FD9EDF /* VKSnifferProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VKSnifferProtocol.h; sourceTree = ""; }; 40 | 6CA85A871E6D541200FD9EDF /* VKSnifferProtocol.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VKSnifferProtocol.m; sourceTree = ""; }; 41 | 6CA85A931E7296D100FD9EDF /* VKSnifferWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VKSnifferWindow.h; sourceTree = ""; }; 42 | 6CA85A941E7296D100FD9EDF /* VKSnifferWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VKSnifferWindow.m; sourceTree = ""; }; 43 | 6CA85A961E7296E200FD9EDF /* VKSnifferViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VKSnifferViewController.h; sourceTree = ""; }; 44 | 6CA85A971E7296E200FD9EDF /* VKSnifferViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VKSnifferViewController.m; sourceTree = ""; }; 45 | 6CA85A991E72C3BA00FD9EDF /* VKSniffer+UI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "VKSniffer+UI.h"; sourceTree = ""; }; 46 | 6CA85A9A1E72C3BA00FD9EDF /* VKSniffer+UI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "VKSniffer+UI.m"; sourceTree = ""; }; 47 | 6CA85AA01E73A47900FD9EDF /* VKSnifferCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VKSnifferCell.h; sourceTree = ""; }; 48 | 6CA85AA11E73A47900FD9EDF /* VKSnifferCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VKSnifferCell.m; sourceTree = ""; }; 49 | 6CA85AA31E73A88000FD9EDF /* VKSnifferResult+UI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "VKSnifferResult+UI.h"; sourceTree = ""; }; 50 | 6CA85AA41E73A88000FD9EDF /* VKSnifferResult+UI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "VKSnifferResult+UI.m"; sourceTree = ""; }; 51 | 90901BD52555F2E52065544C /* Pods-VKSnifferDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-VKSnifferDemo.release.xcconfig"; path = "Pods/Target Support Files/Pods-VKSnifferDemo/Pods-VKSnifferDemo.release.xcconfig"; sourceTree = ""; }; 52 | BE715BB1A2D7A0D49B22CFC9 /* Pods-VKSnifferDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-VKSnifferDemo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-VKSnifferDemo/Pods-VKSnifferDemo.debug.xcconfig"; sourceTree = ""; }; 53 | DE2D964D7340892D1C836BED /* libPods-VKSnifferDemo.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-VKSnifferDemo.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 54 | /* End PBXFileReference section */ 55 | 56 | /* Begin PBXFrameworksBuildPhase section */ 57 | 6CA85A651E6D538B00FD9EDF /* Frameworks */ = { 58 | isa = PBXFrameworksBuildPhase; 59 | buildActionMask = 2147483647; 60 | files = ( 61 | 3BD17D08734CC27D32B7325B /* libPods-VKSnifferDemo.a in Frameworks */, 62 | ); 63 | runOnlyForDeploymentPostprocessing = 0; 64 | }; 65 | /* End PBXFrameworksBuildPhase section */ 66 | 67 | /* Begin PBXGroup section */ 68 | 6CA85A5F1E6D538B00FD9EDF = { 69 | isa = PBXGroup; 70 | children = ( 71 | 6CA85A911E71280900FD9EDF /* VKSnifferUI */, 72 | 6CA85A821E6D53A400FD9EDF /* VKSniffer */, 73 | 6CA85A6A1E6D538B00FD9EDF /* VKSnifferDemo */, 74 | 6CA85A691E6D538B00FD9EDF /* Products */, 75 | AB4E6DAEF47D835EFE48AD69 /* Pods */, 76 | B9CAFC5A4B20A575DC5F5DC5 /* Frameworks */, 77 | ); 78 | sourceTree = ""; 79 | }; 80 | 6CA85A691E6D538B00FD9EDF /* Products */ = { 81 | isa = PBXGroup; 82 | children = ( 83 | 6CA85A681E6D538B00FD9EDF /* VKSnifferDemo.app */, 84 | ); 85 | name = Products; 86 | sourceTree = ""; 87 | }; 88 | 6CA85A6A1E6D538B00FD9EDF /* VKSnifferDemo */ = { 89 | isa = PBXGroup; 90 | children = ( 91 | 6CA85A6E1E6D538B00FD9EDF /* AppDelegate.h */, 92 | 6CA85A6F1E6D538B00FD9EDF /* AppDelegate.m */, 93 | 6CA85A711E6D538B00FD9EDF /* ViewController.h */, 94 | 6CA85A721E6D538B00FD9EDF /* ViewController.m */, 95 | 6CA85A741E6D538B00FD9EDF /* Main.storyboard */, 96 | 6CA85A771E6D538B00FD9EDF /* Assets.xcassets */, 97 | 6CA85A791E6D538B00FD9EDF /* LaunchScreen.storyboard */, 98 | 6CA85A7C1E6D538B00FD9EDF /* Info.plist */, 99 | 6CA85A6B1E6D538B00FD9EDF /* Supporting Files */, 100 | ); 101 | path = VKSnifferDemo; 102 | sourceTree = ""; 103 | }; 104 | 6CA85A6B1E6D538B00FD9EDF /* Supporting Files */ = { 105 | isa = PBXGroup; 106 | children = ( 107 | 6CA85A6C1E6D538B00FD9EDF /* main.m */, 108 | ); 109 | name = "Supporting Files"; 110 | sourceTree = ""; 111 | }; 112 | 6CA85A821E6D53A400FD9EDF /* VKSniffer */ = { 113 | isa = PBXGroup; 114 | children = ( 115 | 6CA85A831E6D53F800FD9EDF /* VKSniffer.h */, 116 | 6CA85A841E6D53F800FD9EDF /* VKSniffer.m */, 117 | 6CA85A861E6D541200FD9EDF /* VKSnifferProtocol.h */, 118 | 6CA85A871E6D541200FD9EDF /* VKSnifferProtocol.m */, 119 | ); 120 | name = VKSniffer; 121 | path = ../VKSniffer; 122 | sourceTree = ""; 123 | }; 124 | 6CA85A911E71280900FD9EDF /* VKSnifferUI */ = { 125 | isa = PBXGroup; 126 | children = ( 127 | 6CA85A931E7296D100FD9EDF /* VKSnifferWindow.h */, 128 | 6CA85A941E7296D100FD9EDF /* VKSnifferWindow.m */, 129 | 6CA85A961E7296E200FD9EDF /* VKSnifferViewController.h */, 130 | 6CA85A971E7296E200FD9EDF /* VKSnifferViewController.m */, 131 | 6CA85A991E72C3BA00FD9EDF /* VKSniffer+UI.h */, 132 | 6CA85A9A1E72C3BA00FD9EDF /* VKSniffer+UI.m */, 133 | 6CA85AA01E73A47900FD9EDF /* VKSnifferCell.h */, 134 | 6CA85AA11E73A47900FD9EDF /* VKSnifferCell.m */, 135 | 6CA85AA31E73A88000FD9EDF /* VKSnifferResult+UI.h */, 136 | 6CA85AA41E73A88000FD9EDF /* VKSnifferResult+UI.m */, 137 | ); 138 | name = VKSnifferUI; 139 | path = ../VKSnifferUI; 140 | sourceTree = ""; 141 | }; 142 | AB4E6DAEF47D835EFE48AD69 /* Pods */ = { 143 | isa = PBXGroup; 144 | children = ( 145 | BE715BB1A2D7A0D49B22CFC9 /* Pods-VKSnifferDemo.debug.xcconfig */, 146 | 90901BD52555F2E52065544C /* Pods-VKSnifferDemo.release.xcconfig */, 147 | ); 148 | name = Pods; 149 | sourceTree = ""; 150 | }; 151 | B9CAFC5A4B20A575DC5F5DC5 /* Frameworks */ = { 152 | isa = PBXGroup; 153 | children = ( 154 | DE2D964D7340892D1C836BED /* libPods-VKSnifferDemo.a */, 155 | ); 156 | name = Frameworks; 157 | sourceTree = ""; 158 | }; 159 | /* End PBXGroup section */ 160 | 161 | /* Begin PBXNativeTarget section */ 162 | 6CA85A671E6D538B00FD9EDF /* VKSnifferDemo */ = { 163 | isa = PBXNativeTarget; 164 | buildConfigurationList = 6CA85A7F1E6D538B00FD9EDF /* Build configuration list for PBXNativeTarget "VKSnifferDemo" */; 165 | buildPhases = ( 166 | 8C974F2D7E32942694B5876C /* [CP] Check Pods Manifest.lock */, 167 | 6CA85A641E6D538B00FD9EDF /* Sources */, 168 | 6CA85A651E6D538B00FD9EDF /* Frameworks */, 169 | 6CA85A661E6D538B00FD9EDF /* Resources */, 170 | 559D93598BC802070A411630 /* [CP] Embed Pods Frameworks */, 171 | FCB7CDC287A7FDB17DE9A1ED /* [CP] Copy Pods Resources */, 172 | ); 173 | buildRules = ( 174 | ); 175 | dependencies = ( 176 | ); 177 | name = VKSnifferDemo; 178 | productName = VKSnifferDemo; 179 | productReference = 6CA85A681E6D538B00FD9EDF /* VKSnifferDemo.app */; 180 | productType = "com.apple.product-type.application"; 181 | }; 182 | /* End PBXNativeTarget section */ 183 | 184 | /* Begin PBXProject section */ 185 | 6CA85A601E6D538B00FD9EDF /* Project object */ = { 186 | isa = PBXProject; 187 | attributes = { 188 | LastUpgradeCheck = 0820; 189 | ORGANIZATIONNAME = baidu; 190 | TargetAttributes = { 191 | 6CA85A671E6D538B00FD9EDF = { 192 | CreatedOnToolsVersion = 8.2.1; 193 | ProvisioningStyle = Automatic; 194 | }; 195 | }; 196 | }; 197 | buildConfigurationList = 6CA85A631E6D538B00FD9EDF /* Build configuration list for PBXProject "VKSnifferDemo" */; 198 | compatibilityVersion = "Xcode 3.2"; 199 | developmentRegion = English; 200 | hasScannedForEncodings = 0; 201 | knownRegions = ( 202 | en, 203 | Base, 204 | ); 205 | mainGroup = 6CA85A5F1E6D538B00FD9EDF; 206 | productRefGroup = 6CA85A691E6D538B00FD9EDF /* Products */; 207 | projectDirPath = ""; 208 | projectRoot = ""; 209 | targets = ( 210 | 6CA85A671E6D538B00FD9EDF /* VKSnifferDemo */, 211 | ); 212 | }; 213 | /* End PBXProject section */ 214 | 215 | /* Begin PBXResourcesBuildPhase section */ 216 | 6CA85A661E6D538B00FD9EDF /* Resources */ = { 217 | isa = PBXResourcesBuildPhase; 218 | buildActionMask = 2147483647; 219 | files = ( 220 | 6CA85A7B1E6D538B00FD9EDF /* LaunchScreen.storyboard in Resources */, 221 | 6CA85A781E6D538B00FD9EDF /* Assets.xcassets in Resources */, 222 | 6CA85A761E6D538B00FD9EDF /* Main.storyboard in Resources */, 223 | ); 224 | runOnlyForDeploymentPostprocessing = 0; 225 | }; 226 | /* End PBXResourcesBuildPhase section */ 227 | 228 | /* Begin PBXShellScriptBuildPhase section */ 229 | 559D93598BC802070A411630 /* [CP] Embed Pods Frameworks */ = { 230 | isa = PBXShellScriptBuildPhase; 231 | buildActionMask = 2147483647; 232 | files = ( 233 | ); 234 | inputPaths = ( 235 | ); 236 | name = "[CP] Embed Pods Frameworks"; 237 | outputPaths = ( 238 | ); 239 | runOnlyForDeploymentPostprocessing = 0; 240 | shellPath = /bin/sh; 241 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-VKSnifferDemo/Pods-VKSnifferDemo-frameworks.sh\"\n"; 242 | showEnvVarsInLog = 0; 243 | }; 244 | 8C974F2D7E32942694B5876C /* [CP] Check Pods Manifest.lock */ = { 245 | isa = PBXShellScriptBuildPhase; 246 | buildActionMask = 2147483647; 247 | files = ( 248 | ); 249 | inputPaths = ( 250 | ); 251 | name = "[CP] Check Pods Manifest.lock"; 252 | outputPaths = ( 253 | ); 254 | runOnlyForDeploymentPostprocessing = 0; 255 | shellPath = /bin/sh; 256 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; 257 | showEnvVarsInLog = 0; 258 | }; 259 | FCB7CDC287A7FDB17DE9A1ED /* [CP] Copy Pods Resources */ = { 260 | isa = PBXShellScriptBuildPhase; 261 | buildActionMask = 2147483647; 262 | files = ( 263 | ); 264 | inputPaths = ( 265 | ); 266 | name = "[CP] Copy Pods Resources"; 267 | outputPaths = ( 268 | ); 269 | runOnlyForDeploymentPostprocessing = 0; 270 | shellPath = /bin/sh; 271 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-VKSnifferDemo/Pods-VKSnifferDemo-resources.sh\"\n"; 272 | showEnvVarsInLog = 0; 273 | }; 274 | /* End PBXShellScriptBuildPhase section */ 275 | 276 | /* Begin PBXSourcesBuildPhase section */ 277 | 6CA85A641E6D538B00FD9EDF /* Sources */ = { 278 | isa = PBXSourcesBuildPhase; 279 | buildActionMask = 2147483647; 280 | files = ( 281 | 6CA85A9B1E72C3BA00FD9EDF /* VKSniffer+UI.m in Sources */, 282 | 6CA85A951E7296D100FD9EDF /* VKSnifferWindow.m in Sources */, 283 | 6CA85A851E6D53F800FD9EDF /* VKSniffer.m in Sources */, 284 | 6CA85A731E6D538B00FD9EDF /* ViewController.m in Sources */, 285 | 6CA85A981E7296E200FD9EDF /* VKSnifferViewController.m in Sources */, 286 | 6CA85AA51E73A88000FD9EDF /* VKSnifferResult+UI.m in Sources */, 287 | 6CA85A701E6D538B00FD9EDF /* AppDelegate.m in Sources */, 288 | 6CA85AA21E73A47900FD9EDF /* VKSnifferCell.m in Sources */, 289 | 6CA85A6D1E6D538B00FD9EDF /* main.m in Sources */, 290 | 6CA85A881E6D541200FD9EDF /* VKSnifferProtocol.m in Sources */, 291 | ); 292 | runOnlyForDeploymentPostprocessing = 0; 293 | }; 294 | /* End PBXSourcesBuildPhase section */ 295 | 296 | /* Begin PBXVariantGroup section */ 297 | 6CA85A741E6D538B00FD9EDF /* Main.storyboard */ = { 298 | isa = PBXVariantGroup; 299 | children = ( 300 | 6CA85A751E6D538B00FD9EDF /* Base */, 301 | ); 302 | name = Main.storyboard; 303 | sourceTree = ""; 304 | }; 305 | 6CA85A791E6D538B00FD9EDF /* LaunchScreen.storyboard */ = { 306 | isa = PBXVariantGroup; 307 | children = ( 308 | 6CA85A7A1E6D538B00FD9EDF /* Base */, 309 | ); 310 | name = LaunchScreen.storyboard; 311 | sourceTree = ""; 312 | }; 313 | /* End PBXVariantGroup section */ 314 | 315 | /* Begin XCBuildConfiguration section */ 316 | 6CA85A7D1E6D538B00FD9EDF /* Debug */ = { 317 | isa = XCBuildConfiguration; 318 | buildSettings = { 319 | ALWAYS_SEARCH_USER_PATHS = NO; 320 | CLANG_ANALYZER_NONNULL = YES; 321 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 322 | CLANG_CXX_LIBRARY = "libc++"; 323 | CLANG_ENABLE_MODULES = YES; 324 | CLANG_ENABLE_OBJC_ARC = YES; 325 | CLANG_WARN_BOOL_CONVERSION = YES; 326 | CLANG_WARN_CONSTANT_CONVERSION = YES; 327 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 328 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 329 | CLANG_WARN_EMPTY_BODY = YES; 330 | CLANG_WARN_ENUM_CONVERSION = YES; 331 | CLANG_WARN_INFINITE_RECURSION = YES; 332 | CLANG_WARN_INT_CONVERSION = YES; 333 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 334 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 335 | CLANG_WARN_UNREACHABLE_CODE = YES; 336 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 337 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 338 | COPY_PHASE_STRIP = NO; 339 | DEBUG_INFORMATION_FORMAT = dwarf; 340 | ENABLE_STRICT_OBJC_MSGSEND = YES; 341 | ENABLE_TESTABILITY = YES; 342 | GCC_C_LANGUAGE_STANDARD = gnu99; 343 | GCC_DYNAMIC_NO_PIC = NO; 344 | GCC_NO_COMMON_BLOCKS = YES; 345 | GCC_OPTIMIZATION_LEVEL = 0; 346 | GCC_PREPROCESSOR_DEFINITIONS = ( 347 | "DEBUG=1", 348 | "$(inherited)", 349 | ); 350 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 351 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 352 | GCC_WARN_UNDECLARED_SELECTOR = YES; 353 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 354 | GCC_WARN_UNUSED_FUNCTION = YES; 355 | GCC_WARN_UNUSED_VARIABLE = YES; 356 | IPHONEOS_DEPLOYMENT_TARGET = 10.2; 357 | MTL_ENABLE_DEBUG_INFO = YES; 358 | ONLY_ACTIVE_ARCH = YES; 359 | SDKROOT = iphoneos; 360 | TARGETED_DEVICE_FAMILY = "1,2"; 361 | }; 362 | name = Debug; 363 | }; 364 | 6CA85A7E1E6D538B00FD9EDF /* Release */ = { 365 | isa = XCBuildConfiguration; 366 | buildSettings = { 367 | ALWAYS_SEARCH_USER_PATHS = NO; 368 | CLANG_ANALYZER_NONNULL = YES; 369 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 370 | CLANG_CXX_LIBRARY = "libc++"; 371 | CLANG_ENABLE_MODULES = YES; 372 | CLANG_ENABLE_OBJC_ARC = YES; 373 | CLANG_WARN_BOOL_CONVERSION = YES; 374 | CLANG_WARN_CONSTANT_CONVERSION = YES; 375 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 376 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 377 | CLANG_WARN_EMPTY_BODY = YES; 378 | CLANG_WARN_ENUM_CONVERSION = YES; 379 | CLANG_WARN_INFINITE_RECURSION = YES; 380 | CLANG_WARN_INT_CONVERSION = YES; 381 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 382 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 383 | CLANG_WARN_UNREACHABLE_CODE = YES; 384 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 385 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 386 | COPY_PHASE_STRIP = NO; 387 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 388 | ENABLE_NS_ASSERTIONS = NO; 389 | ENABLE_STRICT_OBJC_MSGSEND = YES; 390 | GCC_C_LANGUAGE_STANDARD = gnu99; 391 | GCC_NO_COMMON_BLOCKS = YES; 392 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 393 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 394 | GCC_WARN_UNDECLARED_SELECTOR = YES; 395 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 396 | GCC_WARN_UNUSED_FUNCTION = YES; 397 | GCC_WARN_UNUSED_VARIABLE = YES; 398 | IPHONEOS_DEPLOYMENT_TARGET = 10.2; 399 | MTL_ENABLE_DEBUG_INFO = NO; 400 | SDKROOT = iphoneos; 401 | TARGETED_DEVICE_FAMILY = "1,2"; 402 | VALIDATE_PRODUCT = YES; 403 | }; 404 | name = Release; 405 | }; 406 | 6CA85A801E6D538B00FD9EDF /* Debug */ = { 407 | isa = XCBuildConfiguration; 408 | baseConfigurationReference = BE715BB1A2D7A0D49B22CFC9 /* Pods-VKSnifferDemo.debug.xcconfig */; 409 | buildSettings = { 410 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 411 | INFOPLIST_FILE = VKSnifferDemo/Info.plist; 412 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 413 | PRODUCT_BUNDLE_IDENTIFIER = com.baidu.VKSnifferDemo; 414 | PRODUCT_NAME = "$(TARGET_NAME)"; 415 | }; 416 | name = Debug; 417 | }; 418 | 6CA85A811E6D538B00FD9EDF /* Release */ = { 419 | isa = XCBuildConfiguration; 420 | baseConfigurationReference = 90901BD52555F2E52065544C /* Pods-VKSnifferDemo.release.xcconfig */; 421 | buildSettings = { 422 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 423 | INFOPLIST_FILE = VKSnifferDemo/Info.plist; 424 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 425 | PRODUCT_BUNDLE_IDENTIFIER = com.baidu.VKSnifferDemo; 426 | PRODUCT_NAME = "$(TARGET_NAME)"; 427 | }; 428 | name = Release; 429 | }; 430 | /* End XCBuildConfiguration section */ 431 | 432 | /* Begin XCConfigurationList section */ 433 | 6CA85A631E6D538B00FD9EDF /* Build configuration list for PBXProject "VKSnifferDemo" */ = { 434 | isa = XCConfigurationList; 435 | buildConfigurations = ( 436 | 6CA85A7D1E6D538B00FD9EDF /* Debug */, 437 | 6CA85A7E1E6D538B00FD9EDF /* Release */, 438 | ); 439 | defaultConfigurationIsVisible = 0; 440 | defaultConfigurationName = Release; 441 | }; 442 | 6CA85A7F1E6D538B00FD9EDF /* Build configuration list for PBXNativeTarget "VKSnifferDemo" */ = { 443 | isa = XCConfigurationList; 444 | buildConfigurations = ( 445 | 6CA85A801E6D538B00FD9EDF /* Debug */, 446 | 6CA85A811E6D538B00FD9EDF /* Release */, 447 | ); 448 | defaultConfigurationIsVisible = 0; 449 | defaultConfigurationName = Release; 450 | }; 451 | /* End XCConfigurationList section */ 452 | }; 453 | rootObject = 6CA85A601E6D538B00FD9EDF /* Project object */; 454 | } 455 | -------------------------------------------------------------------------------- /VKSnifferDemo/VKSnifferDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /VKSnifferDemo/VKSnifferDemo.xcodeproj/xcuserdata/Awhisper.xcuserdatad/xcschemes/VKSnifferDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /VKSnifferDemo/VKSnifferDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // VKSnifferDemo 4 | // 5 | // Created by Awhisper on 2017/3/6. 6 | // Copyright © 2017年 baidu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /VKSnifferDemo/VKSnifferDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // VKSnifferDemo 4 | // 5 | // Created by Awhisper on 2017/3/6. 6 | // Copyright © 2017年 baidu. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 27 | } 28 | 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 38 | } 39 | 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 43 | } 44 | 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /VKSnifferDemo/VKSnifferDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /VKSnifferDemo/VKSnifferDemo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /VKSnifferDemo/VKSnifferDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /VKSnifferDemo/VKSnifferDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /VKSnifferDemo/VKSnifferDemo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // VKSnifferDemo 4 | // 5 | // Created by Awhisper on 2017/3/6. 6 | // Copyright © 2017年 baidu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /VKSnifferDemo/VKSnifferDemo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // VKSnifferDemo 4 | // 5 | // Created by Awhisper on 2017/3/6. 6 | // Copyright © 2017年 baidu. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "VKSniffer+UI.h" 11 | #import 12 | 13 | #pragma clang diagnostic push 14 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 15 | 16 | 17 | #define VKSnifferAppWidth ([[UIScreen mainScreen] bounds].size.width) 18 | #define VKSnifferAppHeight ([[UIScreen mainScreen] bounds].size.height) 19 | 20 | @interface ViewController () 21 | 22 | @property (nonatomic,strong) NSTimer *timer; 23 | 24 | @property (nonatomic,strong) AFURLSessionManager *manager; 25 | 26 | @end 27 | 28 | @implementation ViewController 29 | 30 | - (void)viewDidLoad { 31 | [super viewDidLoad]; 32 | // Do any additional setup after loading the view, typically from a nib. 33 | 34 | //Start Sniffer 35 | [VKSniffer setupSnifferHandler:^(VKSnifferResult *result) { 36 | NSLog(@"%@",result); 37 | }]; 38 | [VKSniffer startSniffer]; 39 | 40 | [self commenSessionTaskTest]; 41 | [self commenConnectionTest]; 42 | [self afnetworkingTest]; 43 | 44 | UIButton *button = [[UIButton alloc]initWithFrame:CGRectMake((VKSnifferAppWidth - 200)/2, (VKSnifferAppHeight - 40)/2, 200, 40)]; 45 | [button setTitle:@"Open VKSniffer" forState:UIControlStateNormal]; 46 | [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; 47 | [button addTarget:self action:@selector(clickBt) forControlEvents:UIControlEventTouchUpInside]; 48 | [self.view addSubview:button]; 49 | 50 | NSTimer * timer = [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(timertimer) userInfo:nil repeats:YES]; 51 | self.timer = timer; 52 | } 53 | 54 | -(void)clickBt{ 55 | [VKSniffer showSnifferView]; 56 | } 57 | 58 | -(NSArray *)networkApiArray 59 | { 60 | return @[@"https://api.github.com/users/xmartlabs", 61 | @"https://api.github.com/users/xmartlabs/broke", 62 | @"https://api.github.com/users/xmartlabs/repos", 63 | @"https://api.github.com/users/xmartlabs/followers"]; 64 | } 65 | 66 | -(void)afnetworkingTest{ 67 | //init Afnetworking manager 68 | NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; 69 | //setupConfiguration before init manager 70 | [VKSniffer setupConfiguration:configuration]; 71 | AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration]; 72 | self.manager = manager; 73 | 74 | for (NSString *urlstr in [self networkApiArray]) { 75 | NSURL *URL = [NSURL URLWithString:urlstr]; 76 | NSURLRequest *request = [NSURLRequest requestWithURL:URL]; 77 | NSURLSessionDataTask *dataTask = [self.manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) { 78 | 79 | }]; 80 | [dataTask resume]; 81 | } 82 | } 83 | 84 | -(void)commenConnectionTest{ 85 | for (NSString *urlstr in [self networkApiArray]) { 86 | NSURL *url = [NSURL URLWithString:urlstr]; 87 | NSURLRequest *req = [[NSURLRequest alloc] initWithURL:url]; 88 | NSOperationQueue *queue=[NSOperationQueue mainQueue]; 89 | [NSURLConnection sendAsynchronousRequest:req queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) 90 | { 91 | 92 | }]; 93 | 94 | } 95 | } 96 | 97 | -(void)commenSessionTaskTest 98 | { 99 | for (NSString *urlstr in [self networkApiArray]) { 100 | NSURLSession *session = [NSURLSession sharedSession]; 101 | NSURL *url = [NSURL URLWithString:urlstr]; 102 | NSURLSessionTask *task = [session dataTaskWithURL:url 103 | completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 104 | 105 | }]; 106 | [task resume]; 107 | } 108 | } 109 | 110 | -(void)timertimer{ 111 | [self commenConnectionTest]; 112 | } 113 | 114 | - (void)didReceiveMemoryWarning { 115 | [super didReceiveMemoryWarning]; 116 | // Dispose of any resources that can be recreated. 117 | } 118 | 119 | 120 | #pragma clang diagnostic pop 121 | @end 122 | -------------------------------------------------------------------------------- /VKSnifferDemo/VKSnifferDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // VKSnifferDemo 4 | // 5 | // Created by Awhisper on 2017/3/6. 6 | // Copyright © 2017年 baidu. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /VKSnifferUI/VKSniffer+UI.h: -------------------------------------------------------------------------------- 1 | // 2 | // VKSniffer+UI.h 3 | // VKSnifferDemo 4 | // 5 | // Created by Awhisper on 2017/3/10. 6 | // Copyright © 2017年 baidu. All rights reserved. 7 | // 8 | 9 | #import "VKSniffer.h" 10 | 11 | @class VKSnifferWindow; 12 | 13 | @interface VKSniffer (UI) 14 | 15 | @property(nonatomic,strong) VKSnifferWindow *snifferWindow; 16 | 17 | @property (nonatomic,strong) NSNumber *isReverse; 18 | 19 | + (void)showSnifferView; 20 | 21 | + (void)hideSnifferView; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /VKSnifferUI/VKSniffer+UI.m: -------------------------------------------------------------------------------- 1 | // 2 | // VKSniffer+UI.m 3 | // VKSnifferDemo 4 | // 5 | // Created by Awhisper on 2017/3/10. 6 | // Copyright © 2017年 baidu. All rights reserved. 7 | // 8 | 9 | #import "VKSniffer+UI.h" 10 | #import "VKSnifferWindow.h" 11 | #import 12 | 13 | @implementation VKSniffer (UI) 14 | 15 | -(VKSnifferWindow *)snifferWindow{ 16 | return objc_getAssociatedObject(self, @selector(snifferWindow)); 17 | } 18 | 19 | -(void)setSnifferWindow:(VKSnifferWindow *)snifferWindow{ 20 | objc_setAssociatedObject(self, @selector(snifferWindow), snifferWindow, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 21 | } 22 | 23 | -(NSNumber *)isReverse{ 24 | return objc_getAssociatedObject(self, @selector(isReverse)); 25 | } 26 | 27 | -(void)setIsReverse:(NSNumber *)isReverse{ 28 | objc_setAssociatedObject(self, @selector(isReverse), isReverse, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 29 | } 30 | 31 | 32 | +(void)showSnifferView{ 33 | [VKSniffer singleton].snifferWindow = [VKSnifferWindow showSnifferView]; 34 | } 35 | 36 | +(void)hideSnifferView 37 | { 38 | [VKSnifferWindow hideSnifferView]; 39 | [VKSniffer singleton].snifferWindow = nil; 40 | } 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /VKSnifferUI/VKSnifferCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // VKSnifferCell.h 3 | // VKSnifferDemo 4 | // 5 | // Created by Awhisper on 2017/3/11. 6 | // Copyright © 2017年 baidu. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "VKSnifferResult+UI.h" 11 | 12 | #define VKSnifferCellHeight 60 13 | 14 | @interface VKSnifferCell : UITableViewCell 15 | 16 | - (void)setSnifferResult:(VKSnifferResult *)result; 17 | 18 | + (CGFloat)caculateSnifferResultHeight:(VKSnifferResult *)result; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /VKSnifferUI/VKSnifferCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // VKSnifferCell.m 3 | // VKSnifferDemo 4 | // 5 | // Created by Awhisper on 2017/3/11. 6 | // Copyright © 2017年 baidu. All rights reserved. 7 | // 8 | 9 | #import "VKSnifferCell.h" 10 | 11 | 12 | #define VKSnifferCellAppWidth ([[UIScreen mainScreen] bounds].size.width) 13 | #define VKSnifferCellAppHeight ([[UIScreen mainScreen] bounds].size.height) 14 | #define VKSnifferCellUrlWidth VKSnifferCellAppWidth - 20 15 | 16 | static NSInteger VKSnifferMaxUrlLine = 4; 17 | static CGFloat VKSnifferMaxUrlFontSize = 12.0f; 18 | static CGFloat VKSnifferMaxLabelLineHeight = 15; 19 | 20 | 21 | @interface VKSnifferCell () 22 | 23 | @property (nonatomic,strong) UILabel *urlLabel; 24 | 25 | @property (nonatomic,strong) UILabel *statusLabel; 26 | 27 | @property (nonatomic,strong) UILabel *timeLabel; 28 | 29 | @property (nonatomic,strong) UILabel *detailLabel; 30 | 31 | 32 | @end 33 | 34 | @implementation VKSnifferCell 35 | 36 | -(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier 37 | { 38 | self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; 39 | if (self) { 40 | [self setupUI]; 41 | } 42 | return self; 43 | } 44 | 45 | - (void)setupUI{ 46 | CGFloat secondLineTop = 45; 47 | UILabel *urllb = [[UILabel alloc]initWithFrame:CGRectMake(10, 0, VKSnifferCellUrlWidth, 45)]; 48 | urllb.textColor = [UIColor whiteColor]; 49 | urllb.numberOfLines = VKSnifferMaxUrlLine; 50 | urllb.font = [UIFont systemFontOfSize:VKSnifferMaxUrlFontSize]; 51 | self.urlLabel = urllb; 52 | [self.contentView addSubview:urllb]; 53 | 54 | // UILabel *detail = [[UILabel alloc]initWithFrame:CGRectMake(10, 0, VKSnifferCellAppWidth - 20, 0)]; 55 | // urllb.textColor = [UIColor whiteColor]; 56 | // urllb.numberOfLines = 1; 57 | // self.urlLabel = urllb; 58 | // [self.contentView addSubview:urllb]; 59 | 60 | UILabel *statusLb = [[UILabel alloc]initWithFrame:CGRectMake(10, secondLineTop, VKSnifferCellUrlWidth, VKSnifferMaxLabelLineHeight)]; 61 | statusLb.textColor = [UIColor greenColor]; 62 | statusLb.numberOfLines = 1; 63 | statusLb.textAlignment = NSTextAlignmentLeft; 64 | statusLb.font = [UIFont systemFontOfSize:VKSnifferMaxUrlFontSize]; 65 | self.statusLabel = statusLb; 66 | [self.contentView addSubview:statusLb]; 67 | 68 | UILabel *timelb = [[UILabel alloc]initWithFrame:CGRectMake(10, secondLineTop, VKSnifferCellUrlWidth, VKSnifferMaxLabelLineHeight)]; 69 | timelb.textColor = [UIColor whiteColor]; 70 | timelb.numberOfLines = 1; 71 | timelb.textAlignment = NSTextAlignmentRight; 72 | timelb.font = [UIFont systemFontOfSize:VKSnifferMaxUrlFontSize]; 73 | self.timeLabel = timelb; 74 | [self.contentView addSubview:timelb]; 75 | } 76 | 77 | - (void)setSnifferResult:(VKSnifferResult *)result 78 | { 79 | NSString *url = result.request.URL.absoluteString; 80 | url = [NSString stringWithFormat:@"URL: - %@",url]; 81 | self.urlLabel.text = url; 82 | NSTimeInterval ms = result.duration * 1000.0f; 83 | self.urlLabel.frame = CGRectMake(self.urlLabel.frame.origin.x, self.urlLabel.frame.origin.y, VKSnifferCellUrlWidth, [result.cellHeightCache floatValue] - VKSnifferMaxLabelLineHeight - 2); 84 | 85 | CGFloat secondLineTop = [result.cellHeightCache floatValue] - VKSnifferMaxLabelLineHeight - 2; 86 | self.timeLabel.text = [NSString stringWithFormat:@"%.2f ms",ms]; 87 | if (ms < 500.0f) { 88 | self.timeLabel.textColor = [UIColor whiteColor]; 89 | }else if(ms > 500.0f && ms < 1000.0f){ 90 | self.timeLabel.textColor = [UIColor yellowColor]; 91 | }else{ 92 | self.timeLabel.textColor = [UIColor redColor]; 93 | } 94 | self.timeLabel.frame = CGRectMake(self.timeLabel.frame.origin.x, secondLineTop, VKSnifferCellUrlWidth, VKSnifferMaxLabelLineHeight); 95 | 96 | NSString * statusStr = (result.response.statusCode >= 200 && result.response.statusCode < 300) ? @"SUCCESS" : @"ERROR"; 97 | self.statusLabel.text = [NSString stringWithFormat:@"%@: - %@",statusStr,@(result.response.statusCode)]; 98 | 99 | if ([statusStr isEqualToString:@"SUCCESS"]) { 100 | self.statusLabel.textColor = [UIColor greenColor]; 101 | }else{ 102 | self.statusLabel.textColor = [UIColor redColor]; 103 | } 104 | self.statusLabel.frame = CGRectMake(self.statusLabel.frame.origin.x, secondLineTop, VKSnifferCellUrlWidth, VKSnifferMaxLabelLineHeight); 105 | } 106 | 107 | +(CGFloat)caculateSnifferResultHeight:(VKSnifferResult *)result{ 108 | NSString *url = result.request.URL.absoluteString; 109 | url = [NSString stringWithFormat:@"URL: - %@",url]; 110 | 111 | NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc]init]; 112 | paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping; 113 | NSDictionary *attributes = @{NSFontAttributeName:[UIFont systemFontOfSize:VKSnifferMaxUrlFontSize], NSParagraphStyleAttributeName:paragraphStyle.copy}; 114 | 115 | CGRect rect = [url boundingRectWithSize:CGSizeMake(VKSnifferCellUrlWidth, 999) options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil]; 116 | 117 | if (rect.size.height > VKSnifferMaxUrlFontSize * VKSnifferMaxUrlLine) { 118 | rect.size.height = (VKSnifferMaxUrlFontSize + 2) * VKSnifferMaxUrlLine; 119 | } 120 | 121 | return rect.size.height + VKSnifferMaxLabelLineHeight + 4; 122 | } 123 | 124 | 125 | - (void)awakeFromNib { 126 | [super awakeFromNib]; 127 | // Initialization code 128 | } 129 | 130 | - (void)setSelected:(BOOL)selected animated:(BOOL)animated { 131 | [super setSelected:selected animated:animated]; 132 | 133 | // Configure the view for the selected state 134 | } 135 | 136 | @end 137 | -------------------------------------------------------------------------------- /VKSnifferUI/VKSnifferResult+UI.h: -------------------------------------------------------------------------------- 1 | // 2 | // VKSnifferResult+UI.h 3 | // VKSnifferDemo 4 | // 5 | // Created by Awhisper on 2017/3/11. 6 | // Copyright © 2017年 baidu. All rights reserved. 7 | // 8 | 9 | #import "VKSniffer.h" 10 | 11 | @interface VKSnifferResult (UI) 12 | 13 | @property (nonatomic,strong) NSNumber* cellHeightCache; 14 | //未开发完成 15 | @property (nonatomic,strong) NSNumber* isShowDetail; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /VKSnifferUI/VKSnifferResult+UI.m: -------------------------------------------------------------------------------- 1 | // 2 | // VKSnifferResult+UI.m 3 | // VKSnifferDemo 4 | // 5 | // Created by Awhisper on 2017/3/11. 6 | // Copyright © 2017年 baidu. All rights reserved. 7 | // 8 | 9 | #import "VKSnifferResult+UI.h" 10 | #import 11 | @implementation VKSnifferResult (UI) 12 | 13 | -(NSNumber *)isShowDetail 14 | { 15 | return objc_getAssociatedObject(self, @selector(isShowDetail)); 16 | } 17 | 18 | -(void)setIsShowDetail:(NSNumber *)isShowDetail{ 19 | objc_setAssociatedObject(self, @selector(isShowDetail), isShowDetail, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 20 | } 21 | 22 | -(NSNumber *)cellHeightCache{ 23 | return objc_getAssociatedObject(self, @selector(cellHeightCache)); 24 | } 25 | 26 | -(void)setCellHeightCache:(NSNumber *)cellHeightCache{ 27 | objc_setAssociatedObject(self, @selector(cellHeightCache), cellHeightCache, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 28 | } 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /VKSnifferUI/VKSnifferViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // VKSnifferViewController.h 3 | // VKSnifferDemo 4 | // 5 | // Created by Awhisper on 2017/3/10. 6 | // Copyright © 2017年 baidu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface VKSnifferViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /VKSnifferUI/VKSnifferViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // VKSnifferViewController.m 3 | // VKSnifferDemo 4 | // 5 | // Created by Awhisper on 2017/3/10. 6 | // Copyright © 2017年 baidu. All rights reserved. 7 | // 8 | 9 | #import "VKSnifferViewController.h" 10 | #import "VKSniffer+UI.h" 11 | #import "VKSnifferCell.h" 12 | 13 | #pragma clang diagnostic push 14 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 15 | 16 | #define VKSnifferViewControllerUIWidth ([[UIScreen mainScreen] bounds].size.width) 17 | #define VKSnifferViewControllerUIHeight ([[UIScreen mainScreen] bounds].size.height) 18 | 19 | 20 | @interface VKSnifferViewController () 21 | 22 | @property (nonatomic,strong) UIActionSheet *actionSheet; 23 | 24 | @property (nonatomic,strong) UITableView *requestTable; 25 | 26 | @property (nonatomic,strong) NSString *pasteboardString; 27 | 28 | @property (nonatomic,assign) BOOL isReverse; 29 | 30 | @property (nonatomic,strong) NSMutableArray* dataArr; 31 | 32 | @end 33 | 34 | @implementation VKSnifferViewController 35 | 36 | - (void)viewDidLoad { 37 | [super viewDidLoad]; 38 | self.title = @"VKSniffer Panel"; 39 | self.view.backgroundColor = [UIColor blackColor]; 40 | [self setupNavigationBar]; 41 | [self setupTableView]; 42 | [self addLogNotificationObserver]; 43 | self.dataArr = [[VKSniffer singleton].netResultArray mutableCopy]; 44 | // Do any additional setup after loading the view. 45 | } 46 | 47 | -(void)viewDidAppear:(BOOL)animated{ 48 | [self.requestTable reloadData]; 49 | } 50 | 51 | -(void)setIsReverse:(BOOL)isReverse{ 52 | [VKSniffer singleton].isReverse = @(isReverse); 53 | } 54 | 55 | -(BOOL)isReverse 56 | { 57 | if ([VKSniffer singleton].isReverse) { 58 | return [[VKSniffer singleton].isReverse boolValue]; 59 | }else{ 60 | return YES; //default 61 | } 62 | } 63 | 64 | -(void)dealloc 65 | { 66 | [self removeLogNotificationObserver]; 67 | } 68 | #pragma mark notification 69 | -(void)addLogNotificationObserver 70 | { 71 | [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(logNotificationGet:) name:VKNetSnifferReqLogNotification object:nil]; 72 | } 73 | 74 | -(void)removeLogNotificationObserver 75 | { 76 | [[NSNotificationCenter defaultCenter]removeObserver:self]; 77 | } 78 | 79 | -(void)logNotificationGet:(NSNotification *)noti{ 80 | VKSnifferResult *result = noti.object; 81 | if (result) { 82 | [self.dataArr addObject:result]; 83 | [self.requestTable reloadData]; 84 | } 85 | } 86 | 87 | #pragma mark tableview 88 | -(void)setupTableView{ 89 | _requestTable = [[UITableView alloc]initWithFrame:CGRectMake(0, 64,VKSnifferViewControllerUIWidth, VKSnifferViewControllerUIHeight - 20)]; 90 | _requestTable.delegate = self; 91 | _requestTable.dataSource = self; 92 | _requestTable.backgroundColor = [UIColor clearColor]; 93 | [self.view addSubview:_requestTable]; 94 | } 95 | 96 | -(NSInteger)tableViewConvertIndexPath:(NSIndexPath *)indexPath{ 97 | if (self.isReverse) { 98 | NSInteger index = self.dataArr.count - indexPath.row - 1; 99 | return index>=0?index:0; 100 | }else{ 101 | return indexPath.row; 102 | } 103 | } 104 | 105 | -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 106 | { 107 | return self.dataArr.count; 108 | } 109 | 110 | -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 111 | { 112 | NSInteger trueIndex = [self tableViewConvertIndexPath:indexPath]; 113 | NSArray *resultArr = self.dataArr; 114 | VKSnifferResult *result = resultArr[trueIndex]; 115 | if (result.cellHeightCache) { 116 | return [result.cellHeightCache floatValue]; 117 | }else{ 118 | CGFloat cellheight = [VKSnifferCell caculateSnifferResultHeight:result]; 119 | result.cellHeightCache = [NSNumber numberWithFloat:cellheight]; 120 | return cellheight; 121 | } 122 | return VKSnifferCellHeight; 123 | } 124 | 125 | -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 126 | { 127 | NSArray *resultArr = self.dataArr; 128 | NSString *requestID = @"VKSnifferCellID"; 129 | VKSnifferCell *cell = [tableView dequeueReusableCellWithIdentifier:requestID]; 130 | if (!cell) { 131 | cell = [[VKSnifferCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:requestID]; 132 | } 133 | NSInteger trueIndex = [self tableViewConvertIndexPath:indexPath]; 134 | VKSnifferResult *result = resultArr[trueIndex]; 135 | [cell setSnifferResult:result]; 136 | cell.backgroundColor = [UIColor clearColor]; 137 | return cell; 138 | } 139 | 140 | -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 141 | { 142 | NSInteger trueIndex = [self tableViewConvertIndexPath:indexPath]; 143 | NSArray *resultArr = self.dataArr; 144 | [tableView deselectRowAtIndexPath:indexPath animated:YES]; 145 | VKSnifferResult *result = resultArr[trueIndex]; 146 | NSData *reqData = result.data; 147 | NSString *strdata = [[NSJSONSerialization JSONObjectWithData:reqData options:kNilOptions error:nil] description]; 148 | UIAlertView * alert = [[UIAlertView alloc]initWithTitle:@"Response Detail" message:strdata delegate:self cancelButtonTitle:@"OK" otherButtonTitles:@"Copy", nil]; 149 | [alert show]; 150 | NSString *pasteboardstr = [result description]; 151 | self.pasteboardString = pasteboardstr; 152 | } 153 | 154 | -(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex 155 | { 156 | if (self.pasteboardString) { 157 | if (buttonIndex == 1) {//复制 158 | UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; 159 | pasteboard.string = self.pasteboardString; 160 | } 161 | }else{ 162 | [self alertView:alertView clickedMenuButtonAtIndex:buttonIndex]; 163 | } 164 | self.pasteboardString = nil; 165 | } 166 | 167 | 168 | #pragma mark navigationbar 169 | -(void)setupNavigationBar{ 170 | 171 | UILabel *titlelb = [[UILabel alloc]initWithFrame:CGRectMake(0, 20, VKSnifferViewControllerUIWidth, 44)]; 172 | titlelb.textColor = [UIColor whiteColor]; 173 | titlelb.text = @"VKSniffer"; 174 | [self.view addSubview:titlelb]; 175 | titlelb.textAlignment = NSTextAlignmentCenter; 176 | titlelb.font = [UIFont boldSystemFontOfSize:titlelb.font.pointSize]; 177 | 178 | UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeCustom]; 179 | CGFloat x = VKSnifferViewControllerUIWidth - 50 - 20; 180 | rightButton.frame = CGRectMake(x, 20, 50, 44); 181 | [rightButton setTitle:@"Menu" forState:UIControlStateNormal]; 182 | [rightButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; 183 | [rightButton addTarget:self action:@selector(clickMenu) forControlEvents:UIControlEventTouchUpInside]; 184 | 185 | [self.view addSubview:rightButton]; 186 | 187 | UIButton *leftButton = [UIButton buttonWithType:UIButtonTypeCustom]; 188 | leftButton.frame = CGRectMake(10, 20, 50, 44); 189 | [leftButton setTitle:@"Exit" forState:UIControlStateNormal]; 190 | [leftButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; 191 | [leftButton addTarget:self action:@selector(clicExit) forControlEvents:UIControlEventTouchUpInside]; 192 | [self.view addSubview:leftButton]; 193 | 194 | 195 | UIView *line = [[UIView alloc]initWithFrame:CGRectMake(0, 64, VKSnifferViewControllerUIWidth, 0.5f)]; 196 | line.backgroundColor = [UIColor whiteColor]; 197 | [self.view addSubview:line]; 198 | 199 | } 200 | 201 | -(void)clicExit{ 202 | [VKSniffer hideSnifferView]; 203 | } 204 | 205 | -(void)clickMenu{ 206 | [self showMenu]; 207 | } 208 | 209 | #pragma mark menu 210 | -(void)showMenu 211 | { 212 | UIActionSheet *actionSheet = [UIActionSheet new]; 213 | self.actionSheet = actionSheet; 214 | actionSheet.title = @"VKSnifferMenu"; 215 | actionSheet.delegate = self; 216 | if ([VKSniffer singleton].enableSniffer) { 217 | [actionSheet addButtonWithTitle:@"Disable Sniffer"]; 218 | }else{ 219 | [actionSheet addButtonWithTitle:@"Enable Sniffer"]; 220 | } 221 | 222 | [actionSheet addButtonWithTitle:@"Change Filter"]; 223 | [actionSheet addButtonWithTitle:@"Remove All"]; 224 | if (self.isReverse) { 225 | [actionSheet addButtonWithTitle:@"Forward Sequence"]; 226 | }else{ 227 | [actionSheet addButtonWithTitle:@"Reverse Sequence"]; 228 | } 229 | [actionSheet addButtonWithTitle:@"Cancel"]; 230 | actionSheet.cancelButtonIndex = actionSheet.numberOfButtons - 1; 231 | [actionSheet showInView:[UIApplication sharedApplication].keyWindow.rootViewController.view]; 232 | } 233 | 234 | -(void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex 235 | { 236 | if (!_actionSheet) { 237 | return; 238 | } 239 | switch (buttonIndex) { 240 | case 0: 241 | { 242 | [VKSniffer singleton].enableSniffer = ![VKSniffer singleton].enableSniffer; 243 | } 244 | break; 245 | case 1: 246 | { 247 | UIAlertView *inputbox = [[UIAlertView alloc] initWithTitle:@"Change Filter" message:nil delegate:self cancelButtonTitle:@"cancel" otherButtonTitles:@"ok", nil]; 248 | [inputbox setAlertViewStyle:UIAlertViewStylePlainTextInput]; 249 | UITextField *nameField = [inputbox textFieldAtIndex:0]; 250 | nameField.placeholder = @"域名过滤器"; 251 | [inputbox show]; 252 | } 253 | break; 254 | case 2: 255 | { 256 | [self.dataArr removeAllObjects]; 257 | [self.requestTable reloadData]; 258 | } 259 | break; 260 | case 3: 261 | { 262 | self.isReverse = !self.isReverse; 263 | [self.requestTable reloadData]; 264 | } 265 | break; 266 | default: 267 | break; 268 | } 269 | _actionSheet = nil; 270 | } 271 | 272 | -(void)alertView:(UIAlertView *)alertView clickedMenuButtonAtIndex:(NSInteger)buttonIndex{ 273 | 274 | if (buttonIndex == alertView.firstOtherButtonIndex) { 275 | UITextField *nameField = [alertView textFieldAtIndex:0]; 276 | if (nameField.text.length <= 0) { 277 | [VKSniffer singleton].hostFilter = nil; 278 | }else{ 279 | [VKSniffer singleton].hostFilter = nameField.text; 280 | } 281 | } 282 | } 283 | 284 | 285 | - (void)didReceiveMemoryWarning { 286 | [super didReceiveMemoryWarning]; 287 | // Dispose of any resources that can be recreated. 288 | } 289 | 290 | /* 291 | #pragma mark - Navigation 292 | 293 | // In a storyboard-based application, you will often want to do a little preparation before navigation 294 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 295 | // Get the new view controller using [segue destinationViewController]. 296 | // Pass the selected object to the new view controller. 297 | } 298 | */ 299 | 300 | #pragma clang diagnostic pop 301 | 302 | @end 303 | -------------------------------------------------------------------------------- /VKSnifferUI/VKSnifferWindow.h: -------------------------------------------------------------------------------- 1 | // 2 | // VKSnifferWindow.h 3 | // VKSnifferDemo 4 | // 5 | // Created by Awhisper on 2017/3/10. 6 | // Copyright © 2017年 baidu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface VKSnifferWindow : UIWindow 12 | 13 | + (VKSnifferWindow *)showSnifferView; 14 | 15 | + (void)hideSnifferView; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /VKSnifferUI/VKSnifferWindow.m: -------------------------------------------------------------------------------- 1 | // 2 | // VKSnifferWindow.m 3 | // VKSnifferDemo 4 | // 5 | // Created by Awhisper on 2017/3/10. 6 | // Copyright © 2017年 baidu. All rights reserved. 7 | // 8 | 9 | #import "VKSnifferWindow.h" 10 | #import "VKSnifferViewController.h" 11 | 12 | #define VKSnifferViewAlpha 0.8f 13 | 14 | @interface VKSnifferWindow () 15 | 16 | @property (nonatomic,strong) VKSnifferViewController * snifferVC; 17 | 18 | @property (nonatomic,weak) UIWindow *preWindow; 19 | 20 | @end 21 | 22 | @implementation VKSnifferWindow 23 | 24 | -(instancetype)initWithFrame:(CGRect)frame{ 25 | self = [super initWithFrame:frame]; 26 | if (self) { 27 | [self setup]; 28 | } 29 | return self; 30 | } 31 | 32 | -(void)setup{ 33 | self.backgroundColor = [UIColor clearColor]; 34 | self.clipsToBounds = true; 35 | self.windowLevel = UIWindowLevelStatusBar + 1; 36 | [self setupRootViewController]; 37 | } 38 | 39 | -(void)setupRootViewController{ 40 | self.snifferVC = [[VKSnifferViewController alloc]init]; 41 | self.rootViewController = self.snifferVC; 42 | self.rootViewController.view.alpha = 0; 43 | } 44 | 45 | 46 | +(VKSnifferWindow *)showSnifferView 47 | { 48 | if (![[UIApplication sharedApplication].keyWindow isKindOfClass:[VKSnifferWindow class]]) { 49 | VKSnifferWindow *snifferWindow = [[VKSnifferWindow alloc]initWithFrame:[UIScreen mainScreen].bounds]; 50 | [snifferWindow showSnifferView]; 51 | return snifferWindow; 52 | } 53 | return nil; 54 | } 55 | 56 | -(void)showSnifferView 57 | { 58 | [UIView animateWithDuration:0.3 animations:^{ 59 | self.rootViewController.view.frame = [UIScreen mainScreen].bounds; 60 | self.rootViewController.view.alpha = VKSnifferViewAlpha; 61 | self.frame = [UIScreen mainScreen].bounds; 62 | } completion:^(BOOL finished) { 63 | self.preWindow = [UIApplication sharedApplication].keyWindow; 64 | [self makeKeyAndVisible]; 65 | }]; 66 | } 67 | 68 | +(void)hideSnifferView{ 69 | 70 | } 71 | 72 | 73 | -(void)hideSnifferView{ 74 | [UIView animateWithDuration:0.3 animations:^{ 75 | self.rootViewController.view.frame = [UIScreen mainScreen].bounds; 76 | self.rootViewController.view.alpha = 0.0f; 77 | self.frame = [UIScreen mainScreen].bounds; 78 | } completion:^(BOOL finished) { 79 | [self.preWindow makeKeyAndVisible]; 80 | self.preWindow = nil; 81 | self.rootViewController = nil; 82 | self.snifferVC = nil; 83 | }]; 84 | } 85 | 86 | /* 87 | // Only override drawRect: if you perform custom drawing. 88 | // An empty implementation adversely affects performance during animation. 89 | - (void)drawRect:(CGRect)rect { 90 | // Drawing code 91 | } 92 | */ 93 | 94 | @end 95 | --------------------------------------------------------------------------------