iOS原生介面與RN介面互調及傳值
阿新 • • 發佈:2018-12-04
文章目錄
3. iOS原生與RN互調及傳值
iOS原生專案(Objective-C)整合React Native(0.57.3版本)圖文教程–(1)基本環境
iOS原生專案(Objective-C)整合React Native(0.57.3版本)圖文教程–(2)整合過程
一個RNDemo(React Native 0.57.3 + ES6)實現(包含RN與原生相互跳轉和通訊)
3.1 RN跳轉原生介面
iOS端
:
- 匯入
#import <React/RCTBridgeModule.h>
. - 需要建立一個類遵守
RCTBridgeModule
協議. RCT_EXPORT_MODULE()
寫呼叫的方法.
RCT_EXPORT_MODULE(); RCT_EXPORT_METHOD(openNativeVC) { dispatch_async(dispatch_get_main_queue(), ^{ AppDelegate *delegate = (AppDelegate *)([UIApplication sharedApplication].delegate); UINavigationController *rootNav = delegate.navigationController; ZYViewController *nativeVC = [[ZYViewController alloc] init]; [rootNav pushViewController:nativeVC animated:YES]; }); }
RN端
:
- 引入
NativeModules
模組. - 建立nativeModule變數.
- RN方法中呼叫對應的函式
var nativeModule = NativeModules.OpenNativeModule;
//跳轉到原生介面
jumpToNative() {
nativeModule.openNativeVC()
}
3.2 RN跳轉原生介面並傳值
所傳引數可以是已知的資料型別,不過最好用NSDictionary
和NSArray
來傳,其實原理就是RN
那邊傳遞個json
過來,在RN
中json
也是個物件
- 原生介面
RCT_EXPORT_METHOD(openNativeVCWithParams:(NSDictionary *)params) { dispatch_async(dispatch_get_main_queue(), ^{ AppDelegate *delegate = (AppDelegate *)([UIApplication sharedApplication].delegate); UINavigationController *rootNav = delegate.navigationController; ZYViewController *nativeVC = [[ZYViewController alloc] init]; nativeVC.params = params; [rootNav pushViewController:nativeVC animated:YES]; }); }
- RN介面
//跳轉到原生介面
jumpToNativeWithParams() {
var params = {"title": "定位地址: 北京"};
nativeModule.openNativeVCWithParams(params)
}
3.3 RN跳轉原生介面並傳值後,原生介面再回調給RN介面相關資訊
- 原生定義block以便回撥
- bridge橋接類,新增方法
- 登入頁面事件回撥
#import "ViewController.h"
@interface ZYLoginViewController : UIViewController
@property (nonatomic, copy) void(^loginBlock) (NSArray* resultArr);
@end
RCT_EXPORT_METHOD(loginState:(NSString *)state callback:(RCTResponseSenderBlock)callback) {
dispatch_async(dispatch_get_main_queue(), ^{
AppDelegate *delegate = (AppDelegate *)([UIApplication sharedApplication].delegate);
ZYLoginViewController *login = [[ZYLoginViewController alloc] init];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:login];
[delegate.navigationController presentViewController:nav animated:YES completion:nil];
//登入成功後,login控制器就可以呼叫block,進行回調了
login.loginBlock = ^(NSArray *resultArr) {
callback(@[[NSNull null], resultArr]);
};
});
}
- (void)doLogin {
self.loginBlock(@[@"zhouyu", @"123456"]);
[self dismiss];
}
- (void)dismiss {
[self dismissViewControllerAnimated:YES completion:nil];
}
3. 4. 原生頁面向RN頁面傳值
主要分兩種情況: 一種是原生介面向下級RN介面傳值; 另一種是原生介面向上級RN介面傳值
3.4.1 原生介面向下級RN介面傳值
這種情況不能用NativeEventEmitter
結合iOS的通知來實現傳值,因為通知是現有監聽者再有傳送者,向下級RN介面傳值,這種方式有可能下級RN頁面還沒加載出來,通知就已經發送了,導致下級RN頁面獲取不到值
可以利用載入js的budle檔案時,利用initialProperties引數進行傳值
NSDictionary *properties = @{@"name": @"zhangsan"};
NSURL *url = [NSURL URLWithString:@"http://localhost:8081/NewIndex.bundle?platform=ios&dev=true"];
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:url moduleName:@"RNDemo" initialProperties:properties launchOptions:nil];
self.view = rootView;
3.4.2 原生介面向上級RN介面傳值
此種情況可以使用RN的NativeEventEmitter
結合iOS的通知來實現傳值
- 原生介面建立事件傳遞的module類,繼承RCTEventEmitter,遵守RCTBridgeModule協議
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
@interface NativeToRNEventEmitter : RCTEventEmitter <RCTBridgeModule>
+ (instancetype)shareInstance;
@end
- 原生module類實現和重寫相關方法
#import "NativeToRNEventEmitter.h"
@interface NativeToRNEventEmitter()
@property (nonatomic,assign)BOOL hasListeners;
@end
@implementation NativeToRNEventEmitter
+ (instancetype)shareInstance {
static NativeToRNEventEmitter *instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[NativeToRNEventEmitter alloc] init];
});
return instance;
}
RCT_EXPORT_MODULE();
//init方法中使用NSNotificationCenter監聽iOS端要傳送事件的操作
- (instancetype)init {
if (self = [super init]) {
[self registerNotifications];
}
return self;
}
//在NSNotification對應的通知方法中將事件傳送給RN
- (void)registerNotifications {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(sendCustomEvent:)
name:@"CustomEventNameNotifation"
object:nil];
}
- (void)sendCustomEvent:(NSNotification *)notification {
// NSString *eventName = notification.userInfo[@"name"];
if (self.hasListeners) {
[self sendEventWithName:@"CustomEventName" body:@{@"name": @"東皇大廈"}];
}
}
#pragma RCTEventEmitter
//重寫supportedEvents方法,在這個方法中宣告支援的事件名稱
- (NSArray<NSString *> *)supportedEvents {
return @[@"CustomEventName"];
}
// 在新增第一個監聽函式時觸發
-(void)startObserving {
self.hasListeners = YES;
}
-(void)stopObserving {
self.hasListeners = NO;
}
@end
- RN介面: 匯入NativeEventEmitter
var nativeToRNEventModule = NativeModules.NativeToRNEventEmitter;
componentDidMount() {
var eventEmitter = new NativeEventEmitter(nativeToRNEventModule);
this.listener = eventEmitter.addListener("CustomEventName", (result) => {
alert("監聽到通知事件" + result);
this.setState({
add: result.name
});
})
}
componentWillUnmount() {
this.listener && this.listener.remove();
}