WKWebView Persistent Storage of Cookies

后端 未结 8 1197
时光说笑
时光说笑 2020-11-29 22:22

I am using a WKWebView in my native iPhone application, on a website that allows login/registration, and stores the session information in cookies. I am tryin

8条回答
  •  天涯浪人
    2020-11-29 22:49

    After days of research and experiments, I have found a solution to manage sessions in WKWebView, This is a work around because I didn’t find any other way to achieve this, below are the steps:

    First you need to create methods to set and get data in user defaults, when I say data it means NSData, here are the methods.

    +(void)saveDataInNSDefault:(id)object key:(NSString *)key{
        NSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:object];
        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
        [defaults setObject:encodedObject forKey:key];
        [defaults synchronize];
    }
    
    + (id)getDataFromNSDefaultWithKey:(NSString *)key{
        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
        NSData *encodedObject = [defaults objectForKey:key];
        id object = [NSKeyedUnarchiver unarchiveObjectWithData:encodedObject];
        return object;
    }
    

    For maintaining session on webview I made my webview and WKProcessPool singleton.

    - (WKWebView *)sharedWebView {
        static WKWebView *singleton;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            WKWebViewConfiguration *webViewConfig = [[WKWebViewConfiguration alloc] init];
            WKUserContentController *controller = [[WKUserContentController alloc] init];
    
            [controller addScriptMessageHandler:self name:@"callNativeAction"];
            [controller addScriptMessageHandler:self name:@"callNativeActionWithArgs"];
            webViewConfig.userContentController = controller;
            webViewConfig.processPool = [self sharedWebViewPool];
    
            singleton = [[WKWebView alloc] initWithFrame:self.vwContentView.frame configuration:webViewConfig];
    
        });
        return singleton;
    }
    
    - (WKProcessPool *)sharedWebViewPool {
        static WKProcessPool *pool;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
    
            pool = [Helper getDataFromNSDefaultWithKey:@"pool"];
    
            if (!pool) {
                pool = [[WKProcessPool alloc] init];
            }
    
        });
        return pool;
    }
    

    In ViewDidLoad, I check if it’s not the login page and load cookies into HttpCookieStore from User Defaults so It will by pass authentication or use those cookies to maintain session.

    if (!isLoginPage) {
                [request setValue:accessToken forHTTPHeaderField:@"Authorization"];
    
                NSMutableSet *setOfCookies = [Helper getDataFromNSDefaultWithKey:@"cookies"];
                for (NSHTTPCookie *cookie in setOfCookies) {
                    if (@available(iOS 11.0, *)) {
    
                        [webView.configuration.websiteDataStore.httpCookieStore setCookie:cookie completionHandler:^{}];
                    } else {
                        // Fallback on earlier versions
                        [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
                    }
                }
            }
    

    And, Load the request.

    Now, we will maintain webview sessions using cookies, so on your login page webview, save cookies from httpCookieStore into user defaults in viewDidDisappear method.

    - (void)viewDidDisappear:(BOOL)animated {
    
        if (isLoginPage) { //checking if it’s login page.
            NSMutableSet *setOfCookies = [Helper getDataFromNSDefaultWithKey:@"cookies"]?[Helper getDataFromNSDefaultWithKey:@"cookies"]:[NSMutableArray array];
            //Delete cookies if >50
            if (setOfCookies.count>50) {
                [setOfCookies removeAllObjects];
            }
            if (@available(iOS 11.0, *)) {
                [webView.configuration.websiteDataStore.httpCookieStore getAllCookies:^(NSArray * _Nonnull arrCookies) {
    
                    for (NSHTTPCookie *cookie in arrCookies) {
                        NSLog(@"Cookie: \n%@ \n\n", cookie);
                        [setOfCookies addObject:cookie];
                    }
                    [Helper saveDataInNSDefault:setOfCookies key:@"cookies"];
                }];
            } else {
                // Fallback on earlier versions
                NSArray *cookieStore = NSHTTPCookieStorage.sharedHTTPCookieStorage.cookies;
                for (NSHTTPCookie *cookie in cookieStore) {
                    NSLog(@"Cookie: \n%@ \n\n", cookie);
                    [setOfCookies addObject:cookie];
                }
                [Helper saveDataInNSDefault:setOfCookies key:@"cookies"];
            }
        }
    
        [Helper saveDataInNSDefault:[self sharedWebViewPool] key:@"pool"];
    }
    

    Note: Above method is tested for iOS 11 only, although I have written fallback for lower versions also but didn’t test those.

    Hope this solves your problems !!! :)

提交回复
热议问题