IOS 进阶之 WKWebView
来源:互联网 发布:js删除指定class 编辑:程序博客网 时间:2024/05/16 11:51
来源:o翻滚的牛宝宝o
链接:http://www.jianshu.com/p/4fa8c4eb1316
前言
Xcode8发布以后,编译器开始不支持IOS7,所以很多应用在适配IOS10之后都不在适配IOS7了,其中包括了很多大公司,网易新闻,滴滴出行等。因此,我们公司的应用也打算淘汰IOS7。
支持到IOS8,第一个要改的自然是用WKWebView替换原来的UIWebView。WKWebView有很多明显优势:
更多的支持HTML5的特性
官方宣称的高达60fps的滚动刷新率以及内置手势
将UIWebViewDelegate与UIWebView拆分成了14类与3个协议,以前很多不方便实现的功能得以实现。
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/WebKit/ObjC_classic/index.html
Safari相同的JavaScript引擎
占用更少的内存
UIWebView
WKWebView
因此,使用WkWebview替换UIWebView还是很有必要的。
基本使用方法
WKWebView有两个delegate,WKUIDelegate 和 WKNavigationDelegate。WKNavigationDelegate主要处理一些跳转、加载处理操作,WKUIDelegate主要处理JS脚本,确认框,警告框等。因此WKNavigationDelegate更加常用。
比较常用的方法:
#pragma mark - lifeCircle
-(void)viewDidLoad{
[superviewDidLoad];
webView = [[WKWebViewalloc]init];
[self.viewaddSubview:webView];
[webViewmas_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;
[webViewloadRequest:[NSURLRequestrequestWithURL:[NSURLURLWithString:@"http://www.baidu.com"]]];
}
#pragma mark - WKNavigationDelegate
// 页面开始加载时调用
-(void)webView:(WKWebView *)webViewdidStartProvisionalNavigation:(WKNavigation *)navigation{
}
// 当内容开始返回时调用
-(void)webView:(WKWebView *)webViewdidCommitNavigation:(WKNavigation *)navigation{
}
// 页面加载完成之后调用
-(void)webView:(WKWebView *)webViewdidFinishNavigation:(WKNavigation *)navigation{
}
// 页面加载失败时调用
-(void)webView:(WKWebView *)webViewdidFailProvisionalNavigation:(WKNavigation *)navigation{
}
// 接收到服务器跳转请求之后调用
-(void)webView:(WKWebView *)webViewdidReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation{
}
// 在收到响应后,决定是否跳转
-(void)webView:(WKWebView *)webViewdecidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponsedecisionHandler:(void(^)(WKNavigationResponsePolicy))decisionHandler{
NSLog(@"%@",navigationResponse.response.URL.absoluteString);
//允许跳转
decisionHandler(WKNavigationResponsePolicyAllow);
//不允许跳转
//decisionHandler(WKNavigationResponsePolicyCancel);
}
// 在发送请求之前,决定是否跳转
-(void)webView:(WKWebView *)webViewdecidePolicyForNavigationAction:(WKNavigationAction *)navigationActiondecisionHandler:(void(^)(WKNavigationActionPolicy))decisionHandler{
NSLog(@"%@",navigationAction.request.URL.absoluteString);
//允许跳转
decisionHandler(WKNavigationActionPolicyAllow);
//不允许跳转
//decisionHandler(WKNavigationActionPolicyCancel);
}
#pragma mark - WKUIDelegate
// 创建一个新的WebView
-(WKWebView *)webView:(WKWebView *)webViewcreateWebViewWithConfiguration:(WKWebViewConfiguration *)configurationforNavigationAction:(WKNavigationAction *)navigationActionwindowFeatures:(WKWindowFeatures *)windowFeatures{
return[[WKWebViewalloc]init];
}
// 输入框
-(void)webView:(WKWebView *)webViewrunJavaScriptTextInputPanelWithPrompt:(NSString *)promptdefaultText:(nullable NSString *)defaultTextinitiatedByFrame:(WKFrameInfo *)framecompletionHandler:(void(^)(NSString *__nullableresult))completionHandler{
completionHandler(@"http");
}
// 确认框
-(void)webView:(WKWebView *)webViewrunJavaScriptConfirmPanelWithMessage:(NSString *)messageinitiatedByFrame:(WKFrameInfo *)framecompletionHandler:(void(^)(BOOLresult))completionHandler{
completionHandler(YES);
}
// 警告框
-(void)webView:(WKWebView *)webViewrunJavaScriptAlertPanelWithMessage:(NSString *)messageinitiatedByFrame:(WKFrameInfo *)framecompletionHandler:(void(^)(void))completionHandler{
NSLog(@"%@",message);
completionHandler();
}
OC与JS交互
WKWebview提供了API实现js交互 不需要借助JavaScriptCore或者webJavaScriptBridge。使用WKUserContentController实现js native交互。简单的说就是先注册约定好的方法,然后再调用。
JS调用OC方法
oc代码(有误,内存不释放):
@interfaceViewController(){
WKWebView *webView;
WKUserContentController*userContentController;
}
@end
@implementationViewController
#pragma mark - lifeCircle
-(void)viewDidLoad{
[superviewDidLoad];
//配置环境
WKWebViewConfiguration *configuration = [[WKWebViewConfigurationalloc]init];
userContentController =[[WKUserContentControlleralloc]init];
configuration.userContentController = userContentController;
webView = [[WKWebViewalloc]initWithFrame:CGRectMake(0,0,100,100)configuration:configuration];
//注册方法
[userContentControlleraddScriptMessageHandler:self name:@"sayhello"];//注册一个name为sayhello的js方法
[self.viewaddSubview:webView];
[webViewmas_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;
[webViewloadRequest:[NSURLRequestrequestWithURL:[NSURLURLWithString:@"http://www.test.com"]]];
}
-(void)dealloc{
//这里需要注意,前面增加过的方法一定要remove掉。
[userContentControllerremoveScriptMessageHandlerForName:@"sayhello"];
}
#pragma mark - WKScriptMessageHandler
-(void)userContentController:(WKUserContentController *)userContentControllerdidReceiveScriptMessage:(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代码(正确写法):
@interfaceViewController(){
WKWebView *webView;
WKUserContentController*userContentController;
}
@end
@implementationViewController
#pragma mark - lifeCircle
-(void)viewDidLoad{
[superviewDidLoad];
//配置环境
WKWebViewConfiguration *configuration = [[WKWebViewConfigurationalloc]init];
userContentController =[[WKUserContentControlleralloc]init];
configuration.userContentController = userContentController;
webView = [[WKWebViewalloc]initWithFrame:CGRectMake(0,0,100,100)configuration:configuration];
//注册方法
WKDelegateController *delegateController = [[WKDelegateControlleralloc]init];
delegateController.delegate = self;
[userContentControlleraddScriptMessageHandler:delegateController name:@"sayhello"];
[self.viewaddSubview:webView];
[webViewmas_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;
[webViewloadRequest:[NSURLRequestrequestWithURL:[NSURLURLWithString:@"http://www.test.com"]]];
}
-(void)dealloc{
//这里需要注意,前面增加过的方法一定要remove掉。
[userContentControllerremoveScriptMessageHandlerForName:@"sayhello"];
}
#pragma mark - WKScriptMessageHandler
-(void)userContentController:(WKUserContentController *)userContentControllerdidReceiveScriptMessage:(WKScriptMessage *)message{
NSLog(@"name:%@\\\\n body:%@\\\\n frameInfo:%@\\\\n",message.name,message.body,message.frameInfo);
}
@end
WKDelegateController代码:
#import
#import
@protocolWKDelegate
-(void)userContentController:(WKUserContentController *)userContentControllerdidReceiveScriptMessage:(WKScriptMessage *)message;
@end
@interfaceWKDelegateController : UIViewController
@property(weak,nonatomic)iddelegate;
@end
.m代码:
#import "WKDelegateController.h"
@interfaceWKDelegateController()
@end
@implementationWKDelegateController
-(void)viewDidLoad{
[superviewDidLoad];
}
-(void)userContentController:(WKUserContentController *)userContentControllerdidReceiveScriptMessage:(WKScriptMessage *)message{
if([self.delegaterespondsToSelector:@selector(userContentController:didReceiveScriptMessage:)]){
[self.delegateuserContentController:userContentControllerdidReceiveScriptMessage:message];
}
}
@end
h5代码:
<html>
<head>
<script>
functionsay()
{
//前端需要用 window.webkit.messageHandlers.注册的方法名.postMessage({body:传输的数据} 来给native发送消息
window.webkit.messageHandlers.sayhello.postMessage({body:'hello world!'});
}
</script>
</head>
<body>
<h1>helloworld</h1>
<buttononclick="say()">sayhello</button>
</body>
</html>
打印出的log:
name:sayhello
body:{
body = "hello world!";
}
frameInfo:{URL:http://www.test.com/ }>
注意点
addScriptMessageHandler要和removeScriptMessageHandlerForName配套出现,否则会造成内存泄漏。
h5只能传一个参数,如果需要多个参数就需要用字典或者json组装。
oc调用JS方法
代码如下:
-(void)webView:(WKWebView *)tmpWebViewdidFinishNavigation:(WKNavigation *)navigation{
//say()是JS方法名,completionHandler是异步回调block
[webViewevaluateJavaScript:@"say()"completionHandler:^(id _Nullable result,NSError *_Nullableerror){
NSLog(@"%@",result);
}];
}
h5代码同上。
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*)handlerNamehandler:(WVJBHandler)handler;
//调用函数名
-(void)callHandler:(NSString*)handlerName;
-(void)callHandler:(NSString*)handlerNamedata:(id)data;
-(void)callHandler:(NSString*)handlerNamedata:(id)dataresponseCallback:(WVJBResponseCallback)responseCallback;
//重置
-(void)reset;
//设置WKNavigationDelegate
-(void)setWebViewDelegate:(id)webViewDelegate;
基本的实现方法和上面写的差不多,就是封装了一下,有兴趣的童鞋可以自己pod下来使用。
- IOS 进阶之 WKWebView
- iOS开发 之 WKWebView
- iOS进阶 - 是时候学习WKWebView了
- iOS进阶 - 是时候学习WKWebView了
- iOS开发 ☞ Wkwebview使用进阶
- iOS WKWebView——UIWebView的进阶
- ios之wkwebview与UIwebview的对比
- iOS开发之WKWebView代替UIWebView
- iOS开发之WKWebView代替UIWebView
- IOS WKWebView
- 【iOS】WKWebView
- iOS - WKWebView
- IOS-WKWebView
- IOS网络篇20之IO8新特性WKWebView
- kidd风的IOS日志之从UIWebView到WKWebView
- iOS-WebKit之WKWebView(一个高性能的WebView)
- iOS之WKWebview中cookie问题的解决办法
- iOS之WKWebView修改网页页面的值
- Hibernate4自学入门(八)——集合映射
- DP-POJ 1458 (LCS 最长公共子序列)
- 51nod-【1433 0和5】
- select 1和select count(*)区别
- ES的查询模式以及使用场景:
- IOS 进阶之 WKWebView
- SpringBoot 中文版
- linux多用户需要注意的地方-应用程序报错:
- 真正实用的iOS 工程框架, 可直接用在新项目
- 网络资源关闭的总结:
- mybatis中接口参数使用map类型的好处
- 如何使两台机器不通过密码连接起来(linux)
- zookeeker客户端链接zk服务器三个时间
- matlab转载