iOS8.0之后苹果推出了新框架Webkit,提供了WKWebView的组件,用来替换UIWebView。之前UIWebView 加载速度慢,占用内存大,如果加载的网页比较多,占用内存比较大可能还会导致项目crash。WKWebView在性能上有了很大的优化,占用内存小,允许JavaScript的Nitro库加载并使用,支持了更多的HTML5特性。
WKWebView的使用
自定义一个WKWebVC
声明两个属性
@property (nonatomic,strong) WKWebView *webView;
@property (nonatomic,copy) NSString *urlStr;
定义几个静态字符串 用来初始化注册js方法
static NSString * const JSHandlerNameShare = @"share";
static NSString * const JSHandlerNameHideNavBar = @"hideNavBar";
static NSString * const JSHandlerNameShowNavBar = @"showNavBar";
static NSString * const JSHandlerNameSetNavBarAlpha = @"setNavBarAlpha";
初始化WKWebView
- (WKWebView *)webView {
if (!_webView) {
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
//允许html内联播放
config.allowsInlineMediaPlayback = YES;
_webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config];
_webView.backgroundColor = [UIColor whiteColor];
_webView.navigationDelegate = self;
_webView.UIDelegate = self;
_webView.scrollView.delegate = self;
//注册js方法
[_webView.configuration.userContentController addScriptMessageHandler:self name:JSHandlerNameShare];
[_webView.configuration.userContentController addScriptMessageHandler:self name:JSHandlerNameHideNavBar];
[_webView.configuration.userContentController addScriptMessageHandler:self name:JSHandlerNameSetNavBarAlpha];
}
return _webView;
}
加载webView
- (void)setUrlStr:(NSString *)urlStr
{
_urlStr = urlStr;
NSURL *url = [NSURL URLWithString:urlStr];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url cachePolicy:0 timeoutInterval:10.0];
[self.webView loadRequest:request];
[self.view addSubview:self.webView];
}
遵守相应的代理协议并实现相应的代理方法
WKNavigationDelegate 代理方法如下:
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation
{
//在此可以显示加载动画
NSLog(@"页面开始加载时调用");
}
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
{
//停止加载动画
NSLog(@"页面加载完毕");
}
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error
{
//页面加载失败,添加失败页面,或者是添加重新加载按钮
//重新加载需要重新赋值请求链接 重新loadRequest
NSLog(@"页面加载失败");
}
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation
{
//内容返回后,加载动画停止
NSLog(@"当内容返回的时候调用");
}
跳转前会调用以下这个方法,在跳转前可以进行判断跳转的链接,根据跟前端开发协商好的协议头和主机位判断是属于那种跳转,在这个方法中可以进行相应的操作。
- (void)webView:(WKWebView )webView decidePolicyForNavigationAction:(WKNavigationAction )navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;
声明一个通知 用于监听是属于那种跳转
extern NSString * const WKJumpNotification;
为该属性赋值
NSString * const WKJumpNotification = @"WKJumpNotification";
在viewDidLoad 中添加通知
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(jumpAction:) name:WKJumpNotification object:nil];
}
在请求链接跳转前进行如下监听
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
//可以在此进行判断是属于那种跳转类型
//获取跳转链接
NSURL *url = navigationAction.request.URL;
//根据约定好的协议头进行判断
if ([url.scheme isEqualToString:@"saga"]) {
[[NSNotificationCenter defaultCenter] postNotificationName:WKJumpNotification object:nil userInfo:@{@"url":url}];
//不允许跳转
decisionHandler(WKNavigationActionPolicyCancel);
} else {
//允许页面跳转
decisionHandler(WKNavigationActionPolicyAllow);
}
NSLog(@"跳转前调用,决定是否跳转");
}
定义一个枚举判断是属于那种跳转
typedef enum {
WKWebVCRequestTypeCustomerService = 1001,//客服列表
WKWebVCRequestTypeProductDetail = 1002,//商品详情
WKWebVCRequestTypeOrderDetail = 1003//订单详情
}WKWebVCRequestType;
通知方法的执行
- (void)jumpAction:(NSNotification *)notification
{
NSDictionary *dict = notification.userInfo;
id url = dict[@"url"];
if (![url isKindOfClass:[NSURL class]]) {
NSLog(@"参数不是请求URL");
return;
}
NSURL *requestUrl = url;
//根据主机位判断是属于那种跳转类型 这主机位事先跟web前端约定好
WKWebVCRequestType type = requestUrl.host.intValue;
switch (type) {
case WKWebVCRequestTypeCustomerService:
NSLog(@"跳转到客服列表");
break;
case WKWebVCRequestTypeProductDetail:
NSLog(@"跳转到商品详情");
break;
case WKWebVCRequestTypeOrderDetail:
NSLog(@"跳转到订单详情");
break;
default:
break;
}
}
WKUIDelegate 的相应代理方法的使用 处理web界面的三种提示框(警告框、确认框、输入框)
//弹出提示框
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"温馨提示" message:message delegate:self cancelButtonTitle:@"确定" otherButtonTitles: nil];
[alertView show];
completionHandler();
}
//弹出确认框
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"确认框" message:message delegate:self cancelButtonTitle:@"取消" otherButtonTitles: @"确定",nil];
[alertView show];
}
//弹出输入框
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:prompt message:nil delegate:self cancelButtonTitle:@"取消" otherButtonTitles: @"确定",nil];
[alertView show];
}
WKScriptMessageHandler 协议的使用,它能让网页通过JS把消息发送给OC
//网页通过JS把消息发送给OC
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
//判断网页是进行那种操作
if ([message.name isEqualToString:JSHandlerNameShare]) { //分享
if ([message.body isKindOfClass:[NSDictionary class]]) {
//分享字典模型数据
NSDictionary *dict = message.body;
}
NSLog(@"在此可以弹出分享面板");
} else if ([message.name isEqualToString:JSHandlerNameHideNavBar]) {
NSLog(@"隐藏导航栏");
} else if ([message.name isEqualToString:JSHandlerNameShowNavBar]) {
NSLog(@"显示导航栏");
} else if ([message.name isEqualToString:JSHandlerNameSetNavBarAlpha]) {
if ([message.body isKindOfClass:[NSDictionary class]]) {
//根据模型字典中的数据设置导航栏的透明度
NSDictionary *dict = message.body;
}
NSLog(@"设置导航栏的透明度");
} else {
NSLog(@"没有注册此操作");
}
}
在开发中使用WKWebView遇到一些问题
- (void)dealloc;中发现self没有被释放,原因是注册的js事件没有移除
为了释放self 我在viewWillDisAppear里进行了如下操作
- (void)viewWillDisappear:(BOOL)animated
{
//移除之前注册的js回调,不然会导致webView无法正常释放。
[self.webView.configuration.userContentController removeScriptMessageHandlerForName:JSHandlerNameShare];
[self.webView.configuration.userContentController removeScriptMessageHandlerForName:JSHandlerNameHideNavBar];
[self.webView.configuration.userContentController removeScriptMessageHandlerForName:JSHandlerNameShowNavBar];
[self.webView.configuration.userContentController removeScriptMessageHandlerForName:JSHandlerNameSetNavBarAlpha];
}
由于webView指定了UIScrollViewDelegate,所以要在dealloc中将webView的滚动代理赋值为nil,否则会导致crash
- (void)dealloc
{
//需要将滚动的代理赋值为nil否则会导致crash
_webView.scrollView.delegate = nil;
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
这是个人使用WKWebView的总结