iOS原生界面与RN界面互调及传值

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kuangdacaikuang/article/details/83384008

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();
}

在这里插入图片描述

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/kuangdacaikuang/article/details/83384008