React-Native iOS - How can I navigate to a non-React-Native view (native iOS view controller) from a React-Native view with a button press?

前端 未结 3 1822
清歌不尽
清歌不尽 2020-12-03 05:37

The RN doco and other examples show how to launch a React-Native view from a native iOS view controller, but not the other way around. Can someone explain how I can do this

3条回答
  •  有刺的猬
    2020-12-03 06:33

    I was able to figure this out. In my case, I am using an Obj-C base project (which is the RN default) with my own Swift native view controller. My solution is here in case this comes up for anyone else:

    Simply put, the answer is to use an RCTBridge module to allow the RN JavaScript to call a native iOS method.

    Here is an outline of the components, followed by the implementation:

    1. AppDelegate.h/.m - Initialize the RN JavaScript index file for the initial RN view, also setup a method to swap the root view controller to a native view controller (this method will be called from the RTCBridge module.

    2. MyViewController.swift - A normal UIViewController with a standard implementation.

    3. MyProject-Bridging-Header.h - provides Obj-C <-> Swift communication

    4. ChangeViewBridge.h/.m - This provides the binding to allow you to call native iOS methods from the RN JavaScript.

    5. index.ios.js - Initialize your custom RCTBridge module and call the bound method to switch to your native view with a button press.

    AppDelegate.h:

    #import 
    
    @interface AppDelegate : UIResponder  {
      NSDictionary *options;
      UIViewController *viewController;
    }
    
    @property (nonatomic, strong) UIWindow *window;
    
    - (void) setInitialViewController;
    - (void) goToRegisterView; // called from the RCTBridge module
    
    @end
    

    AppDelegate.m:

    #import "AppDelegate.h"
    #import 
    #import 
    #import "FidoTestProject-Swift.h" // Xcode generated import to reference MyViewController.swift from Obj-C
    
    @implementation AppDelegate
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
      options = launchOptions;
      [self setInitialViewController];
      return YES;
    }
    
    - (void) setInitialViewController {
      NSURL *jsCodeLocation;
    
      jsCodeLocation = [NSURL URLWithString:@"http://192.168.208.152:8081/index.ios.bundle?platform=ios&dev=true"];
    
      RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation moduleName:@"FidoTestProject" initialProperties:nil launchOptions:options];
    
      self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
      UIViewController *rootViewController = [UIViewController new];
      rootViewController.view = rootView;
      self.window.rootViewController = rootViewController;
    
      viewController = rootViewController;
    
      [self.window makeKeyAndVisible];
    }
    
    // this method will be called from the RCTBridge
    - (void) goToNativeView {
      NSLog(@"RN binding - Native View - MyViewController.swift - Load From "main" storyboard);
      UIViewController *vc = [UIStoryboard storyboardWithName:@"main" bundle:nil].instantiateInitialViewController;
      self.window.rootViewController = vc;
    }
    
    @end
    

    MyViewController.swift:

    class RegisterViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
            print("MyViewController loaded...")
            // standard view controller will load from RN
        }
    }
    

    MyProject-Bridging-Header.h:

    @import Foundation;
    @import UIKit;
    @import CoreLocation;
    @import AVFoundation;
    
    #import "React/RCTBridge.h"
    #import "React/RCTBridgeModule.h"
    #import "React/RCTBundleURLProvider.h"
    #import "React/RCTRootView.h"
    #import "AppDelegate.h"
    

    ChangeViewBridge.h:

    #import 
    
    @interface ChangeViewBridge : NSObject 
    
    - (void) changeToNativeView;
    
    @end
    

    ChangeViewBridge.m:

    #import "RegisterBridge.h"
    #import "FidoTestProject-Swift.h"
    #import "AppDelegate.h"
    
    @implementation ChangeViewBridge
    
    // reference "ChangeViewBridge" module in index.ios.js
    RCT_EXPORT_MODULE(ChangeViewBridge);
    
    RCT_EXPORT_METHOD(changeToNativeView) {
      NSLog(@"RN binding - Native View - Loading MyViewController.swift");
      AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
      [appDelegate goToNativeView];
    }
    
    @end
    

    index.ios.js

    /**
     * Sample React Native App
     * https://github.com/facebook/react-native
     * @flow
     */
    
    'use strict';
    
    import React, { Component } from 'react';
    import {
      AppRegistry,
      StyleSheet,
      Alert,
      Text,
      View,
      NativeModules,
      TouchableHighlight
    } from 'react-native';
    
    export default class FidoTestProject extends Component {
    
      constructor(props) {
         super(props)
         this.done = false;
       }
    
        _changeView() {
          this.done = true;
          this.render();
          NativeModules.ChangeViewBridge.changeToNativeView();
        }
    
      render() {
        if (!this.done) {
          return (
            
               this._changeView()}>
                
                  Press to Change to Native View
                
              
            
          );
        } else {
          return ();
        }
      }
    };
    
    const styles = StyleSheet.create({
      container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#F5FCFF',
      }
    });
    
    AppRegistry.registerComponent('FidoTestProject', () => FidoTestProject);
    

提交回复
热议问题