WKWebView和UIWebView及其四种交互

来源:互联网 发布:希拉里 邮件门 岛 知乎 编辑:程序博客网 时间:2024/05/29 17:02

**

UIWebView

官方文档翻译

**
继承关系:NSObject→UIResponder→UIView-→UIWebView

遵循:NSCoding NSObject UIAppearance UIAppearanceContainer UICoordinateSpace UIDynamicItem UIScrollViewDelegate UITraitEnvironment

你可以使用UIWebView类嵌入网页内容在您的应用程序。这样做,您只需创建一个UIWebView对象,将它附加到一个窗口,并发送一个请求来加载网页内容。你也可以使用这个类来搬回和网页历史的前进,你甚至可以以编程方式设置的一些网页内容的性质。

注:

在iOS 8及以后的运行应用程序,建议您使用WKwebview代替使用UIWebView。此外,如果你使用不能运行的JavaScript文件,应该设置WKpreferences属性 javascriptenabled为NO。

使用loadhtmlstring:baseURL:开始加载本地HTML文件,loadRequest的方法:开始加载的Web内容的方法。使用stopLoading方法停止加载,loading 属性是去发现是否有一个Web视图是在加载过程中。

如果你允许用户通过网页历史向前向后移动了,那么你可以使用goForward和goBack方法做完按钮的动作。使用canGoBack和canGoForward属性禁用的按钮时当用户不能在一个方向移动。

默认情况下,一个webview会自动将出现在网络内容中的电话号码转换为电话号码。当电话链接被点击时,手机应用将进行拨号。设置detectsphonenumbers属性为NO 关闭此默认行为。

当网页内容显示时,你也可以使用scalesPageToFit属性去设置网页内容的比例。此后,用户可以使用手势改变尺度。

如果你想跟踪Web内容加载设置代表性对象符合UIWebviewdelegate协议等。

重点:
你不应该嵌入UIWebView或UITableView对象到UIScrollView对象里。如果你这样做,意外的行为可能会导致因为触摸事件的对象可以混淆和错误处理。
一般的处理方式是直接在html中调用JS或者CSS,或者是最近比较流行的query mobile ,都可以直接调用系统的API,执行操作。

WKWebView

苹果在iOS8中加入的用来替代UIWebView的控件。比UIWebView加载块一倍的控件,内存方面却比它少一半,但是相对的缓存处理方面会稍微差一点。

整理下优缺点如下:
优点:
将浏览器内核渲染进程提取出 App,由系统进行统一管理,这减少了相当一部分的性能损失。
js 可以直接使用已经事先注入 js runtime 的 js 接口给 Native 层传值,不必再通过苦逼的 iframe 制造页面刷新再解析自定义协议的奇怪方式。
支持高达 60 fps 的滚动刷新率,内置了手势探测。

缺点:
MK对缓存和Cookie操作没有UIWebView那么方便。(调用的API没有那么显著的用途。)
MK从iOS8才开始支持,也就是说在我们同时对iOS7支持的情况下,如果为了减少代码量及适配等方面因素,一样会选择UIWebView。

鉴于 UIWebView的钟爱,浅谈一下其缓存机制

1、NSURLRequestUseProtocolCachePolicy NSURLRequest默认的cache policy,使用Protocol协议定义。

2、NSURLRequestReloadIgnoringCacheData 忽略缓存直接从原始地址下载。

3、NSURLRequestReturnCacheDataElseLoad 只有在cache中不存在data时才从原始地址下载。

4、NSURLRequestReturnCacheDataDontLoad 只使用cache数据,如果不存在cache,请求失败;用于没有建立网络连接离线模式;

5、NSURLRequestReloadIgnoringLocalAndRemoteCacheData:忽略本地和远程的缓存数据,直接从原始地址下载,与NSURLRequestReloadIgnoringCacheData类似。

6、NSURLRequestReloadRevalidatingCacheData:验证本地数据与远程数据是否相同,如果不同则下载远程数据,否则使用本地数据。

**

OC与H5的交互

**
当然我们在用到webview的时候会经常用到交互类的,实际即为WEB端和iOS手势的结合,而带来的一些数据的交换。

方法一、用来监听当前web的协议方法

-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType 

此方法用于,web加载新的网络请求,监听并得到webview的一些信息

方法二、调用JS执行语句,在点击之后直接执行对应JS语句。

另个就是直接调用JS语句(学一些比较基本的JS语句还是很有必要的)
[webview stringByEvaluatingJavaScriptFromString:@”JS方法”]; //添加到head标签中
然后当前web就会直接执行那个JS方法

还有一种就是JS调OC的方法
其实和第一种类似,在html里面约定好,你给传一个方法名(其实只是约定的一个string)然后我再根据方法

-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType

来判断是否调用了,然后直接执行相应的方法。

方法三、比较实用的H5调用OC自定义方法。无需使用代理方法**

其实还是有一种H5直接调用OC的方法的。此方法很好的解决了H5和iOS上架应用的交互问题.

现在要求web中遇到404的情况,直接在H5中判断到然后调用OC自定义方法。执行操作。

//H5调用的OC方法- (void)jsValue{    //获取H5中的JS上下文    JSContext *context = [webview valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];    //JS方法中约定的一个方法名     NSString *overtime = @"logee";    //执行H5调用的方法后,iOS执行的方法。执行方法名对应的代码块。    context[overtime] = ^() {        NSURL *url = [[NSURL alloc]initWithString:URL_LOGIN];        NSURLRequest *request = [NSURLRequest requestWithURL:url];        [webview loadRequest:request];        NSArray *args = [JSContext currentArguments];        for (JSValue *jsVal in args) {            NSLog(@"%11111@", jsVal);        }        JSValue *this = [JSContext currentThis];        NSLog(@"jsValue:%@",this);    };    //执行H5调用的方法后,iOS执行的方法。    context[@"overTime"] = ^(){        NSURL *url = [[NSURL alloc]initWithString:@"https://www.baidu.com"];        NSURLRequest *request = [NSURLRequest requestWithURL:url];        [webview loadRequest:request];    };}

H5中的index.html代码部分

<html lang="en">      <head>           <meta charset="utf-8">            <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">              <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />                  <meta name="description" content="">              <meta name="viewport" content="width=device-width; initial-scale=1.0">               <script type="text/javascript" src="index.js"></script>                   </head>      <button id="hallo" onclick="buttonClick()"> 点击button</button>      </body>  </html>  

我们在JS代码中要写的index.js

点击Button执行的操作。

function buttonClick()  {      overTime("hello world");  }  

产生的效果就是点击Button,然后执行了OC代码块

注意:最好不要使用以下代码获取状态码
在使用过程中容易产生重复发送表单。

#pragma mark -  #pragma mark - UIWebView Delegate Methods  - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType  {      static BOOL isRequestWeb = YES;      if (isRequestWeb) {          NSHTTPURLResponse *response = nil;            //重新发送了数据请求,重复表单。        NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];          if (response.statusCode == 404) {              // code for 404              return NO;          } else if (response.statusCode == 403) {              // code for 403              return NO;          }          [webView loadData:data MIMEType:@"text/html" textEncodingName:nil baseURL:[request URL]];          isRequestWeb = NO;          return NO;      }      return YES;  }  

方法四、 使用三方库WebViewJavascriptBridge ,iOS 8之后使用WKwebview,所以也是也有很多使用的

是WKWebViewJavascriptBridge。

一般我们都保留两个版本,支持iOS 8以上,webview 基本就背放弃了,所以这样也就简单介绍下WKWebViewJavascriptBridge的使用。具体的demo可以下载阅读。

下面是OC的代码也是他的官网demo

首先下载WKWebViewJavascriptBridge 导入项目中,加入头文件

import "WKWebViewJavascriptBridge.h"
  if (_bridge) { return; }    WKWebView* webView = [[NSClassFromString(@"WKWebView") alloc] initWithFrame:self.view.bounds];    webView.navigationDelegate = self;    [self.view addSubview:webView];//wk的类方法,相当于注册,里面就一个返回值默认false,调用后直接返回yes    [WKWebViewJavascriptBridge enableLogging];    //相当于将 _bridge对象绑定到这个webview中。    _bridge = [WKWebViewJavascriptBridge bridgeForWebView:webView];    //设置WKwebview的代理 WKNavigationDelegate ,看原文件就知道了。    [_bridge setWebViewDelegate:self];    /**     *  注册回调     *     *  @param data             JS传给前端的数据     *  @param responseCallback     *     *  @ testObjcCallback 就是handlerName,是和前端约定好的,     *     */    [_bridge registerHandler:@"testObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) {        //objc  回调的数据,也就是JS传给objc的数据        NSLog(@"JS发送给objc的数据:%@", data);         //回调的响应,就是前端接收到数据后,然后可将有用的数据返回给JS        responseCallback(@"需要回调给js的数据");    }];
 //JS 给约定的js方法testJavascriptHandler" 发送数据    [_bridge callHandler:@"testJavascriptHandler" data:@{ @"foo":@"before ready" }];
// 此方法为了将data 数据放送给js - (void)callHandler:(id)sender {    id data = @{ @"greetingFromObjC": @"Hi there, JS!" };    [_bridge callHandler:@"testJavascriptHandler" data:data responseCallback:^(id response) {        NSLog(@"testJavascriptHandler responded: %@", response);    }];}
1 0