美文网首页iOS开发你需要知道的
iOS - WKWebView Cookie 设置

iOS - WKWebView Cookie 设置

作者: GarrettGao | 来源:发表于2019-02-26 01:35 被阅读3次

    从UIWebview换到WKWebView之后,会发现管理Cookie是很麻烦事,经常出现 App自定义Cookie的值丢失 或 更新不及时 的情况。苹果iOS11之后也提供了WKWebView的Cookie API WKHTTPCookieStore,但是目前大多数App最低版本不可能设置最低版本到iOS11,所以我们只能想别的办法。

    什么是Cookie?

    Cookie是一种早期的客户端存储机制,起初是针对服务端脚本设计使用的。以Cookie存储的数据,不论服务端是否需要,每次HTTP请求都会把这些数据传送到服务端。

    Cookie是指Web浏览器存储的少量数据,同时它是与具体的Web页面或者站点相关。Cookie最早是设置为被服务端所用的,从最底层来看,作为http协议的一种拓展实现它。

    Cookie数据会自动在Web浏览器和Web服务器之间传输,因此服务端脚本就可以读写存储在客户端的cookie值。

    Cookie的属性

    除了 name 与 value,Cookie其他属性:

    domain:作用域名

    举例:
    设置domain为 bj.jiehun.com.cn,则在app.jiehun.com.cn 等子域名不会生效;
    如设置domain为 .jiehun.com.cn,则在jiehun.com.cn 的所有子域名生效。
    注意:IP地址特殊,直接设置原地址即可。

    path:作用路径

    举例:
    如在 www.jiehun.com.cn,设置 path=/m,则只在 www.jiehun.com.cn/m 或 /m子目录下生效,如 www.jiehun.com.cn/app 就不会生效;
    不设置默认为当前URL默认路径;我们通常会设置 “/” 代表所有目录。

    expires:过期时间,格林威治时间 (GMT)字符串格式,设置过期时间后将会存储在一个文件直到过期。

    // 打印当前时间
    var date = new Date();
    date.setTime(date.getTime());
    console.log(date.toGMTString());
    // 打印结果为:Mon, 25 Feb 2019 15:35:03 GMT
    
    // 设置cookie时间
    document.cookie='name=value;expires=' + date.toGMTString();
    

    max-age:有效时长,单位秒。

    // 设置 cookie 有效期 10秒
    document.cookie='name=value;max-age=10;
    

    Cookie默认的有效期很短暂,只能维持在Web浏览器的回话期间,一旦用户关闭浏览器,Cookie保存的数据就全部丢失。
    如果想要延长Cookie的有效期,可以通过设置max-age或expires属性。一旦设置有效期,浏览器就会将Cookie数据存储在一个文件中,并且直到过了指定的有效期才会删除该文件。

    secure: Bool值,是否为安全传输,如设置true,在Https或其他网络安全协议才会传输。

    演示

    我们可以随便找一个浏览器,如Safari,打开后快捷键 command + alt + c 打开调试窗口:


    image.png

    读取Cookie

    document.cookie
    

    保存Cookie

    document.cookie='testName=testValue;path=/;max-age=60*60';
    

    因为Cookie的名和值中不允许包含分号、逗号和空格,因此,在存储前可以采用全局函数 encodeURIComponent()对值进行编码。相应的,读取cookie值的时候采用decodeURIComponent() 函数解码。

    删除Cookie

    相同的名字随意设置一个值,并将max-age指定为0,相当于删除Cookie。

    document.cookie='testName=;domain=.jiehun.com.cn;path=/;max-age=0';
    

    Cookie的局限性

    个数限制300(现在已经可以超越),每个Cookie数据即名字和值的总量不能超过4KB。

    WKWebView 管理Cookie

    上面了解了Cookie的基本知识,我们如何应用到iOS开发中?这里主要介绍WKWebview的使用方法。

    因为JavaScript只能设置浏览器本地的cookie,往往客户端第一次请求由开发者创建Request对象请求:

    [webview loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"url"]]];
    
    

    所以第一次请求需要手动设置请求头中的Cookie,可以继承WKWebView重写 loadRequest 方法,或者直接通过runtime Swizzling loadRequest 方法:

    /**重写 loadRequest 方法,在请求头中添加自定义到cookie*/
    - (nullable WKNavigation *)loadRequest:(NSURLRequest *)request{
        
        NSMutableURLRequest *newRequeset = [request mutableCopy];
        
        // 自定义cookie值
        NSDictionary *customCookieDic =@{
                                         @"testName1":@"value1",
                                         @"testName2":@"value2"
                                         };
        
        // 拼接cookie字符
        NSString *cookie = @"";
        for (NSString *key in customCookieDic.allKeys) {
            NSString *keyValue = [NSString stringWithFormat:@"%@=%@;",key,[customCookieDic objectForKey:key]];
            cookie = [cookie stringByAppendingString:keyValue];
        }
        
        // 设置到请求头
        [newRequeset setValue:cookie forHTTPHeaderField:@"Cookie"];
        
        return [super loadRequest:newRequeset];
    }
    

    此时请求发出,服务端可以收到我们请求头中的cookie值,且请求头的cookie会自动保存到浏览器。

    但我们发现请求头中自动保存到浏览器的cookie并不可靠,因为没有设置域名和目录的作用区,往往浏览器内二次跳转就会丢失,我们如何来保证浏览器的Cookie永不丢失?

    WKUserScript

    Webkit支持通过 WKUserScript 向网页中注入js脚本:

    // 设置代码块
    // @Source 脚本代码
    // @injectionTime 执行时机,网页渲染前或渲染后
    // @MainFrameOnly Bool值,YES只注入主帧,NO所有帧
    WKUserScript *cookieInScript = [[WKUserScript alloc] initWithSource:@"js脚本代码"
                                                                  injectionTime:WKUserScriptInjectionTimeAtDocumentStart
                                                               forMainFrameOnly:NO];
    // 插入脚本
    [webview.configuration.userContentController addUserScript:cookieInScript];
    

    所以,保证Cookie不丢失可以通过此方法注入设置cookie js代码,在页面每次渲染都会设置,从而保证不会丢失。

    每个cookie值可以设置为一个代码块,为了表示每个代码块的唯一,我们可以在注入脚本的最后添加 注释标示;其实就是一句注释掉的代码,来确定cookie代码块的唯一性,为以后删除某个代码块做铺垫。
    举例设置某个cookie值的 js代码:

    document.cookie ='cityId=10010;domain=.jiehun.com.cn;path=/';
    // The cookie code  identified is cityId (代码块标示)
    

    为了避免Cookie重复问题,可以直接把cookie设置在根域名。

    删除代码块

    每次调用 addUserScript方法插入脚本块,代码块会保存在WKUserContentController类的 userScripts数组属性中:

    @interface WKUserContentController : NSObject <NSSecureCoding>
    
    /*! @abstract The user scripts associated with this user content
     controller.
    */
    @property (nonatomic, readonly, copy) NSArray<WKUserScript *> *userScripts;
    

    因为 userScripts 为只读权限,我们并不能修改,所以修改某个某一个cookie代码块的时候,需要先全部清除,再把不需要删除的代码块重新添加进去,这里就需要用到前面所说的代码块注释的唯一标示:

    /**
     删除某个代码片段
     @param tag 片段标示,//The cookie code  identified is cookieName
     */
    - (void)deleteUserSciptWithTag:(NSString *)tag {
        
        if (tag) {
            WKUserContentController *userContentController = webView.configuration.userContentController;
            NSMutableArray<WKUserScript *> *array = [userContentController.userScripts mutableCopy];
            int i = 0;
            BOOL isHave = NO;
            for (WKUserScript* wkUScript in userContentController.userScripts) {
                // 通过注释标示判断代码块是否为某个cookie
                if ([wkUScript.source containsString:tag]) {
                    [array removeObjectAtIndex:i];
                    isHave = YES;
                    continue;
                }
                i ++;
            }
            
            if (isHave) {
                ///没法修改数组 只能移除全部 再将不需要删除的cookie重新添加
                [userContentController removeAllUserScripts];
                for (WKUserScript* wkUScript in array) {
                    [userContentController addUserScript:wkUScript];
                }
            }
        }
    }
    

    通过这个Webkit可注入脚本的逻辑,我们基本可以保证使用cookie在WKWebview准确性和不丢失。

    下面也写了一个Demo来演示如何通过一个代理方法来管理WKWebView所有Cookie:
    github地址:https://github.com/GaoGuohao/GGWkCookie

    相关文章

      网友评论

        本文标题:iOS - WKWebView Cookie 设置

        本文链接:https://www.haomeiwen.com/subject/iwqoyqtx.html