美文网首页
WKWebview 使用中遇到的问题

WKWebview 使用中遇到的问题

作者: 编程猫猫 | 来源:发表于2018-02-05 14:26 被阅读0次

    之前项目中使用的是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

    相关文章

      网友评论

          本文标题:WKWebview 使用中遇到的问题

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