我们知道,在iOS开发过程中,有时候会用webview加载一张网页,网页上有一些按钮或者其他的一些链接,要使这些按钮有实际的作用,1??要么就是网页部分在HTML文件内部自己实现方法,2??要么就是通过OC和网页的交互,在本app内OC实现点击网页的按钮,可以触发自己OC写的方法。
下面我讲两种常用的方法。
第一种是遵守webview的协议,通过实现协议方法截取网络请求,通过这个截取到的网络请求进行解析,然后实现自己的方法。
第二种方法是用了一个叫WebViewJavascriptBridge 的第三方库进行桥接,这个方法就比较强大了,它既可以在oc部分写实现代码,也可以在网页JS部分写实现代码。
先放上我整理后的demo下载链接:
本人github上的JSandOC交互的demo
并且附上我参考的这个库下载地址为:(里面有demo,可以学着看看)
github上的下载地址
好了现在先上图,说明一下,现在的网页上的按钮和我本app内部,需要做哪些交互。
此页面为webview加载的图片,要做的便是分别点击这5个按钮(Facebook分享、QQ分享、微信分享、短信分享、邮件分享)在app内部得到响应。分享集成部分再次就不多说了,谢谢。
方法一:webview协议截取网络请求
- (void)viewDidLoad {
[super viewDidLoad];
UIWebView * webview = [[UIWebView alloc]initWithFrame:self.view.bounds];
webview.delegate = self;
//http://127.0.0.1/WEB/initHtml.html 是我放在自己服务器的网页文件
[webview loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://127.0.0.1/WEB/initHtml.html"]]];
[self.view addSubview:webview];
}
#pragma mark ---webview协议方法
#pragma mark ---拦截web网络请求
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
//获取自己的网络请求的网址字符串
NSString *url = request.URL.absoluteString;
//自己定义的协议前缀 网页部分一会儿也是要设置成这个协议!
NSString *scheme = @"xmg://";
//打印出自己获取的网络请求的网址是什么
NSLog(@"~~~~~ %@",url);
//解析网址前缀是否为@"xmg://"
if ([url hasPrefix:scheme])
{
//截出方法名
NSString *actionName = [url substringFromIndex:scheme.length];、
//动态方法选择器 比如我获取的网址是xmg://mailShare 则会执行mailShare这个方法
[self performSelector:NSSelectorFromString(actionName) withObject:nil];
//不加载这个网络请求的页面
return NO;
}
//YES:加载这个网络请求的页面
return YES;
}
-(void)mailShare{
NSLog(@"1shareMail");
}
-(void)facebookShare{
NSLog(@"facebookShare");
}
这个方法比较简单!
方法二:利用WebViewJavascriptBridge第三方库进行JS和OC的桥接
1.app部分(OC部分)
①在新开的工程引用静态库
CoreGraphics.framework
Foundation.framework
UIKit.framework
WebKit.framework
②导入WebViewJavascriptBridge第三方库
③在使用的页面加入头文件WebViewJavascriptBridge.h 这个文件内包含了其他文件,所以只用导入这一个
④开始写代码
#import "ViewController.h"
#import "WebViewJavascriptBridge.h"
@interface ViewController ()<UIWebViewDelegate>
//声明`WebViewJavascriptBridge`对象为属性
@property (nonatomic,strong) WebViewJavascriptBridge * bridge;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
-(void)viewWillAppear:(BOOL)animated{
if (_bridge) { return; }
//用UIWebView加载web网页
UIWebView * webview = [[UIWebView alloc]initWithFrame:self.view.bounds];
webview.delegate = self;
[self.view addSubview:webview];
//设置能够进行桥接
[WebViewJavascriptBridge enableLogging];
_bridge = [WebViewJavascriptBridge bridgeForWebView:webview];
[_bridge registerHandler:@"facebookObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@" ======FacebookObjcCallback ========= %@", data);
//传话给网页说已经接收到
responseCallback(@"facebookObjcCallback回复网页,已经收到消息");
//
}];
[_bridge registerHandler:@"QQShareObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@" ======QQShareObjcCallback ========= %@", data);
//传话给网页说已经接收到
responseCallback(@"QQShareObjcCallback回复网页,已经收到消息");
}];
[_bridge registerHandler:@"WXShareObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@" ======WXShareObjcCallback ========= %@", data);
//传话给网页说已经接收到
responseCallback(@"WXShareObjcCallback回复网页,已经收到消息");
//
}];
[_bridge registerHandler:@"MessageShareObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@" ======MessageShareObjcCallback ========= %@", data);
//传话给网页说已经接收到
responseCallback(@"MessageShareObjcCallback回复网页,已经收到消息");
//
}];
[_bridge registerHandler:@"MailShareObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@" ======MailShareObjcCallback ========= %@", data);
//传话给网页说已经接收到
responseCallback(@"MailShareObjcCallback回复网页,已经收到消息");
//
}];
// oc传话给JS(网页执行) 网页部分会执行以下代码:
/*
bridge.registerHandler(‘testJavascriptHandler‘, function(data, responseCallback) {
log(‘ObjC called testJavascriptHandler with‘, data)
var responseData = { ‘Javascript Says‘:‘Right back atcha!‘ }
log(‘JS responding with‘, responseData)
responseCallback(responseData)
})
接收
*/
//网页接收OC的方法句柄名叫testJavascriptHandler 此时OC给JS传的数据是@{ @"foo":@"before ready" }
[_bridge callHandler:@"testJavascriptHandler" data:@{ @"foo":@"before ready" }];
// 自定义按钮 此处没用,需要的可以自己打开使用
// [self renderButtons:webView];
//当你没有把网页放入服务器的话,可以把网页放在本地工程,这个时候就要执行以下的方法,用NSBoundle加载本地文件
// [self loadExamplePage:webview];
}
//自定义按钮
- (void)renderButtons:(UIWebView*)webView {
UIFont* font = [UIFont fontWithName:@"HelveticaNeue" size:12.0];
UIButton *callbackButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[callbackButton setTitle:@"呼叫JS的Handle" forState:UIControlStateNormal];
[callbackButton addTarget:self action:@selector(callHandler:) forControlEvents:UIControlEventTouchUpInside];
[self.view insertSubview:callbackButton aboveSubview:webView];
callbackButton.frame = CGRectMake(10, 400, 100, 35);
callbackButton.titleLabel.font = font;
}
//可以通过自定义按钮实现方法,动态和JS进行交互
//注:本代码中没有写按钮去实现此方法,需要的同学可以自己去定义按钮实现此方法
- (void)callHandler:(id)sender {
id data = @{ @"OC第一次发信息给JS": @"Hi there, JS,I am OC !" };
// testJavascriptHandler是JS部分接收OC传送消息的方法句柄
// data 是OC给JS传的数据
// response是JS接收到消息后给OC传的数据
[_bridge callHandler:@"testJavascriptHandler" data:data responseCallback:^(id response) {
NSLog(@"JS收到消息后,回复给OC的消息为: %@", response);
}];
}
//加载本地网页
//本代码中的网页是从服务器获取,不是放在本地,放在本地的同学,可以用以下的方法加载
- (void)loadExamplePage:(UIWebView*)webView {
NSString* htmlPath = [[NSBundle mainBundle] pathForResource:@"codetest" ofType:@"html"];
NSString* appHtml = [NSString stringWithContentsOfFile:htmlPath encoding:NSUTF8StringEncoding error:nil];
NSURL *baseURL = [NSURL fileURLWithPath:htmlPath];
[webView loadHTMLString:appHtml baseURL:baseURL];
}
2.网页部分(JS部分)
①在script标签内写桥接方法
②在a标签内记得表面id唯一标示,以便script能够获取此标签元素
<script>
window.onerror = function(err) {
log(‘window.onerror: ‘ + err)
}
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)
}
setupWebViewJavascriptBridge(function(bridge) {
// JS注册接收消息的部分 名字叫testJavascriptHandler
// function是接收消息后做的处理
bridge.registerHandler(‘testJavascriptHandler‘, function(data, responseCallback) {
var responseData = { ‘Javascript Says‘:‘Right back atcha!‘};
//给OC的消息回执
responseCallback(responseData);
});
document.body.appendChild(document.createElement(‘br‘));
//facebook连接出发方法
var facebookButton = document.getElementById(‘Facebook‘);
facebookButton.onclick = function(e) {
e.preventDefault();
<!-- log(‘JS calling handler "FacebookObjcCallback"‘)-->
//桥接呼叫OC句柄:facebookObjcCallback
//并传送数据{‘foo‘: ‘bar‘}过去
bridge.callHandler(‘facebookObjcCallback‘, {‘foo‘: ‘bar‘}, function(response) {
//JS接收到OC的消息回执
<!--log(‘JS got response‘, response)-->
});
};
var QQShareBtn = document.getElementById(‘QQShare‘)
QQShareBtn.onclick = function(a){
a.preventDefault();
bridge.callHandler(‘QQShareObjcCallback‘,{‘QQ‘:‘share‘},function(response){
});
};
var wxShareBtn = document.getElementById(‘WXShare‘)
wxShareBtn.onclick = function(a){
a.preventDefault();
bridge.callHandler(‘WXShareObjcCallback‘,{‘WX‘:‘share‘},function(response){
});
};
var messageShareBtn = document.getElementById(‘MessageShare‘)
messageShareBtn.onclick = function(a){
a.preventDefault();
bridge.callHandler(‘MessageShareObjcCallback‘,{‘Message‘:‘share‘},function(response){
});
};
var mailShareBtn = document.getElementById(‘MailShare‘)
mailShareBtn.onclick = function(a){
a.preventDefault();
bridge.callHandler(‘MailShareObjcCallback‘,{‘Mail‘:‘share‘},function(response){
});
};
});
</script>
<div class="share_box row-eq-height">
<div class="share_box_bg">
<div class="col-xs-3 share_btn share_btn_left" style="">
來分享給好友! </div>
<div class="col-xs-9 share_btn">
<div id=‘log‘>
<a href="" id=‘Facebook‘> <img src="http://152.101.133.203:82/O2OBeauty/assets/images/invite_friend/invitefd_02-02.png"></a>
<a href="" id=‘QQShare‘> <img src="http://152.101.133.203:82/O2OBeauty/assets/images/invite_friend/invitefd_02-03.png"></a>
<a href="" id="WXShare"> <img src="http://152.101.133.203:82/O2OBeauty/assets/images/invite_friend/invitefd_02-04.png"></a>
<a href="" id="MessageShare"> <img src="http://152.101.133.203:82/O2OBeauty/assets/images/invite_friend/invitefd_02-05.png"></a>
<a href="" id="MailShare"> <img src="http://152.101.133.203:82/O2OBeauty/assets/images/invite_friend/invitefd_02-06.png"></a>
</div>
</div>
</div>
</div>
总结:
1??利用桥接的话,就可以进行双方的通信,JS部分可以做回执处理,OC部分也可以做回执处理。
注意点就是JS的Handle要命名好,OC部分的Handle也要命名好,不要搞混淆。
2??而利用webview的协议方法的话,好处是只要双方规定了某一个协议,比如xmg://或其他,
单方面在OC处的webview协议方法解决,解析截取到的网络请求,这种方法实现起来比较快捷,
坏处就是,JS得不到回执啦(但好像也不是什么坏处)~
大家根据自己的需求选择自己适合的方法吧,谢谢大家能够看完!
原文:http://blog.csdn.net/boring_cat/article/details/51240819