iOS中JS 与OC的交互(JavaScriptCore.framework)

iOS中实现js与oc的交互,目前网上也有不少流行的开源解决方案;

如:react native

当然一些轻量级的任务使用系统提供的UIWebView 以及JavaScriptCore.framework 里面提供的api就能快速满足的。

 

方式一:iOS6上使用UIWebView 拦截url方式

以下是演示的js和oc端的代码

<html>
<head><title>JAAndOC1</title></head>
<script>
        function sdkhi()
        {
            alert("hello world!");
        }

        function sdkhito(name)
        {
            alert("hello to "+name);
        }
    
</script>
<body>
    
    <h1>hello world</h1>
    <h1>hello world</h1>
    <h1>hello world</h1>
    <h1>hello world</h1>

    <h1><a href="TCSDK://START?name=cc&age=18&phone=10086">START</a></h1>
    <h1><a href="javascript:sdkhi()">SDKHI</a></h1>

</body>

</html>
View Code
@interface ViewController ()<UIWebViewDelegate>
{
    UIWebView *theWeb;
}
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    theWeb = [[UIWebView alloc]initWithFrame:self.view.bounds];
    theWeb.scalesPageToFit = YES;
    theWeb.delegate = self;
    [self.view addSubview:theWeb];
    
    
    //本示例方法适用于iOS 6 +
    
    NSURL *reqUrl = [NSURL URLWithString:[[NSBundle mainBundle] pathForResource:@"js1.html" ofType:nil]];
    [theWeb loadRequest:[NSURLRequest requestWithURL:reqUrl]];
    
    
    
    
    UIButton *clickBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    clickBtn.frame = CGRectMake(100, 100, 100, 100);
    [clickBtn setTitle:@"clisk" forState:0];
    [clickBtn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    [self.view addSubview:clickBtn];
    [clickBtn addTarget:self action:@selector(clickToCloseAlert) forControlEvents:UIControlEventTouchUpInside];
    
    

}

//OC调JS 并传参数
- (void)clickToCloseAlert
{
    //在弹出的alert中可能会有来自 xxx.html 字样 (百度去掉)
    [theWeb stringByEvaluatingJavaScriptFromString:@"sdkhito('cc')"];
}



//JS 调 OC 并传参数
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    
    //访问如下自定义协议连接
    //request.URL   tcsdk://START?name=cc&age=18&phone=10086
    //request.URL.scheme   tcsdk 取出协议
    //request.URL.host     START 取出host
    //request.URL.query name=cc&age=18&phone=10086  取出参数
    NSLog(@"%@",request.URL);
    NSLog(@"%@",request.URL.scheme);
    

    
    return YES;
}
View Code

1. OC 调用js代码主要通过如下接口 

    [theWeb stringByEvaluatingJavaScriptFromString:@"sdkhito('cc')"];

     流程:iOS的UIWebView 加载 包含js的网页;在js中定义好函数接口;

      然后在oc上就可以通过上面接口直接调用的;

2. JS 调用OC 主要通过UIWebView的代理方法shouldStartLoadWithRequest 拦截URL

//JS 调 OC 并传参数

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType

{

    

    //访问如下自定义协议连接

    //request.URL   tcsdk://START?name=cc&age=18&phone=10086

    //request.URL.scheme   tcsdk 取出协议

    //request.URL.host     START 取出host

    //request.URL.query name=cc&age=18&phone=10086  取出参数

    NSLog(@"%@",request.URL);

    NSLog(@"%@",request.URL.scheme);

    

    return YES;

}

  流程:iOS UIWebView 加载包含js的网页;在网页中用<a> 标签名其他跳转方式改变url的操作;

   然后在代理中通过拆分url的结构,分别取出协议,host,参数等;来达到js调用oc方法的的目的。

  问题:通过url传参有限制

 

方式二:iOS7之后使用 JavaScriptCore.framework

 该框架提供完整的js运行环境,在处理oc与js的交互中非常的方法;

如下测试代码

<html>
    <head><title>JAAndOC2</title></head>
    <script>
        
        //以下方法由oc 调用 js
        function sdkhi3TO(name)
        {
            alert("hello world2!"+name);
        }
    
        function sdkhi2()
        {
            alert("hello world2!");
        }
    
        function sdkhito(name)
        {
            alert("hello to "+name);
        }
        
        </script>
    <body>
        
        <h1>hello world</h1>
        <h1>hello world</h1>
        <h1>hello world</h1>
        <h1>hello world</h1>
        
        <h1><a href="TCSDK://START?name=cc&age=18&phone=10086">START</a></h1>
        <h1><a href="javascript:sdkhi2()">SDKHI</a></h1>
        
        <!-- 以下由js 调用oc 的方法 -->
        <h1><a href="javascript:ocsayhi('abc')">OCHI</a></h1>
        <h1><a href="javascript:alert(pl.fullyName())">OCHI</a></h1>

    </body>
    
</html>
View Code
#import "ViewController.h"
#import <JavaScriptCore/JavaScriptCore.h>
#import "Person.h"

@interface ViewController ()<UIWebViewDelegate>
{
    UIWebView *theWeb;
    JSContext *jsCXT;
}

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    //以下使用javascriptcore.framewordk
    
    //适用于iOS7.0
    
    theWeb = [[UIWebView alloc]initWithFrame:self.view.bounds];
    theWeb.scalesPageToFit = YES;
    theWeb.delegate = self;
    [self.view addSubview:theWeb];
    
    NSURL *reqUrl = [NSURL URLWithString:[[NSBundle mainBundle] pathForResource:@"js2.html" ofType:nil]];
    [theWeb loadRequest:[NSURLRequest requestWithURL:reqUrl]];


}

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    //使用webview的js执行环境
    jsCXT = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    
    //异常处理
    jsCXT.exceptionHandler =
    ^(JSContext *context, JSValue *exceptionValue)
    {
        context.exception = exceptionValue;
        NSLog(@"%@", exceptionValue);
    };
    
    
    
    //OC 调用JS
    //[jsCXT[@"sdkhi2"] callWithArguments:nil];
    //sdkhito
    //[jsCXT[@"sdkhito"] callWithArguments:@[@"aa"]];
    
    
    //注册一个方法由js调用
    jsCXT[@"ocsayhi"] = ^(NSString *name) {
        NSLog(@"say hi to %@",name);
    };
    
    
    Person *pp = [[Person alloc]init];
    pp.firstName = @"cc";
    pp.lastName = @"j";
    pp.site = @"baidu.com";
    jsCXT[@"pl"] = pp;
    
    
    [jsCXT evaluateScript:@"alert(pl.fullyName())"];
    
    
}
View Code
#import <Foundation/Foundation.h>
#import <JavaScriptCore/JavaScriptCore.h>
@protocol PersonPtl <JSExport>

@property (nonatomic,copy)NSString *site;
/**
 对于多参数的方法,JavaScriptCore的转换方式将Objective-C的方法每个部分都合并在一起,冒号后的字母变为大写并移除冒号。比如下边协议中的方法,在JavaScript调用就是:doFooWithBar(foo, bar);
 
 **/
- (NSString *)fullyName;

@end

@interface Person : NSObject<PersonPtl>

@property (nonatomic, copy) NSString *firstName;
@property (nonatomic, copy) NSString *lastName;


@end
View Code
#import "Person.h"

@implementation Person

@synthesize site;

- (NSString *)fullyName
{
    return [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName];

}

@end
View Code

 

1. OC调用js  

   流程我们创建UIWebView 在 代理中获取当前页面的js环境;就是JSContext

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

  然后在网页js中定义的方法,在这里我们就可以直接调用了;

    //OC 调用JS

    [jsCXT[@"sdkhi2"] callWithArguments:nil];

        [jsCXT[@"sdkhito"] callWithArguments:@[@"aa"]];

 

2. JS 调用 OC

   这里有两个方式,我们可以通过block的方法在oc里为js 注入一下方法,让js调用 

    //注册一个方法由js调用

    jsCXT[@"ocsayhi"] = ^(NSString *name) {

        NSLog(@"say hi to %@",name);

    };

  

   另外一个方法,稍麻烦一点,我们需要先声明协议,然后实现协议方法;通过JSExport 来暴露给JS环境调用

   如上面的代码中的Person类;

   调用方式:

    Person *pp = [[Person alloc]init];

    pp.firstName = @"cc";

    pp.lastName = @"j";

    pp.site = @"baidu.com";

    jsCXT[@"pl"] = pp;

    

   //以下是在当前jscxt中执行代码,当然网页js中也可以直接写 

    [jsCXT evaluateScript:@"alert(pl.fullyName())"];

 

最后完整示例工程:

https://github.com/cocoajin/TDDDemo/tree/master/JSAndOC

参考:http://www.skyfox.org/ios-wkwebview-cookie-opration.html

 

posted @ 2016-10-26 10:31  cocoajin  阅读(575)  评论(0编辑  收藏  举报