RSWebView(UIWebView和WKWebView的混合
UIWebView和WKWebView的混合框架,UIWebView自动切换到WKWebView。只要直接把UIWebView换成RSWebView即可,如果UIWebView还有其它特殊的处理,也需要实现WKWebView对应的代理。iOS8以后,苹果推出了新框架Wekkit,提供了替换UIWebView的组件WKWebView。速度更快了,占用内存少了,转为WKWebView是必然的趋势。RSWebView当UIWebView直接使用。
支持情况说明:
- UIWebView在iOS8及以后自动切换到WKWebView
- 带有网页加载进度条
- 支持设置html, url
- 可注入js脚本
- 可修改WebView请求的userAgent
- 支持忽略ssl验证, 通过
addTrustedDomain
添加 - 支持js交互 WebViewJavascriptBridge,有修改
- 支持进度条 NJKWebViewProgress,有修改
- 支持手势滑动后退,后退时显示上个页面截图(类似safari,wechat)
- 支持从网页打开其他app,需要判断scheme是否允许
- 处理 WKWebView问题 比如打开app store.
- WebView加载本地资源(html,css,js,image...)
使用方法:
pod加入以下部分:
pod 'RSWebView', :git => 'git@github.com:air1120/RSWebView.git'
把UIWebView换成RSWebView即可,支持UIWebView的所有方法和代理不受影响。可以把RSWebView当做UIWebView使用。注意如果在使用RSWebView的ViewController中,如果需要实现了UIWebView的代理方法,也要对应实现WKWebView的代理方法。
扩展功能:
修改userAgent
//使用之后,需要通过[RSWebView setUserAgent:nil];来恢复
+(void)setUserAgent:(NSString *)userAgent;
对于POST或GET的扩展请求,headers是字典类型,body是字典或字符串形式,设置即发送请求。
设置一:
_webView.webSource = [[RSWebSource alloc]initWithUrl:@"http://www.baidu.com" method:@"GET" headers:nil body:nil];
设置二:
_webView.webSource = [[RSWebSource alloc]initWithHtml:@"<html><div>测试</div></html>" baseURL:@""];
读取本地文件:
-(void)loadLocalFile:(NSString *)fileName baseURL:(NSString *)baseURL;
-(void)loadLocalFile:(NSString *)fileName;
WebViewJavascriptBridge的js交互部分:
- (void)registerHandler:(NSString *)handlerName handler:(WVJBHandler)handler;
- (void)callHandler:(NSString *)handlerName;
- (void)callHandler:(NSString *)handlerName data:(id)data;
- (void)callHandler:(NSString *)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback;
添加忽略ssl验证(iOS https请求为什么要忽略证书)
[BBWebViewSSLProtocol addTrustedDomain:@"js.com"];
限制外部应用打开
//包括获取本地资源,所以file必须要加上
webView.trustedScheme = @[@"file",@"mqq"];
trustedScheme不设置,则不会限制。
存在的问题:
stringByEvaluatingJavaScriptFromString的方法执行alert, comfirm,prompt等关于界面的操作并不能直接返回对应的返回值。由于WKWebView的evaluateJavaScript是异步的,但改为同步执行的过程中出问题,目前仍未解决。其它部分经过测试并无问题。当然您可以选择使用evaluateJavaScript的方法代替stringByEvaluatingJavaScriptFromString的执行是完全没问题的。
UIWebView代理对应表
UIWebView代理 |WKWebView代理 |说明
------------------------|---------------
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType; |- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation; |页面开始加载时调用
- (void)webViewDidStartLoad:(UIWebView *)webView |- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation;|当内容开始返回时调用
- (void)webViewDidFinishLoad:(UIWebView *)webView |- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation; | 页面加载完成之后调用
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error |- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation;|页面加载失败时调用
实现思路及遇到的问题(下面部分可不看,总结用)
一些处理思路:
从实际WebView的代理给WebViewJavascriptBridge,WebViewJavascriptBridge回调NJKWebViewProgress的代理方法,NJKWebViewProgress再回调RWWebView的方法,RWWebView再回调对应Controller的方法。
WebViewJavascriptBridge的完全说明:
1.由于WKWebViewJavascriptBridge会截获WKNavigationDelegate的所有响应,所以需要添加事件转发。
2.而事件转发需要提前知道delegate有没有实现对应的方法。所以需要先设置delegate。
3.其实也可以直接重写对应的方法,不过为了尽量保持原有的代理方法,采用了1,2的做法。
WebViewJavascriptBridge的实现js交互的原理:
总结一下:js这边 先把方法名字、参数、处理方法保存成一个字典在转成json字符串,在通过UIWebview调用js中某个方法把这个json字符串传到Native中 去(不是通过url传的,这样太low了),同时把这个处理的方法以key-value形式放到一个js的字典中。UIWebView在收到这个json之后,进行数据处理、还有js的回掉的处理方法(就是那个callbackId)处理完成后也会拼成一个key-value字典通过调用js传回去(可以直接调用js)。js在接到这个json后,根据responseId读取responseCallbacks中处理方法进行处理Native code返回的数据。
总结:native将方法名、参数、回到的id放到一个对象中传给js。js根据方法名字调用相应方法,之后将返回数据和responseId拼装,最后通过src 重定向到UIWebview 的delegate。native得到数据后根据responseId调用事先装入_responseCallbacks的block,动态读取调用,从而完成交互。
- WKWebView的方法说明
- WKWebView不支持的情况处理
1.URL Scheme and App Store links won't work
需要导入两个文件RegExCategories
兼容情况说明:
- 处理 WKWebView不能打开URL Scheme and App Store的问题
- webView支持缩放(scalesPageToFit)
一个关于系统版本的技巧,代码如下:
#if (__MAC_OS_X_VERSION_MAX_ALLOWED > __MAC_10_9 || __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_7_1)
#define supportsWKWebKit
#endif
#if defined(supportsWKWebKit )
//这里写类相关的东西
#endif
相关资料查询:
-
进度条暂时都用了第三方的方法处理,其实有更好的,但是暂时没有处理。WKWebView有estimatedProgress的属性,然后配合UIProgressView设置出来的效果更佳好。