iOS原生 Native和Javascript交互
·
Native中运行JavaScript代码
通过JSContext对象(类似于JavaScript运行环境),执行js代码(从js文件中获取的NSString)
//获取js文件路径
NSString *path = [[NSBundle mainBundle] pathForResource:"main" ofType:@"js"];
//读取js数据
NSData *jsData =[[NSData alloc]initWithContentsOfFile:path];
//从data解码成string类型的JS代码(无参)
NSString *jsCode = [[NSString alloc]initWithData:jsData encoding:NSUTF8StringEncoding];
//组装js代码(若带参,从上面的无参代码中组装参数)
NSString *fiString = [NSString stringWithFormat:jsCode,paramString];
//初始化JSContext对象
self.jsContext = [[JSContext alloc]init];
//执行JS代码(无参)
[self.jsContext evaluateScript:jsCode];
//执行JS代码(带参)
[self.jsContext evaluateScript:fiString];
Javascript中运行Native代码
通过JSContext,将native方法注入并命名,然后在JavaScript运行环境中调用(根据JSContext注入时的命名)
//定义一个block
int (^block)(NSString *) = ^(NSString *name){
NSLog(@"hello javascript");
return 99;
};
//JS注入native方法并将其命名为oc_hello
[self.jsContext setObject:block forKeyedSubscript:@"oc_hello"];
//js调用 oc_hello("someName")即可, !!!必须带括号,否则只是获得了函数体,而非执行
//js调用结束后返回值为99
解析JS代码并渲染native控件和事件
使用上述两种通信方式,可以实现服务端下发JS代码—客户端解析—渲染native控件、布局、事件(react-native原理)
- 假设js文件如下
(function(){
console.log("javaScriptInit");
//javaScript脚本加载完成后,自动render界面
return render();
})();
//定义Label控件
function Label(rect,text,color){
this.rect = rect;
this.text = text;
this.color = color;
this.typeName = "Label";
}
//定义Button控件
function Button(rect,text,callFunc){
this.rect = rect;
this.text = text;
this.callFunc = callFunc;
this.typeName = "Button"
}
//定义矩形(iOS控件布局需要给定矩形)
function Rect(x,y,width,height){
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
//定义UIColor的四个属性
function Color(r,g,b,a){
this.r = r;
this.g = g;
this.b = b;
this.a = a;
}
//描述控件布局、事件绑定
function render(){
var rect = new Rect(20,100,280,30);
var color = new Color(1,0,0,1);
var label = new Label(rect,"hello world",color);
var rect2 = new Rect(20,150,280,30);
var color2 = new Color(0,1,0,1);
var label2 = new Label(rect2,"hello native",color2);
var rect3 = new Rect(20,200,280,30);
var color3 = new Color(0,0,1,1);
var label3 = new Label(rect3,"hello javascript",color3);
var rect4 = new Rect(20,240,280,30);
var button = new Button(rect4,"我是一个按钮",function(){
var randColor = new Color(Math.random(),Math.random(),Math.random(),1);
Globle.changeBackgroundColor(randColor);
});
return [label,label2,label3,button];
}
- 定义Globle.h\Globle.m 工具函数,从jsvalue中获得rgb值并修改viewcontroller背景
//Globle.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <JavaScriptCore/JavaScriptCore.h>
//定义oc类绑定到jscontext上,作为桥接器
@protocol GlobleProtocol <JSExport>
-(void)changeBackgroundColor:(JSValue *)value;
@end
@interface Globle : NSObject <GlobleProtocol>
@property (nonatomic,weak) UIViewController *ownerController;
@end
//Globle.m
#import "Globle.h"
@implementation Globle
- (void)changeBackgroundColor:(JSValue *)value{
self.ownerController.view.backgroundColor = [UIColor colorWithRed:value[@"r"].toDouble green:value[@"g"].toDouble blue:value[@"b"].toDouble alpha:value[@"a"].toDouble];
}
@end
- viewController中读取jsvalue、渲染控件、绑定事件
#import "ViewController.h"
#import <JavaScriptCore/JavaScriptCore.h>
#import "Globle.h"
@interface ViewController ()
@property(strong,nonatomic) JSContext *jsContext;
@property(nonatomic,strong) NSMutableArray *actionArray;
@property(nonatomic,strong) Globle *globle;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.jsContext = [[JSContext alloc]init];
self.globle = [Globle new];
self.globle.ownerController = self;
//绑定桥接器,使得js能够访问到globle
self.jsContext[@"Globle"] = self.globle;
self.actionArray = [NSMutableArray array];
[self render];
}
-(void) render{
//取得js运行后的返回值(K-V类型)
NSString *path = [[NSBundle mainBundle] pathForResource:@"main" ofType:@"js"];
NSData *jsData = [[NSData alloc]initWithContentsOfFile:path];
NSString *jsCode = [[NSString alloc]initWithData:jsData encoding:NSUTF8StringEncoding];
JSValue *jsValue = [self.jsContext evaluateScript:jsCode];
//解析并渲染界面
for(int i = 0;i<jsValue.toArray.count;i++){
JSValue *subValue = [jsValue objectAtIndexedSubscript:i];
if([[subValue objectForKeyedSubscript:@"typeName"].toString isEqualToString:@"Label"]){
UILabel *label = [UILabel new];
//解析Label控件
label.frame = CGRectMake(subValue[@"rect"][@"x"].toDouble, subValue[@"rect"][@"y"].toDouble, subValue[@"rect"][@"width"].toDouble, subValue[@"rect"][@"height"].toDouble);
label.text = subValue[@"text"].toString;
label.textColor = [UIColor colorWithRed:subValue[@"color"][@"r"].toDouble green:subValue[@"color"][@"g"].toDouble blue:subValue[@"color"][@"b"].toDouble alpha:subValue[@"color"][@"a"].toDouble];
[self.view addSubview:label];
}else if ([[subValue objectForKeyedSubscript:@"typeName"].toString isEqualToString:@"Button"]){
//解析Buttons控件
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
button.frame = CGRectMake(subValue[@"rect"][@"x"].toDouble, subValue[@"rect"][@"y"].toDouble, subValue[@"rect"][@"width"].toDouble, subValue[@"rect"][@"height"].toDouble);
[button setTitle:subValue[@"text"].toString forState:UIControlStateNormal];
button.tag = self.actionArray.count;
[button addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
[self.actionArray addObject:subValue[@"callFunc"]];
[self.view addSubview:button];
}
}
}
-(void) buttonAction:(UIButton *)btn{
JSValue *action = self.actionArray[btn.tag];
[action callWithArguments:nil];
}
@end
更多推荐

所有评论(0)