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原理)

  1. 假设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];
   }
  1. 定义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
  1. 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
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐