WKWebview의 쿠키 매듭

9552 단어 iOS
먼저 NSHTTPCookieStorage 클래스를 살펴보겠습니다.
/*!
    @class NSHTTPCookieStorage 
    @discussion NSHTTPCookieStorage implements a singleton object (shared
    instance) which manages the shared cookie store.  It has methods
    to allow clients to set and remove cookies, and get the current
    set of cookies.  It also has convenience methods to parse and
    generate cookie-related HTTP header fields.
*/
@interface NSHTTPCookieStorage : NSObject

Each stored cookie is represented by an instance of the  NSHTTPCookie  class.
이것은 쿠키를 관리하는 단일 용기이고 NSHTTP 쿠키의 실례를 저장한 것으로 이 종류를 사용하여 쿠키를 추가 삭제하고 수정할 수 있다.
//          cookie
@property (nullable , readonly, copy) NSArray *cookies;

//  cookie   :      name domain path cookie
- (void)setCookie:(NSHTTPCookie *)cookie;

//  cookie
- (void)deleteCookie:(NSHTTPCookie *)cookie;

- (void)removeCookiesSinceDate:(NSDate *)date API_AVAILABLE(macos(10.10), ios(8.0), watchos(2.0), tvos(9.0));

//    url cookies
- (nullable NSArray *)cookiesForURL:(NSURL *)URL;
//          NSHTTPCookie                        (     )

그리고 NSHTTP 쿠키 클래스를 살펴보겠습니다.
/*!
    @class NSHTTPCookie
    @abstract NSHTTPCookie represents an http cookie.
    @discussion A NSHTTPCookie instance represents a single http cookie. It is
    an immutable object initialized from a dictionary that contains
    the various cookie attributes. It has accessors to get the various
    attributes of a cookie.
*/
@interface NSHTTPCookie : NSObject

An  NSHTTPCookie  object is immutable, initialized from a dictionary containing the attributes of the cookie. This class supports two different cookie versions:
  • Version 0: The original cookie format defined by Netscape.Most cookies are in this format.
  • Version 1: The cookie format defined in RFC 6265, HTTP State Management Mechanism.

  • 모든 NSHTTP 쿠키 실례 대상은 변할 수 없고 http 쿠키를 대표한다.키가 쿠키 특유의 속성을 포함하는 사전에서만 실례화할 수 있습니다.두 가지 쿠키를 지원합니다.
    - (nullable instancetype)initWithProperties:(NSDictionary *)properties;
    
    + (nullable NSHTTPCookie *)cookieWithProperties:(NSDictionary *)properties;
    
    /*     autoreleased NSHTTPCookie  ,      cookie   key  key        ,    nil*/
    
    
    + (NSDictionary *)requestHeaderFieldsWithCookies:(NSArray *)cookies;
    
    /*@discussion This method will ignore irrelevant header fields so
    you can pass a dictionary containing data other than cookie data.
    */
    + (NSArray *)cookiesWithResponseHeaderFields:(NSDictionary *)headerFields forURL:(NSURL *)URL;

    먼저 사전(key가 있을 수 있음)을 만든 다음 사전을 사용하여 필요한 쿠키를 생성할 수 있습니다.
    FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookieName;
    FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookieValue;
    FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookieVersion;
    FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookieDomain;
    FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookiePath;
    FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookieSecure;
    FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookieExpires;
    ...
    //   NSHTTPCookie.h       key
    //1.  cookie  
    NSMutableDictionary *cookieProperties = [NSMutableDictionary dictionary];
    [cookieProperties setObject:cookieInfo.cookieName forKey:NSHTTPCookieName];
    [cookieProperties setObject:cookieInfo.cookieValue forKey:NSHTTPCookieValue];
    [cookieProperties setObject:cookieInfo.cookieDomain forKey:NSHTTPCookieDomain];
    [cookieProperties setObject:@"/" forKey:NSHTTPCookiePath];
    [cookieProperties setObject:@"0" forKey:NSHTTPCookieVersion];
    
    //2.  NSHTTPCookie  
    NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:cookieProperties];
        
    //3.  cookie
    [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];

    쿠키 저장 & 사용 절차:
    일반적으로 wkwebview로 http 요청을 할 때 서버는 생성된 쿠키를 응답 헤더 Reponse의 헤더를 통해 app로 되돌려줍니다. 이 때 쿠키를 NSHTTPCookieStorage 단일 용기에 맡기거나 스스로 저장할 수 있습니다.다음에 방문할 때 저장된 쿠키를 꺼내서 http 요청 헤더에 놓으면 서버에서 저희가 설정한 쿠키를 통해 저희를 식별할 수 있습니다.
    쿠키 가져오기:
    wkwebview에는 응답 헤더를 얻을 수 있는 프록시 방법이 있습니다:
    - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
    //  1
        NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)navigationResponse.response;
    //    NSURlResponse     NSHTTPURLResponse 
    //        http      NSHTTPURLResponse   NSURlResponse   
        NSDictionary* dict = httpResponse.allHeaderFields;
        NSString* cookiesStr = [dict valueForKey:@"Set-Cookie"];
    
    //  2    
        NSArray* array = [NSHTTPCookie cookiesWithResponseHeaderFields:httpResponse.allHeaderFields forURL:httpResponse.URL];
        for (NSHTTPCookie * cookie in array) {
            //   sharedHTTPCookieStorage 
            [[NSHTTPCookieStorage sharedHTTPCookieStorage]setCookie:cookie];
        }
    
    }
    

    실례 상황과 참고 문서에 근거하여 발견하다
    업계에서는 WKWebView가 자신의 개인 저장소를 가지고 있기 때문에 쿠키를 표준 쿠키 용기인 NSHTTP 쿠키 Storage에 저장하지 않을 것이라고 보편적으로 보고 있다. 실제로 WKWebView 실례도 쿠키를 NSHTTP 쿠키 Storage에 저장하지만 저장 시기가 늦다는 것을 발견했다.
    WKWebView Cookie 문제는 WKWebView에서 시작한 요청이 NSHTTP Cookie Storage 컨테이너에 저장된 Cookie를 자동으로 가져오지 않는다는 점입니다.
    이로 인해 WKWebview를 사용하여 웹 페이지를 방문할 때 저장된 쿠키를 자동으로 가져오지 않고 수동으로 설정해야 합니다.[WKWebView loadReques:]를 실행하기 전에 NSHTTPCookieStorage의 쿠키 내용을 wkwebview 요청에 넣고 WKWebView cookie 주입의 목적을 달성해야 합니다.
    쿠키 설정:
    방식1: 요청 헤더에 추가
    NSString* cookiesStr = [dict valueForKey:@"Set-Cookie"];

    위 응답 헤더에서 얻은 쿠키는 Request의 헤더에 직접 값을 부여할 수 있습니다.
    NSMutableURLRequest* mutableRequest = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:30];
    [mutableRequest setValue:cookiesStr forHTTPHeaderField:@"Cookie"];

    방식2: 여러 개NSHTTPCookie의 실례 대상의 수조를 구축하고 NSHTTPCookie의 실례 수조에 따라 대응하는 HTTP cookieheader를 생성하여 cookierequestheader에 설정한다.
    NSDictionary *properties1 = [NSDictionary dictionaryWithObjectsAndKeys:
                                    @"domain.com", NSHTTPCookieDomain,
                                    @"/", NSHTTPCookiePath,
                                    @"Name1", NSHTTPCookieName,
                                    Value, NSHTTPCookieValue,
                                    nil];
        
    NSDictionary *properties2 = [NSDictionary dictionaryWithObjectsAndKeys:
                                     @"domain.com", NSHTTPCookieDomain,
                                     @"/", NSHTTPCookiePath,
                                     @"Name2", NSHTTPCookieName,
                                     Value2, NSHTTPCookieValue,
                                     nil];
    NSHTTPCookie *cookie1 = [NSHTTPCookie cookieWithProperties:properties1];
    NSHTTPCookie *cookie2 = [NSHTTPCookie cookieWithProperties:properties2];
    NSArray* cookies = [NSArray arrayWithObjects: cookie1, cookie2, nil];
    //  NSHTTPCookie         HTTP cookie header
    NSDictionary * headers = [NSHTTPCookie requestHeaderFieldsWithCookies:cookies];
    //  cookie header 
    request.allHTTPHeaderFields = headers;

    방식3:
    NSString *cookieStr = [self cookieStrWithCookies:[NSHTTPCookieStorage sharedHTTPCookieStorage].cookies];
    WKUserScript * cookieScript = [[WKUserScript alloc]initWithSource:cookieStr injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
    
    WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
    WKUserContentController *userContentController = [[WKUserContentController alloc] init];
    [userContentController addUserScript:cookieScript];
    configuration.userContentController = userContentController;
    _webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:configuration];
    
    - (NSString *)cookieStrWithCookies:(NSArray *)cookies {
        NSMutableString *result = [NSMutableString string];
        for (NSHTTPCookie *cookie in cookies) {
            if (![cookie.domain isEqualToString:@".domain.cn"]) {
                continue;
            }
            //                
            NSString *temp = [NSString stringWithFormat:@"document.cookie = '%@=%@; domain=%@; path=%@; expires=%@; %@=%zd';", cookie.name, cookie.value, cookie.domain, cookie.path, cookie.expiresDate, NSHTTPCookieVersion, cookie.version];
            [result appendString:temp];
        }
        return result;
    }

    iOS11 이후의 편리함:
    ios11 이후 WKHTTP Cookie Store wkwebview 관리를 위한 쿠키 출시
    @interface WKHTTPCookieStore : NSObject
    An object that manages the HTTP cookies associated with a particular WKWebsiteDataStore.
    NSArray* cookiesArr = [NSHTTPCookieStorage sharedHTTPCookieStorage].cookies;
    if (@available(iOS 11.0, *)) {
          WKHTTPCookieStore* wkhttpStore = configuration.websiteDataStore.httpCookieStore;;
          for (NSHTTPCookie* coo in cookiesArr) {
              [wkhttpStore setCookie:coo completionHandler:^{ }];
          }
      } else {
          // Fallback on earlier versions
    }

    이렇게 하면 wkwebview에 쿠키를 쉽게 설정할 수 있습니다.
     
    참조 1
    참조 2
    참조 3
    참조

    좋은 웹페이지 즐겨찾기