**
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 的滚动刷新率,内置了手势探测。
缺点:
WK对缓存和Cookie操作没有UIWebView那么方便。(调用的API没有那么显著的用途。)
WK从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,所以也是也有很多使用的
一般我们都保留两个版本,支持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);
}];
}