react-native提交給IOS客戶端數(shù)據(jù)來實(shí)現(xiàn)通信或者交互有2種方式:
1、雙向通信的方式:
RN to IOS
原生端:
#import <React/RCTBridgeModule.h>
@implementation RNToNativeEmitter
RCT_EXPORT_MODULE(RNToNativeEmitter);
RCT_EXPORT_METHOD(showText:(NSString *)textValue) textHeight:(CGFloat)height
{
dispatch_async(dispatch_get_main_queue(), ^{
//在主線程種接受并處理數(shù)據(jù)
...
});
}
RN端:
import { NativeModules } from 'react-native';
//RNToNativeEmitter為OC的類名稱蚕断,showText是OC宏注冊的方法名稱
NativeModules.RNToNativeEmitter.showText('顯示的文本', 200);
IOS to RN
原生端:
NativeToRNEmitter.h:
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
@interface NativeToRNEmitter : RCTEventEmitter <RCTBridgeModule>
NativeToRNEmitter.m:
- (NSArray<NSString *> *)supportedEvents {
return @[@"EmitterMsg"];//注冊的RN的方法名稱
}
//注冊本地通知來實(shí)現(xiàn)在其他模塊中調(diào)用sendEventWithName的方法
-(void)beginObserving
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(emitEventInternal:)
name:@"EmitterMsg"
object:nil];
}
-(void)endObserving
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
-(void)emitEventInternal:(NSNotification *)notification
{
[self sendEventWithName:@"EmitterMsg"
body:notification.userInfo];
}
OC在需要的地方調(diào)用:
[[NSNotificationCenter defaultCenter] postNotificationName:@"EmitterMsg"
object:self
userInfo:@{}];
RN接收端:
import { NativeEventEmitter } from 'react-native';
var messager = new NativeEventEmitter(NativeToRNEmitter);
messager.addListener("EmitterMsg", (result) => {
//result為上個代碼快中userInfo參數(shù)的字典對象
});
2躏惋、UI綁定通信的方式
原生端:
首先創(chuàng)建一個繼承于UIView的CategoryView(舉栗子)類,這個類有如下功能:
1础淤、有一個成員方法-(void)showCategoryName:(NSString*)textValue
;
2、內(nèi)部渲染了一個RCTView的RN對象雅潭。
CategoryViewManager.h(類名為目標(biāo)對象的UIView對象名稱+Manager)
#import <React/RCTViewManager.h>
@interface CategoryViewManager: RCTViewManager
CategoryViewManager.m
@interface CategoryViewManager()
@property (nonatomic, strong) CategoryView *cView;
@end
@implementation CategoryViewManager
RCT_EXPORT_MODULE()
//創(chuàng)建目標(biāo)UIView的實(shí)例
- (UIView *)view {
self.cView = [[CategoryView alloc] initWithFrame:CGRectZero];
return self.cView;
}
RCT_EXPORT_METHOD(showCategoryName:(nonnull NSNumber *)reactTag textValue:(nonnull NSString*)textValue) {
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
CategoryView *view = viewRegistry[reactTag];//從注冊的CategoryView集合中獲取實(shí)例
if(view&&[view isKindOfClass:[CategoryView class]]){
[view showCategoryName:textValue];
}
}];
}
@end
RN端:
首先一個組件類用于映射到原生組件
import { requireNativeComponent, findNodeHandle, UIManager } from 'react-native';
const CategoryView = requireNativeComponent('CategoryView', Category);//CategoryView與IOS端類名一致
class Category extends PureComponent {
sendTextValue2Native(textValue) {
//CategoryView與IOS端類名一致,showCategoryName方法名與RCT_EXPORT_METHOD注冊的方法名稱保持一致
UIManager.dispatchViewManagerCommand(
findNodeHandle(this),
UIManager.getViewManagerConfig('CategoryView').Commands.showCategoryName,
[textValue]//此處參數(shù)對應(yīng)原生showCategoryName方法的參數(shù),從第二個開始
);
}
render() {
return <CategoryView>
<View>
{this.props.children}
</View>
</CategoryView>;
}
}
export default Category;
如何使用:
import { Category } from 'local/Category';
<Category ref={ref => { this.categoryRef = ref }}>
<TouchableWithoutFeedback onPress={() => {
this.categoryRef.sendTextValue2Native('測試文本')
}}>
...
</TouchableWithoutFeedback>;
<Category />
這樣在Category組件時却特,原生同樣就會創(chuàng)建一個原生CategoryView的實(shí)例對象扶供。這樣在RN端調(diào)用sendTextValue2Native就可以將內(nèi)容發(fā)送到原生的showCategoryName方法,然后在原生處理相關(guān)的邏輯裂明。文章中的調(diào)用還是較為簡單椿浓,涉及到屬性等更復(fù)雜的使用可以參考文章:https://reactnative.cn/docs/native-components-ios
總結(jié):
2種通信方式應(yīng)用的場景是不一樣的,第一種雙向通信使用相對更加普遍闽晦,因?yàn)橥ㄐ啪帉懛绞脚c2端不會有太多代碼上的耦合度扳碍,第二種方式相對來說就和UI的使用綁定結(jié)合的更緊密,限制也更多一些~