iOS UIWebView 和 WKWebView 的 cookie 獲取,設(shè)置,刪除

Cookie簡介

說到Cookie,或許有些小伙伴會(huì)比較陌生,有些小伙伴會(huì)比較熟悉。如果項(xiàng)目中,所有頁面都是純原生來實(shí)現(xiàn)的話,一般Cookie這個(gè)東西或許我們永遠(yuǎn)也不會(huì)接觸到。但是,這里還是要說一下Cookie,因?yàn)樗娴暮苤匾?,由它產(chǎn)生的一些坑也很多。

Cookie 在 web中應(yīng)用比較多,主要是記錄一個(gè)狀態(tài),比如我在網(wǎng)頁上登錄了,我就可以拿到網(wǎng)頁登錄后 Cookie,下次再 Cookie 的生效期內(nèi)我就可以不用輸入賬號(hào)密碼,直接跳轉(zhuǎn)登錄狀態(tài),在App中,Cookie最常用的也就是維持登錄狀態(tài)了.因?yàn)楣P者最近就在做這個(gè),其中也遇到過很多坑,這里說先踩坑和用法

iOS Cookie 的管理

  • NSHTTPCookie和NSHTTPCookieStorage

iOS中進(jìn)行HTTP網(wǎng)絡(luò)請求Cookie管理主要由兩個(gè)類負(fù)責(zé),一個(gè)類是NSHTTPCookieStorage類,一個(gè)是NSHTTPCookie類。

NSHTTPCookieStorage

NSHTTPCookieStorage類采用單例的設(shè)計(jì)模式,其中管理著所有HTTP請求的Cookie信息
官方解釋:NSHTTPCookieStorage 是一個(gè)用來管理 cookie 存儲(chǔ)的單例。一個(gè) NSHTTPCookie 單例代表一個(gè) cookie。通常來講,cookie 可以在應(yīng)用間共享,并且在進(jìn)程之間保持同步。 對于單進(jìn)程,Session cookies (這里的 cookie 對象的 isSessionOnly 方法返回 YES)是局部的并且不能被共享。

**常用方法**
// 獲取單例對象
+ (NSHTTPCookieStorage *)sharedHTTPCookieStorage;

// 所有Cookie數(shù)據(jù)數(shù)組 其中存放NSHTTPCookie對象
@property (nullable , readonly, copy) NSArray<NSHTTPCookie *> *cookies;

// 手動(dòng)設(shè)置一條Cookie數(shù)據(jù)
- (void)setCookie:(NSHTTPCookie *)cookie;

// 刪除某條Cookie信息
- (void)deleteCookie:(NSHTTPCookie *)cookie;

// 刪除某個(gè)時(shí)間后的所有Cookie信息 iOS8后可用
- (void)removeCookiesSinceDate:(NSDate *)date NS_AVAILABLE(10_10, 8_0);

// 獲取某個(gè)特定URL的所有Cookie數(shù)據(jù)
- (nullable NSArray<NSHTTPCookie *> *)cookiesForURL:(NSURL *)URL;

// 為某個(gè)特定的URL設(shè)置Cookie
- (void)setCookies:(NSArray<NSHTTPCookie *> *)cookies forURL:(nullable NSURL *)URL mainDocumentURL:(nullable NSURL *)mainDocumentURL;

// Cookie數(shù)據(jù)的接收協(xié)議
枚舉如下:
typedef NS_ENUM(NSUInteger, NSHTTPCookieAcceptPolicy) {
    NSHTTPCookieAcceptPolicyAlways,//接收所有Cookie信息
    NSHTTPCookieAcceptPolicyNever,//不接收所有Cookie信息
    NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain//只接收主文檔域的Cookie信息
};
@property NSHTTPCookieAcceptPolicy cookieAcceptPolicy;

系統(tǒng)下面的兩個(gè)通知與Cookie管理有關(guān):
據(jù)說,在Mac OS是cookie可以共享的(Session cookies 不能共享),在Mac OS app中更改cookie的接收策略會(huì)影響到其他正在運(yùn)行的在使用cookie storage的app.這時(shí)NSHTTPCookieStorage會(huì)發(fā)出兩個(gè)通知:
// Cookie數(shù)據(jù)的接收協(xié)議改變時(shí)發(fā)送的通知
FOUNDATION_EXPORT NSString * const NSHTTPCookieManagerAcceptPolicyChangedNotification;
// 管理的Cookie數(shù)據(jù)發(fā)生變化時(shí)發(fā)送的通知
FOUNDATION_EXPORT NSString * const NSHTTPCookieManagerCookiesChangedNotification;

NSHTTPCookie介紹

NSHTTPCookie是具體的HTTP請求Cookie數(shù)據(jù)對象.

// 下面兩個(gè)方法用于對象的創(chuàng)建和初始化 都是通過字典進(jìn)行鍵值設(shè)置
- (nullable instancetype)initWithProperties:(NSDictionary<NSString *, id> *)properties;
+ (nullable NSHTTPCookie *)cookieWithProperties:(NSDictionary<NSString *, id> *)properties;

// 返回Cookie數(shù)據(jù)中可用于添加HTTP頭字段的字典
+ (NSDictionary<NSString *, NSString *> *)requestHeaderFieldsWithCookies:(NSArray<NSHTTPCookie *> *)cookies;

// 從指定的響應(yīng)頭和URL地址中解析出Cookie數(shù)據(jù)
+ (NSArray<NSHTTPCookie *> *)cookiesWithResponseHeaderFields:(NSDictionary<NSString *, NSString *> *)headerFields forURL:(NSURL *)URL;

// Cookie數(shù)據(jù)中的屬性字典
@property (nullable, readonly, copy) NSDictionary<NSString *, id> *properties;

// 請求響應(yīng)的版本
@property (readonly) NSUInteger version;

// 請求相應(yīng)的名稱
@property (readonly, copy) NSString *name;

// 請求相應(yīng)的值
@property (readonly, copy) NSString *value;

// 過期時(shí)間
@property (nullable, readonly, copy) NSDate *expiresDate;

// 請求的域名
@property (readonly, copy) NSString *domain;

//請求的路徑
@property (readonly, copy) NSString *path;

// 是否是安全傳輸
@property (readonly, getter=isSecure) BOOL secure;

// 是否只發(fā)送HTTP的服務(wù)
@property (readonly, getter=isHTTPOnly) BOOL HTTPOnly;

// 響應(yīng)的文檔
@property (nullable, readonly, copy) NSString *comment;

// 相應(yīng)的文檔URL
@property (nullable, readonly, copy) NSURL *commentURL;

// 服務(wù)端口列表
@property (nullable, readonly, copy) NSArray<NSNumber *> *portList;

HTTP cookie的屬性鍵

屬性 解讀
NSHTTPCookieName Cookie的名字
NSHTTPCookieValue Cookie的值
NSHTTPCookieOriginURL 和域名一樣,NSHTTPCookieDomain或NSHTTPCookieOriginURL必須指定一個(gè)值
NSHTTPCookieVersion 接收器的版本
NSHTTPCookieDomain 域名
NSHTTPCookiePath Cookie 存放路徑
NSHTTPCookieSecure Cookie是否只應(yīng)通過安全通道發(fā)送,設(shè)置Cookie的secure屬性為true。只會(huì)在HTTPS和SSL等安全協(xié)議中傳輸此類Cookie。默認(rèn)為false
NSHTTPCookieComment 包含Cookie的評論,只有有效的版本1的cookies或更高版本。 這頭字段是可選的
NSHTTPCookieCommentURL 接收器的評論URL
NSHTTPCookieDiscard Cookie是否應(yīng)在會(huì)議結(jié)束時(shí)丟棄NSString,字符串值必須是“true”或“假”。 這個(gè)字段是可選的。 默認(rèn)為“假”,除非這是Cookie是第1版或以上,NSHTTPCookieMaximumAge未指定,在這種情況下,它被假定為“TRUE”
NSHTTPCookieMaximumAge NSString對象,包含一個(gè)整數(shù),在Cookie內(nèi)保持最多幾秒 。僅適用于第1版和更高版本的有效。 默認(rèn)為“0”。 此字段是可選的
NSHTTPCookiePort 接收機(jī)的端口
  • UIWebView的 Cookie 機(jī)制

UIWebView 在瀏覽網(wǎng)頁后會(huì)將網(wǎng)頁中的 cookie 自動(dòng)存入 NSHTTPCookieStorage 標(biāo)準(zhǔn)容器中,[NSHTTPCookieStorage sharedHTTPCookieStorage]這個(gè)單例管理,在后續(xù)訪問中會(huì)將 cookie 自動(dòng)帶到 request 請求當(dāng)中。并且在同一個(gè)app內(nèi)多個(gè)UIWebView之間共享。

  • webView 中獲取 cookie
//加載成功
- (void)webViewDidFinishLoad:(UIWebView *)webView {
    NSString *requestUrl = webView.request.URL.absoluteString;
    NSLog(@" requestUrl: %@",requestUrl);

//設(shè)置原始 cookie 根據(jù)key 存儲(chǔ)本地
    NSMutableArray *cookieArray = [[NSMutableArray alloc] init];

//網(wǎng)頁加載完成取出 cookies
    NSArray *nCookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies];
    NSHTTPCookie *cookie;
    for (id c in nCookies) {
        if ([c isKindOfClass:[NSHTTPCookie class]]) {
            cookie=(NSHTTPCookie *)c;
          //我這里是cookie存入字典中 去重
            if ([cookie value]) {
                //如果 vaule 值不為 nil 存入字典中,
                [self.mutableDic setValue:[cookie value] forKey:[cookie name]];
              }
//設(shè)置原始 cookie
            NSMutableDictionary *cookieProperties = [NSMutableDictionary dictionary];
            [cookieProperties setObject:cookie.name forKey:NSHTTPCookieName];
            [cookieProperties setObject:cookie.value forKey:NSHTTPCookieValue];
            [cookieProperties setObject:cookie.domain forKey:NSHTTPCookieDomain];
            [cookieProperties setObject:cookie.path forKey:NSHTTPCookiePath];
            [cookieProperties setObject:[[NSDate date] dateByAddingTimeInterval:2629743] forKey:NSHTTPCookieExpires];
            [cookieArray addObject:cookieProperties];

            [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
        }
    }
//cookie 存入本地
   [[NSUserDefaults standardUserDefaults] setObject:cookieArray forKey:@"cookieArray"];
        [[NSUserDefaults standardUserDefaults] synchronize];

//下面 cookie 去重是為了得到 key=Value;形式的字符串,這里由于我有需求這樣做,實(shí)際中下面可以忽略
        NSMutableString *cookieValue = [NSMutableString stringWithFormat:@""];
        // cookie重復(fù),先放到字典進(jìn)行去重,再進(jìn)行拼接
        for (NSString *key in self.mutableDic) {
            NSString *appendString = [NSString stringWithFormat:@"%@=%@;", key, [self.mutableDic valueForKey:key]];
            [cookieValue appendString:appendString];
        }
NSLog(@"########################     %@        ####################",cookieValue);
  • 設(shè)置 cookie
 NSMutableArray* cookieDictionary = [[NSUserDefaults standardUserDefaults] valueForKey:@"cookieArray"];
        
        NSLog(@"cookie dictionary found is %@",cookieDictionary);
        
        if (cookieDictionary) {
            for (NSInteger i = 0; i < cookieDictionary.count; i++) {
                
                NSLog(@"cookie found is %@",[cookieDictionary objectAtIndex:i]);
                
                NSDictionary *cookieDic = [cookieDictionary objectAtIndex:i];
                NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:cookieDic];
                [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
            }
        }
    //設(shè)置請求之前加載 cookie 確保 cookie 在請求頭之前設(shè)置
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:self.URLString] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10];

    //加載網(wǎng)頁
    [self.webView loadRequest:request];

  • 刪除 cookie
// 清空 cookie
- (void)deleteCookie {
    // 清空 cookie
    NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    NSArray *_tmpArray = [NSArray arrayWithArray:[cookieJar cookies]];
    for (id obj in _tmpArray) {
        [cookieJar deleteCookie:obj];
    }
}
  • WKWebView 的 Cookie 機(jī)制

NSURLCache和NSHTTPCookieStroage無法操作(WKWebView)WebCore進(jìn)程的緩存和Cookie
WKWebView實(shí)例將會(huì)忽略任何的默認(rèn)網(wǎng)絡(luò)存儲(chǔ)器(NSURLCache, NSHTTPCookieStorage, NSCredentialStorage) 和一些標(biāo)準(zhǔn)的自定義網(wǎng)絡(luò)請求類(NSURLProtocol,等等.),WKWebView實(shí)例不會(huì)把Cookie存入到App標(biāo)準(zhǔn)的的Cookie容器(NSHTTPCookieStorage)中,因?yàn)?NSURLSession/NSURLConnection等網(wǎng)絡(luò)請求使用NSHTTPCookieStorage進(jìn)行訪問Cookie,所以不能訪問WKWebView的Cookie,現(xiàn)象就是WKWebView存了Cookie,其他的網(wǎng)絡(luò)類如NSURLSession/NSURLConnection卻看不到。這是很多人的說法。
還有一種是說法是通過實(shí)踐發(fā)現(xiàn) WKWebView 實(shí)例其實(shí)也會(huì)將 Cookie 存儲(chǔ)于 NSHTTPCookieStorage 中,但存儲(chǔ)時(shí)機(jī)有延遲,因?yàn)閃KWebView內(nèi)也有cookie的容器,而且每隔一段時(shí)間就和app側(cè)NSHTTPCookieStorage進(jìn)行同步,而且這個(gè)同步是進(jìn)程級(jí)別的同步,而且這個(gè)同步是單向。
至于以上兩種說法,最終WKWebView Cookie 問題在于 WKWebView 發(fā)起的請求不會(huì)自動(dòng)帶上存儲(chǔ)于 NSHTTPCookieStorage 容器中的 Cookie。

  • iOS11
    iOS11 的 API 可以解決該問題,只要是存在 WKHTTPCookieStore 里的 cookie,WKWebView 每次請求都會(huì)攜帶,存在 NSHTTPCookieStorage 的cookie,并不會(huì)每次都攜帶。于是會(huì)發(fā)生首次 WKWebView 請求不攜帶 Cookie 的問題。

  • ios 11 WKWebView cookie 的注入
    在執(zhí)行 -[WKWebView loadReques:] 前將 NSHTTPCookieStorage 中的內(nèi)容復(fù)制到 WKHTTPCookieStore 中,以此來達(dá)到 WKWebView Cookie 注入的目的。示例代碼如下:

[self copyNSHTTPCookieStorageToWKHTTPCookieStoreWithCompletionHandler:^{
            NSURL *url = [NSURL URLWithString:@"https://www.v2ex.com"];
            NSURLRequest *request = [NSURLRequest requestWithURL:url];
            [_webView loadRequest:request];
        }];

- (void)copyNSHTTPCookieStorageToWKHTTPCookieStoreWithCompletionHandler:(nullable void (^)())theCompletionHandler; {
    NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies];
    WKHTTPCookieStore *cookieStroe = self.webView.configuration.websiteDataStore.httpCookieStore;
    if (cookies.count == 0) {
        !theCompletionHandler ?: theCompletionHandler();
        return;
    }
    for (NSHTTPCookie *cookie in cookies) {
        [cookieStroe setCookie:cookie completionHandler:^{
            if ([[cookies lastObject] isEqual:cookie]) {
                !theCompletionHandler ?: theCompletionHandler();
                return;
            }
        }];
    }
}

  • ios11 之前
    注入 Cookie 就是從之前保存 cookie 的 NSHTTPCookieStorage 中取出相關(guān) Cookie,然后在再次請求訪問的時(shí)候在 request 中注入 Cookie。注入Cookie同樣有多種方式。

  • 1.JS注入1

//取出 storage 中的cookie并將其拼接成正確的形式
NSArray<NSHTTPCookie *> *tmp = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies];    
    NSMutableString *jscode_Cookie = [@"" mutableCopy];
    [tmp enumerateObjectsUsingBlock:^(NSHTTPCookie * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        NSLog(@"%@   =  %@", obj.name, obj.value);
        [jscode_Cookie appendString:[NSString stringWithFormat:@"document.cookie =  '%@=%@';", obj.name, obj.value]];
    }];

WKUserContentController* userContentController = WKUserContentController.new;
    WKUserScript * cookieScript = [[WKUserScript alloc] initWithSource: @"" injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
    
    [userContentController addUserScript:cookieScript];
    WKWebViewConfiguration* webViewConfig = WKWebViewConfiguration.new;
    webViewConfig.userContentController = userContentController;
WKWebView * webView = [[WKWebView alloc] initWithFrame:CGRectMake(/*set your values*/) configuration:webViewConfig];
  • JS注入2
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
    [webView evaluateJavaScript:@"document.cookie ='TeskCookieKey1=TeskCookieValue1';" completionHandler:^(id result, NSError *error) {
        //...
    }];
}

  • NSMutableURLRequest 注入Cookie
NSURL *url = request.URL;
NSMutableString *cookies = [NSMutableString string];
NSMutableURLRequest *requestObj = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10];
    
NSArray *tmp = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies];
NSDictionary *dicCookies = [NSHTTPCookie requestHeaderFieldsWithCookies:tmp];
NSString *cookie = [self readCurrentCookie];
[requestObj setValue:cookie forHTTPHeaderField:@"Cookie"];
[_webView loadRequest:requestObj];


-(NSString *)readCurrentCookie{
    NSMutableDictionary *cookieDic = [NSMutableDictionary dictionary];
    NSMutableString *cookieValue = [NSMutableString stringWithFormat:@""];
    NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    for (NSHTTPCookie *cookie in [cookieJar cookies]) {
        [cookieDic setObject:cookie.value forKey:cookie.name];
    }
    
    // cookie重復(fù),先放到字典進(jìn)行去重,再進(jìn)行拼接
    for (NSString *key in cookieDic) {
          NSString *appendString = [NSString stringWithFormat:@"%@=%@;", key, [cookieDic valueForKey:key]];
            [cookieValue appendString:appendString];
    }
    return cookieValue;
}

獲取Cookie
由于 WKWebView 的 Cookie 存儲(chǔ)容器 WKWebsiteDataStore 是私有存儲(chǔ),所以無法從這里獲取到Cookie,目前的方法是(1)從網(wǎng)站返回的 response headerfields 中獲取。(2)通過調(diào)用js的方法獲取 cookie。

  • 1.從網(wǎng)站返回的 response headerfields 中獲取,因?yàn)閏ookie都存在http respone的headerfields,找到能獲得respone的WKWebView回調(diào),打印
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
    NSHTTPURLResponse *response = (NSHTTPURLResponse *)navigationResponse.response;
    NSArray *cookies =[NSHTTPCookie cookiesWithResponseHeaderFields:[response allHeaderFields] forURL:response.URL];
    //讀取wkwebview中的cookie 方法1
    for (NSHTTPCookie *cookie in cookies) {
//        [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
        NSLog(@"wkwebview中的cookie:%@", cookie);
 
    }
    //讀取wkwebview中的cookie 方法2 讀取Set-Cookie字段
    NSString *cookieString = [[response allHeaderFields] valueForKey:@"Set-Cookie"];
    NSLog(@"wkwebview中的cookie:%@", cookieString);
 
    //看看存入到了NSHTTPCookieStorage了沒有
    NSHTTPCookieStorage *cookieJar2 = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    for (NSHTTPCookie *cookie in cookieJar2.cookies) {
        NSLog(@"NSHTTPCookieStorage中的cookie%@", cookie);
    }
//下面是將 原始cookie本地 化
NSMutableArray *cookieArray = [[NSMutableArray alloc] init];
    for (NSHTTPCookie *cookie in [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]) {

        NSMutableDictionary *cookieProperties = [NSMutableDictionary dictionary];
        [cookieProperties setObject:cookie.name forKey:NSHTTPCookieName];
        [cookieProperties setObject:cookie.value forKey:NSHTTPCookieValue];
        [cookieProperties setObject:cookie.domain forKey:NSHTTPCookieDomain];
        [cookieProperties setObject:cookie.path forKey:NSHTTPCookiePath];
        [cookieProperties setObject:[NSNumber numberWithInt:cookie.version] forKey:NSHTTPCookieVersion];
        [cookieProperties setObject:[[NSDate date] dateByAddingTimeInterval:2629743] forKey:NSHTTPCookieExpires];
      [cookieArray addObject:cookieProperties];
    }
    
    [[NSUserDefaults standardUserDefaults] setValue:cookieArray forKey:@"cookieArray"];
    [[NSUserDefaults standardUserDefaults] synchronize];

    decisionHandler(WKNavigationResponsePolicyAllow);
}

// 頁面加載完成之后調(diào)用需要重新給WKWebView設(shè)置Cookie防止因?yàn)閍標(biāo)簽跳轉(zhuǎn),導(dǎo)致下一次跳轉(zhuǎn)的時(shí)候Cookie丟失。
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
    //取出cookie
    NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    //js函數(shù)
    NSString *JSFuncString =
    @"function setCookie(name,value,expires)\
    {\
    var oDate=new Date();\
    oDate.setDate(oDate.getDate()+expires);\
    document.cookie=name+'='+value+';expires='+oDate+';path=/'\
    }\
    function getCookie(name)\
    {\
    var arr = document.cookie.match(new RegExp('(^| )'+name+'=({FNXX==XXFN}*)(;|$)'));\
    if(arr != null) return unescape(arr[2]); return null;\
    }\
    function delCookie(name)\
    {\
    var exp = new Date();\
    exp.setTime(exp.getTime() - 1);\
    var cval=getCookie(name);\
    if(cval!=null) document.cookie= name + '='+cval+';expires='+exp.toGMTString();\
    }";

    //拼湊js字符串
    NSMutableString *JSCookieString = JSFuncString.mutableCopy;
    for (NSHTTPCookie *cookie in cookieStorage.cookies) {
        NSString *excuteJSString = [NSString stringWithFormat:@"setCookie('%@', '%@', 1);", cookie.name, cookie.value];
        [JSCookieString appendString:excuteJSString];
    }
    //執(zhí)行js
    [webView evaluateJavaScript:JSCookieString completionHandler:^(id obj, NSError * _Nullable error) {
        NSLog(@"%@",error);
    }];
}

  • 通過 JS 獲取 cookie
- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation
{
    
    [webView evaluateJavaScript:[NSString stringWithFormat:@"document.cookie"] completionHandler:^(id _Nullable response, NSError * _Nullable error) {
        if (response != 0) {
            NSLog(@"\n\n\n\n\n\n document.cookie%@,%@",response,error);
        }
    }];
}

注意

document.cookie 的方法獲取 cookie并不支持跨越獲取,如果設(shè)置 httponly則獲取不到 cookie
不論是(1)還是(2)方法,似乎都無法解決302請求的 Cookie 問題。舉例來說,假設(shè)你要訪問網(wǎng)站A,在A中點(diǎn)擊登錄,跳轉(zhuǎn)頁面到B地址,在B中完成登錄之后302跳轉(zhuǎn)回A網(wǎng)站。此時(shí)cookie是存在于B地址的 response 中的,在A地址的 response 中并沒有 cookie 的字段。然而我們只能獲取到A地址的 response ,無法截獲到B地址的response。因此獲取不到該類型網(wǎng)站的 cookie 。
由于我并沒有遇到302這樣的問題,所有看了下網(wǎng)上的資料,希望對遇到這個(gè)問題的小伙伴一下辦法,網(wǎng)上給出的解決辦法是:

  • 1.加載一個(gè)本地為空的html,域名指向你的第一次加載的url的域名。
//加載本地html
[self.webView loadHTMLString:@"" baseURL:[NSURL URLWithString:@"https:/a.com"]];
  • 2.通過以下方法,在第一次加載完成后,將需要設(shè)置的Cookies設(shè)置到WKWebView中,因?yàn)槭羌虞d的本地的html以下方法會(huì)立即執(zhí)行。
// 頁面加載完成之后調(diào)用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
    
    if (isFirstLoaded) {
        NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
        //js函數(shù)
        NSString *JSFuncString =
        @"function setCookie(name,value,expires)\
        {\
        var oDate=new Date();\
        oDate.setDate(oDate.getDate()+expires);\
        document.cookie=name+'='+value+';expires='+oDate+';path=/'\
        }";
        
        //拼湊js字符串,按照自己的需求拼湊Cookie
        NSMutableString *JSCookieString = JSFuncString.mutableCopy;
        for (NSHTTPCookie *cookie in cookieStorage.cookies) {
            if (![cookie.name isEqualToString:@"__cust"]) {
                NSString *excuteJSString = [NSString stringWithFormat:@"setCookie('%@', '%@', 3);", cookie.name, cookie.value];
                [JSCookieString appendString:excuteJSString];
            }
        }
        
        //執(zhí)行js
        [webView evaluateJavaScript:JSCookieString completionHandler:^(id obj, NSError * _Nullable error) {
            //加載真正的第一次Request
            [self loadRealRequest];
        }];
    }
}

如果cookie 存儲(chǔ)到本地獲取本地的 cookie

//修改從 storage 中讀取 cookie 的方法
-(NSString *)readCurrentCookie{
    
    NSMutableArray* cookieDictionary = [[NSUserDefaults standardUserDefaults] valueForKey:@"cookieArray"];
    NSLog(@"cookie dictionary found is %@",cookieDictionary);
    
    for (int i=0; i < cookieDictionary.count; i++) {
        NSLog(@"cookie found is %@",[cookieDictionary objectAtIndex:i]);
        NSMutableDictionary* cookieDictionary1 = [[NSUserDefaults standardUserDefaults] valueForKey:[cookieDictionary objectAtIndex:i]];
        NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:cookieDictionary1];
        [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
    }
    
    NSMutableDictionary *cookieDic = [NSMutableDictionary dictionary];
    NSMutableString *cookieValue = [NSMutableString stringWithFormat:@""];
    NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    for (NSHTTPCookie *cookie in [cookieJar cookies]) {
        [cookieDic setObject:cookie.value forKey:cookie.name];
    }
    
    // cookie重復(fù),先放到字典進(jìn)行去重,再進(jìn)行拼接
    for (NSString *key in cookieDic) {
        NSString *appendString = [NSString stringWithFormat:@"%@=%@;", key, [cookieDic valueForKey:key]];
        [cookieValue appendString:appendString];
    }
    return cookieValue;
}

清除 cookie

#pragma mark - 清空cookie
-(void)deleCookie {
//    NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];
//    NSArray *_tmpArray = [NSArray arrayWithArray:[cookieJar cookies]];
//    for (id obj in _tmpArray) {
//        [cookieJar deleteCookie:obj];
//    }
    if (@available(iOS 9.0, *)) {//iOS9及以上
        WKWebsiteDataStore *dateStore = [WKWebsiteDataStore defaultDataStore];
        [dateStore fetchDataRecordsOfTypes:[WKWebsiteDataStore allWebsiteDataTypes]
                         completionHandler:^(NSArray<WKWebsiteDataRecord *> * __nonnull records) {
                             for (WKWebsiteDataRecord *record in records)
                             {
                                 //if ( [record.displayName containsString:@"baidu"]) //取消備注,可以針對某域名做專門的清除,否則是全部清除
                                 //               {
                                 [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:record.dataTypes
                                                                           forDataRecords:@[record]
                                                                        completionHandler:^{
                                                                            NSLog(@"Cookies for %@ deleted successfully",record.displayName);
                                                                        }];
                                 //               }
                             }
                         }];
    }else { //iOS9以下
        NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
        NSString *cookiesFolderPath = [libraryPath stringByAppendingString:@"/Cookies"];
        NSError *errors;
        [[NSFileManager defaultManager] removeItemAtPath:cookiesFolderPath error:&errors];
    }
}

最后

UIWebView 和 WKWebView 所遇到問題 cookie 同步,獲取,刪除,設(shè)置這些問題,目前就這么多解決辦法吧,我一開始嘗試用 WKWebView 獲取 cookie 但是最后遇到網(wǎng)頁跨域問題以及低版本兼容問題我還是換回 UIWebView 了,如果有更好的解決辦法可以在下面留言,謝謝!
參考(http://www.itdecent.cn/p/4ae4fd25a4b8

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容