iOS - OC和网页JS的交互

我们知道,在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得不到回执啦(但好像也不是什么坏处)~

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

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值