• iOS React Native 学习总结


    一、简单介绍

    不同于Hybrid ap,React Native里面没有webview,iOS7中加入了JavaScriptCore.framework框架,而RN正是用JavascriptCore执行js代码的。

    二、环境配置

    需要安装Watchman Flow Node环境,推荐使用Homebrew,注意Xcode版本不能低于7.0

    • brew install node Node安装
    • brew install watchman
    • brew install flow
    • brew update && brew upgrade 环境更新

    三、工程创建

    国内需要换源

    1 npm config set registry https://registry.npm.taobao.org
    2 npm config set disturl https://npm.taobao.org/dist

    执行以下两条命令安装全局npm环境和初始化工程RNDEMO

    $ sudo npm install -g react-native-cli
    $ react-native init RNDemo
    

    cd到工程根目录中用npm start(如果开启了自动启动调试服务器则不需要)启动服务,然后运行工程

    集成RN环境到Native中

    1.拷贝node_modules环境到工程中

    2.将需要的.xcodeproj文件添加到工程中

    3.点击 项目>Targets>Bulid Phases>Link Binary With Libraries添加对应的静态库

    4.点击 项目>Targets>Bulid Settings>Search Paths>Header Search Paths注册React.xcodeproj文件路径

    5.因为静态库里面可能有Category 所以需要在项目>Targets>Build Settings -> other linker flags 中加入-ObjC或者-all_load

    四、RN在工程用的一些应用

    关于原生组件

      RN能用JS方便地调用官方封装的组件来加大开发效率,但是一些个性化或者js不太方便的东西还是需要native实现,于是需要native提供一些原生组件来完善。这主要分为两类,Module类和View类

    1. Module类需要导入头文件#import "RCTBridgeModule.h"并遵守RCTBridgeModule协议
    2. ViewManager类需要导入头文件#import "RCTViewManager.h"并继承至RCTViewManager,遵守RCTBridgeModule协议并实现- (UIView *)view方法return view;即为自定义组件。

      两种类都需要实现 RCT_EXPORT_MODULE(js_name) 协议宏,js_name是js调用该类名称,缺省情况下截取类所在文件名,一个类所在文件被引用时,系统会调用其+(void)load函数,当RCT_EXPORT_MODULE()所在文件被引用时,系统调用load 函数,函数里简单的调用RCTRegisterModule(self) 把自己注册到一个全局数组RCTModuleClasses,这样系统中导出的类都会自动注册到这个全局变量数组里

    void RCTRegisterModule(Class moduleClass)
    {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            RCTModuleClasses = [NSMutableArray new];
        });
    
        RCTAssert([moduleClass conformsToProtocol:@protocol(RCTBridgeModule)], @"%@ does not conform to the RCTBridgeModule protocol", moduleClass);
    
        // Register module
        [RCTModuleClasses addObject:moduleClass];
    }
    
    属性导出

      RN可以向Native传递多种参数,可以以这些支持的类型传递数据native组件用EXPORT_VIEW_PROPERTY(<#name#>, <#type#>)来导出类的属性,js传递数据会调用相应的set方法,native可以在set方法里面做些逻辑和数据处理。支持字符串NSString,NSArray数组,基本数据类型,NSnumeber,NSDictionary字典等,自定义类型,并在RCTCovert中,重定义了如下几种数据类型来处理一些泛型

    typedef NSArray NSArrayArray __deprecated_msg("Use NSArray");
    typedef NSArray NSStringArray __deprecated_msg("Use NSArray");
    typedef NSArray NSStringArrayArray __deprecated_msg("Use NSArray<NSArray *>");
    typedef NSArray NSDictionaryArray __deprecated_msg("Use NSArray");
    typedef NSArray NSURLArray __deprecated_msg("Use NSArray");
    typedef NSArray RCTFileURLArray __deprecated_msg("Use NSArray");
    typedef NSArray NSNumberArray __deprecated_msg("Use NSArray");
    typedef NSArray UIColorArray __deprecated_msg("Use NSArray");
    

      枚举类型用RCT_ENUM_CONVERTER(type, values, default, getter)导出 例如:

    RCT_ENUM_CONVERTER(UIActivityIndicatorViewStyle, (@{
    @"large": @(UIActivityIndicatorViewStyleWhiteLarge),
    @"small": @(UIActivityIndicatorViewStyleWhite),
    }), UIActivityIndicatorViewStyleWhiteLarge, integerValue)
    
      values为字典类型,default在js传递数据为空时候使用         
    方法导出

      RCT_EXPORT_METHOD(<#method#>)可导出方法,js通过注册到全局数组RCTModuleClasses中的实例来调用方法

    RCT_EXPORT_METHOD(getCurrentVersion:(RCTResponseSenderBlock)callback)
    {
    
        NSString *events = [self appVersion];
        callback(@[events]);
    
    }
    
      
    Nativ模块实现

      React Native 在一个单独的串行 GCD 队列中调用 native 模块方法,如果 native 模块需要调用 main-thread-only iOS API例如刷新UI,push viewController 应该在主队列操作:

    -(void)whatYouWantTodo{
      dispatch_async(dispatch_get_main_queue(), ^{
        coding......
      }
    }
    
    Block回调

      对应属性导出,native也可以向js传递数据,RCTBridgeMethod中定义了一个block typedef void (^RCTResponseSenderBlock)(NSArray *response);用来返回数据给js。   

    发送事件到 JavaScript

    RCTEventDispatcher类中定义了一些事件处理方法

    例如Native 模块可以在不被直接调用的情况下向 JavaScript 发送事件信号

    - (void)calendarEventReminderReceived:(NSNotification *)notification
    {
        NSString *eventName = notification.userInfo[@"name"];
        [self.bridge.eventDispatcher sendAppEventWithName:@"EventReminder"
                                               body:@{@"name": eventName}];
    }
    @end
    

    JavaScript 代码可以订阅这些事件:

    var subscription = DeviceEventEmitter.addListener(
    
        'EventReminder',
        (reminder) => console.log(reminder.name)
    );
    

    tips:js需要移除订阅事件

    subscription.remove();
    

    五、简单提提JavaScriptCore

    OC调用js
    -(void)webViewDidFinishLoad:(UIWebView *)webView  
    {  
        //网页加载完成调用此方法     
        //首先创建JSContext 对象(此处通过当前webView的键获取到jscontext)  
        JSContext *context=[webView valueForKeyPath: @"documentView.webView.mainFrame.javaScriptContext"];  
        NSString *alertJS=@"alert('超哥你好,大河向东流')"; //准备执行的js代码  
        [context evaluateScript:alertJS];//通过oc方法调用js的alert
    }
    

      效果如下: 

    block中JSContext注意防止循环引用,

      用[JSContext currentContext]

      JSContext *context1 = [[JSContext alloc] init];
    context1[@"callback"] = ^{
        JSValue *object = [JSValue valueWithNewObjectInContext:[JSContext currentContext]];
        object[@"one"] = @(1);
        object[@"two"] = @(2);
        return object;
    };
    
    JSValue内存泄漏

      JS中对象为弱类型,OC中为强类型直接保存会内存泄漏

    - (void)setOnClickHandler:(JSValue *)handler
    {
        _onClickHandler = [JSManagedValue managedValueWithValue:handler];
        [_context.virtualMachine addManagedReference:_onClickHandler
                                        withOwner:self]
    }
    
    资料参考:
    1. JavaScriptCore的使用和消息传递
    2. JavaScriptCore与内存管理
    3. React Native官方文档中文
    4. 通讯以及消息循环

    知识浅薄,如有错漏请指正。

  • 相关阅读:
    ubuntu16.04编译安装PHP7.0.9,Nginx1.10,Phalcon3.1扩展
    阿里云云大使推广产品集合
    mysql性能优化-慢查询分析、优化索引和配置
    Js学习笔记(二)
    Javascript学习笔记(一)
    HashMap
    JDK 1.8 新特性
    Java转型
    Java IO
    Java正则表达式
  • 原文地址:https://www.cnblogs.com/luanchen/p/5344218.html
Copyright © 2020-2023  润新知