使用JavaScriptCore实现交互

  JavaScriptCore是封装了JavaScript和Objective-C桥接的Objective-C API,只需要较少的的代码,就可以实现JavaScript与Objective-C的相互调用。

JavaScriptCore中类及协议:

  • JSContext:给JavaScript提供运行的上下文环境   
  • JSValue:JavaScript和Objective-C数据和方法的桥梁,OC和JS对象之间的转换也是通过它,相应的类型转换如下:

    Objective-C type|JavaScript type
    —–|——
    nil | undefined
    NSNull | null
    NSString | string
    NSNumber | number, boolean
    NSDictionary | Object object
    NSArray | Array object
    NSDate | Date object
    NSBlock (1) | Function object (1)
    id (2) | Wrapper object (2)
    Class (3) | Constructor object (3)

  • JSManagedValue:管理数据和方法的类   
  • JSVirtualMachine:处理线程相关,使用较少

  • JSExport:这是一个协议,如果采用协议的方法交互,自己定义的协议必须遵守此协议,如果JS对象想直接调用OC对象里面的方法和属性,那么这个OC对象只要实现这个JSExport协议就可以了。


直接看简单代码示例吧:

JavaScript -> Objective-C

JS调用OC有两个方法:block和JSExport protocol。

1.JSExport protocol方式(JS–>OC)

JS端实现

//iOSNative 这个是随便定义的 只要和JS那边商议好就ok
//share 这个是function name,方法名称 要和JS商议确定
//shareContent这个是传过来给iOS的参数
iOSNative. share(shareContent)
  • JS代码:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
</head>
<body>
<h1>OC和JS的交互代理方式</h1>
<div>
<!-- 生成一个 button 添加点击事件-->
<input type="button" value="JsToOcShare" onclick="callShare()">
</div>
<script>
function callShare() {
var shareContent = JSON.stringify({"title": "分享", "desc": "分享内容", "shareUrl": "http://dely.vip"});
iOSNative.share(shareContent);
}
<!-- OC调JS-->
function showAlert(message){
alert(message);
}
<!-- JS调OC成功后回调-->
var shareCallback = function(a){
alert('success'+a);
}
</script>
</body>
</html>
  • OC实现

自己要定义一个继承\的Protocol,并在Web所在的ViewController中实现这个Protocol。

#import <JavaScriptCore/JavaScriptCore.h>
@protocol JSObjcExport <JSExport>
JSExportAs(share, - (void)share:(NSString *)shareContent);
//解释:JSExportAs是JSExport中的一个宏。意思就是,我把OC的- (void)share:(NSString *)shareContent)方法对应给JS中的share方法。就给把OC方法映射到JS中
@end

.m文件中,实现JSObjcExport-protocol的方法

@interface ViewController ()<UIWebViewDelegate,JSObjcExport>
@property (nonatomic,strong) JSContext *jsContext;
@end
- (void)webViewDidFinishLoad:(UIWebView *)webView{
//获取WebView的JS运行环境上下文环境
_jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
//代理方式JS调OC方法
//iOSNative 相当于桥接,通过它将 OC 与 JS 联系起来 把JS环境中的iOSNative指向self
_jsContext[@"iOSNative"] = self;//类似_jsContext.delegate = self
//[_jsContext setObject:self forKeyedSubscript:@"iOSNative"];
//异常捕捉
_jsContext.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) {
context.exception = exceptionValue;
NSLog(@"异常信息:%@", exceptionValue);
};
}
#pragma mark - 代理模式JS调用OC的protocol实现
- (void)share:(NSString *)shareContent {
NSLog(@"share:%@", shareContent);
// 分享成功后,回调js的方法shareCallback
// 也即是 OC 调用 JS 方法,
JSValue *shareCallback = self.jsContext[@"shareCallback"];
[shareCallback callWithArguments:@[@"成功"]];
}
  • 总结:JSExport protocol方式(JS–>OC)

    实现上面步骤,只要JS端调用 iOSNative.share(shareContent)就会回调到OC中的- (void)share:(NSString *)shareContent)方法。这里你就可以处理很大事情。

    上面的代码,大致干的事情就是:

    第一 把JS的iOSNative指针指向自己

    第二 掉JS端的iOSNative.function就等于掉self.function

    第三 实现Protocol实现代理,回调

2.Block方式(JS–>OC)

  • JS代码:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
</head>
<body>
<h1>OC和JS的交互Block方式</h1>
<div>
<input type="button" value="JsToOcShare" onclick="callShare(shareContent)">
</div>
<script>
var shareContent = JSON.stringify({"title":"分享", "desc":"分享内容", "shareUrl":"http://dely.vip"});
function callShare(share) {
//share为形参,shareContent为实参,即要传递的参数
}
// OC调JS message为传递的参数
function showAlert(message){
alert(message);
}
</script>
</body>
</html>
  • OC代码:
- (void)webViewDidFinishLoad:(UIWebView *)webView{
_jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
//block 方式 JS直接调用OC,并传参,简单明了
__weak typeof(self) weakSelf = self;
_jsContext[@"callShare"] = ^(id obj){
//把传过来的Json字符串,转为字典
NSData *data = [(NSString *)obj dataUsingEncoding:NSUTF8StringEncoding ];
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
NSLog(@"%@",dict);
//做相应操作。。。。。。。。
//OC调用JS
[weakSelf showAlertTest];
};
_jsContext.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) {
context.exception = exceptionValue;
//比如把js中的方法名改掉,OC找不到相应方法,这里就会打印异常信息
NSLog(@"异常信息:%@", exceptionValue);
};
}
- (void)showAlertTest{
//直接调用该方法实现OC调用JS,并传参
NSString *jsStr = @"showAlert('ios js交互成功,我是网页 alert')";
[_jsContext evaluateScript:jsStr];
// JSValue *shareCallback = self.jsContext[@"showAlert"];
// [shareCallback callWithArguments:@[@"我成功了"]];
}

Objective-C -> JavaScript

OC调用Javascript较为简单,只要通过evaluateScript即可:

- (void)OCToJSMethod{
NSString *jsStr = @"showAlert('ios js交互成功,我是网页 alert')";
[_jsContext evaluateScript:jsStr];
// JSValue *shareCallback = self.jsContext[@"showAlert"];
// [shareCallback callWithArguments:@[@"我成功了"]];
}

参考博客:

http://www.jianshu.com/p/c3c184e460e5
http://www.jianshu.com/p/5a35625a1439