1. 程式人生 > IOS開發 >iOS網路(三)

iOS網路(三)

一、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)