React-native 自定义模块

React-Native 系统模块

例如相机,摄像头,录音等等需要调用原生能力的API都是通过模块完成

JSX和OC交互简单说明

1.JSX 和 OC 环境中各保留一份所有模块配置对象
2.JSX调用对应模块,React就会调用OC对应模块的对应方法开发准备开发准备

准备

XCode,React-native环境,WebStrome

创建工程并且运行

react-native init Custom --version 0.48.3
cd Custom
react-native run-ios

修改index.ios.js

import { NativeModules} from 'react-native';
export default class Custom extends Component {
    componentWillMount(){
        console.log(NativeModules) 打印所有模块
    }
    render...
}

开发插件

  • 打开Custom下的XCode工程
  • 创建模块LocalTimeManager 实现协议RCTBridgeModule

        #import <Foundation/Foundation.h>
        #import <React/RCTBridgeModule.h>
        @interface LocalTimeManager : NSObject<RCTBridgeModule>
        @end
  • 编写LocalTimeManager.m

        #import "LocalTimeManager.h"
        @implementation LocalTimeManager
        //修改源文件后注意重新运行
        //如果仅仅导出模块 无常量和方法  JSX是没有这个模块的
        //导出该模块到JSX环境中
        RCT_EXPORT_MODULE() 
        //导出常量
        - (NSDictionary *)constantsToExport{
              return @{@"name":@"无名氏"};
        }
        //导出方法
        RCT_EXPORT_METHOD(create:(NSString *)a BB:(double)bb){}
        RCT_REMAP_METHOD(AABB,A:(double)a B:(double)b){}
        //指定方法执行队列
        -(dispatch_queue_t)methodQueue{
              return dispatch_get_main_queue()
        }
        @end
        //扩展RCTConvert 
        typedef NS_ENUM(NSInteger, TimeType) {
          Year,Month,Day,Hour,Minu,Second
        };
        @implementation RCTConvert (AAAAA)
            RCT_ENUM_CONVERTER(TimeType,(@{@"Year":@(Year),@"Month":@(Month),...}),Year, integerValue);
        @end
    • 效果(chrome控制台打印)
      这里写图片描述
    • 导出模块

      RCT_EXPORT_MODULE()  导出模块为LocalTimeManager
      RCT_EXPORT_MODULE(AAManager)  导出模块为AAManager
      
    • 导出常量

      1:作为导出模块的属性存在
      2:已经导出的属性是不会随你的 constantsToExport返回值改变而改变
      3:使用   LocalTimeManager.Pro_Name
    • 导出方法

      方式 
             A:RCT_EXPORT_METHOD(create:(NSString *)a BB:(double)bb){}
             B:RCT_REMAP_METHOD(AABB,A:(double)a B:(double)b){}
          A:JSX端方法名会以第一部分create来命名
          B:JSX端方法名会AABB来命名
      
      参数:
              string (NSString)
              number (NSInteger, float, double, CGFloat, NSNumber)
              boolean (BOOL, NSNumber)
              array (NSArray) 包含本列表中任意类型
              object (NSDictionary) 包含string类型的键和本列表中任意类型的值
              function (RCTResponseSenderBlock)
          说明:
              函数
                  1:OC函数参数 可以为RCTResponseErrorBlock/RCTResponseSenderBlock/RCTPromiseResolveBlock/RCTPromiseRejectBlock
                     > 如果为四个单独出现在函数中 JSX需要传入一个函数作为回调
                     > 如果RCTPromiseResolveBlock/RCTPromiseRejectBlock同时作为在函数最后两个参数。那么JSX端不需要传对应参数,而是Promise作为函数的返回值。
                     > 函数不一定一定要在该方法中执行。可以保存在合适的地方执行
      
                 2:OC函数参数个数无限制,但你必须在合适的时候回调一个。以保证内存不泄露
      
                 3:JSX函数参数不是同步回调 (但是你可以你也可以使用async达到同步目的)
      
                 4:OC函数调用线程你不要做任何假想。如果你控制需要指定执行队列。当然你可以在某个方法中异步执行
      
              自定义参数类型:(使用RCTConvert来自定义)
                  A:扩展枚举
                      1:如上扩展枚举
                      2:导出以便JS调用 在相关模块中
                          -(NSDictionary *)constantsToExport{
                              常量.....,
                              @"Year":@(Year)},
                              @"Month":@(Month)
                              ...
                          }
                      3:JSX使用
                          RCT_REMAP_METHOD(AABB,Dir:(TimeType)type){}
                          JSX:AABB(LocalTimeManager.Year)
      
                  B:扩展实例
                      1:OC类
                          @interface TimeInfo : NSObject
                              @property(nonatomic,copy)NSString *Year;
                              @property(nonatomic,copy)NSString *Month;
                              @property(nonatomic,copy)NSString *Day;
                          @end
                      2:扩展RCTConvert
                          @implementation RCTConvert (TimeInfo)
                          -(TimeInfo*)TimeInfo:(id)info{
                              //方法名和类名一致
                            NSDictionary *dic = [RCTConvert NSDictionary:info];
                                TimeInfo *res = [[TimeInfo alloc] init];
                                res.Year = dic[@"year"];
                                res.Month = dic[@"month"];
                                res.Day = dic[@"day"];
                                return res;
                          }
                          @end
                      3:JSX使用
                          RCT_REMAP_METHOD(CCDD,Dir:(TimeInfo*)info){}
                          CCDD(@{"year":"",@"month":@""...})
      

交互

通过上面的导出属性,枚举,方法 JSX可以做到调用原生。但是目前原生还无法调用JSX。

RCTEventEmitter 赋予模块调用JSX代码的能力,利用事件通知

A:修改模块基类
    #import <React/RCTEventEmitter.h>
    @interface LocalTimeManager : RCTEventEmitter
    RCTEventEmitter 已经实现了RCTBridgeModule 你的代码无需做其他修改
    @end
B:设置支持的事件
    -(NSArray<NSString *> *)supportedEvents{
        return @[@"Event1",@"Event2",...];
     }
C:jSX订阅事件
    import { NativeEventEmitter, NativeModules } from 'react-native';
    const { LocalTimeManager } = NativeModules;
    const LocalTimeManagerEmitter = new NativeEventEmitter(LocalTimeManager);
    subscription = LocalTimeManagerEmitter.addListener('Event1',
            (body) =>

    );
    //移除监听  subscription.remove();
 D:OC发布事件Pulish
     [self sendEventWithName:@"Event1" body:id];
 E:解决JSX还没订阅的Pulish
     -(void)startObserving { 注册第一个监听是调用 }
     -(void)stopObserving { 移除最后一个监听调用 }

Swift 和 OC混编

React目前仅仅有OC版本,这里的混编值得是你的模块由Swift开发

A:桥接文件导入
    #import <React/RCTBridgeModule.h>
    #import <React/RCTConvert.h>
    #import <React/RCTEventEmitter.h>
B:创建模块
    import React
    @objc(LocalTimeManager)
    class LocalTimeManager: RCTEventEmitter {
        @objc func constantsToExport()->Dictionary<String, String>{
             return ["name":"朱子豪2"];
        }

        @objc func ILoveYou( _ name:String,time:NSDate,call:((Array<Any>)->Void))->Void{
            由于Swift 和 OC 方法参数声明不一致,Swift方法第一个参数外部名称不需要(指定为 _ )
            call([1,2]);
        }
    }
C:方法导出 
    创建LocalTimeManager.m文件
    #import <Foundation/Foundation.h>
    #import <React/RCTBridgeModule.h>
    #import <React/RCTConvert.h>
    #import <React/RCTEventEmitter.h>
    @interface RCT_EXTERN_MODULE(LocalTimeManager, RCTEventEmitter )
        RCT_EXTERN_METHOD(ILoveYou:(NSString *)name time:(NSDate *)date call:(RCTResponseSenderBlock)call);
        。。。
    @end

献上代码

//
//  LocalTimeManager.h
//  Custom
//
//  Created by 朱子豪 on 2018/1/31.
//  Copyright © 2018年 Facebook. All rights reserved.
//

#import <Foundation/Foundation.h>
 #import <React/RCTBridgeModule.h>
#import <React/RCTConvert.h>
#import <React/RCTEventEmitter.h>
@interface LocalTimeManager : RCTEventEmitter
@end


@interface TimeInfo : NSObject
@property(nonatomic,copy)NSString *Year;
@property(nonatomic,copy)NSString *Month;
@property(nonatomic,copy)NSString *Day;
@end


@interface RCTConvert (TimeType)
@end

@interface RCTConvert (TimeInfo)
@end

/*******************************/

//
//  LocalTimeManager.m
//  Custom
//
//  Created by 朱子豪 on 2018/1/31.
//  Copyright © 2018年 Facebook. All rights reserved.
//

#import "LocalTimeManager.h"
typedef NS_ENUM(NSInteger, TimeType) {
  Year,Month,Day,Hour,Minu,Second
};
@implementation LocalTimeManager
RCT_EXPORT_MODULE() //导出该模块到JSX环境中
- (NSDictionary *)constantsToExport{//导出常量
  return @{
           @"name":@"无名氏",
           @"Year":@(Year),
           @"Month":@(Month),
           @"Day":@(Day),
           @"Hour":@(Hour),
           @"Minu":@(Minu),
           @"Second":@(Second)
        };
}
RCT_EXPORT_METHOD(create:(NSString *)a pars:(double)bb){}
RCT_REMAP_METHOD(create2,items:(NSArray*)items){}
-(dispatch_queue_t)methodQueue{return dispatch_get_main_queue();}
@end
/******/
@implementation TimeInfo
@end
/******/
@implementation RCTConvert (TimeType)
RCT_ENUM_CONVERTER(TimeType, (@{
                                                       @"Year":@(Year),
                                                       @"Month":@(Month),
                                                       @"Day":@(Day),
                                                       @"Hour":@(Hour),
                                                       @"Minu":@(Minu),
                                                       @"Second":@(Second),
                                                       }), Year, integerValue);



@end
/******/
@implementation RCTConvert (TimeInfo)
-(TimeInfo*)TimeInfo:(id)info{
  NSDictionary *dic = [RCTConvert NSDictionary:info];
  TimeInfo *res = [[TimeInfo alloc] init];
  res.Year = dic[@"year"];
  res.Month = dic[@"month"];
  res.Day = dic[@"day"];
  return res;
}
@end
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值