WKWebView的cookie共享問題:與native之間羹呵、多webView之間

這是兩個不同的項目的總結:
項目一骂际,只需多個webView之間共享cookie
項目二,在項目一的基礎上冈欢,增加了與native之間cookie的共享問題歉铝。
沒有耐心的同學,可以直接到文章末尾查看凑耻。
項目二中太示,共享cookie時,我最初沒有注意到cookie去重的問題香浩,導致加載時类缤,始終提示未登錄,仔細查找了問題弃衍,才發(fā)現(xiàn)是cookie重復呀非,并且最后一個cookie值為undefined導致的。

因項目一需求,需要在app中岸裙,初次加載首頁的webView時猖败,先行做webView的登錄,因為由首頁跳轉新的webView降允,打開新頁面是需要網(wǎng)頁上已經(jīng)登錄方可恩闻。
在使用了WKWebView后,這已經(jīng)是我第三次在嘗試處理這個問題了剧董,各種嘗試幢尚。
1.在loadRequest時,添加cookie信息

self.webRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlStr]];
    
    NSData *cookiesdata = [[NSUserDefaults standardUserDefaults] objectForKey:HHUserDefaultCookie];
    if([cookiesdata length]) {
        NSArray *cookies = [NSKeyedUnarchiver unarchiveObjectWithData:cookiesdata];
        NSHTTPCookie *cookie;
        for (cookie in cookies) {
            NSString *cookieStr = [NSString stringWithFormat:@"%@=%@",cookie.name,cookie.value];
            [self.webRequest addValue:cookieStr forHTTPHeaderField:@"Cookie"];
        }
        HHLog(@"請求時需要的Cookie %@",cookies);
    }
    [self.webView loadRequest:self.webRequest];

失敵崧ァ尉剩!

2.為webView的configuration設置cookie

HHWeakSelf(weakSlef);
    WKUserContentController *userCC = self.webView.configuration.userContentController;
    HHWKJSOCHandle *weakHandle = [[HHWKJSOCHandle alloc]initWithDelegate:weakSlef isActivity:NO];
    [userCC addScriptMessageHandler:weakHandle name:HHNativeCategorymoreMethod];
    [userCC addScriptMessageHandler:weakHandle name:HHNaviveCategoryMethod];
    [userCC addScriptMessageHandler:weakHandle name:HHNativeProductMethod];
    [userCC addScriptMessageHandler:weakHandle name:HHNativeActivityMethod];
    
    //        [userCC addScriptMessageHandler:weakSelf name:HHNativeShareMethod];
    
    NSData *cookiesdata = [[NSUserDefaults standardUserDefaults] objectForKey:HHUserDefaultCookie];
    NSArray *cookies = [NSKeyedUnarchiver unarchiveObjectWithData:cookiesdata];
    NSHTTPCookie *cookie;
    for (cookie in cookies) {
        NSString *cookieStr = [NSString stringWithFormat:@"document.cookie = '%@=%@';",cookie.name,cookie.value];
        WKUserScript * cookieScript = [[WKUserScript alloc] initWithSource: cookieStr injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
        [userCC addUserScript:cookieScript];
        
    }

失敗毅臊!

3.網(wǎng)頁加載完成后理茎,設置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];
    }
    
    HHLog(@"JS字符串Cookie:  %@",JSCookieString);
    //執(zhí)行js
    [webView evaluateJavaScript:JSCookieString completionHandler:^(id obj, NSError * _Nullable error) {
        NSLog(@"執(zhí)行js  %@",error);
    }];

失敗管嬉!

包括這三種方式全部設置上皂林,依然失敗。
靜下心來思考蚯撩,確定出我的問題并不是讓WKWebView和Native共享cookie础倍,而是多個WKWebView之間如何共享cookie。
問題根源確定了胎挎,下一步就簡單多了沟启,只需要讓多個WKWebView共用同一個WKProcessPool實例就可以。

那么犹菇,如何能滿足WKWebView和Native共享cookie的同時美浦,并且使得多個WKWebView共用同一個WKProcessPool實例。

很簡單项栏,只要兩者相結合就好。

基于這個思路蹬竖,我們是不是可以先行讓webView加載一個網(wǎng)址沼沈,在加載之初就先行為webView的configuration設置cookie,如此,當?shù)谝粋€網(wǎng)址加載完畢之后币厕,webView之間就可以共享cookie了呢列另。

基于這個設想,來實現(xiàn)旦装。
使用示例页衙,在WKWebViewontroller中

- (WKWebView *)webView{
    if (_webView == nil) {
        WKUserContentController *userCC = [WKUserContentController new];
        [userCC addScriptMessageHandler:self name:@"urlDirect"];
        
        WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc]init];
        //設置HTML5視頻是否允許網(wǎng)頁播放 設置為NO則會使用本地播放器
        config.allowsInlineMediaPlayback = YES;
        config.preferences.javaScriptCanOpenWindowsAutomatically = YES;
        config.userContentController = userCC;
        config.preferences.javaScriptEnabled = YES;
        //        config.suppressesIncrementalRendering = YES;
        config.processPool = [HHWKCookieSyncManager sharedCookieManager].processPool;
       
     
        _webView = [[WKWebView alloc]initWithFrame:ScreenBounds configuration:config];
        _webView.backgroundColor = [UIColor whiteColor];
        _webView.navigationDelegate = self;
        _webView.UIDelegate = self;
        _webView.scrollView.delegate = self;
        [_webView sizeToFit];
    
        if (@available(iOS 11.0, *)) {
            _webView.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
        }
        [self.view addSubview:_webView];
        [_webView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.edges.mas_equalTo(UIEdgeInsetsMake(0, 0, QSJSafeAreaBottomHeight, 0));
        }];
     
    }
    return _webView;
}

注意關鍵代碼

  config.processPool = [HHWKCookieSyncManager sharedCookieManager].processPool;

加載網(wǎng)絡請求時

- (void)refreshData{
    if (self.errView) {
        [self.errView removeFromSuperview];
    }
    //設置請求頭
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:self.url]];
    if ([AccountManager shareInstance].isLogin) {
        [request setValue:[QSJUserDefaults objectForKey:QSJUserID] forHTTPHeaderField:@"userId"];
        [request setValue:[QSJUserDefaults objectForKey:QSJUserToken] forHTTPHeaderField:@"token"];
    }
    request.timeoutInterval = 10;

    HHWKCookieSyncManager *cookieManager = [HHWKCookieSyncManager sharedCookieManager];
//這行代碼可以注釋
    [cookieManager setWebViewCookie:self.webView];
    
    if (@available(iOS 11.0, *)) {
        [self.webView loadRequest:request];
    }else{
        @axc_weakify_self;
        cookieManager.loadAction = ^{
            @axc_strongify_self;
            [self.webView loadRequest:request];
        };
        cookieManager.loadFailure = ^(NSString *errMsg) {
            @axc_strongify_self;
            [self createErrViewWithMsg:errMsg];
        };
        [cookieManager syncCookieForURL:[NSURL URLWithString:self.url] loadAction:cookieManager.loadAction];
    }
    
}

下面是主要文件代碼
HHWKCookieSyncManager.h文件

//
//  HHWKCookieSyncManager.h
//  GlobalTimes
//
//  Created by apple on 2017/4/11.
//  Copyright ? 2017年 Hannah. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface HHWKCookieSyncManager : NSObject

@property (nonatomic, strong) WKProcessPool *processPool;
@property (nonatomic, strong) WKWebView *cookieWebview;
@property (nonatomic, copy) void(^loadAction)(void);
@property (nonatomic, copy) void(^loadFailure)(NSString *errMsg);

+ (instancetype)sharedCookieManager;
+ (NSString *)getCookieStr;
- (void)setWebViewCookie:(WKWebView *)webView;
- (void)syncCookieForURL:(NSURL *)url loadAction:(void(^)(void))loadAction;
- (void)shouldLoadRequestURL:(NSURL *)url scriptCallback:(void (^)(NSString *))scriptCallback ;
+ (void)removeCookieWithURL:(NSURL *)url;
@end

HHWKCookieSyncManager.m文件

//
//  HHWKCookieSyncManager.m
//  GlobalTimes
//
//  Created by apple on 2017/4/11.
//  Copyright ? 2017年 Hannah. All rights reserved.
//

#import "HHWKCookieSyncManager.h"

@interface HHWKCookieSyncManager ()<WKNavigationDelegate,WKUIDelegate>

@property (nonatomic, strong) WKWebView *webView;
@property (nonatomic, strong) NSURL *testUrl;

@end

@implementation HHWKCookieSyncManager

static inline WKUserScript * WKCookieUserScript(NSString *cookieString) {
    if (!cookieString.length) {
        return nil;
    }
    WKUserScript *cookieScript = [[WKUserScript alloc] initWithSource:cookieString
                                                        injectionTime:WKUserScriptInjectionTimeAtDocumentStart
                                                     forMainFrameOnly:NO];
    return cookieScript;
}

+ (instancetype)sharedCookieManager{
    
    static HHWKCookieSyncManager *__manager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        __manager = [[self alloc] init];
    });
    return __manager;
}


- (WKProcessPool *)processPool{
    if (_processPool == nil) {
        static dispatch_once_t onceToken;
        static WKProcessPool *processPool;
        dispatch_once(&onceToken, ^{
            processPool = [[WKProcessPool alloc] init];
        });
        _processPool = processPool;
    }
    return _processPool;
}

- (WKWebView *)cookieWebview {
    if (!_cookieWebview) {
        WKUserContentController *userContentController = WKUserContentController.new;
        WKWebViewConfiguration* webViewConfig = WKWebViewConfiguration.new;
        webViewConfig.userContentController = userContentController;
        webViewConfig.processPool = [HHWKCookieSyncManager sharedCookieManager].processPool;
        _cookieWebview = [[WKWebView alloc] initWithFrame:CGRectZero configuration:webViewConfig];
        _cookieWebview.UIDelegate = self;
        _cookieWebview.navigationDelegate = self;
    }
    return _cookieWebview;
}


+ (NSString *)getCookieStr{
    NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    NSMutableString *cookieString = [[NSMutableString alloc] init];
    for (NSHTTPCookie *cookie in [cookieJar cookies]) {
//此處可進行cookie去重
        if ([cookie.value isEqualToString:@"undefined"] == NO && cookie.value != NULL && cookie.value.length > 0) {
            [cookieString appendFormat:@"document.cookie = '%@=%@';\n", cookie.name, cookie.value];
        }
    }
    
    //刪除最后一個“;”
    //    [cookieString deleteCharactersInRange:NSMakeRange(cookieString.length - 1, 1)];
    return [cookieString copy];
}



- (void)setWebViewCookie:(WKWebView *)webView{
    NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    
    
    for (NSHTTPCookie *cookie in cookieStorage.cookies) {
        if (@available(iOS 11.0, *)) {
            [webView.configuration.websiteDataStore.httpCookieStore setCookie:cookie completionHandler:nil];
        } else {
            // Fallback on earlier versions
            NSString *cookieString = QSJFormat(@"document.cookie = '%@=%@';\n", cookie.name, cookie.value);
            WKUserScript *script = [[WKUserScript alloc] initWithSource:cookieString injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
            [webView.configuration.userContentController addUserScript:script];
        }
    }
}

- (void)syncCookieForURL:(NSURL *)url loadAction:(void(^)(void))loadAction {
    [self shouldLoadRequestURL:url scriptCallback:^(NSString *cookieScript) {
        if (cookieScript.length) {
            [self.cookieWebview.configuration.userContentController removeAllUserScripts];
            [self.cookieWebview.configuration.userContentController addUserScript:WKCookieUserScript(cookieScript)];
            NSString *baseWebUrl = [NSString stringWithFormat:@"%@://%@", url.scheme,url.host];
            //如果需要加載cookie,則需要再cookie webview加載結束后再加載url店乐,也就是在webView:(WKWebView *)webView didFinishNavigation方法中開始加載url
            [self.cookieWebview loadHTMLString:@"" baseURL:[NSURL URLWithString:baseWebUrl]];
        } else {
            //如果沒有cookie需要加載艰躺,則直接加載url
            if (loadAction) {
                loadAction();
            }
        }
    }];
}

- (void)shouldLoadRequestURL:(NSURL *)url scriptCallback:(void (^)(NSString *))scriptCallback {
    if (!scriptCallback) {
        return;
    }
    //此處可根據(jù)url決定是否需要加載cookie等邏輯
    if (!url.host.length || [url.host isEqualToString:QSJHost] == NO) {
        scriptCallback(nil);
        return;
    }

    scriptCallback([HHWKCookieSyncManager getCookieStr]);
}

+ (void)removeCookieWithURL:(NSURL *)url{
    if (@available(iOS 9.0, *)) {
        NSSet *cookieTypeSet = [NSSet setWithObject:WKWebsiteDataTypeCookies];
        [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:cookieTypeSet modifiedSince:[NSDate dateWithTimeIntervalSince1970:0] completionHandler:^{
            
        }];
    }
}

#pragma mark - WKNavigationDelegate
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
    
    [webView evaluateJavaScript:[HHWKCookieSyncManager getCookieStr] completionHandler:^(id _Nullable response, NSError * _Nullable error) {
        
    }];
    if (self.loadAction) {
        self.loadAction();
    }
}

- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error{

    if (error.code == NSURLErrorCancelled || error.domain == NSURLErrorDomain) {
        return;
    }
    if (self.loadFailure) {
        self.loadFailure(error.localizedDescription);
    }
}




@end

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市眨八,隨后出現(xiàn)的幾起案子腺兴,更是在濱河造成了極大的恐慌,老刑警劉巖廉侧,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件页响,死亡現(xiàn)場離奇詭異,居然都是意外死亡段誊,警方通過查閱死者的電腦和手機闰蚕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來连舍,“玉大人没陡,你說我怎么就攤上這事⊙糖疲” “怎么了诗鸭?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長参滴。 經(jīng)常有香客問我强岸,道長,這世上最難降的妖魔是什么砾赔? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任蝌箍,我火速辦了婚禮,結果婚禮上暴心,老公的妹妹穿的比我還像新娘妓盲。我一直安慰自己,他們只是感情好专普,可當我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布悯衬。 她就那樣靜靜地躺著,像睡著了一般檀夹。 火紅的嫁衣襯著肌膚如雪筋粗。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天炸渡,我揣著相機與錄音娜亿,去河邊找鬼。 笑死蚌堵,一個胖子當著我的面吹牛买决,可吹牛的內(nèi)容都是我干的沛婴。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼督赤,長吁一口氣:“原來是場噩夢啊……” “哼嘁灯!你這毒婦竟也來了?” 一聲冷哼從身側響起够挂,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤旁仿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后孽糖,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體枯冈,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年办悟,在試婚紗的時候發(fā)現(xiàn)自己被綠了尘奏。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡病蛉,死狀恐怖炫加,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情铺然,我是刑警寧澤俗孝,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站魄健,受9級特大地震影響赋铝,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜沽瘦,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一岁忘、第九天 我趴在偏房一處隱蔽的房頂上張望旦委。 院中可真熱鬧涣易,春花似錦锹引、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至并村,卻和暖如春漏健,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背橘霎。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留殖属,地道東北人姐叁。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親外潜。 傳聞我的和親對象是個殘疾皇子原环,可洞房花燭夜當晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容