您的位置:首页 > 移动开发

iOS webView的高级用法之JS交互,js与oc的相互调用(JavaScriptCore)

2016-08-12 15:24 826 查看
重要的事情放前面 github地址:https://github.com/horisea/JSCallOCTest   欢迎star

前言:说起JS交互,很多童鞋会黯然色变,感觉很高深的样子。大部分小伙伴只知道一种,哪一种我也说说吧。

   1.在webView中将要请求的时候,拦截URL,进行重定向,然而该场景实用有限,网上资料也很多下面说说另一种交互方式。

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest
*)request navigationType:(UIWebViewNavigationType)navigationType
  2.先说一下这种交互方式应用的场景吧。
     2.1:需求:假如贵公司在做一个金融项目,有一个版本功能需要提交个人资料信息,只是为了一个业务需要,那么通过h5做一套,然后iOS和Android只需要webView加载就行,明显提高了开发效率。。。如果贵公司的其他产品也想接入这个功能,那也能通过webview方式直接用了,所谓是牛逼哄哄,通用性特别强。
         但是:(1):比如,webview里有一个上传身份证照片的功能,点击网页,需要iOS端调起相册功能。。如何交互??
                    (2): 加载的网页中,点击一个按钮,要查看订单详情功能,但是需要传会订单号,怎么办:
                    (3): 点击下一步,,iOS端进入下一个界面;??
  这就牵扯到JS调用OC方法,传递参数等等。

3.本文将非常详细的说明使用方法,一句代码不少的说明,你只需要按照步骤操作,一定能运行出你想要的JS交互场景,包你能派上大用场。。废话不说了,开始吧

正文:JS交互,就是js 中通过一个对象来调用方法的
   1.js交互,首先我们要准备一个html文件,没有网页文件,要不然怎么交互:至于这些东西怎么创建,这里不做介绍,楼主最后会附上联系方式,提供demo,demo中有,直接复制就行。
   1.1.首先准备一个html文件,html文件里引用了外部的JS文件
 


2.js文件,里面实现了html文件里的一些按钮的点击事件





图片里非常清楚的注释了一些重要代码的注释,非常详细,搞得自己很会h5一样,程序员,不能放弃任何一次装b的机会,

⚠️注意: 这里在网页中写了4个按钮,,分别调OC的方法
                   1. 点击按钮,唤起系统相册功能;
                   2. 就是简单的调一个方法
                   3. 调用一个参数的方法
                   4. 调用多个参数的方法,这里举例是两个。

 
2.首先创建一个类 继承NSObject ,并且规定一个协议,直接上代码

 2.1>创建TestJSObject.h头文件

#import <Foundation/Foundation.h>

#import <JavaScriptCore/JavaScriptCore.h>

@protocol TestJSObjectProtocol <JSExport>

/// 调支付

- (void)ZTHpay;

/// 调系统相册

- (void)ZTHShowPicker;

/// 传参数回来 比如是一个订单号

- (void)ZTHPassParameter:(NSString *)orderNumber;

/// 传两个参数回来 比如是订单号,姓名

- (void)ZTHTestParameteroneAnd:(NSString *)orderNumber Parametertwo:(NSString *)name;

@end

@interface TestJSObject : NSObject<TestJSObjectProtocol>

///定义三种block,回调到控制器中;

@property (nonatomic,copy)void(^showPickerBlock)();

@end

2.2:然后在.m中实现声明的方法,这4个方法,都会被调用

#import "TestJSObject.h"

@implementation TestJSObject

- (void)ZTHpay{

    NSLog(@"调了支付了-----------------");

}

- (void)ZTHShowPicker{

    NSLog(@"调了相机-------------------");

    dispatch_async(dispatch_get_main_queue(), ^{

       //当然回调后要处理的逻辑,肯定不能在这个类里处理,这里采用block回调到控制器中处理,其余的三种方式都可以用这种方式处理,这里就不一一列举了

        self.showPickerBlock();

    });

}

- (void)ZTHPassParameter:(NSString *)orderNumber{

    NSLog(@"%@", orderNumber);

}

//- (void)ZTHTestParameterone:(NSString *)orderNumber AndParametertwo:(NSString *)name{

//    NSLog(@"订单号--%@姓名---%@", orderNumber, name);

//}

- (void)ZTHTestParameteroneAnd:(NSString *)orderNumber Parametertwo:(NSString *)name{

    NSLog(@"订单号--%@姓名---%@",
orderNumber, name);

}

@end

  3最后在控制器中

   3.1>在懒加载中,设置了web view的url,是一个本地文件,也就是我们一开始写的html文件的路径。


#pragma mark - lazy

- (UIWebView *)webview{

    if (!_webview) {

        _webview=[[UIWebViewalloc]initWithFrame:CGRectMake(0,200,self.view.bounds.size.width,300)];

        _webview.delegate =self;

        _webview.backgroundColor=[UIColorlightGrayColor];

        NSString *htmlPath = [[NSBundlemainBundle]pathForResource:@"index"ofType:@"html"];

        NSURL *localUrl = [[NSURLalloc]initFileURLWithPath:htmlPath];

        [_webview
loadRequest:[NSURLRequestrequestWithURL:localUrl]];

    }

    return _webview;

}
3.2.


#pragma mark - UIWebViewDelegate

- (void)webViewDidFinishLoad:(UIWebView *)webView{

    //首先创建JSContext对象(此处通过当前webView的键获取到jscontext)

   _context=[webView
valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];

    

    //第二种情况,js是通过对象调用的,我们假设js里面有一个对象
testobject 在调用方法

    //首先创建我们新建类的对象,将他赋值给js的对象

    TestJSObject *testJO=[TestJSObjectnew];

    testJO.showPickerBlock = ^{

        [selfshowImagePicker];

    };

    _context[@"testobject"]=testJO;

}

到这里,就已经大功告成了。。。文中打红色的文字部分需要您仔细欣赏欣赏,,首先在TestJSObject.h中,我们声明了一个block属性,原因JS调用的方法实现在改类中,但是我们不能在这个类里处理逻辑,那当然需要一个属性回调到控制器中咯,于是在实现中调用了block,然后在上面写了block的实体,去调用
showImagePicker方法,然后你就可以处理了,,,,其实就是block最简单的用法,,但是,,肯定有很多童鞋不了解。。哈哈,不耽误。。下面附上控制器的所有代码,

//  Copyright © 2016年朱同海. All rights reserved.

//  本文主要介绍JS调用OC交互的方式

#import "ViewController.h"

#import <JavaScriptCore/JavaScriptCore.h>

#import "TestJSObject.h"

@interface ViewController () <UIWebViewDelegate,UIActionSheetDelegate>

{

    JSContext *_context;

}

@property (nonatomic,strong)UIWebView *webview;

@end

@implementation ViewController

- (void)viewDidLoad {

    [super viewDidLoad];

    self.view.backgroundColor = [UIColorcyanColor];

    [self.viewaddSubview:self.webview];

}

#pragma mark - lazy

- (UIWebView *)webview{

    if (!_webview) {

        _webview=[[UIWebViewalloc]initWithFrame:CGRectMake(0,200,self.view.bounds.size.width,300)];

        _webview.delegate =self;

        _webview.backgroundColor=[UIColorlightGrayColor];

        NSString *htmlPath = [[NSBundlemainBundle]pathForResource:@"index"ofType:@"html"];

        NSURL *localUrl = [[NSURLalloc]initFileURLWithPath:htmlPath];

        [_webview
loadRequest:[NSURLRequestrequestWithURL:localUrl]];

    }

    return _webview;

}

#pragma mark - UIWebViewDelegate

- (void)webViewDidFinishLoad:(UIWebView *)webView{

    //首先创建JSContext对象(此处通过当前webView的键获取到jscontext)

   _context=[webView
valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];

    

    //第二种情况,js是通过对象调用的,我们假设js里面有一个对象
testobject 在调用方法

    //首先创建我们新建类的对象,将他赋值给js的对象

    TestJSObject *testJO=[TestJSObjectnew];

    testJO.showPickerBlock = ^{

        [self showImagePicker];

    };

    _context[@"testobject"]=testJO;

}

- (void)showImagePicker{

    NSLog(@"开始唤起相机");

    UIActionSheet *actionSheet = [[UIActionSheetalloc]

                                  initWithTitle:@"请选择文件来源"

                                  delegate:self

                                  cancelButtonTitle:@"取消"

                                  destructiveButtonTitle:nil

                                  otherButtonTitles:@"拍照",@"从手机相册选择",nil];

    [actionSheet showInView:self.view];

}

@end

[b]4.上一些运行图吧[/b]
  4.1:web view的界面图;;





4.2,点击第一个按钮,通过调
ZTHShowPicker方法,内部block的调用,唤起控制器中actionsheet。



4.3,点击最后两个按钮,,第一个传递订单号,第二个传递订单号和姓名,点了两次,打印了两次






[b]5.关于带多个参数的JS回调,OC中对应方法的写法:
[/b]
[b] 比如JS中定义了这个方法[/b]

 testobject.ZTHTestParameteroneAndParametertwo("1123425255","ZTH");那ZTHTestParameteroneAndParametertwo为方法名

那么OC中方法名可以这么写:1和2都是可行的

1.- (void)ZTHTestParameterone:(NSString *)orderNumber AndParametertwo:(NSString *)name;

2.- (void)ZTHTestParameteroneAnd:(NSString *)orderNumber Parametertwo:(NSString *)name;

聪明的你看出来了,只要是OC的方法名去掉:(冒号)拼接起来后,,和JS的方法名一致,那么都是会调用改方法的

千万不能作死:说,我这么拼也是我上面说的原理,那么很遗憾的告诉你,不可以,你把And拆开了,是一个单词,不识别(个人见解)
3.- (void)ZTHTestParameteroneA:(NSString *)orderNumber[b]ndParametertwo:([/b]NSString *)name;

最后说两句:这可能是JS交互中最好用的方法了,总结一下也就是我们在OC中定义一个遵守

JSExport协议的类,又定义了一个协议,声明实现的方法和js中按钮的点击事件方法名称一致,用来一一映射。。最后在控制器中webview加载完毕之后,

 TestJSObject *testJO=[TestJSObjectnew];

    testJO.showPickerBlock = ^{

        [selfshowImagePicker];

    };

  _context[@"testobject"]=testJO;
当然OC内部肯定封装了很多东西匹配他们,,这不用我们管,,最后我们看看JS文件中的一个方法名

 testobject.ZTHpay();
原来是根据testobject这个对象联系起来的,
楼主语言能力不行,不知道有没有绕晕你,但是你只要把demo跑一跑,问题就都能解决了。。当然你要是知道点h5的东西,那肯定更简单咯

就先写到这,回头再完善,楼主其他文章里有联系方式,比如这两篇文章就有联系方式,如有不对的地方,欢迎指正。。想要demo的童鞋,可以加扣扣。。在下面的文章最后有。先好好上会班。
http://blog.csdn.net/horisea/article/details/51872619

http://blog.csdn.net/horisea/article/details/52025886

当然楼主也不是凭空就会的,本文参考链接,当时他说的是技术点,我把细节说的很细,结合下更好哦。 http://blog.csdn.net/lwjok2007/article/details/47058795
如果你喜欢这篇文章,或者有任何疑问,可以扫描第一个二维码,加楼主好友哦

也可以扫第二个二维码,关注楼主个人微信公众号。这里有很多生活,职业,技术相关的文章哦。欢迎您的到来。

微信号:

 
                                           公众号
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息