WKWebview 使用中遇到的问题

之前项目中使用的是UIWebview,因为需求变更需要替换成WKWebView,在使用WKWebView的过程中遇到不少问题,现记录一下,以便后续使用。

一、cookie 不同步的问题
(1)先处理URL的cookie

###处理URL的cookie
-(void)handleCookieForURLString:(NSString *)url{
    //失去登录态则删除cookie
    if (!self.isLogin) {
        return;
    }
    //有登陆则写入Cookie
     NSHTTPCookie *sessionCookie = [NSHTTPCookie cookieWithProperties:@{NSHTTPCookieValue : self.sessionId, NSHTTPCookieName : kSessionID, NSHTTPCookiePath : @"/", NSHTTPCookieDomain : host}];
        DLog(@"usermanager======%@",sessionCookie);
        [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:sessionCookie];
    }];
    DLog(@"====%@",_cookieHostArray);

(2)分别在以下两个地方调用(1)方法

a、http数据请求的时候,实例如下
#pragma mark- HTTP 数据请求
+ (void)qb_requestActionWithUrl:(NSString *)url
                         params:(NSDictionary *)params
                         method:(QBRequestMethod)method
                         isLoad:(BOOL)isLoad
                        success:(QBRequestSuccessBlock)success
                        failure:(QBRequestFailureBlock)failure
{
    [QBRequest startLoading:isLoad];
    url = [url stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
    [[UserManager sharedUser] handleCookieForURLString:url];
    switch (method) {
        case QBRequestMethodGet:
        {
            [manager GET:url
              parameters:params
                progress:nil
                 success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
                     DLog(@"MethodGet >> %@\n%@\n%@",url, params, responseObject);
                     [QBRequest requestSuccess:success](task,responseObject);
                 }
                 failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
                     DLog(@"error >> %@\n%@\n%@",url, params, error);
                     [QBRequest requestFailure:failure](task,error);
                 }];
        }
            break;
        case QBRequestMethodPost:
        {
            [manager POST:url
               parameters:params
                 progress:nil
                  success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
                      DLog(@"MethodPost >> %@\n%@\n%@",url, params, responseObject);
                      [QBRequest requestSuccess:success](task,responseObject);
                  }
                  failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
                      DLog(@"error >> %@\n%@\n%@",url, params, error);
                      [QBRequest requestFailure:failure](task,error);
                  }];
        }
            break;
}

附上图片


1.png

b、webview 加载完毕的代理方法中

-(void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
 
    //解决ajax发起请求无效的问题
    [self injectJSForWebview:webView];
}
- (void)injectJSForWebview:(WKWebView *)webview
{
    [[UserManager sharedUser] handleCookieForURLString:webview.URL.absoluteString];
    NSString *JSFuncString =
    @"function setCookie(cname,cvalue,exdays)\
    {\
    var d = new Date();\
    d.setTime(d.getTime()+(exdays*24*60*60*1000));\
    var expires = 'expires='+d.toGMTString();\
    document.cookie = cname + '=' + cvalue + '; ' + expires + ';path=/‘;\
    }”;
    
    //拼接js字符串
    NSMutableString *JSCookieString = JSFuncString.mutableCopy;
    NSString *userSessionID = [[UserManager sharedUser] sessionId];
    
    if ([userSessionID isValidString]) {
        NSString *excuteJSString = [NSString stringWithFormat:@"setCookie('SESSIONID', '%@', 12);", userSessionID];
        [JSCookieString appendString:excuteJSString];
    }
    if (JSFuncString.length && JSCookieString.length >= JSFuncString.length) {
        //执行js
        [webview evaluateJavaScript:JSCookieString completionHandler:nil];
    }
}

(3)、webview的请求头传入cookie

@implementation QBSuperWebViewController

- (void)setUrl:(NSString *)url
{
    _url = [url isValidString] ? url : kOfficialWebsite;
    
    NSDictionary *parameters = [_url containsString:@"clientType=h5"] ? @{@"fromapp": @1} : @{@"fromapp":@1, @"clientType":@"ios”};
    _url = [NSString addQueryStringToUrl:_url params:parameters];
    _url = [NSString stringWithFormat:@"%@&%@",_url,[GToolUtil getCurrentAppVersionCode]];
    _url = [_url urlClear];
    
    [self webReload];
}

/**
 网页加载
 */
- (void)webReload
{
    NSMutableURLRequest *urlRequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:_url]];
    
    if ([UserManager sharedUser].isLogin) {
        NSString *cookieStr = [self fetchLoginUserSession];
        DLog(@"=====%@",cookieStr);
        
        //请求头传入cookie
        [urlRequest setHTTPShouldHandleCookies:YES];
        //设置请求头部信息
        [urlRequest setValue:cookieStr forHTTPHeaderField:@"Cookie”];
    }
    
    [self.webView loadRequest:urlRequest];
}
- (NSString *)fetchLoginUserSession
{
    NSString *cookieStr = @“”;
    if ([UserManager sharedUser].isLogin) {
        NSString *sessionID = [UserManager sharedUser].sessionId;
        cookieStr = [NSString stringWithFormat:@"%@=%@;",kSessionID,sessionID];
    }
    return cookieStr;
}

4、在webView的代理方法中,获取cookie,并设置到本地

- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
    
    NSHTTPURLResponse *response = (NSHTTPURLResponse *)navigationResponse.response;
    // 获取cookie,并设置到本地
    NSArray *cookies =[NSHTTPCookie cookiesWithResponseHeaderFields:[response allHeaderFields] forURL:response.URL];
    for (NSHTTPCookie *cookie in cookies) {
        if ([cookie.name isEqualToString:kSessionID]) {
            if ([UserManager sharedUser].isLogin) {
                if (![cookie.value isEqualToString:[UserManager sharedUser].sessionId]) {
                    [cookie setValue:[UserManager sharedUser].sessionId forKey:cookie.name];
                }
                DLog(@"^^^^^^^^^^^^^^^^^”);
                [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
            }
        }
    }
    decisionHandler(WKNavigationResponsePolicyAllow);
}

好了,完成以上4步就可以保证cookie同步了(棒棒哒,有木有)

二、userAgent异步返回问题

以下介绍两种方法

###1、由于项目中需要传递userAgent给后台,后台根据传递的userAgent下发不同的数据。
一开始在代码中,是这样写的,WKWebView获取userAgent是异步的
 WKWebView *webview = [[WKWebView alloc] initWithFrame:CGRectZero];
                [webview evaluateJavaScript:@"navigator.userAgent" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
                    NSString *userAgent = result;
                    //存值用来供AFNetworking设置UA使用《详见AFURLRequestSerialization.m文件》
                    [[NSUserDefaults standardUserDefaults] setObject:result forKey:@"uaResult”];
                    NSString *ua = [NSString stringWithFormat:@"%@ %@ %@  IOS xqb/%@",userAgent,dic[@"bundleId"],dic[@"companyName"],dic[@"appVersion”]];
                    if ( @available(iOS 9.0, *) ){
                        [webview setCustomUserAgent:ua];
                    }
                    DLog(@"load====%@",ua);
                    [[NSUserDefaults standardUserDefaults] registerDefaults:@{@"UserAgent" : ua, @"User-Agent" : ua}];
                }];
###但是由于之前的版本是用UIWebview获取userAgent的是同步的,代码如下
 UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectZero];
                NSString* userAgent = [webView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent”];
                NSString *ua = [NSString stringWithFormat:@"%@ %@ %@  IOS xqb/%@",userAgent,dic[@"bundleId"],dic[@"companyName"],dic[@"appVersion”]];
                [[NSUserDefaults standardUserDefaults] registerDefaults:@{@"UserAgent" : ua, @"User-Agent" : ua}];

由于项目中需要根据userAgent去下发不同的内容,用WKWebView去获取userAgent时,异步结果还没有返回呢,就进行后续的一些接口请求工作,所以就出现了错误,解决办法如下
//------修改webview user agent
UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectZero];
                NSString* userAgent = [webView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent”];
                NSString *ua = [NSString stringWithFormat:@"%@ %@ %@  IOS xqb/%@",userAgent,dic[@"bundleId"],dic[@"companyName"],dic[@"appVersion”]];
                [[NSUserDefaults standardUserDefaults] registerDefaults:@{@"UserAgent" : ua, @"User-Agent" : ua}];
                webView  = nil;

                WKWebView *webview = [[WKWebView alloc] initWithFrame:CGRectZero];
                [webview evaluateJavaScript:@"navigator.userAgent" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
                    NSString *userAgent = result;
                    //存值用来供AFNetworking设置UA使用《详见AFURLRequestSerialization.m文件》
                    [[NSUserDefaults standardUserDefaults] setObject:result forKey:@"uaResult”];
                    NSString *ua = [NSString stringWithFormat:@"%@ %@ %@  IOS xqb/%@",userAgent,dic[@"bundleId"],dic[@"companyName"],dic[@"appVersion”]];
                    if ( @available(iOS 9.0, *) ){
                        [webview setCustomUserAgent:ua];
                    }
                    DLog(@"load====%@",ua);
                    [[NSUserDefaults standardUserDefaults] registerDefaults:@{@"UserAgent" : ua, @"User-Agent" : ua}];
                }];

##2、这下面的方法更简单
- (void)setUpUserAgent
{
    //------修改webview user agent
    NSDictionary *dic = [GToolUtil getAppConfig];
    NSString* userAgent = [[[UIWebView alloc] initWithFrame:CGRectZero] stringByEvaluatingJavaScriptFromString:@"navigator.userAgent”];
    NSLog(@"====%@",userAgent);
    NSString *ua = [NSString stringWithFormat:@"%@ %@ %@  IOS xqb/%@",userAgent,dic[@"bundleId"],dic[@"companyName"],dic[@"appVersion”]];
    //存值用来供AFNetworking设置UA使用《详见AFURLRequestSerialization.m文件》
    [[NSUserDefaults standardUserDefaults] setObject:ua forKey:@"uaResult”];
}

##在AFURLRequestSerialization.m中
- (instancetype)init {
    self = [super init];
    if (!self) {
        return nil;
    }

    self.stringEncoding = NSUTF8StringEncoding;

    self.mutableHTTPRequestHeaders = [NSMutableDictionary dictionary];
    self.requestHeaderModificationQueue = dispatch_queue_create("requestHeaderModificationQueue", DISPATCH_QUEUE_CONCURRENT);

    // Accept-Language HTTP Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
    NSMutableArray *acceptLanguagesComponents = [NSMutableArray array];
    [[NSLocale preferredLanguages] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        float q = 1.0f - (idx * 0.1f);
        [acceptLanguagesComponents addObject:[NSString stringWithFormat:@"%@;q=%0.1g", obj, q]];
        *stop = q <= 0.5f;
    }];
    [self setValue:[acceptLanguagesComponents componentsJoinedByString:@", "] forHTTPHeaderField:@"Accept-Language”];

    NSString *userAgent = nil;
#if TARGET_OS_IOS
    // User-Agent Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.43
    userAgent = [[NSUserDefaults standardUserDefaults] objectForKey:@"uaResult”];
    [[NSUserDefaults standardUserDefaults] registerDefaults:@{@"UserAgent" : userAgent ? userAgent:@"", @"User-Agent" : userAgent ? userAgent:@"”}];
    
#elif TARGET_OS_WATCH
    // User-Agent Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.43
    userAgent = [NSString stringWithFormat:@"%@/%@ (%@; watchOS %@; Scale/%0.2f)", [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleExecutableKey] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleIdentifierKey], [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleVersionKey], [[WKInterfaceDevice currentDevice] model], [[WKInterfaceDevice currentDevice] systemVersion], [[WKInterfaceDevice currentDevice] screenScale]];
#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
    userAgent = [NSString stringWithFormat:@"%@/%@ (Mac OS X %@)", [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleExecutableKey] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleIdentifierKey], [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleVersionKey], [[NSProcessInfo processInfo] operatingSystemVersionString]];
#endif
    if (userAgent) {
        if (![userAgent canBeConvertedToEncoding:NSASCIIStringEncoding]) {
            NSMutableString *mutableUserAgent = [userAgent mutableCopy];
            if (CFStringTransform((__bridge CFMutableStringRef)(mutableUserAgent), NULL, (__bridge CFStringRef)@"Any-Latin; Latin-ASCII; [:^ASCII:] Remove", false)) {
                userAgent = mutableUserAgent;
            }
        }
        [self setValue:userAgent forHTTPHeaderField:@"User-Agent”];
    }

    // HTTP Method Definitions; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
    self.HTTPMethodsEncodingParametersInURI = [NSSet setWithObjects:@"GET", @"HEAD", @"DELETE", nil];

    self.mutableObservedChangedKeyPaths = [NSMutableSet set];
    for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
        if ([self respondsToSelector:NSSelectorFromString(keyPath)]) {
            [self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:AFHTTPRequestSerializerObserverContext];
        }
    }

    return self;
}

修改的代码如下图红色框选的


1111.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,470评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,393评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,577评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,176评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,189评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,155评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,041评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,903评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,319评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,539评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,703评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,417评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,013评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,664评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,818评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,711评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,601评论 2 353

推荐阅读更多精彩内容