最近应公司要求,把项目里用到的UIWebView全都用WKWebView替换掉。于是就去研究了WKWebview,加上在使用中遇到的一些问题加以总结,如有不足之处,还望指出,本人将会加以修改。
UIWebView
自iOS2就有,WKWebView
从iOS8才有,毫无疑问WKWebView
将逐步取代笨重的UIWebView
。通过简单的测试即可发现UIWebView
占用过多内存,且内存峰值更是夸张。WKWebView
网页加载速度也有提升,但是并不像内存那样提升那么多。下面列举一些其它的优势:
estimatedProgress
缺点: WKWebView 不支持缓存 和 NSURLProtocol 拦截了
UIWebView
使用非常简单,可以分为三步,也是最简单的用法,显示网页
// 1.创建webview,并设置大小,"20"为状态栏高度
UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectMake(0,20, self.view.frame.size.width,self.view.frame.size.height -20)];
// 2.创建请求
NSMutableURLRequest *request =[NSMutableURLRequestrequestWithURL:[NSURLURLWithString:@"http://www.cnblogs.com/mddblog/"]];
// 3.加载网页
[webView loadRequest:request];
// 最后将webView添加到界面
[self.view addSubview:webView];
- (void)loadRequest:(NSURLRequest *)request;
- (void)loadHTMLString:(NSString *)string baseURL:(nullable NSURL *)baseURL;
- (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)textEncodingName baseURL:(NSURL *)baseURL;
UIWebView
不仅可以加载HTML页面,还支持pdf、word、txt、各种图片等等的显示。下面以加载mac桌面上的png图片:/Users/coohua/Desktop/bigIcon.png
为例// 1.获取url
NSURL *url = [NSURLfileURLWithPath:@"/Users/coohua/Desktop/bigIcon.png"];
// 2.创建请求
NSURLRequest *request=[NSURLRequestrequestWithURL:url];
// 3.加载请求
[self.webView loadRequest:request];
// 刷新
- (void)reload;
//停止加载
- (void)stopLoading;
//后退函数
- (void)goBack;
//前进函数
- (void)goForward;
//是否可以后退
@property (nonatomic,readonly, getter=canGoBack)BOOL canGoBack;
//是否可以向前
@property (nonatomic,readonly, getter=canGoForward)BOOL canGoForward;
//是否正在加载
@property (nonatomic,readonly, getter=isLoading)BOOL loading;
一共有四个方法
///是否允许加载网页,也可获取js要打开的url,通过截取此url可与js交互
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSString *urlString = [[request URL] absoluteString];
urlString = [urlString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSArray *urlComps = [urlString componentsSeparatedByString:@"://"];
NSLog(@"urlString=%@---urlComps=%@",urlString,urlComps);
returnYES;
}
///开始加载网页
- (void)webViewDidStartLoad:(UIWebView *)webView {
NSURLRequest *request = webView.request;
NSLog(@"webViewDidStartLoad-url=%@--%@",[request URL],[request HTTPBody]);
}
///网页加载完成
- (void)webViewDidFinishLoad:(UIWebView *)webView {
NSURLRequest *request = webView.request;
NSURL *url = [request URL];
if ([url.path isEqualToString:@"/normal.html"]) {
NSLog(@"isEqualToString");
}
NSLog(@"webViewDidFinishLoad-url=%@--%@",[request URL],[request HTTPBody]);
NSLog(@"%@",[self.webView stringByEvaluatingJavaScriptFromString:@"document.title"]);
}
///网页加载错误
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
NSURLRequest *request = webView.request;
NSLog(@"didFailLoadWithError-url=%@--%@",[request URL],[request HTTPBody]);
}
///加载完成时调用
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
[self.webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitUserSelect='none';"];
[self.webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitTouchCallout='none';"];
[self.showView removeFromSuperview];
NSString *jsToGetHTMLSource = @"document.getElementsByTagName('html')[0].innerHTML";
NSString *HTMLSource = [self.webView stringByEvaluatingJavaScriptFromString:jsToGetHTMLSource];
[self.activityView stopAnimating];
NSRange range = [HTMLSource rangeOfString:@"Bad Gateway"];//判断字符串是否包含
bool urlIsTrue = (range.location == NSNotFound);
if (urlIsTrue ==true ) {
range = [HTMLSource rangeOfString:@"Network is unreachable"];
urlIsTrue = (range.location == NSNotFound);
}
if (urlIsTrue ==true ) {
range = [HTMLSource rangeOfString:@"页面不存在"];
urlIsTrue = (range.location == NSNotFound);
}
if (urlIsTrue ==true) {
range = [HTMLSource rangeOfString:@"网页无法访问"];
urlIsTrue = (range.location == NSNotFound);
}
if (urlIsTrue ==true) {
range = [HTMLSource rangeOfString:@"Not Found"];
urlIsTrue = (range.location == NSNotFound);
}
//网页可访问隐藏我们自己的返回按钮
if (urlIsTrue==true)
{
self.topView.hidden =YES;
}
else
{
[webView stopLoading];
[self addShowView];
}
}
与UIWebview一样,仅需三步:记住导入(#import
- (void)simpleExampleTest {
// 1.创建webview,并设置大小,"20"为状态栏高度
WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectMake(0,20, self.view.frame.size.width,self.view.frame.size.height -20)];
// 2.创建请求
NSMutableURLRequest *request =[NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.cnblogs.com/mddblog/"]];
// 3.加载网页
[webView loadRequest:request];
//最后将webView添加到界面
[self.view addSubview:webView];
}
loadFileURL
函数,顾名思义加载本地文件。///模拟器调试加载mac本地文件
- (void)loadLocalFile {
// 1.创建webview,并设置大小,"20"为状态栏高度
WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectMake(0,20, self.view.frame.size.width,self.view.frame.size.height -20)];
// 2.创建url userName:电脑用户名
NSURL *url = [NSURL fileURLWithPath:@"/Users/userName/Desktop/bigIcon.png"];
// 3.加载文件
[webView loadFileURL:url allowingReadAccessToURL:url];
//最后将webView添加到界面
[self.view addSubview:webView];
}
/// 其它三个加载函数
- (WKNavigation *)loadRequest:(NSURLRequest *)request;
- (WKNavigation *)loadHTMLString:(NSString *)string baseURL:(nullable NSURL *)baseURL;
- (WKNavigation *)loadData:(NSData *)data MIMEType:(NSString *)MIMEType characterEncodingName:(NSString *)characterEncodingName baseURL:(NSURL *)baseURL;
reloadFromOrigin
和
goToBackForwardListItem
。
@property (nonatomic,readonly) BOOL canGoBack;
@property (nonatomic,readonly) BOOL canGoForward;
- (WKNavigation *)goBack;
- (WKNavigation *)goForward;
- (WKNavigation *)reload;
- (WKNavigation *)reloadFromOrigin; //增加的函数
- (WKNavigation *)goToBackForwardListItem:(WKBackForwardListItem *)item;// 增加的函数
- (void)stopLoading;
一共有三个代理协议:
三个是否允许跳转加载的函数:
/// 接收到服务器跳转请求之后调用 (服务器端redirect),不一定调用
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation;
/// 3 在收到服务器的响应头,根据response相关信息,决定是否跳转。decisionHandler必须调用,来决定是否跳转,参数WKNavigationActionPolicyCancel取消跳转,WKNavigationActionPolicyAllow允许跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;
/// 1 在发送请求之前,决定是否跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;
追踪加载过程函数:
/// 2 页面开始加载
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation;
/// 4 开始获取到网页内容时返回
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation;
/// 5 页面加载完成之后调用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation;
/// 页面加载失败时调用
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation;
/// message: 收到的脚本信息.
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;
/// 创建一个新的WebView
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures;
/// 输入框
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString *__nullable result))completionHandler {
NSLog(@"%s",__FUNCTION__);
NSLog(@"%@", prompt);
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"textinput" message:@"JS调用输入框" preferredStyle:UIAlertControllerStyleAlert];
[alert addTextFieldWithConfigurationHandler:^(UITextField *_Nonnull textField) {
textField.textColor = [UIColor redColor];
}];
[alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler([[alert.textFields lastObject] text]);
}]];
[self presentViewController:alert animated:YES completion:NULL];
}
/// 确认框
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler {
NSLog(@"%s", __FUNCTION__);
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"confirm" message:@"JS调用confirm"preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler(YES);
}]];
[alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
completionHandler(NO);
}]];
[self presentViewController:alert animated:YES completion:NULL];
NSLog(@"%@", message);
}
/// 警告框
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
NSLog(@"%s", __FUNCTION__);
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"alert"message:@"JS调用alert" preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"确定"style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler();
}]];
[self presentViewController:alert animated:YES completion:NULL];
NSLog(@"%@", message);
}
/// 5 页面加载完成之后调用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation;
{
// 直接调用js
[self.webViewevaluateJavaScript:@"document.documentElement.style.webkitUserSelect='none';"completionHandler:nil];
// 调用js参数
[self.webViewevaluateJavaScript:@"document.documentElement.style.webkitTouchCallout='none';"completionHandler:nil];
[self.showViewremoveFromSuperview];
NSString *jsToGetHTMLSource =@"document.getElementsByTagName('html')[0].innerHTML";
[self.activityViewstopAnimating];
// 调用js获取返回值
[self.webViewevaluateJavaScript:jsToGetHTMLSourcecompletionHandler:^(id_Nullable HTMLSource, NSError * _Nullable error) {
NSRange range = [HTMLSourcerangeOfString:@"Bad Gateway"];//判断字符串是否包含
bool urlIsTrue = (range.location ==NSNotFound);
if (urlIsTrue ==true ) {
range = [HTMLSource rangeOfString:@"Network is unreachable"];
urlIsTrue = (range.location ==NSNotFound);
}
if (urlIsTrue ==true ) {
range = [HTMLSource rangeOfString:@"页面不存在"];
urlIsTrue = (range.location ==NSNotFound);
}
if (urlIsTrue ==true) {
range = [HTMLSource rangeOfString:@"网页无法访问"];
urlIsTrue = (range.location ==NSNotFound);
}
if (urlIsTrue ==true) {
range = [HTMLSource rangeOfString:@"Not Found"];
urlIsTrue = (range.location ==NSNotFound);
}
//网页可访问隐藏我们自己的返回按钮
if (urlIsTrue==true)
{
self.topView.hidden =YES;
}
else
{
[webView stopLoading];
[selfaddShowView];
}
}];
[webView stopLoading];
}
//在发送请求之前,决定是否跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
if (navigationAction.targetFrame ==nil) {
[webView loadRequest:navigationAction.request];
}
// 没有这一句页面就不会显示
decisionHandler(WKNavigationActionPolicyAllow);
}