iOS網路(三)
阿新 • • 發佈:2019-12-25
一、NSURLProtocol網路攔截
-
NSURLProtocol
是抽象類,使用時要使用其子類// 使用子類需先註冊 [NSURLProtocol registerClass:[SONURLProtocol class]]; 複製程式碼
// 子類實現 + (BOOL)canInitWithRequest:(NSURLRequest *)request { NSLog(@"*** %@",request); // 能監聽uiwebview和WKWebview,但是不能攔截WKWebview只能攔截uiwebview // 因為WKWebview走的WebKit,同時不走cookie,走的也是webkit,用的另外一套核心 // connection可以攔截成功,session不行 //ProtocolKey 經過標記的request不處理,防止出現自迴圈(最好經過md5或其他方式處理保證唯一性) if ([NSURLProtocol propertyForKey:ProtocolKey inRequest:request]) { return NO; } // 攔截百度的logo if ([[request.URL absoluteString] isEqualToString:@"https://m.baidu.com/static/index/plus/plus_logo_web.png"]) { return YES;// 攔截後會新發起新任務執行startLoading ↓ } // 直接hook 所有圖片 NSArray *array = @[@"png",@"jpg",@"jpeg"]; if ([array containsObject:[request.URL pathExtension]]) { return YES; } return NO;// 不接受hook處理,直接載入原資料 // 重定向,對每次的網路請求都可以監聽 } 複製程式碼
- (void)startLoading { // 攔截並給與自己資料 ↑ // 用於 程式碼注入、去廣告等 if ([[self.request.URL absoluteString] isEqualToString:@"https://m.baidu.com/static/index/plus/plus_logo_web.png"]) { NSData *data = [self getImageData]; [self.client URLProtocol:self didLoadData:data]; } } 複製程式碼
-
攔截session
需要特殊處理,因為session不走自定義的NSURLProtocol子類,session有自己的NSURLProtocol子類
afn也是走的session
// 攔截session的特殊處理 + (void)hookNSURLSessionConfiguration { Class cls = NSClassFromString(@"__NSCFURLSessionConfiguration") ?: NSClassFromString(@"NSURLSessionConfiguration"); Method originalMethod = class_getInstanceMethod(cls,@selector(protocolClasses)); Method stubMethod = class_getInstanceMethod([self class],@selector(protocolClasses)); if (!originalMethod || !stubMethod) { [NSException raise:NSInternalInconsistencyException format:@"沒有這個方法 無法交換"]; } method_exchangeImplementations(originalMethod,stubMethod); } - (NSArray *)protocolClasses { return @[[SONURLProtocol class]]; //如果還有其他的監控protocol,也可以在這裡加進去 } 複製程式碼
二、cookie
WKWebview帶不上httpcookie
因為用的不是一套東西,WKWebview用的webkit,沙盒裡找不到cookie
// 解決辦法:拉取同步NSHTTPCookie
- (IBAction)didClickCookieAction:(id)sender
{
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:configuration];
self.webView.navigationDelegate = self;
[self.view addSubview:self.webView];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]];
[self.webView loadRequest:[self cookieAppendRequest]];
}
- (NSURLRequest *)cookieAppendRequest
{
// 替換header
// 該方法在跨域請求時會丟cookie ---- 解決辦法看下面 ↓
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]];
NSArray *cookies = [NSHTTPCookieStorage sharedHTTPCookieStorage].cookies;
//Cookies陣列轉換為requestHeaderFields
NSDictionary *requestHeaderFields = [NSHTTPCookie requestHeaderFieldsWithCookies:cookies];
//設定請求頭
request.allHTTPHeaderFields = requestHeaderFields;
NSLog(@"%@",request.allHTTPHeaderFields);
return request;
}
複製程式碼
// 跨域請求時會丟cookie的解決 ↑
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
// WKWebview所有請求動作都會來這裡
[[WKCookieManager shareManager] fixNewRequestCookieWithRequest:navigationAction.request];
decisionHandler(WKNavigationActionPolicyAllow);
}
- (NSURLRequest *)fixNewRequestCookieWithRequest:(NSURLRequest *)originalRequest
{
NSMutableURLRequest *fixedRequest;
if ([originalRequest isKindOfClass:[NSMutableURLRequest class]])
{
fixedRequest = (NSMutableURLRequest *)originalRequest;
}
else
{
fixedRequest = originalRequest.mutableCopy;
}
//防止Cookie丟失
NSDictionary *dict = [NSHTTPCookie requestHeaderFieldsWithCookies:[NSHTTPCookieStorage sharedHTTPCookieStorage].cookies];
if (dict.count)
{
NSMutableDictionary *mDict = originalRequest.allHTTPHeaderFields.mutableCopy;
[mDict setValuesForKeysWithDictionary:dict];
fixedRequest.allHTTPHeaderFields = mDict;
}
return fixedRequest;
}
複製程式碼
三、構建HTTP網路框架
-
url-request-請求時間/請求序列化/蜂窩/formadata/url處理(%編碼)
-
構建request的目標是發起task任務,session利用request來構建task
-
封裝:1、在vc中摒棄任何介面
2、在vc中不進行資料處理
1、manager類
用於收集:url、timeout、post/get、回撥(block、delegate)
2、代理層
session代理資料
3、request層
處理url
4、error
5、快取
6、工具層
加密、網路狀態
7、response
json、xml
8、資料返回層
json → model、mvvm、rac(signal、subscriNext)