1. 程式人生 > >iOS原生介面與RN介面互調及傳值

iOS原生介面與RN介面互調及傳值

文章目錄

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與原生相互跳轉和通訊)

iOS原生介面與RN介面互調及傳值

3.1 RN跳轉原生介面

iOS端:

  1. 匯入#import <React/RCTBridgeModule.h>.
  2. 需要建立一個類遵守RCTBridgeModule協議.
  3. 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端:

  1. 引入NativeModules模組.
  2. 建立nativeModule變數.
  3. RN方法中呼叫對應的函式
var nativeModule = NativeModules.OpenNativeModule;
//跳轉到原生介面
jumpToNative() {
    nativeModule.openNativeVC()
}

3.2 RN跳轉原生介面並傳值

所傳引數可以是已知的資料型別,不過最好用NSDictionaryNSArray來傳,其實原理就是RN那邊傳遞個json過來,在RNjson也是個物件

  1. 原生介面
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];
    });
}
  1. RN介面
    //跳轉到原生介面
    jumpToNativeWithParams() {
        var params = {"title": "定位地址: 北京"};
        nativeModule.openNativeVCWithParams(params)
    }

3.3 RN跳轉原生介面並傳值後,原生介面再回調給RN介面相關資訊

  1. 原生定義block以便回撥
  2. bridge橋接類,新增方法
  3. 登入頁面事件回撥
#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頁面傳值

React Native中文網: 和原生端通訊

React Native中文網: 回撥函式及通訊

主要分兩種情況: 一種是原生介面向下級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的通知來實現傳值

  1. 原生介面建立事件傳遞的module類,繼承RCTEventEmitter,遵守RCTBridgeModule協議
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>

@interface NativeToRNEventEmitter : RCTEventEmitter <RCTBridgeModule>
+ (instancetype)shareInstance;
@end
  1. 原生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
  1. 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();
}

在這裡插入圖片描述

在這裡插入圖片描述