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