IOS进阶之WKWebView
前言
Xcode8发布以后,编译器开始不支持IOS7,所以很多应用在适配IOS10之后都不在适配IOS7了,其中包括了很多大公司,网易新闻,滴滴出行等。因此,我们公司的应用也打算淘汰IOS7。
支持到IOS8,第一个要改的自然是用WKWebView替换原来的UIWebView。WKWebView有很多明显优势:
更多的支持HTML5的特性
官方宣称的高达60fps的滚动刷新率以及内置手势
将UIWebViewDelegate与UIWebView拆分成了14类与3个协议,以前很多不方便实现的功能得以实现。文档
Safari相同的JavaScript引擎
占用更少的内存
UIWebView

WKWebView

基本使用方法
WKWebView有两个delegate,WKUIDelegate 和 WKNavigationDelegate。WKNavigationDelegate主要处理一些跳转、加载处理操作,WKUIDelegate主要处理JS脚本,确认框,警告框等。因此WKNavigationDelegate更加常用。
1、WKWebView的初始化
- (void)viewDidLoad
{
[super viewDidLoad];
webView = [[WKWebView alloc] initWithFrame:self.view.frame];
[self.view addSubview:webView];
webView.UIDelegate = self;
webView.navigationDelegate = self;
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]]];
}
#pragma mark - WKUIDelegate
// 创建一个新的WebView
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures{
return [[WKWebView alloc]init];
} // 输入框
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler{
completionHandler(@"http");
} // 确认框
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler{
completionHandler(YES);
} // 警告框
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler{
NSLog(@"%@",message);
completionHandler();
}
#pragma mark - WKNavigationDelegate
// 页面开始加载时调用
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{ } // 当内容开始返回时调用
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation{ } // 页面加载完成之后调用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{ } // 页面加载失败时调用
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation{ } // 接收到服务器跳转请求之后调用
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation{ } // 在收到响应后,决定是否跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
NSLog(@"%@",navigationResponse.response.URL.absoluteString);
//允许跳转
decisionHandler(WKNavigationResponsePolicyAllow);
//不允许跳转
//decisionHandler(WKNavigationResponsePolicyCancel);
} // 在发送请求之前,决定是否跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
NSLog(@"%@",navigationAction.request.URL.absoluteString);
//允许跳转
decisionHandler(WKNavigationActionPolicyAllow);
//不允许跳转
//decisionHandler(WKNavigationActionPolicyCancel);
}
OC与JS交互
WKWebview提供了API实现js交互 不需要借助JavaScriptCore或者webJavaScriptBridge。使用WKUserContentController实现js native交互。简单的说就是先注册约定好的方法,然后再调用。
1、JS调用OC方法
@interface ViewController ()<WKUIDelegate,WKNavigationDelegate,WKScriptMessageHandler>{
WKWebView * webView;
WKUserContentController* userContentController;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//配置环境
WKWebViewConfiguration * configuration = [[WKWebViewConfiguration alloc]init];
userContentController =[[WKUserContentController alloc]init];
configuration.userContentController = userContentController;
webView = [[WKWebView alloc]initWithFrame:self.view.frame configuration:configuration];
//注册方法
[userContentController addScriptMessageHandler:self name:@"sayhello"];//注册一个name为sayhello的js方法
[self.view addSubview:webView];
webView.UIDelegate = self;
webView.navigationDelegate = self;
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]]];
}
- (void)dealloc{
//这里需要注意,前面增加过的方法一定要remove掉。
[userContentController removeScriptMessageHandlerForName:@"sayhello"];
}
#pragma mark - WKScriptMessageHandler
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
NSLog(@"name:%@\\\\n body:%@\\\\n frameInfo:%@\\\\n",message.name,message.body,message.frameInfo);
}
@end
2、WKDelegateController.h代码:
#import <UIKit/UIKit.h>
#import <WebKit/WebKit.h>
@protocol WKDelegate <NSObject> - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message; @end @interface WKDelegateController : UIViewController <WKScriptMessageHandler> @property (weak , nonatomic) id<WKDelegate> delegate;
@end
3、WKDelegateController.m代码:
#import "WKDelegateController.h"
@interface WKDelegateController ()
@end
@implementation WKDelegateController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
if ([self.delegate respondsToSelector:@selector(userContentController:didReceiveScriptMessage:)]) {
[self.delegate userContentController:userContentController didReceiveScriptMessage:message];
}
}
@end
<html>
<head>
<script>
function say()
{
//前端需要用 window.webkit.messageHandlers.注册的方法名.postMessage({body:传输的数据} 来给native发送消息
window.webkit.messageHandlers.sayhello.postMessage({body: 'hello world!'});
}
</script>
</head>
<body>
<h1>hello world</h1>
<button onclick="say()">say hello</button>
</body> </html>
注意点
1、addScriptMessageHandler要和removeScriptMessageHandlerForName配套出现,否则会造成内存泄漏。
2、h5只能传一个参数,如果需要多个参数就需要用字典或者json组装。
OC调用JS方法
- (void)webView:(WKWebView *)tmpWebView didFinishNavigation:(WKNavigation *)navigation{
//say()是JS方法名,completionHandler是异步回调block
[webView evaluateJavaScript:@"say()" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
NSLog(@"%@",result);
}];
}
WebViewJavascriptBridge
一般来说,一个好的UI总有一个大神会开发出一个好的第三方封装框架。WebViewJavascriptBridge的作者也做了一套支持WKWebView与JS交互的第三方框架:WKWebViewJavascriptBridge。
cocoaPods: pod 'WebViewJavascriptBridge', '~> 5.0.5'
github地址:https://github.com/marcuswestin/WebViewJavascriptBridge
主要方法:
//初始化方法
+ (instancetype)bridgeForWebView:(WKWebView*)webView; + (void)enableLogging; //注册函数名
- (void)registerHandler:(NSString*)handlerName handler:(WVJBHandler)handler; //调用函数名
- (void)callHandler:(NSString*)handlerName;
- (void)callHandler:(NSString*)handlerName data:(id)data;
- (void)callHandler:(NSString*)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback; //重置
- (void)reset; //设置WKNavigationDelegate
- (void)setWebViewDelegate:(id<WKNavigationDelegate>)webViewDelegate;
基本的实现方法和上面写的差不多,就是封装了一下,有兴趣的童鞋可以自己pod下来使用。
IOS进阶之WKWebView的更多相关文章
- IOS 进阶之 WKWebView
前言 Xcode8发布以后,编译器开始不支持IOS7,所以很多应用在适配IOS10之后都不在适配IOS7了,其中包括了很多大公司,网易新闻,滴滴出行等.因此,我们公司的应用也打算淘汰IOS7. 支持到 ...
- iOS进阶_地图上定位的标志——大头针
一.添加大头针 地图使用的框架是MapKit 大头针走的是MKAnnotation协议 /* 注意:因为是满足协议MKAnnotation,所以没有MKAnnotation的系统大头针类,必须自定义大 ...
- iOS开发之WKWebView简单使用
iOS开发之WKWebView简单使用 iOS开发之 WKWebVeiw使用 想用UIWebVeiw做的,但是突然想起来在iOS8中出了一个新的WKWebView,算是UIWebVeiw的升级版. ...
- iOS进阶指南试读之UI篇
iOS进阶指南试读之UI篇 UI篇 UI是一个iOS开发工程师的基本功.怎么说?UI本质上就是你调用苹果提供给你的API来完成设计师的设计.所以,想提升UI的功力也很简单,没事就看看UIKit里的各个 ...
- iOS进阶读物
不知不觉作为 iOS 开发也有两年多的时间了,记得当初看到 OC 的语法时,愣是被吓了回去,隔了好久才重新耐下心去啃一啃.啃了一阵,觉得大概有了点概念,看到 Cocoa 那么多的 Class,又懵了, ...
- iOS进阶推荐的书目
<Effective Objective-C 2.0:编写高质量iOS与OS X代码的52个有效方法>([英]Matt Galloway) 很多面试题有涉及 <IOS数据库应用高级编 ...
- [iOS开发]WKWebView加载JS
最近项目要用webView加载js文件,挺同事说WKWebView比UIWebView更加好用,于是我今天就试试,百度一发,自己写了个demo. 先看我写的代码,然后再来看WKWebView跟UIWe ...
- iOS进阶之使用 NSURLProtocol 拦截 HTTP 请求(转载)
这篇文章会提供一种在 Cocoa 层拦截所有 HTTP 请求的方法,其实标题已经说明了拦截 HTTP 请求需要的了解的就是 NSURLProtocol. 由于文章的内容较长,会分成两部分,这篇文章介绍 ...
- ios开发之--WKWebView的使用
WKWebView是ios 8 出来的,是为了解决UIWebView卡慢,占用内存过大的问题. 在以往时候,如果用UIWebView加载加载网页的时候,卡慢现象会很严重,有时候往往会卡到一个页面无法动 ...
随机推荐
- Unity Animator动画状态机 深入理解(三)二维混合树
介绍二维之前,先说说一维吧~ 这个是通过旋转角度速度快慢来表现身体的大转和中转~ 通过一个-133~133的数值来进行控制. 注:后面的那个对钩是镜像的意思. 其实二维混合树并没有想象中的那么难.先来 ...
- SHELL编写NGINX服务控制脚本
使用源码包安装的Nginx没办法使用"service nginx start"或"/etc/init.d/nginx start"进行操作和控制,所以写了以下的 ...
- 疯狂Java笔记
第四章: 4.6深入数组 1.栈内存和堆内存 每个方法都会建立自己的内存栈,在这个方法内定义的变量会逐个放入栈内存里,随着方法的执行结束,这个方法的内存栈也将自然销毁.因此,所有在方法中定义的局部变量 ...
- C语言基础(10)-数组
一.数组的定义 数组就是在内存中连续的相同类型的变量空间. 二.数组在内存中的存储方式 同一个数组所有的成员都是相同的数据类型,同时所有的成员在内存中的地址是连续的,数组名是一个地址的常量,代表数组中 ...
- eclipse项目打包
一.直接在eclipse里export即可 二.如果需要打好的包可以直接使用,则需要修改包中的META-INF文件夹中的MANIFEST.MF文件,主要可能会涉及到的字段主要有以下两个. 1.Main ...
- [从产品角度学EXCEL 01]-EXCEL是怎样运作的
这是<从产品角度学EXCEL>系列第二篇. 前言请看:从产品角度学EXCEL-系列0-为什么要关注EXCEL的本质 本文不接受无授权转载,如需转载,请先联系我,非常感谢. 1.EXCEL是 ...
- java关于压缩包的处理,我这里贴出三中格式的(zip,rar,tar)解压方法(目前只用到解压,所以压缩过多研究)。
1.首先我们先来说下为什么会有这三中格式: (1)rar格式:rar格式是最先出现的压缩方式,它主要是用于商业机构一些文件的压缩,它可以根据不同公司的要求,去设定制定不同的压缩算法,这种算法是不对外公 ...
- C/C++面试题集锦(一)
C/C++面试题集锦(一) */--> C/C++面试题集锦(一) 在类的头文件中进行声明然后在定义文件中实现有什么意义? 一方面使类的实现只编译一次,提高编译效率:另一方面可以实现类的接口和实 ...
- jq添加数组
var array=new Array(); array.push(值); //向数组中添加值 array.shift(值);//向数组中移除值
- POJ1753(位操作和枚举)
题目:http://poj.org/problem?id=1753 题意:一块4*4的棋盘,黑白块不规律分布,翻动一个色块,其上下左右,都会被翻动,知道全黑全白为止.输出最小次数,达不到则输出“Imp ...