浅谈WKWebView
2019-01-08 本文已影响0人
JiangDaDaaa
由于项目经常性会使用到WKWebView,于是在这里记录下一下关于苹果WKWebView的要点与遇到的问题
基本配置
使用WKWebView之前需要先导入 #import <WebKit/WebKit.h>
//配置WKWebViewConfiguration
注意加上WKScriptMessageHandler
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
//WKUserContentController 主要用于与JS交互
config.userContentController = [[WKUserContentController alloc] init];
[config.userContentController addScriptMessageHandler:self name:@"xxx"];
// 创建WKPreferences
WKPreferences *preference = [[WKPreferences alloc]init];
//最小字体大小 当将javaScriptEnabled属性设置为NO时,可以看到明显的效果
preference.minimumFontSize = 0;
//设置是否支持javaScript 默认是支持的
preference.javaScriptEnabled = YES;
// 在iOS上默认为NO,表示是否允许不经过用户交互由javaScript自动打开窗口
preference.javaScriptCanOpenWindowsAutomatically = YES;
config.preferences = preference;
//创建WKWebView
注意写上WKUIDelegate,WKNavigationDelegate
_webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height) configuration:config];
//不显示滚动条
_webView.scrollView.showsVerticalScrollIndicator = NO;
_webView.scrollView.showsHorizontalScrollIndicator = NO;
//设置代理
_webView.navigationDelegate = self;
_webView.UIDelegate = self;
核心代理方法
webview最主要是使用下面的方法与js进行交互
JS端
<script>
let body = {
method1 = "hello world"
}
window.webkit.messageHandlers.xxx.postMessage(body)
</script>
//其中xxx为JS与iOS双方规定的相同字符串,body为传入iOS端的参数
iOS端
-(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
if ([message.name isEqualToString:@"xxx"]) {
if [(message.body["method1"] isEqualToString:@"hello world"]) {
//进行逻辑处理
}
}
}
关于webView传参给JS
WKWebView传参给JS主要靠evaluateJavaScript方法,由于接触JS比较少,传参也着实费了一番功夫才弄明白
1.传入String类型
这个类型是最简单的
[webView evaluateJavaScript:[NSString stringWithFormat:@"JSCallBack('%@')",str] completionHandler:^(id _Nullable object, NSError * _Nullable error) { }
];
2.传入Array类型
[webView evaluateJavaScript:[NSString stringWithFormat:@"JSCallBack(%@)",array] completionHandler:^(id _Nullable object, NSError * _Nullable error) { }
];
3.传入Dictionary类型
字典类型的需要转换为json字符串再传,并且去掉空格跟换行符
NSData *data1 = [NSJSONSerialization dataWithJSONObject:dic
options:NSJSONWritingPrettyPrinted error:nil];
NSString *jsonStr = [[NSString alloc] initWithData:data1
encoding:NSUTF8StringEncoding];
jsonStr = [jsonStr stringByReplacingOccurrencesOfString:@" " withString:@""];
jsonStr = [jsonStr stringByReplacingOccurrencesOfString:@"\n" withString:@""];
[webView evaluateJavaScript:[NSString stringWithFormat:@"JSCallBack('%@')",jsonStr] completionHandler:^(id _Nullable object, NSError * _Nullable error) {
}];
关于使用Masonry时webview显示不完全的问题
有时候webview加载出来的页面会跟预期的有偏差,比如位置变了,大小变了,这些时候只能在loadRequest之前使用Masonry,将webview约束好
[_webView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.mas_equalTo(UIEdgeInsetsZero);
}];
[_webView loadRequest:request];
关于userAgent
有时候应服务端要求,需要给webView自定义userAgent,这里涉及到了html端与后端的获取,正常获取逻辑是这样的
[_webView evaluateJavaScript:"navigator.userAgent" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
NSString *cusUserAgent = [NSString stringWithFormat:@"%@ %@",result,@"customMethod"];
_webView.customUserAgent = cusUserAgent;
}];
这样子看起来似乎没什么问题,后端可以获取的到,但是html端并不可以获取到已经修改后的userAgent,具体原因小生也找不出来。。。
解决办法
我解决的办法是,创建两个webView,利用其中一个获取userAgent,另外一个在第一个获取到的时候,使用第一个的UserAgent,利用第二个webview进行之后的逻辑操作
//注意,这两个webview都已经初始化,网上有一些说初始化之前调用,是不可以的。
[_webView1 evaluateJavaScript:@"navigator.userAgent" completionHandler:
^(id _Nullable result, NSError * _Nullable error) {
NSString *cusAgent = [result stringByAppendingString:@"customMethod"];
_webView2.customUserAgent = cusAgent;
}];
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:
customAgent, @"UserAgent", nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:dictionary];
[[NSUserDefaults standardUserDefaults] synchronize];
其他
这里记录一下一些可能会用到的方法
删除缓存
- (void)deleteWebCache {
//allWebsiteDataTypes清除所有缓存
NSSet *websiteDataTypes = [WKWebsiteDataStore allWebsiteDataTypes];
NSDate *dateFrom = [NSDate dateWithTimeIntervalSince1970:0];
[[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:websiteDataTypes modifiedSince:dateFrom completionHandler:^{
}];
}