React Native(以下简称RN)开发app过程中大部分都可以在JS端完成,但是也有一些功能是需要原生端来完成的。这时RN与原生端就不可避免的需要进行交互,比如页面跳转和数据传递。本篇文章主要以RN——原生、原生——RN——原生为例来讲解如何进行基本的页面跳转操作。
关于页面跳转,我写了三个demo。这里发下地址:
RNAddNative
和RNPushToNative
差不多,都是RN页面跳转到原生的实例,区别是一个RNAddNative
使用了react-native-navigation
,RNPushToNative
使用了react-navigation
。在试过两种导航库之后,我更倾向于使用react-native-navigation
,谁用谁知道。
NativeJumpToRN
是原生页面跳转到RN,再从RN跳转到原生的示例。
在实际开发中,我认为RN页面(JS写的)和原生页面(iOS和Android写的)之间最好还是做到分离开来,通用页面还是用RN实现,各自需要定制化的、功能复杂的页面还是原生写。尽量不要搞RN和原生组件内嵌,毕竟写UI组件的话是相对比较简单的事,没必要在原生页面内嵌一个RN页面作为组件,或者RN页面内嵌一个原生组件。将两者分离开,有需要就直接页面间进行跳转,这样也方便处理。
RN——Native
如果你还没有创建原生项目,那直接react-native init
创建一个RN项目,android和iOS的工程会自动给你创建好。android和iOS的工程都是可以拿来独立开发的,不会受RN的影响。如果已经有原生项目了,请自行搜索如何集成react native到现有原生项目,为了精简篇幅这里不多做赘述。
以RNPushToNative为例先来说明一下如何从RN跳转到原生页面。从RN跳转到原生,其实是在原生端创建Module类通过桥接的方式导出到JS端供JS代码调用原生端代码来实现的。
Android
Android分三步:
1. 定义Module类,继承ReactContextBaseJavaModule
在Module类中,重写getName方法声明Module类名称,创建我们自己的方法用来做页面跳转。
2. 定义Package类,实现接口ReactPackage
Package类需要实现createNativeModules
和createViewManagers
两个方法。在createNativeModules
中初始化Module类并添加到集合
3. 定义Application类,继承android的Application,并实现ReactApplication接口。
在getPackages方法中初始化Package类,并添加到集合。
RN项目创建的时候Application类就有了,不需要再创建。如果是集成到现有原生项目,就需要手动修改Application类。
Module类核心代码:
public class OpenNativeModule extends ReactContextBaseJavaModule {
private ReactContext mReactContext;
public OpenNativeModule(ReactApplicationContext context) {
super(context);
this.mReactContext = context;
}
@Override
public String getName() {
return "OpenNativeModule";
}
@ReactMethod
public void openNativeVC() {
Intent intent = new Intent();
intent.setClass(mReactContext, SettingsActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mReactContext.startActivity(intent);
}
}
Package类核心代码:
public class TestReactPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(
ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new OpenNativeModule(reactContext));
return modules;
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
Application类核心代码:
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new VectorIconsPackage(),
new TestReactPackage()
);
}
iOS
iOS端比Android就简单多了,只需要创建一个Module类,实现RCTBridgeModule协议就行了。
OpenNativeModule.h
代码:
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
@interface OpenNativeModule : NSObject<RCTBridgeModule>
@end
OpenNativeModule.m
代码:
#import "OpenNativeModule.h"
#import "AppDelegate.h"
#import "NativeViewController.h"
@implementation OpenNativeModule
RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(openNativeVC) {
dispatch_async(dispatch_get_main_queue(), ^{
AppDelegate *delegate = (AppDelegate *)([UIApplication sharedApplication].delegate);
UINavigationController *rootNav = delegate.navController;
NativeViewController *nativeVC = [[NativeViewController alloc] init];
[rootNav pushViewController:nativeVC animated:YES];
});
}
@end
最后在RN端调用:
import React from 'react';
import {View, Text, Button, NativeModules} from 'react-native';
var nativeModule = NativeModules.OpenNativeModule;
export default class HomeScreen extends React.Component {
render() {
return (
<View>
<Text>首页</Text>
<Button title={'跳转到原生页面'} onPress={() => {
this.jumpToNativeView();
}}/>
</View>
)
}
jumpToNativeView() {
nativeModule.openNativeVC();
}
}
Native——RN——Native
原生跳转到RN再由RN跳转到原生页面,这个示例可以参考NativeJumpToRN。RN到原生的跳转与上述原理相同,不同的是原生到RN的跳转。这个demo中我只是将原生项目启动后的初始页面由RN页面改为了原生页面,而原本的RN页面我将它内嵌在一个原生页面当中了。
对于Android来说,原本的启动页面是MainActivity
, MainActivity
就对应着RN页面。 我创建了一个LaunchActivity
作为启动页面,在AndroidManifest.xml
中将其设置为启动页。在LaunchActivity
中添加一个button,设置点击跳转到MainActivity
就完成了原生页面到RN的跳转,是不是很简单?
public class LaunchActivity extends AppCompatActivity {
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_launch);
button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(LaunchActivity.this, MainActivity.class);
startActivity(intent);
}
});
}
}
iOS端也一样,RN页面的初始化是在AppDelegate
中完成的,这里我们将window的rootViewController
改为原生的UIViewController
。AppDelegate
核心代码:
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
_navController = [[UINavigationController alloc] initWithRootViewController:[[HomeViewController alloc] init]];
self.window.rootViewController = _navController;
[self.window makeKeyAndVisible];
return YES;
}
@end
在HomeViewController
中创建一个button,点击button跳转到RNViewController
。
@implementation HomeViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"这是iOS原生页面";
self.view.backgroundColor = [UIColor brownColor];
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 200, 50)];
[button setTitle:@"点击跳转到RN页面" forState:UIControlStateNormal];
[button addTarget:self action:@selector(onClickButton) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
}
- (void)onClickButton {
RNViewController *vc = [[RNViewController alloc] init];
[self.navigationController pushViewController:vc animated:YES];
}
@end
AppDelegate
中RN页面的初始化操作放到RNViewController
中来:
@implementation RNViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"这是RN页面";
NSURL *jsCodeLocation;
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName:@"NativeJumpToRN"
initialProperties:nil
launchOptions:nil];
rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
self.view = rootView;
}
这样就完成了原生到RN的跳转。
作者:不變旋律
链接:https://juejin.im/post/5b20810ff265da6e432e697c
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。