在WWDC2014中,苹果推出了最新的iOS8系统,其中也伴随着很多控件的更新与升级。其中全新的WebKit库让人很是兴奋。本文也将讲解到WebKit中更新的WKWebView控件的新特性与使用方法,它很好的解决了UIWebView存在的内存、加载速度等诸多问题。
环境信息:
Mac OS X 10.10.1
Xcode 6.1.1
iOS 8.1
正文:
一、WKWebView新特性
- 在性能、稳定性、功能方面有很大提升(最直观的体现就是加载网页是占用的内存,模拟器加载百度与开源中国网站时,WKWebView占用23M,而UIWebView占用85M);
- 允许JavaScript的Nitro库加载并使用(UIWebView中限制);
- 支持了更多的HTML5特性;
- 高达60fps的滚动刷新率以及内置手势;
- 将UIWebViewDelegate与UIWebView重构成了14类与3个协议(查看苹果官方文档);
二、初始化
1. 首先需要引入WebKit库
#import <WebKit/WebKit.h>
2. 初始化方法分为以下两种
- (instancetype)initWithFrame:(CGRect)frame; - (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration NS_DESIGNATED_INITIALIZER;
3. 加载网页与HTML代码的方式与UIWebView相同,代码如下:
WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.bounds]; [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]]]; [self.view addSubview:webView];
三、 WKWebView的代理方法
1. 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; - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;
2. WKUIDelegate
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures;
剩下三个代理方法全都是与界面弹出提示框相关的,针对于web界面的三种提示框(警告框、确认框、输入框)分别对应三种代理方法。下面只举了警告框的例子。
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(void (^)())completionHandler;
3. WKScriptMessageHandler
这个协议中包含一个必须实现的方法,这个方法是提高App与web端交互的关键,它可以直接将接收到的JS脚本转为OC或Swift对象。(当然,在UIWebView也可以通过“曲线救国”的方式与web进行交互,著名的Cordova框架就是这种机制)
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;
四、WKWebView加载JS
NSString *js = @"var count = document.images.length;for (var i = 0; i < count; i++) {var image = document.images[i];image.style.width=320;};window.alert('找到' + count + '张图');"; WKUserScript *script = [[WKUserScript alloc] initWithSource:js injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES]; WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init]; [config.userContentController addUserScript:script]; _webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config]; [_webView loadHTMLString:@"<head></head><img src='http://www.nsu.edu.cn/v/2014v3/img/background/3.jpg' />"baseURL:nil]; [self.view addSubview:_webView];
五、本文Demo下载
https://github.com/saitjr/WKWebViewSimpleDemo.git
六、关于JS的加载或WebView的其他使用技巧,可查看一下文章:
使用Safari对WebView进行调试
WebView加载HTML图片大小自适应与文章自动换行
参考资料:
http://nshipster.cn/wkwebkit/
http://www.cocoachina.com/webapp/20141121/10277.html
http://blog.csdn.net/cyforce/article/details/37657009
- - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
- NSLog(@"didStartProvisionalNavigation");
- [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
- }
-
- - (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation {
- NSLog(@"didCommitNavigation");
- }
-
- - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
- NSLog(@"didFinishNavigation");
- [self resetControl];
- if (webView.title.length > 0) {
- self.title = webView.title;
- }
-
- }
- - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error {
-
-
- NSLog(@"didFailProvisionalNavigation");
-
- }
- - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler {
-
- decisionHandler(WKNavigationResponsePolicyAllow);
- }
-
-
- - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
-
-
- NSLog(@"4.%@",navigationAction.request);
-
-
- NSString *url = [navigationAction.request.URL.absoluteString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
-
-
-
- decisionHandler(WKNavigationActionPolicyAllow);
-
- }
- - (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler {
-
- }
2 UIDelegate
- - (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures {
-
- [self createNewWebViewWithURL:webView.URL.absoluteString config:configuration];
-
- return currentSubView.webView;
- }
-
- - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)())completionHandler
- {
- UIAlertController *alertController = [UIAlertController alertControllerWithTitle:message
- message:nil
- preferredStyle:UIAlertControllerStyleAlert];
- [alertController addAction:[UIAlertAction actionWithTitle:@"确定"
- style:UIAlertActionStyleCancel
- handler:^(UIAlertAction *action) {
- completionHandler();
- }]];
-
- [self presentViewController:alertController animated:YES completion:^{}];
-
- }
-
-
- - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler {
-
-
- UIAlertController *alertController = [UIAlertController alertControllerWithTitle:message
- message:nil
- preferredStyle:UIAlertControllerStyleAlert];
- [alertController addAction:[UIAlertAction actionWithTitle:@"确定"
- style:UIAlertActionStyleDefault
- handler:^(UIAlertAction *action) {
- completionHandler(YES);
- }]];
- [alertController addAction:[UIAlertAction actionWithTitle:@"取消"
- style:UIAlertActionStyleCancel
- handler:^(UIAlertAction *action){
- completionHandler(NO);
- }]];
-
- [self presentViewController:alertController animated:YES completion:^{}];
-
- }
-
- - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString *))completionHandler {
-
- completionHandler(@"Client Not handler");
-
- }
3. WKWebView 执行脚本方法
- - (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^)(id, NSError *))completionHandler;
- completionHandler 拥有两个参数,一个是返回错误,一个可以返回执行脚本后的返回值
4. WKWebView 的Cookie问题
UIWebView 中会自动保存Cookie,如果登录了一次,下次再次进入的时候,会记住登录状态
而在WKWebView中,并不会这样,WKWebView在初始化的时候有一个方法
- - (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration
通过这个方法,设置 configuration 让WKWebView知道登录状态,configuration 可以通过已有的Cookie进行设置,也可以通过保存上一次的configuration进行设置
参考 stackoverflow上回答:http://stackoverflow.com/questions/26573137/can-i-set-the-cookies-to-be-used-by-a-wkwebview/26577303#26577303
- WKWebView * webView =
- NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://example.com/index.html"]];
- [request addValue:@"TeskCookieKey1=TeskCookieValue1;TeskCookieKey2=TeskCookieValue2;" forHTTPHeaderField:@"Cookie"];
-
- [webView loadRequest:request];
- WKUserContentController* userContentController = WKUserContentController.new;
- WKUserScript * cookieScript = [[WKUserScript alloc]
- initWithSource: @"document.cookie = 'TeskCookieKey1=TeskCookieValue1';document.cookie = 'TeskCookieKey2=TeskCookieValue2';"
- injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
-
- [userContentController addUserScript:cookieScript];
- WKWebViewConfiguration* webViewConfig = WKWebViewConfiguration.new;
- webViewConfig.userContentController = userContentController;
- WKWebView * webView = [[WKWebView alloc] initWithFrame:CGRectMake() configuration:webViewConfig];