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":@""...})
- 效果(chrome控制台打印)
交互
通过上面的导出属性,枚举,方法 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