iOS开发中从swiftUI现有接入 React Native
iOS 原生与 React Native 混合开发集成文档(新架构)
本文档完整整理了iOS 原生(UIKit/SwiftUI)+ React Native 新架构 桥接、页面跳转、全局初始化、配置项的全套代码与步骤,可直接用于项目集成。
一、集成前提
-
已完成 React Native 项目基础搭建,RN 注册模块名为:** MYRN**(可自行修改)
-
使用 RN 新架构(Fabric)
-
开发环境:Xcode + RN 开发服务器(
npm start)
二、项目文件结构(本次创建/修改的文件)
-
ViewController.swift(原生主页面,点击按钮打开 RN) -
ReactViewController.swift(RN 容器控制器) -
RNPageView.swift(SwiftUI 包装 RN 页面,可选) -
AppDelegate.swift(全局 RN 初始化、桥接配置) -
Info.plist 网络/架构配置
三、完整代码实现
1. 原生主页面(ViewController.swift)
功能:屏幕中央按钮,点击模态跳转 RN 页面
import UIKit
class ViewController: UIViewController {
// RN 页面控制器(单例,避免重复创建)
var reactViewController: ReactViewController?
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
// 打开 RN 页面按钮
let openRNButton = UIButton()
openRNButton.setTitle("打开 React Native", for: .normal)
openRNButton.setTitleColor(.systemBlue, for: .normal)
openRNButton.setTitleColor(.blue, for: .highlighted)
// 按钮点击事件
openRNButton.addAction(UIAction { [weak self] _ in
guard let self = self else { return }
// 懒加载创建 RN 控制器,仅初始化一次
if self.reactViewController == nil {
self.reactViewController = ReactViewController()
}
// 模态弹出 RN 页面
self.present(self.reactViewController!, animated: true)
}, for: .touchUpInside)
view.addSubview(openRNButton)
// 自动布局(居中)
openRNButton.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
openRNButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
openRNButton.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
}
}
2. RN 容器控制器(ReactViewController.swift)
功能:纯 UIKit 容器,加载 RN 根视图
import UIKit
import React
import React_RCTAppDelegate
import ReactAppDependencyProvider
class ReactViewController: UIViewController {
// RN 核心工厂 + 代理
var reactNativeFactory: RCTReactNativeFactory?
var reactFactoryDelegate: RCTReactNativeFactoryDelegate?
override func viewDidLoad() {
super.viewDidLoad()
setupReactNative()
}
private func setupReactNative() {
// 初始化 RN 代理 + 依赖提供者
reactFactoryDelegate = ReactNativeDelegate()
reactFactoryDelegate?.dependencyProvider = RCTAppDependencyProvider()
// 创建 RN 工厂
reactNativeFactory = RCTReactNativeFactory(delegate: reactFactoryDelegate!)
// 加载 RN 注册的模块: MYRN(与 RN 注册名保持一致)
guard let rnRootView = reactNativeFactory?.rootViewFactory.view(withModuleName: " MYRN") else {
print("RN 视图加载失败")
return
}
view = rnRootView
}
}
3. SwiftUI 包装 RN 页面(RNPageView.swift,可选)
功能:SwiftUI 项目中使用 RN 页面,自带加载提示
import SwiftUI
import React
import React_RCTAppDelegate
import ReactAppDependencyProvider
// RN 业务页面(SwiftUI 层)
struct RNPageView: View {
var body: some View {
ZStack {
// 加载占位提示
Text("RN 加载中...")
.font(.title)
.padding()
// 包装 RN 控制器
RNWrapper()
.edgesIgnoringSafeArea(.all)
}
}
}
// SwiftUI 包装 UIKit 控制器(RN 容器)
struct RNWrapper: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> ReactViewController {
ReactViewController()
}
func updateUIViewController(_ uiViewController: ReactViewController, context: Context) {
// 无需更新
}
}
4. 全局 RN 代理类(直接写在 AppDelegate 内/外部均可)
import React
import React_RCTAppDelegate
class ReactNativeDelegate: RCTDefaultReactNativeFactoryDelegate {
// RN 包路径配置
override func sourceURL(for bridge: RCTBridge) -> URL? {
bundleURL()
}
override func bundleURL() -> URL? {
#if DEBUG
// 开发环境:加载本地 RN 服务器
RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")
#else
// 生产环境:加载本地打包文件
Bundle.main.url(forResource: "main", withExtension: "jsbundle")
#endif
}
}
5. AppDelegate.swift(全局初始化核心)
功能:全局唯一初始化 RN 桥接、工厂、启动 RN 引擎
import UIKit
import React
import React_RCTAppDelegate
import ReactAppDependencyProvider
@main
class AppDelegate: UIResponder, UIApplicationDelegate, RCTBridgeDelegate {
var window: UIWindow?
// RN 全局单例对象(只初始化一次)
var reactNativeDelegate: ReactNativeDelegate?
var reactNativeFactory: RCTReactNativeFactory?
var reactBridge: RCTBridge!
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// 1. 初始化 RN 全局配置
setupGlobalReactNative(launchOptions: launchOptions)
// 2. 设置主窗口(默认加载 ViewController)
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = ViewController()
window?.makeKeyAndVisible()
return true
}
// MARK: - 全局初始化 RN
private func setupGlobalReactNative(launchOptions: [UIApplication.LaunchOptionsKey: Any]?) {
// 初始化代理 + 工厂
let rnDelegate = ReactNativeDelegate()
let rnFactory = RCTReactNativeFactory(delegate: rnDelegate)
rnDelegate.dependencyProvider = RCTAppDependencyProvider()
// 赋值全局对象
reactNativeDelegate = rnDelegate
reactNativeFactory = rnFactory
// 启动 RN 引擎(模块名: MYRN)
rnFactory.startReactNative(
withModuleName: " MYRN",
in: window!,
launchOptions: launchOptions
)
// 初始化全局桥接(单例,仅一次)
reactBridge = RCTBridge(delegate: self, launchOptions: launchOptions)
}
// MARK: - RCTBridgeDelegate 协议
func sourceURL(for bridge: RCTBridge) -> URL? {
#if DEBUG
return URL(string: "http://localhost:8081/index.bundle?platform=ios")
#else
return Bundle.main.url(forResource: "main", withExtension: "jsbundle")
#endif
}
}
四、Info.plist 配置(必须添加)
方式:在 Info.plist 中右键 -> Open As -> Source Code,粘贴以下配置:
<key>NSAllowsLocalNetworking</key>
<true/>
<key>NSAllowsArbitraryLoads</key>
<true/>
<!-- RN 新架构启用 -->
<key>RCTNewArchEnabled</key>
<true/>
<!-- 状态栏样式全局控制 -->
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
五、关键说明(必看)
-
RN 模块名统一
所有
withModuleName: " MYRN"必须与你 RN 项目中注册的模块名完全一致。 -
全局单例原则
-
RCTBridge、RCTReactNativeFactory必须全局初始化一次 -
禁止在多个页面重复初始化,否则会导致崩溃/内存泄漏
-
-
开发/生产环境区分
-
调试:加载
localhost:8081本地包 -
发布:加载打包后的
main.jsbundle
-
-
页面跳转逻辑
-
原生页面 → RN 页面:使用
present模态弹出 -
RN → 原生:需要额外实现桥接方法(本文未包含)
-
六、运行流程
-
启动 RN 开发服务器:
npm start -
Xcode 运行 iOS 项目
-
原生页面点击按钮 → 加载 RN 页面
iOS 模拟器启动与调试模式指定指南
本文整理 查看模拟器、指定模拟器、指定 Debug/Release 模式、组合启动、调试操作、Xcode 操作、常见问题 全套命令与步骤,可直接复制使用。
一、查看所有可用模拟器
用于获取准确模拟器名称 / UDID,避免启动报错
# 列出所有已安装模拟器(名称 + UDID + 运行状态)
xcrun simctl list devices
输出示例
iPhone 15 (XXXX-XXXX-XXXX-XXXX) (Shutdown)
iPhone 15 Pro (YYYY-YYYY-YYYY-YYYY) (Shutdown)
iPad Pro (12.9-inch) (ZZZZ-ZZZZ-ZZZZ-ZZZZ) (Shutdown)
二、指定模拟器启动(3 种写法)
1. 模拟器名称(最常用)
# npm
npm run ios -- --simulator="iPhone 15 Pro"
# yarn
yarn ios --simulator="iPhone 15 Pro"
# npx 直接启动
npx react-native run-ios --simulator="iPhone 15 Pro"
2. UDID(模拟器名称重复时使用)
npm run ios -- --simulator="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
3. 名称+系统版本(精确匹配)
npm run ios -- --simulator="iPhone 15 Pro (17.5)"
三、指定 Debug / Release 模式
1. 强制 Debug 模式(开发/热重载/调试)
# 标准写法(推荐)
npm run ios -- --mode=Debug --simulator="iPhone 15 Pro"
# 旧版兼容写法
npm run ios -- --configuration=Debug --simulator="iPhone 15 Pro"
2. 强制 Release 模式(打包测试/性能验证)
npm run ios -- --mode=Release --simulator="iPhone 15 Pro"
四、组合启动(指定模拟器 + Debug + 端口)
最常用完整命令,支持热重载、调试、指定设备
npm run ios -- \
--simulator="iPhone 15 Pro" \
--mode=Debug \
--port=8081
五、启动后开启 JS 远程调试(Debug 必备)
- 模拟器中打开 RN 页面
- 快捷键:
Cmd + D - 选择:
Debug with Chrome/Debug with VS Code - 浏览器访问调试地址:
http://localhost:8081/debugger-ui/
六、Xcode 中指定模拟器与模式(图形化操作)
- 打开
ios/XXX.xcworkspace - 左上角选择项目
Scheme和目标模拟器 - 菜单栏:
Product → Scheme → Edit Scheme Run → Build Configuration选择Debug- 点击运行按钮 ▶️ 启动
七、常见问题
- 报错:Could not find simulator
→ 模拟器名称错误,用xcrun simctl list devices复制准确名称 - Release 模式无调试菜单、无法热重载
→ 正常,Release 环境默认禁用开发者功能 - 端口 8081 被占用
→ 启动命令添加--port=8082更换端口
版本仅供参考:
RN版本:0.85.1
Node版本: v22.22.2
官方文档:https://reactnative.dev/docs/integration-with-existing-apps?language=apple&ios-language=swift
更多推荐



所有评论(0)