iOS开发-JavaScriptCore的使用-WebiOS开发

        就目前市面上的App来说很多都是原生+ H5的作为基底开发的,因为H5在页面交互的处理以及动画效果存在很大的优势,所以现在开发的App原生界面里面掺杂着H5页面是很常见的。

        最近在开发的App也是,使用谷歌地图,在iOS端原生的需要付费才能提供更多的支持,而在Web端api都是开放使用的,而且就于开发而言Web端更为简单。

        大量的趋势造就了需求,在技术群很多人都在问原生和H5怎么用来交互,我就趁着最近的工作给大家写一篇相关的开发文档,简单解释一下JavaScriptCore的使用。


1.什么是JavaScriptCore?
        JavaScriptCore是苹果Safari浏览器的JavaScript引擎,是基于webkit中以C/C++实现的JavaScriptCore的一个包装,在旧版本iOS开发中,很多开发者也会自行将webkit的库引入项目编译使用。不过在iOS7之后苹果就把它做成了一个标准库,提供开发者使用

2.JavaScriptCore中的类
        在项目中引入JavaScriptCore后,链到头文件中,除了大段的Copyright注释可以看到里面只要引入了5个文件,每个文件里都定义跟文件名对应的类:
· JSContext
· JSValue
· JSManagedValue
· JSVirtualMachine
· JSExport


3.JSContext和JSValue
        JSVirtualMachine为JavaScript的运行提供了底层资源,JSContext就为其提供着运行环境,通过- (JSValue *)evaluateScript:(NSString *)script;方法就可以执行一段JavaScript脚本,并且如果其中有方法、变量等信息都会被存储在其中以便在需要的时候使用。而JSContext的创建都是基于JSVirtualMachine:- (id)initWithVirtualMachine:(JSVirtualMachine *)virtualMachine;,如果是使用- (id)init;进行初始化,那么在其内部会自动创建一个新的JSVirtualMachine对象然后调用前边的初始化方法。

        JSValue则可以说是JavaScript和Object-C之间互换的桥梁,它提供了多种方法可以方便地把JavaScript数据类型转换成Objective-C,或者是转换过去。

4.Objective-C调用JavaScript
        oc想要调用js代码的话,先创建一个JSContext对象实例,接着通过evaluateScript加载js代码到context对象中,然后获取js对象,如果为js函数对象,通过callWithArguments调用该js函数,并且可以以数组的方式传递参数。

//js代码段
var appendString = function(name) {
return 'string:' + name;
};
var arr = [1, 2 , 'hello world'];

//m文件
NSString *jsPath = [[NSBundle mainBundle] pathForResource:@"test"ofType:@"js"];
NSString *jsContent = [NSString stringWithContentsOfFile:jsPath encoding:NSUTF8StringEncoding error:nil];

JSContext *context = [[JSContext alloc] init];
[context evaluateScript:jsContent];

JSValue *value = [context[@"appendString"] callWithArguments:@[@"hello"]];
JSValue *value1 = context[@"arr"];

NSLog(@"appendString:%@",[value toString] );//appendString:string:hello
NSLog(@"arr:%@",[value1 toArray] );

5.JavaScript调用Objective-C

JS调用OC有两种实现方式:
(1)Block方式
        我们可以通过block的方式将oc代码暴露给js,JavaScriptCore会自动将oc block包装在js函数中,我们就可以直接在js中调用该block函数

    JSContext *context = [[JSContext alloc] init];
    context[@"sayhi"] = ^(NSString *name) {
        NSLog(@"say hi to %@",name);
    };
    [context evaluateScript:@"sayhi('Greg')"]; 

(2)JSExport协议
如果你到头文件中去查看JSExport协议,你会发现这个协议其实没有定义任何东西。JavaScriptCore提供这个协议用来将oc的方法跟属性暴露给js调用,其中@property会转换成js的getter和setter方法,实例方法会转换成js函数,而类方法则转换成js中global object的方法。

//定义需要暴露给js的内容,这里我们只暴露personName和queryPersonName接口
@protocol PersonProtocol <JSExport>
@property(nonatomic,copy)NSString *personName;
-(NSString *)queryPersonName;
@end

//Person实现PersonProtocol协议,而自己定义的age和queryPersonAge接口不暴露给js
@interface Person : NSObject <PersonProtocol>
@property(nonatomic,assign)NSInteger age;
-(NSInteger)queryPersonAge;
@end

@implementation Person
@synthesize personName = _personName;

-(NSString *)queryPersonName{
    return self.personName;
}
-(NSInteger)queryPersonAge{
    return self.age;
}
@end

JSContext *context = [[JSContext alloc] init];

//创建Person类的对象,将他赋值给js对象
Person *person=[Person new];
person.personName = @"Greg";
person.age = 27;
context[@"person"]=person;

//可以调用获取PersonProtocol暴露的内容
NSString *personName = [[context evaluateScript:@"person.personName"] toString];
NSString *personName1 = [[context evaluateScript:@"person.queryPersonName()"] toString];

//js无法调用跟age相关的内容
NSInteger age = [[context evaluateScript:@"person.age"] toInt32];
NSInteger age1 = [[context evaluateScript:@"person.queryPersonAge()"] toInt32];

6.JavaScriptCore在Web容器中的使用

在UIWebView中,我们可以在- (void)webViewDidFinishLoad:(UIWebView *)webView方法中,通过KVC的方式获取到当前容器的JSContent对象,通过该对象,我们就可以方便的进行hybrid操作。

JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];

功能例子:在html中调研OC代码中的分享功能和调用相机功能。

(1)HelloWord.html代码如下:
function jsCallNative(){
    WBBridge.callCamera();
}
function jsCallNative2(){
    var shareInfo = "分享内容";
    var str = WBBridge.share(shareInfo);
    alert(str);
}<input type="button" οnclick="jscallnative()" value="jscallnative" ><input type="button" οnclick="jscallnative2()" value="jscallnative2" >
</input type="button" οnclick="jscallnative2()" value="jscallnative2" ></input type="button" οnclick="jscallnative()" value="jscallnative" >

(2)实现一个遵守JSExport的协议WebViewJSExport
@protocol WebViewJSExport - (void)callCamera;
- (NSString*)share:(NSString*)shareString;
@end

(3)当前VC需要实现WebViewJSExport
@interface ViewController ()<uiwebviewdelegate,webviewjsexport>@property (nonatomic, strong) JSContext *context;
@property (nonatomic, strong) UIWebView *webView;
@end
@implementation ViewController
-(void)initWebView{
    self.context = [[JSContext alloc] init];

    _webView = [[UIWebView alloc] initWithFrame:self.view.bounds];
    _webView.delegate = self;
    [self.view addSubview:_webView];

    NSURL *url = [[NSURL alloc] initWithString:@"http://localhost:8080/myDiary/HelloWorld.html"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    [self.webView loadRequest:request];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView{

    JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    _context = context;

    // 将本对象与 JS 中的 WBBridge 对象桥接在一起,在 JS 中 WBBridge 代表本对象
    [_context setObject:self forKeyedSubscript:@"WBBridge"];
    _context.exceptionHandler = ^(JSContext* context, JSValue* exceptionValue) {
        context.exception = exceptionValue;
        NSLog(@"异常信息:%@", exceptionValue);
    };
}
- (void)callCamera{
    NSLog(@"调用相机");
}
- (NSString*)share:(NSString*)shareString{
    NSLog(@"分享::::%@",shareString);
    return @"分享成功";
}
@end</uiwebviewdelegate,webviewjsexport>





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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值