目录
1. WKWebView
2. UIWebView+原生框架(javascriptcore.framework)
3. 第三方WebViewJavascriptBridge框架
1. WKWebView(iOS8后推出)
简介
相比WebView更省内存。
iPhone 与 mac 中的 Safari 都是基于WKWebView 实现的。
使用
#import <WebKit/WebKit.h>
// <WKScriptMessageHandler,WKUIDelegate,WKNavigationDelegate>
// 创建WKWebView
WKWebView *webView=[[WKWebView alloc]initWithFrame:CGRectZero configuration:({
// 1.创建配置类
WKWebViewConfiguration *config=[WKWebViewConfiguration new];
// 1.1设置偏好设置
config.preferences=({
WKPreferences *pre=[WKPreferences new];
[pre setMinimumFontSize:10]; // 最小字体(默认:0)
[pre setJavaScriptEnabled:true]; // js是否可用(默认:true)
[pre setJavaScriptCanOpenWindowsAutomatically:false]; // js是否能通过打开窗口 (默认:false)
pre;
});
// 1.2设置内容处理池
config.processPool=[WKProcessPool new];
// 1.3设置交互(通过js)
[config setUserContentController:({
WKUserContentController *userC=[WKUserContentController new];
// 添加交互,当收到js调用ssbb后 回调didReceiveScriptMessage <WKScriptMessageHandler>
[userC addScriptMessageHandler:self name:@"ssbb"];
userC;
})];
// ---------- 其他常用属性 start----------
// 设置 持久化
// 一个WKWebsiteDataStore对象代表了被网页使用的各种类型的数据。包括cookies,磁盘文件,内存缓存以及持久化数据如WebSQL,IndexedDB数据库,local storage。
[config setWebsiteDataStore:[WKWebsiteDataStore defaultDataStore]];
// 设置 在web全部加载到内存前是否阻止其显示
[config setSuppressesIncrementalRendering:true];
// 设置 UserAgent中的应用名称
[config setApplicationNameForUserAgent:@""];
// 设置 是否允许AirPlay播放媒体(默认:true)
[config setAllowsInlineMediaPlayback:true];
// 设置 是否忽略缩放属性(默认:false)覆盖网页中的user-scalable HTML属性
[config setIgnoresViewportScaleLimits:true];
// 设置 需要检测的数据类型(可对相应的类型做处理,如链接则可跳转)
[config setDataDetectorTypes:WKDataDetectorTypeLink];
/*
WKDataDetectorTypeNone 不检测(默认)
WKDataDetectorTypePhoneNumber 电话
WKDataDetectorTypeLink 链接
WKDataDetectorTypeAddress 地址
WKDataDetectorTypeCalendarEvent 日历提醒事件
WKDataDetectorTypeTrackingNumber 跟踪号码/查询号/运单号
WKDataDetectorTypeFlightNumber 航班号
WKDataDetectorTypeLookupSuggestion
WKDataDetectorTypeAll 检测所有类型
*/
// 设置 是否允许画中画播放?
[config setAllowsPictureInPictureMediaPlayback:true];
// 设置 选择内容的粒度级别
[config setSelectionGranularity:WKSelectionGranularityDynamic];
/*
WKSelectionGranularityDynamic, 用户可自定义选择区域(默认)
WKSelectionGranularityCharacter, 不可自定义选择区域
*/
// 设置 是否使用在线的控制器(默认:false,使用本地的全屏控制器)
[config setAllowsInlineMediaPlayback:true];
// 设置 哪些视频需要用户手势才能自动播放
[config setMediaTypesRequiringUserActionForPlayback:WKAudiovisualMediaTypeAll];
/*
WKAudiovisualMediaTypeNone 所有视频自动播放
WKAudiovisualMediaTypeAudio 音频
WKAudiovisualMediaTypeVideo 视频
WKAudiovisualMediaTypeAll 所有都需要手势才能播放
*/
//
// ---------- 其他常用属性 end----------
config;
})];
// 1.1 dele <WKUIDelegate,WKNavigationDelegate>
[webView setUIDelegate:self];
[webView setNavigationDelegate:self];
// 1.2 loadRequest
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"url"]]];
[self.view addSubview:webView];
常用
获取常用信息
// 标题(readOnly)
NSString *title=webView.title;
// url地址(readOnly)
NSURL *URL=webView.URL;
// 是否正在加载(readOnly)
BOOL loading=webView.isLoading
// 加载进度(readOnly)
double estimatedProgress=webView.estimatedProgress;
// 是否加密(readOnly)
BOOL hasOnlySecureContent=webView.hasOnlySecureContent;
// scrollView(readOnly)
UIScrollView *scrollView=webView.scrollView;
// 调用js中的方法
[webView evaluateJavaScript:@"" completionHandler:^(id _Nullable obj, NSError * _Nullable error) {
}];
// 设置 是否支持手势前进后退(默认:false)
[webView setAllowsBackForwardNavigationGestures:true];
// 设置 是否允许预览链接(默认:true)
[webView setAllowsLinkPreview:true];
加载请求
// loadRequest
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"url"]]];
// 加载fileURL
[webView loadFileURL:[NSURL URLWithString:@""] allowingReadAccessToURL:[NSURL URLWithString:@""]];
// 加载data
[webView loadData:[NSData data] MIMEType:@"" characterEncodingName:@"" baseURL:[NSURL URLWithString:@""]];
// 加载本地html
NSString *urlStr=[[NSBundle mainBundle]pathForResource:@"index.html" ofType:nil];
[webView loadHTMLString:[NSString stringWithContentsOfFile:urlStr encoding:NSUTF8StringEncoding error:nil] baseURL:[NSURL URLWithString:urlStr]];
向前向后
// 是否允许向后(readOnly)
BOOL canGoBack=webView.canGoBack;
// 是否允许向前(readOnly)
BOOL canGoForward=webView.canGoForward;
// 向后
[webView goBack];
// 向前
[webView goForward];
// 重新加载
[webView reload];
// 重新加载初始网址
[webView reloadFromOrigin];
// 停止加载
[webView stopLoading];
前进后退列表
// 获取页面前进后退列表(readOnly)
WKBackForwardList *list=webView.backForwardList;
// 当前(readOnly)
WKBackForwardListItem *item=list.currentItem;
// 前一个(readOnly)
WKBackForwardListItem *itemForward=list.forwardItem;
// 后一个(readOnly)
WKBackForwardListItem *itemBack=list.backItem;
// 后列表(readOnly)
NSArray *backList=list.backList;
// 前列表(readOnly)
NSArray *forwardList=list.forwardList;
// 根据下标获取
WKBackForwardListItem *item=[list itemAtIndex:0];
// 前进或后退到指定页
[webView goToBackForwardListItem:item];
// (readOnly)
NSURL *URL=item.URL;
NSURL *initialURL=item.initialURL;
NSString *title=item.title;
dele
#pragma mark dele <WKScriptMessageHandler> @required
// js调用OC方法后调用
-(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
// message.name
// message.body
}
#pragma mark dele<WKUIDelegate> @optional
// 创建webView后回调
-(WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures{
}
// 关闭webView后调用
-(void)webViewDidClose:(WKWebView *)webView{
}
// js中调用alert后调用
-(void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler{
}
// js中调用confirm后调用
-(void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler{
}
// js中调用prompt后调用
-(void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler{
}
// 是否允许预览指定的WKPreviewElementInfo
- (BOOL)webView:(WKWebView *)webView shouldPreviewElement:(WKPreviewElementInfo *)elementInfo{
}
// 当用户发出了预览操作(比如3D Touch按压)时调用
- (nullable UIViewController *)webView:(WKWebView *)webView previewingViewControllerForElement:(WKPreviewElementInfo *)elementInfo defaultActions:(NSArray<id <WKPreviewActionItem>> *)previewActions{
}
// 预览时用户触发pop操作(继续按压)时调用
- (void)webView:(WKWebView *)webView commitPreviewingViewController:(UIViewController *)previewingViewController{
}
#pragma mark dele<WKNavigationDelegate> @optional
// 设置 是否允许跳转(发送请求之前)
-(void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
// navigationAction.targetFrame navigationAction.sourceFrame
NSString *hostStr=navigationAction.request.URL.host.lowercaseString;
if(navigationAction.navigationType==WKNavigationTypeLinkActivated && ![hostStr containsString:@".com"]){
// 不允许
decisionHandler(WKNavigationActionPolicyCancel);
}else{
// 允许
decisionHandler(WKNavigationActionPolicyAllow);
}
}
// 设置 是否允许跳转(发送请求并收到响应后)
-(void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
// onlyRead:
// navigationResponse.forMainFrame(是否是main frame) navigationResponse.response(获取响应response) navigationResponse.canShowMIMEType
}
// 重定向后调用(接收到服务器的跳转请求)
-(void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation{
}
// 跳转失败后调用
-(void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error{}
// https则调用
-(void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler{}
// 页面开始加载时调用
-(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 withError:(NSError *)error{
}
// 内容处理中断时调用
-(void)webViewWebContentProcessDidTerminate:(WKWebView *)webView{
}
2. UIWebView+原生框架(javascriptcore.framework)
OC中可以直接调用JS方法
JS可通过拦截url间接调用OC
#import <JavaScriptCore/JavaScriptCore.h>
<UIWebViewDelegate>
// 创建UIWebView
UIWebView *webV=[UIWebView new];
[self.view addSubview:webV];
// 位置布局。。。
// loadRequest(加载网页)
[webV loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"url"]]];
其他常用属性
//
[webV setScalesPageToFit:true];
// 滚动速度:正常速,默认慢速
[webV.scrollView setDecelerationRate:UIScrollViewDecelerationRateNormal];
dele
// dele
[webV setDelegate:self];
// 加载完成后调用
-(void)webViewDidFinishLoad:(UIWebView *)webView{
》》》》》OC调js
// 初始化一些操作 (如:提交表单,插入内容,删除内容,修改内容,查询内容)
[webView stringByEvaluatingJavaScriptFromString:@"js代码"];
举例:
// 提交表单
[webView stringByEvaluatingJavaScriptFromString:@"document.froms[0].submit();"];
// 插入内容
[webView stringByEvaluatingJavaScriptFromString:@" js 代码"];
// 例:
@"var script=document.createElement('script');" // 可以是普通控件如img(.src .width .height)
@"script.type='text/javascript';"
@"script.text=\"function myFun(){"
@"var f=document.getElementsByName(‘q’)[0];"
@"f.value='11';"
@"document.forms[0].submit();"
@"}\";"
@"document.getElementsByTagName('head')[0].appendChild(script);"
// 删除内容
[webView stringByEvaluatingJavaScriptFromString:@"document.getElementById('a').remove()"];
// 修改内容值、显示值
[webView stringByEvaluatingJavaScriptFromString:@"document.getElementsByName('a')[0].value='123'"];
[webView stringByEvaluatingJavaScriptFromString:@"document.getElementsByName('a')[0].innerHTML='h123'"];
// 查询内容
// url
NSString *urlStr=[webView stringByEvaluatingJavaScriptFromString:@"document.location.href"];
// title : document.title
// 禁用 页面元素选择
[webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitUserSelect='none';"];
// 禁用 长按弹出ActionSheet
[webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitTouchCallout='none';"];
》》》》》 js调用OC (方式一,原生JavaScriptCore.framework框架(iOS7))
#import<JavaScriptCore/JavaScriptCore.h>
/* 2种方式:
1、Block:暴露单个方法(不能直接使用JSValue、JSContext,造成循环引用)
2、JSExport协议:暴露单个对象
*/
方式一(Block):
OC代码
#import <JavaScriptCore/JavaScriptCore.h>
// 获取 js代码的执行环境
JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
// Block (注册)
context[@"js中的函数名"] = ^{
NSArray *arg = [JSContext currentArguments];
};
context[@"js中的函数名"] = ^(NSDictionary *dic){
NSLog(@"函数的实参值:%@", dic[@"color"]);
};
js代码
function testClick(){
var str1=document.getElementById("text1").value;
var str2=document.getElementById("text2").value;
函数名(str1,str2);
}
方式二(<JSExport>):
实现协议遵守<JSExport>,JS中调用时(会将方法转为驼峰式,也可以使用宏JSExportAs(sbAdd,+(void)method:(int)a with:(int)b))此宏只对带参有效
JS中调用:对象.属性 , 对象.方法 (不能在这增加成员变量)
}
// 是否允许加载网络请求
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
》》》》》 js调用OC (方式二,拦截url)
//
NSString *urlStr=request.URL.absoluteString;
//
NSRange range=[urlStr rangeOfString:@"ssbb://"];
if(range.location!=NSNotFound){
NSString *method=[urlStr substringFromIndex:range.location+range.length];
[self performSelector:NSSelectorFromString(method)];
return false;
}
return true;
}
// 开始加载后调用
-(void)webViewDidStartLoad:(UIWebView *)webView{}
// 加载失败后调用
-(void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error{}
注意事项
1.JS值的包装
JS中的值拿到OC中是不能直接用的
不能作为OC对象的属性
JSValue *value=[context evalutateScript:@"2+2"]; [value toInt32];
/*
OC type JS type
nil undefined
NSNull null
NSString string
NSNumber number,boolean
NSDictionary Object object
NSArray Array object
NSDate Date Object
NSBlock Function Object
id Wrapper object
Class Constructor object
*/
3. WebViewJavascriptBridge框架(第三方框架)
原理:拦截URL
pod 'WebViewJavascriptBridge'
#import "WebViewJavascriptBridge.h"
// 基于WKWebView,则不用再设置WKWebView 的navigationDelegate(navDele为bridge)
// 基于UIWebView,则不用再设置dele(dele为bridge)
// 0.开启日志调试
[WebViewJavascriptBridge enableLogging];
// 1.创建WKWebView或UIWebView
// 2.创建JavascriptBridge
WebViewJavascriptBridge *_webViewBridge=[WebViewJavascriptBridge bridgeForWebView:webView];
[_webViewBridge setWebViewDelegate:self];
// 2.1配置
// js调OC(注册多个handleName,用于js中调用)
[_webViewBridge registerHandler:@"getUserIdFromOC" handler:^(id data, WVJBResponseCallback responseCallback) {
// data
// callBack
if(responseCallback){
responseCallback(@{@"userId":@"ssbb"});
}
}];
// OC调js
[_webViewBridge callHandler:@"getUserName" data:@{@"name":@"ssbb"} responseCallback:^(id responseData) {
// responseData
}];
~~~~~~~~JS
<script>
/*这段代码固定,必须要放到js中(第一次加载HTML时起作用,目的是加载一次wvjbscheme://__BRIDGE_LOADED__,注册JS方法)*/
function setupWebViewJavascriptBridge(callback) {
if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
window.WVJBCallbacks = [callback];
var WVJBIframe = document.createElement('iframe');
WVJBIframe.style.display = 'none';
WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__';
document.documentElement.appendChild(WVJBIframe);
setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0)
}
/*与OC交互的所有JS方法都要放在此处注册,才能调用通过JS调用OC或者让OC调用这里的JS*/
setupWebViewJavascriptBridge(function(bridge) {
/*注册OC调JS*/
bridge.registerHandler('openWebviewBridgeArticle', function() {
log("openWebviewBridgeArticle was called with by ObjC")
})
/*注册OC调JS*/
bridge.registerHandler('token', function(data, responseCallback) {
log("G星爷: ", data)
responseCallback({这里给我返回拼接后的地址})
})
/* 注册js调OC */
document.getElementById('register').onclick = function () {
bridge.callHandler('ww', {'blogdURL': 'weidsfdl'}, function(response) {
log('JS got response', response)
})
}
})
</script>