美文网首页react-native相关
iOS - React-Native : 原生跳转RN/RN跳转

iOS - React-Native : 原生跳转RN/RN跳转

作者: Jamesholy | 来源:发表于2019-03-18 17:56 被阅读0次

    React-Native开发经常遇到需要使用跳转原生界面或者要嵌入原生界面在RN界面中等等交互。此处记录一下自己的一些处理方式

    1.RN跳转原生界面

    2.RN嵌入原生界面

    3.原生跳转RN界面


    RN跳转原生界面

    第一步 导出方法供RN调用

    新建交互类,如有该类可忽略

    .h

    #import <Foundation/Foundation.h>
    #import <React/RCTBridgeModule.h>
    #import <React/RCTLog.h>
    // RN调用原生的
    @interface xkMerchantModule : NSObject<RCTBridgeModule>
    @end
    

    .m

    #import "xkMerchantModule.h"
    #import "NSObject+XKController.h"
    #import "NativeController.h"
    #define KEY_WINDOW   [UIApplication sharedApplication].keyWindow
    
    @interface xkMerchantModule()
    @end
    
    @implementation xkMerchantModule
    RCT_EXPORT_MODULE();
    
    
    RCT_EXPORT_METHOD(pushNative)
    {
      dispatch_async(dispatch_get_main_queue(), ^{
        NativeController *vc =[NativeController new];
        [self.getCurrentUIVC.navigationController pushViewController:vc animated:YES];
      });
    }
    @end
    

    #######注:rn调用是不在主线程,需要回到主线程进行UI操作,否则可能崩溃。

    第二步 RN中调用方法

    相应界面导入原生交互模块

    import {Text, View, Button, NativeModules} from 'react-native';
    

    使用原生提供的方法进行跳转

    class SettingsScreen extends React.Component {
        render() {
            return (
                <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
                    <Button
                        title="跳转原生界面"
                        onPress={() => {
                            NativeModules.xkMerchantModule.pushNative();
                        }}
                    />
                </View>
            );
        }
    }
    

    对于RN跳转的原生界面,原生界面返回时使用原生的pop就可以完成原生回到RN界面的功能

    RN嵌入原生界面

    在开发一些需求时,可能有些界面必须使用原生界面。在某些场景,并不是RN跳转到原生,而是原生界面嵌入到RN界面中,比如原生界面作为RN tabBar中的一个界面。
    (具体细节 参考:https://github.com/crazycodeboy/RNStudyNotes)

    第一步 将需要嵌入的界面/控制器 制作成RN的组件

    rn无法将原生控制器直接嵌入,所以需要把嵌入的界面以UIView的形式创建。
    创建桥接代码

    .h

    #import <React/RCTViewManager.h>
    @interface MyTableView : RCTViewManager
    @end
    

    .m

    #import "MyTableView.h"
    #import "FirstViewController.h"
    
    @implementation MyTableView
    
    RCT_EXPORT_MODULE()
    
    - (UIView *)view {
      FirstViewController *vc = [[FirstViewController alloc] init];
      vc.backgroundColor = [UIColor redColor];
      return vc;
    }
    @end
    

    FirstViewController 其实是UIView

    第二步 RN代码中使用原生组件

    新建组件类 MyTableView.js 导出原生的组件

    import { requireNativeComponent } from 'react-native';
    module.exports = requireNativeComponent('MyTableView', null);
    

    使用

    import MyTablView from './MyTableView'
    
    class TablView extends React.Component {
        render() {
            return (
                <MyTablView style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
                </MyTablView>
            );
        }
    }
    
    const TabNavigator = createBottomTabNavigator({
        RN: { screen: RootStack },
        Native: { screen: TablView },
    });
    

    原生跳转RN界面

    第一步 导出原生使用的界面

    import {AppRegistry} from 'react-native';
    import App from './nativeInsert';
    import TestPage from './TestPage'
    import {name as appName} from './app.json';
    
    AppRegistry.registerComponent(appName, () => App);
    
    AppRegistry.registerComponent('TestPageName', () => TestPage);
    

    导出TestPageName。有多少界面需要导出原生使用就写多少

    第二步 原生加载RN界面

    RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                           moduleName:@"TestPageName"
                                                    initialProperties:nil
                                                       launchOptions:nil];
    BaseRNViewController *rootViewController = [BaseRNViewController new];    rootViewController.view = rootView;
    [self.navigationController pushViewController:rootViewController animated:YES];
     });
    

    第三步 处理RN pop回原生

    通RN跳转原生的思路一致,提供原生方法供RN调用

    @interface xkMerchantModule()
    @end
    
    @implementation xkMerchantModule
    RCT_EXPORT_MODULE();
    RCT_EXPORT_METHOD(popNative)
    {
      dispatch_async(dispatch_get_main_queue(), ^{
        [self.getCurrentUIVC.navigationController popViewControllerAnimated:YES];
      });
    }
    
    @end
    

    RN代码中:

     <Button  title={"我是RN界面 p o p 回到原生界面" + this.props.itemId}
                        onPress={() => {
                            NativeModules.xkMerchantModule.popNative();
                        }}
                    />
    

    注:上述原生跳转RN界面是最开始的方案,确实是可以实现的,但是在调试时,每次由原生跳转到RN时,都会重新加载JS资源,会出现白屏的现象。并且新的RN界面,和最初的RN界面的环境不一致,RN内部无法获取之前的全局配置以及缓存信息。

    所以需要有两个优化点:
    1.提前加载资源
    2.保证RN环境的一致。

    如果对于RN项目,Appdelegate里已经调用了下面方法了加载过了资源一次。

    - (instancetype)initWithBundleURL:(NSURL *)bundleURL
                           moduleName:(NSString *)moduleName
                    initialProperties:(NSDictionary *)initialProperties
                        launchOptions:(NSDictionary *)launchOptions
    {
      RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:bundleURL
                                                moduleProvider:nil
                                                 launchOptions:launchOptions];
    
      return [self initWithBridge:bridge moduleName:moduleName initialProperties:initialProperties];
    }
    
    

    查看源码内部,其实创建了一个桥接类RCTBridge *bridge
    这里我们可以将该bridge保存下来,

     RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                          moduleName:@"xkMerchant"
                                                   initialProperties:nil
                                                       launchOptions:launchOptions];
      rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
      [ReactRootViewManager manager].bridge = rootView.bridge;
    

    下次使用bridge加载新的rootView,也就是RN提供给我们的下列方法创建。即可解决重新加载时间长和环境不一致的问题。

    - (instancetype)initWithBridge:(RCTBridge *)bridge
                        moduleName:(NSString *)moduleName
                 initialProperties:(NSDictionary *)initialProperties NS_DESIGNATED_INITIALIZER;
    
     RCTRootView * rnView = [[RCTRootView alloc] initWithBridge:[ReactRootViewManager manager].bridge
                                                      moduleName:viewName
                                               initialProperties:initialProperty];
    

    如果对于原生项目想集成RN,进行部分页面跳转。实现逻辑同理,在使用之前,
    先调用RCTBridge初始化方法,提前加载资源,再缓存bridge即可。

    [[RCTBridge alloc] initWithBundleURL:bundleURL
                                                moduleProvider:nil
                                                 launchOptions:launchOptions];
    

    demo:https://github.com/sy5075391/iOS-native-RN.git

    相关文章

      网友评论

        本文标题:iOS - React-Native : 原生跳转RN/RN跳转

        本文链接:https://www.haomeiwen.com/subject/ovdbmqtx.html