WKWebView问题小结
来源:互联网 发布:三金冠淘宝店值多少钱 编辑:程序博客网 时间:2024/06/05 09:13
内存泄漏
当需要拦截Web页面的Javascript函数时会使用以下方法
- (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name;
在Web页面需要调用以下方法
window.webkit.messageHandlers.name.postMessage();
这两个方法的name
必须一样才能被WKWebView
拦截到。
但是如果不及时移除Handler
的话WebView
不会被释放。所以只要调用了addScriptMessageHandler
方法就要调用相对应的方法移除
- (void)removeScriptMessageHandlerForName:(NSString *)name;
内嵌在Cell里显示不全
在iOS10及以上系统里在TableViewCell中嵌入WKWebView时,滚动TableView时WebView渲染会出错。往往内容显示不出来。
具体解决办法在TableView的代理方法中调用WKWebView的setNeedsLayout方法:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{ [webView setNeedsLayout];}
WKWebView不能打开新窗口<a target=_blank />
如果Web页面的链接是<a target=_blank />
时,正常结果是新建窗口打开这个页面。但在WKWebView
中,如果没有实现相关的代理方法,那么这个方法失效,点击网页中任何外部链接都没有反应。期望的结果是通过Safari
来打开这个外部链接。原来的WebView
不进行任何处理。如果这样需要在WebView
的代理方法中进行如下处理:
- (void)webView:(WKWebView*)webView decidePolicyForNavigationAction:(WKNavigationAction*)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{ if (!navigationAction.targetFrame) { //处理<a target=_blank />这种情况 NSURL *url = navigationAction.request.URL; UIApplication *app = [UIApplication sharedApplication]; if ([app canOpenURL:url]) { [app openURL:url]; } }}
在WKWebView中动态更改UserAgent
往往在访问我们自己的域名时会修改相关UserAgent
上传。而访问其他域名时会将UserAgent修改成默认的。这样就需要选择性的修改UserAgent
首先在程序加载时我们先获取系统默认的UserAgent
并将它保存在本地:
+(void)load{ UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectZero]; NSString *oldAgent = [webView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"]; NSDictionary *dictionnary = [[NSDictionary alloc] initWithObjectsAndKeys:oldAgent, @"originAgent", nil]; [[NSUserDefaults standardUserDefaults] registerDefaults:dictionnary]; }
然后在加载新页面时来判断是否为我们自己的域名,调用如下方法针对性的修改UserAgent
:
- (void)setUserAgent:(NSString *)userAgent{ if ([URL.host hasSuffix:baseDomain] { //如果是我们自己的域名将传进来的userAgent设置到http的请求header中 NSDictionary *dictionnary = [[NSDictionary alloc] initWithObjectsAndKeys:userAgent, @"UserAgent", nil]; [[NSUserDefaults standardUserDefaults] registerDefaults:dictionnary]; } else{ //否则设置成系统默认的UserAgent NSString *string = [[NSUserDefaults standardUserDefaults] objectForKey:@"originAgent"]; NSDictionary *dictionnary = [[NSDictionary alloc] initWithObjectsAndKeys:OutNull(string), @"UserAgent", nil]; [[NSUserDefaults standardUserDefaults] registerDefaults:dictionnary]; }}
本地Request的Cookies与WKWebView的Cookies共享
往往我们想将本地URL请求的Cookies同步到WKWebView中,在使用UIWebView时会自动同步我们请求URL的Cookies,但在WKWebView中会失效,因为WKWebView自己独立管理Cookies,不与NSURLRequest的公用。因此要通过一下方法进行设置WKWebview的Cookies。
首先在初始化是执行一下脚本来设置Cookies
-(void)initWebView{ WKWebViewConfiguration *webViewconfiguration = [[WKWebViewConfiguration alloc] init]; WKUserContentController *wkUController = [[WKUserContentController alloc] init]; if(URL.host hasSuffix:baseDomain){ //在此处要判断域名是否是自己网站。 NSString *jScript = [self setCookies]; WKUserScript *wkUScript = [[WKUserScript alloc] initWithSource:jScript injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO]; [wkUController addUserScript:wkUScript]; } webViewconfiguration.userContentController = wkUController; WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, width, height) configuration:webViewconfiguration];}//执行的脚本,可能略有不同+(NSString *)setCookies{ NSString *script = [NSString string]; for (NSHTTPCookie *httpCookie in [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]) { NSString *cookie = [NSString stringWithFormat:@"%@=%@;domain=%@;path=%@",httpCookie.name,httpCookie.value,httpCookie.domain,httpCookie.path?:@"/"]; script = [script stringByAppendingString:[NSString stringWithFormat:@"document.cookie='%@';",cookie]]; } return script;}
然后在创建NSURLRequest
对象时手动添加cookies
到HTTP的Header中:
- (void)loadRequest:(NSURLRequest *)request{ //此处也要判断要加载的url是否是我们自己的域名 if ([request.URL.host hasSuffix:baseDomain]){ NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:request.URL]; NSString *cookies = @""; //设置Cookies [mutableRequest addValue:cookies forHTTPHeaderField:@"Cookie"]; } // do request }
WKWebView在iOS10及以上系统设置新的Cookies不能覆盖旧的Cookies
在使用WKWebView时发现在iOS10以下的系统中如果按照上面的方法设置完Cookies
后会生效,并且会自动覆盖旧的Cookies
。而在iOS10及以上系统时设置新的Cookies
并不会生效,WKWebView还会使用之前的设置过的Cookies
。所以我们在切换用户时需要调用以下方法手动删除Cookies
。
-(void)clearCookies{ WKWebsiteDataStore *dateStore = [WKWebsiteDataStore defaultDataStore]; [dateStore fetchDataRecordsOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] completionHandler:^(NSArray<WKWebsiteDataRecord *> * __nonnull records) { for (WKWebsiteDataRecord *record in records){ if ([record.displayName isEqualToString:baseDomain]){ //判断如果是我们自己的域名那么删除该域名下的Cookies [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:record.dataTypes forDataRecords:@[record] completionHandler:^{ }]; } } }];}
WKWebView在在iOS10及以上系统清除Cookies失效
使用上面的方法清除Cookies
时会发现有时会清除失败。加载新的页面时还会使用旧的Cookies
。这是因为清除Cookies
的时机不对,我们应该在清除完成的回调内再加载新的页面。
- (void)loadRequest:(NSURLRequest *)request{ WKWebsiteDataStore *dateStore = [WKWebsiteDataStore defaultDataStore]; [dateStore fetchDataRecordsOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] completionHandler:^(NSArray<WKWebsiteDataRecord *> * __nonnull records) { BOOL isExit = NO; for (WKWebsiteDataRecord *record in records){ if ([record.displayName isEqualToString:baseDomain]){ //判断如果是我们自己的域名那么删除该域名下的Cookies isExit = YES; [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:record.dataTypes forDataRecords:@[record] completionHandler:^{ [webView loadRequest:request]; }]; break; } } if (!isExit) { [webView loadRequest:[mutableRequest copy]]; } }];}
注意:如果在退出页面时清除Cookies,也会出现清除失败的情况。
Native页面内嵌WKWebView高度计算问题
计算WKWebView的高度是我们往往调用document.body.scrollHeight
这个方法来计算。如果在下面的代理方法里调用那么计算的高度是不准确的:
- (void)webView:(WKWebView*)webView decidePolicyForNavigationAction:(WKNavigationAction*)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{}
因为页面内部有很多图片还没有加载出来。所以此时调用document.body.scrollHeight
这个方法计算的高度是未加载完的页面高度。
如果在加载结束的代理方法里面调用document.body.scrollHeight
,那么页面只能在全部资源下载后才会显示。如果我们想要边加载资源边动态的改变页面高度需要做如下处理:
我们在初始化WebView时监听WebView的加载进度
-(void)initWebView{ WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, width, height)]; [webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:NULL];}
然后边加载边计算WebView的高度,这样就不必等页面全部加载完再计算WebView的高度了。
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{ if ([keyPath isEqualToString:@"estimatedProgress"]) { self.estimatedProgress = [change[NSKeyValueChangeNewKey] doubleValue]; if ([change[NSKeyValueChangeOldKey] doubleValue]) { [self evaluateJavaScript:@"document.body.scrollHeight" completionHandler:^(id heitht, NSError *error) { if (!error) { self.pageHeight = [heitht floatValue]; } }]; } }}
- WKWebView问题小结
- WKWebView 白屏问题
- WKWebView 白屏问题
- WKWebView 内容显示不全问题
- WKWebView
- WKWebView
- WKWebView
- WKWebView
- WKWebView
- WKWebView
- WKWebView
- WKWebView
- WKWebView
- WKWebView
- WKWebView学习过程中碰到的问题
- WKWebView使用遇到的问题与解决办法
- iOS WKWebview的dealloc方法崩溃问题
- WKWebView 和 UIWebView 的适配问题
- JDBC
- 复习java5
- php面试题之四——PHP面向对象(基础部分)
- linux工作中软件运行安装常见问题
- 简单的HTML标签学习
- WKWebView问题小结
- rqnoj 116
- hdu6129(二)
- Blat_类BLAST 比对工具 & GNU Parallel
- Deer的英语学习之路--渐入佳境-2017.08.31
- HTML5的主体结构元素
- SpringMvc的手写版(PS:只是闲来无事写的简化版,仅供大家理解SpringMvc的运作原理)
- Linux虚拟机的Mysql启动失败 ERROR! Multiple MySQL running but PID file could not be found (
- jquery.extend() 方法详解