react-native之原生跳转RN

上一篇文章记录了一下RN跳转原生的一些操作, 这次记录一下原生跳转 RN 页面的一些具体操作.

1.创建 rn 页面并注册

创建页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

import React, {Component} from 'react';
import {
View,
Text
} from 'react-native';

export default class Test extends Component{

render() {
return(
<View style={{flex: 1,backgroundColor: 'red'}}>
<Text style={{marginTop: 100}}> 这是 RN 页面</Text>
</View>
)
}
}

在入口函数中注册组件

1
2

AppRegistry.registerComponent('test',()=>test);

2.在原生文件中加载

具体方案

1
2
3
4
•	建立一个NSObject类,让其实现RCTBridgeDelegate协议
• 这个类添加一个bridge属性作为一个全局的bridge,每一次新建RN页面使用这个bridge
• 类中实现预加载方法,在适当的时候可以预加载RCTRootView
• 类中实现RCTRootView的管理,将预加载的RCTRootView保存起来,在用到的时候直接提取

新建一个继承自NSObject的类ReactRootViewManager:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

//.h文件

#import <Foundation/Foundation.h>
#import <React/RCTRootView.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTBridge.h>

NS_ASSUME_NONNULL_BEGIN

@interface ReactRootViewManager : NSObject<RCTBridgeDelegate>


/* 全局唯一的bridge */
@property (nonatomic, strong, readonly) RCTBridge * bridge;
/*
* 获取单例
*/
+ (instancetype)manager;

/*
* 根据viewName预加载bundle文件
* param:
* viewName RN界面名称
* initialProperty: 初始化参数
*/
- (void)preLoadRootViewWithName:(NSString *)viewName;
- (void)preLoadRootViewWithName:(NSString *)viewName initialProperty:(NSDictionary *)initialProperty;

/*
* 根据viewName获取rootView
* param:
* viewName RN界面名称
*
* return: 返回匹配的rootView
*/
- (RCTRootView *)rootViewWithName:(NSString *)viewName;


@end

NS_ASSUME_NONNULL_END

具体实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

#import "ReactRootViewManager.h"

@interface ReactRootViewManager ()
// 以 viewName-rootView 的形式保存需预加载的RN界面
@property (nonatomic, strong) NSMutableDictionary<NSString *, RCTRootView*> * rootViewMap;
@end


@implementation ReactRootViewManager



- (void)dealloc {
_rootViewMap = nil;
[_bridge invalidate];
}

+ (instancetype)manager {
static ReactRootViewManager * _rootViewManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_rootViewManager = [[ReactRootViewManager alloc] init];
});
return _rootViewManager;
}

- (instancetype)init {
if (self = [super init]) {
_rootViewMap = [NSMutableDictionary dictionaryWithCapacity:0];
_bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:nil];
}
return self;
}

- (void)preLoadRootViewWithName:(NSString *)viewName {
[self preLoadRootViewWithName:viewName initialProperty:nil];
}

- (void)preLoadRootViewWithName:(NSString *)viewName initialProperty:(NSDictionary *)initialProperty {
if (!viewName && [_rootViewMap objectForKey:viewName]) {
return;
}
// 由bridge创建rootView
RCTRootView * rnView = [[RCTRootView alloc] initWithBridge:self.bridge
moduleName:viewName
initialProperties:initialProperty];
[_rootViewMap setObject:rnView forKey:viewName];
}

- (RCTRootView *)rootViewWithName:(NSString *)viewName {
if (!viewName) {
return nil;
}
return [self.rootViewMap objectForKey:viewName];
}

#pragma mark - RCTBridgeDelegate
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge {
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
}



@end

3.创建一个 controller 加载 RN 页面

1
2
3
4
5
6
7
//test为注册组件时定义的名称
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.

self.view=[[ReactRootViewManager manager] rootViewWithName:@"test"];
}

4.跳转操作

预加载 RN 页面

在原生的 controller 里预加载 RN 页面

1
2
3
4

//RN页面预加载
NSString *pageName = @"test";
[[ReactRootViewManager manager] preLoadRootViewWithName:pageName initialProperty:nil];

进行跳转

在按钮的 click 事件里进行跳转:

1
2
3
4
5
6
7

- (void)jumpToRN {

RNRootViewController *vc = [[RNRootViewController alloc] init];
[self.navigationController pushViewController:vc animated:YES];

}

效果:

原生跳转 RN

-------------本文结束感谢您的阅读-------------
分享使我快乐!