专栏名称: Cocoa开发者社区
CocoaChina苹果开发中文社区官方微信,提供教程资源、app推广营销、招聘、外包及培训信息、各类沙龙交流活动以及更多开发者服务。
目录
相关文章推荐
iOS中文站  ·  iPhone ... ·  2 天前  
iOS中文站  ·  iPhone ... ·  2 天前  
51好读  ›  专栏  ›  Cocoa开发者社区

IOS进阶之WKWebView

Cocoa开发者社区  · 公众号  · ios  · 2016-10-26 08:02

正文

▲点击上方“CocoaChina”关注即可免费学习iOS开发


原文链接:http://www.jianshu.com/p/4fa8c4eb1316


前言


Xcode8发布以后,编译器开始不支持IOS7,所以很多应用在适配IOS10之后都不在适配IOS7了,其中包括了很多大公司,网易新闻,滴滴出行等。因此,我们公司的应用也打算淘汰IOS7。


支持到IOS8,第一个要改的自然是用WKWebView替换原来的UIWebView。WKWebView有很多明显优势:


  • 更多的支持HTML5的特性

  • 官方宣称的高达60fps的滚动刷新率以及内置手势

  • 将UIWebViewDelegate与UIWebView拆分成了14类与3个协议,以前很多不方便实现的功能得以实现。文档

  • Safari相同的JavaScript引擎

  • 占用更少的内存


UIWebView



WKWebView



因此,使用WkWebview替换UIWebView还是很有必要的。


基本使用方法


WKWebView有两个delegate,WKUIDelegateWKNavigationDelegate


WKNavigationDelegate主要处理一些跳转、加载处理操作,WKUIDelegate主要处理JS脚本,确认框,警告框等。因此WKNavigationDelegate更加常用。


比较常用的方法:


#pragma mark - lifeCircle

- (void)viewDidLoad {

[super viewDidLoad];

webView = [[WKWebView alloc]init];

[self.view addSubview:webView];

[webView mas_makeConstraints:^(MASConstraintMaker *make) {

make.left.equalTo(self.view);

make.right.equalTo(self.view);

make.top.equalTo(self.view);

make.bottom.equalTo(self.view);

}];

webView.UIDelegate = self;

webView.navigationDelegate = self;

[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]]];

}

#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);

}

#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();

}


OC与JS交互


WKWebview提供了API实现js交互 不需要借助JavaScriptCore或者webJavaScriptBridge。使用WKUserContentController实现js native交互。简单的说就是先注册约定好的方法,然后再调用。


JS调用OC方法


oc代码(有误,内存不释放):


@interface ViewController (){

WKWebView * webView;

WKUserContentController* userContentController;

}

@end

@implementation ViewController

#pragma mark - lifeCircle

- (void)viewDidLoad {

[super viewDidLoad];

//配置环境

WKWebViewConfiguration * configuration = [[WKWebViewConfiguration alloc]init];

userContentController =[[WKUserContentController alloc]init];

configuration.userContentController = userContentController;

webView = [[WKWebView alloc]initWithFrame:CGRectMake(0, 0, 100, 100) configuration:configuration];

//注册方法

[userContentController addScriptMessageHandler:self  name:@"sayhello"];//注册一个name为sayhello的js方法

[self.view addSubview:webView];

[webView mas_makeConstraints:^(MASConstraintMaker *make) {

make.left.equalTo(self.view);

make.right.equalTo(self.view);

make.top.equalTo(self.view);

make.bottom.equalTo(self.view);

}];

webView.UIDelegate = self;

webView.navigationDelegate = self;

[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.test.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


上面的OC代码如果认证测试一下就会发现dealloc并不会执行,这样肯定是不行的,会造成内存泄漏。原因是[userContentController addScriptMessageHandler:self  name:@"sayhello"];这句代码造成无法释放内存。(ps:试了下用weak指针还是不能释放,不知道是什么原因。)因此还需要进一步改进,正确的写法是用一个新的controller来处理,新的controller再绕用delegate绕回来。


oc代码(正确写法):


@interface ViewController (){

WKWebView * webView;

WKUserContentController* userContentController;

}

@end

@implementation ViewController

#pragma mark - lifeCircle

- (void)viewDidLoad {

[super viewDidLoad];

//配置环境

WKWebViewConfiguration * configuration = [[WKWebViewConfiguration alloc]init];

userContentController =[[WKUserContentController alloc]init];

configuration.userContentController = userContentController;

webView = [[WKWebView alloc]initWithFrame:CGRectMake(0, 0, 100, 100) configuration:configuration];

//注册方法

WKDelegateController * delegateController = [[WKDelegateController alloc]init];

delegateController.delegate = self;

[userContentController addScriptMessageHandler:delegateController  name:@"sayhello"];

[self.view addSubview:webView];

[webView mas_makeConstraints:^(MASConstraintMaker *make) {

make.left.equalTo(self.view);

make.right.equalTo(self.view);

make.top.equalTo(self.view);

make.bottom.equalTo(self.view);

}];

webView.UIDelegate = self;

webView.navigationDelegate = self;

[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.test.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


WKDelegateController代码:


#import

#import

@protocol WKDelegate

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;

@end

@interface WKDelegateController : UIViewController

@property (weak , nonatomic) id delegate;

@end


.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


h5代码: