iOS - OC和网页JS的交互

来源:互联网 发布:工艺流程软件软件 编辑:程序博客网 时间:2024/04/28 12:56

我们知道,在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协议截取网络请求

  1. app部分(OC部分)
    1.设置webview 加载网页
    2.实现协议方法
    3.实现网络截取后相应的方法
- (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");}
  1. 网页部分
    在图片连接处 修改:
    修改连接标签的目标属性
    如图,只需要在连接的地方,将href的改成自己设定的协议+方法名即可!

这个方法比较简单!

方法二:利用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得不到回执啦(但好像也不是什么坏处)~

大家根据自己的需求选择自己适合的方法吧,谢谢大家能够看完!

1 0
原创粉丝点击