react native 之 在现有的iOS工程中集成react native
在现有的iOS工程中集成react native, 或者说将react native引入到iOS 项目,是RN和iOS混合开发的必经之路
参考官网教程:https://reactnative.cn/docs/integration-with-existing-apps/
但是会有一些步骤报错,这里记录一下。首先我的项目结构是这样:
RNTEST 是最外面的文件夹的名字,也是iOS项目的名字。ios/ 下是iOS项目文件。
npm安装RN依赖都没问题,按照官网步骤来
最主要的是
cd ios
pod install
会报错。。。
错误提示是找不到XXX索引库,在Podfile文件中将这些对应的注释掉:
Podfile文件参考:https://github.com/facebook/react-native/blob/v0.60.0/template/ios/Podfile
platform :ios, '9.0' require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' target 'RNTEST' do # Pods for HelloWorld pod 'React', :path => '../node_modules/react-native/' pod 'React-Core', :path => '../node_modules/react-native' #pod 'React-DevSupport', :path => '../node_modules/react-native/React' #pod 'React-fishhook', :path => '../node_modules/react-native/Libraries/fishhook' pod 'React-RCTActionSheet', :path => '../node_modules/react-native/Libraries/ActionSheetIOS' pod 'React-RCTAnimation', :path => '../node_modules/react-native/Libraries/NativeAnimation' pod 'React-RCTBlob', :path => '../node_modules/react-native/Libraries/Blob' pod 'React-RCTImage', :path => '../node_modules/react-native/Libraries/Image' pod 'React-RCTLinking', :path => '../node_modules/react-native/Libraries/LinkingIOS' pod 'React-RCTNetwork', :path => '../node_modules/react-native/Libraries/Network' pod 'React-RCTSettings', :path => '../node_modules/react-native/Libraries/Settings' pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text' pod 'React-RCTVibration', :path => '../node_modules/react-native/Libraries/Vibration' #pod 'React-RCTWebSocket', :path => '../node_modules/react-native/Libraries/WebSocket' pod 'React-cxxreact', :path => '../node_modules/react-native/ReactCommon/cxxreact' pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi' pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor' pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector' pod 'Yoga', :path => '../node_modules/react-native/ReactCommon/yoga' pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec' pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec' pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec' use_native_modules! end
结果:
之后就是在iOS工程中写相关代码, 可以运行起来,但是在Native调RN时
然后发现又报错了,改了package.json中的版本如下:
就可以了。
iOS项目代码参考的是慕课网上的教程。
要想在iOS中加载一个JSX页面,有两种方式:
一:在控制器导入头文件
//#import <React/RCTBundleURLProvider.h> //#import <React/RCTRootView.h> //#import <React/RCTEventEmitter.h>
然后加载JSX中注册的模块
// NSURL *jsCodeLocation; // // jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; // // RCTRootView *rootView = // [[RCTRootView alloc] initWithBundleURL: jsCodeLocation // moduleName: @"App" // initialProperties:nil // launchOptions: nil]; // self.view = rootView;
上面这个moduleName (任意取,但是要与OC中一致才能加载对应页面)就是在index.js中的这个:
import {AppRegistry} from 'react-native' import App from './App'; import App2 from './App2'; AppRegistry.registerComponent('App1',()=>App); AppRegistry.registerComponent('App2',()=>App2); AppRegistry.registerComponent('App3',()=>App2);
二:借鉴AppDelegate中加载方式,首先导入头文件,遵循代理,实现代理方法,加载index.js中的模块
// // RNPageController.m // RNTEST // // Created by LiuWei on 2019/10/18. // Copyright © 2019 udc. All rights reserved. // #import "RNPageController.h" //#import <React/RCTBundleURLProvider.h> //#import <React/RCTRootView.h> //#import <React/RCTEventEmitter.h> #import <React/RCTBridge.h> #import <React/RCTBundleURLProvider.h> #import <React/RCTRootView.h> @interface RNPageController ()<RCTBridgeDelegate> @end @implementation RNPageController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. // [self initRCTRootView]; RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:nil]; RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:@"App1" initialProperties:nil]; self.view=rootView; } //-(void)initRCTRootView{ // NSURL *jsCodeLocation; // // jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; // // RCTRootView *rootView = // [[RCTRootView alloc] initWithBundleURL: jsCodeLocation // moduleName: @"App" // initialProperties:nil // launchOptions: nil]; // self.view = rootView; //} - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge { #if DEBUG return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; #else return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; #endif } @end
以上这种开发方式最终打包 ipa时,
先在ios/ 下创建一个 release_ios/
然后执行命令生成必要的jsbundle文件和图片资源文件
react-native bundle --entry-file index.js --platform ios --dev false --bundle-output release_ios/main.jsbundle --assets-dest release_ios/
--platform ios
:代表打包导出的平台为iOS;--dev false
:代表关闭JS的开发者模式;-entry-file index.js
:代表js的入口文件为index.js
;--bundle-output
:后面跟的是打包后将JS bundle包导出到的位置;--assets-dest
:后面跟的是打包后的一些资源文件导出到的位置;
好了之后将生成必要的jsbundle文件和图片资源文件拖进iOS项目
接下来就可以打包了
特别注意:如果项目用到了CodePush热更新:加载js文件的方式变成这样
... NSURL *jsCodeLocation; #ifdef DEBUG jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; #else jsCodeLocation = [CodePush bundleURL]; #endif ...
最后Demo地址:https://github.com/nwgdegitHub/OCCallRNDemo.git