React-Native iOS - 如何通过按下按钮从 React-Native 视图导航到非 React-Nativ



RN doco 和其他示例展示了如何从本机 iOS 视图控制器启动 React-Native 视图,但不是相反。 有人可以解释我如何做到这一点吗?

我能够弄清楚这一点。就我而言,我正在使用带有我自己的 Swift 本机视图控制器的 Obj-C 基础项目(这是 RN 默认值(。我的解决方案在这里,以防万一其他人出现这种情况:

简单地说,答案是使用 RCTBridge 模块来允许 RN JavaScript 调用原生 iOS 方法。

以下是组件的概述,然后是实现:

  1. AppDelegate.h/.m- 初始化初始 RN 视图的 RN JavaScript 索引文件,同时设置一个将根视图控制器交换为本机视图控制器的方法(此方法将从 RTCBridge 模块调用。

  2. MyViewController.swift- 具有标准实现的普通UIViewController

  3. MyProject-Bridging-Header.h- 提供Obj-C <->快速通信

  4. ChangeViewBridge.h/.m- 这提供了绑定,允许您从RN JavaScript调用本机iOS方法。

  5. index.ios.js- 初始化自定义 RCTBridge 模块,并调用绑定方法以通过按下按钮切换到本机视图。

AppDelegate.h

#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate> {
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 <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#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 <React/RCTBridgeModule.h>
@interface ChangeViewBridge : NSObject <RCTBridgeModule>
- (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 (
<View style={styles.container}>
<TouchableHighlight onPress={() => this._changeView()}>
<Text color="#336699">
Press to Change to Native View
</Text>
</TouchableHighlight>
</View>
);
} else {
return (<View></View>);
}
}
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
}
});
AppRegistry.registerComponent('FidoTestProject', () => FidoTestProject);

Swift 5 对此答案的更新。由于

https://github.com/facebook/react-native/issues/1148#issuecomment-102008892

https://stackoverflow.com/a/46007680/7325179 - 由 MStrapko 回答

https://codersera.com/blog/react-native-bridge-for-ios/?unapproved=2851&moderation-hash=77e42524b246d2fda0f763a496156db5#comment-2851 - 威廉·道森的详尽解释和教程

进入解决方案:

在应用程序代表中.swift

import Foundation
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var bridge: RCTBridge!

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let jsCodeLocation: URL

jsCodeLocation = RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index.js", fallbackResource:nil)
let rootView = RCTRootView(bundleURL: jsCodeLocation, moduleName: "RNModuleName", initialProperties: nil, launchOptions: launchOptions)

self.window = UIWindow(frame: UIScreen.main.bounds)
let reactNativeViewController = UIViewController()
reactNativeViewController.view = rootView
let reactNavigationController = UINavigationController(rootViewController: reactNativeViewController)
self.window?.rootViewController = reactNavigationController
self.window?.makeKeyAndVisible()

return true
}
//  func goToReactNative() {
//    window?.rootViewController?.dismiss(animated: true)
//  }
func goNativeStoryboard() {
DispatchQueue.main.async {
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController()
if let vc = vc {
(self.window?.rootViewController as? UINavigationController)?.pushViewController(vc, animated: true)
}
}
}
}

您的视图控制器.swift

Your regular code

您的应用桥接标头。请注意,还有一些额外的标题,您可能不需要。

#import "React/RCTBridgeModule.h"
#import "React/RCTBridge.h"
#import "React/RCTEventDispatcher.h"
#import "React/RCTRootView.h"
#import "React/RCTUtils.h"
#import "React/RCTConvert.h"
#import "React/RCTBundleURLProvider.h"
#import "RCTViewManager.h"
#import "React/RCTEventEmitter.h"

正在连接文件.swift

@objc(Connect)
class Connect: NSObject {
@objc func goToNative() -> Void {
DispatchQueue.main.async {
if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
appDelegate.goNativeStoryboard()
}
}
}
}

连接.m

#import "React/RCTViewManager.h"
@interface RCT_EXTERN_MODULE(Connect, RCTViewManager)
RCT_EXTERN_METHOD(goToNative)
@end

ReactNativeFile.js

import React, { Component } from 'react';
import { StyleSheet, View, NativeModules, Text, TouchableOpacity } from 'react-native';
const { Connect } = NativeModules;
export default class Feed extends Component {
constructor(props) {
super(props)
this.done = false;
}
_changeView() {
this.done = true;
Connect.goToNative()
}
render() {
return (
<View style={styles.container}>
<TouchableOpacity onPress={() => this._changeView()}>
<Text color="#336699">
Press to Change to Native View
</Text>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'pink',
alignItems: 'center',
justifyContent: 'center',
}
});

就是这样,它对我有用,希望它也对你有用。再次感谢所有参考来源。

此解决方案几乎没有改进。使用目前的解决方案,没有办法从iOS回到React-Native。

如果您想再次从iOS返回以 React-Native.Do 以下内容

// AppDelegate.h
- (void) goToNativeView {
UIViewController *vc =  [InitialViewController new];// This is your native iOS VC
UINavigationController* navigationController = [[UINavigationController alloc] initWithRootViewController:vc];

dispatch_async(dispatch_get_main_queue(), ^{
// Never do the below, it will be difficult to come back to react-native
// self.window.rootViewController = navigationController;

// Do this instead
[self.window.rootViewController presentViewController:navigationController animated:true completion:NULL];
});
}
//InitialViewController.m

创建一个按钮以返回到 React-native 并在按钮操作上关闭此视图控制器:

// Dismiss the VC so controll go back from iOS to react-native
[self dismissViewControllerAnimated:TRUE completion:nil];

最新更新