本文主要讲述集成React native的过程,以及简单使用的方法,并就过程中遇到的问题进行论述,按照步骤全程走了一遍,亲测可用。闲话不多说,talk is cheap,let's take a look at the code
一、安装npm(已安装请跳过此步)
- 安装Homebrew
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)”
- 安装npm
brew install node
3.检查是否安装成功及版本号
npm -v
二、使用cocoapods集成导入react native
-
创建项目ReactNativeTestDemo
-
项目主文件夹下新建一个名为package.json的文件和一个index.ios.js的文件
package.json:
{
"name": "ReactNativeTestDemo",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"test": "jest"
},
"dependencies": {
"react": "^16.0.0-alpha.12",
"react-native": "^0.47.2"
},
"devDependencies": {
"babel-jest": "20.0.3",
"babel-preset-react-native": "3.0.2",
"jest": "20.0.4",
"react-test-renderer": "16.0.0-alpha.12"
},
"jest": {
"preset": "react-native"
}
}
index.ios.js
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
export default class ReactNativeTestDemo extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
iOS RN 混合开发的Demo
</Text>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF'
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
}
});
AppRegistry.registerComponent('ReactNativeTestDemo', () => ReactNativeTestDemo);
- cd到项目主文件夹,执行npm install命令,安装成功后会出现node_modules文件夹 (如果需要更新 执行:react-native upgrade)
*** 此处如果出现警告需要注意,会影响后续运行效果,上网查询解决办法***
例:npm WARN react-native@0.47.2 requires a peer of react@16.0.0-alpha.12 but none is installed. You must install peer dependencies yourself.
解决办法:手动更新下载 npm install -save react@16.0.0-alpha.12</pre>
- 在项目根目录下执行vim Podfile创建Podfile文件,并执行pod install
platform :ios, '9.0'
target "ReactNativeTestDemo" do
pod 'Yoga', :path => ‘./node_modules/react-native/ReactCommon/yoga'
pod 'React', :path => ‘./node_modules/react-native', :subspecs => [
'Core',
'RCTText',
'RCTImage',
'RCTAnimation',
'RCTNetwork’,
'RCTWebSocket',
'BatchedBridge'
]
end
-
添加libraries ,设置网络环境
使用xcode打开项目, Build phases -> link binary with libraries 添加libReact.a 和 libYoga.a
plist文件中添加网络允许ATS:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
- 项目中编写代码逻辑
NSURL *jsCodeLocation = [NSURL URLWithString:@"http://localhost:8888/index.ios.bundle?platform=ios&dev=true"];
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation moduleName:@"ReactNativeTestDemo" initialProperties:nil launchOptions:nil];
rootView.backgroundColor = [UIColor whiteColor];
rootView.frame = CGRectMake(0, isIphoneX?88:64, KMainScreenW, isIphoneX?KMainScreenH-122:KMainScreenH-64);//简单适配一下iPhone X
[self.view addSubview:rootView];
-
cd到项目主目录,执行 react-native start 命令,执行成功后直接运行项目
可能会遇到Packager can't listen on port 8081 错误,可以尝试以下任一方法:
一、重启电脑,
二、查找端口:sudo lsof -i :8081 找到pid数字
杀掉端口:sudo kill -9 <pid>
可能会遇到杀掉占用端口的进程后又被占用的情况,一直重复运行查找-杀进程 直到未被占用,迅速执行 react-native start命令占用此端口,就可以放心测试了😁
三、更换端口:react-native start --port=8888
- 遇到的错误
错误: EMFILE: too many open files, watch {"errno":-24,"syscall":"watch","code":"EMFILE","filename":null} Error: EMFILE: too many open files, watch at FSEvent.FSWatcher._handle.onchange (fs.js:1338:28)
解决: 终端 brew install watchman
错误: ReactComponentTreeHook.purgeUnmountedComponents is not a function
解决: npm install安装出现问题,重新安装,注意警告信息
另外,注意package.json、index.ios.js等文件中项目名的替换,以及读取文件路径是否正确,react-native start命令是否执行成功
如果出现红屏问题,根据提示寻找对应解决办法,耐心调试;
如果运行之后出现了RN界面,并按js文件展示出了对应文字,则为集成成功,可以进行下一步使用了。
9.模拟器里运行到此就ok了,如果想把它装到真机上,这时localhost上的网址就无法访问了,需要生成main.jsbundle
1.在React Native项目node_modules同级目录下运行 npm start
运行成功后会显示 React packager ready. Loading dependency graph, done.
2.保持终端运行状态,打开新窗口使用curl命令生成 main.jsbundle
curl http://localhost:8081/index.ios.bundle -o main.jsbundle
3.在项目中选择使用main.jsbundle 注释掉
jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"];
改成下面这一行
jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
三、RN调用原生(Native)
- 新建一个继承自NSObject的类 RNToNativeBridgeModule(取名自定义,类似于桥接文件,用于创建方法供js端调用,并完成回调反馈逻辑处理),实现RCTBridgeModule协议
RNToNativeBridgeModule.h
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
@interface RNToNativeBridgeModule : NSObject<RCTBridgeModule>
@end
RNToNativeBridgeModule.m
#import "RNToNativeBridgeModule.h"
#import <React/RCTBridge.h>
@implementation RNToNativeBridgeModule
@synthesize bridge = _bridge;
RCT_EXPORT_MODULE(RNToNativeBridgeModule);//不加参数也可以,默认导出本身
RCT_EXPORT_METHOD(RNToNative:(NSString *)msg){
dispatch_async(dispatch_get_main_queue(), ^{
// NSLog(@"RN传递过来的消息:%@",msg);
[[NSNotificationCenter defaultCenter] postNotificationName:@"RNToNative" object:msg];
});
}
@end
- 修改index.ios.js文件,实现调用逻辑
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
TouchableOpacity, //新增
NativeModules, //新增
} from 'react-native';
var RNToNativeBridgeModule = NativeModules.RNToNativeBridgeModule; //对象名称可以自己取,跟下面的一致即可
export default class ReactNativeTestDemo extends Component {
render() {
return (
<View style={styles.container}>
<TouchableOpacity activeOpacity={0.5} onPress={() => RNToNativeBridgeModule.RNToNative('测试一下返回功能')}>
<Text style={styles.welcome}>
点我测试RN调Native!
</Text>
</TouchableOpacity>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF'
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
}
});
AppRegistry.registerComponent('ReactNativeTestDemo', () => ReactNativeTestDemo);
- 在需要的地方监听设置的通知方法,进行逻辑处理
四、原生(Native)调用RN
- 建立一个继承自RCTEventEmitter的类 NativeToRNBridgeModule(取名自定义,类似于桥接文件,用于编写逻辑调用RN方法),实现RCTBridgeModule协议
NativeToRNBridgeModule.h
#import <React/RCTEventEmitter.h>
@interface NativeToRNBridgeModule : RCTEventEmitter<RCTBridgeModule>
+(void)emitEventWithName:(NSString *)name andPayload:(NSDictionary *)payload;
@end
NativeToRNBridgeModule.m
#import "NativeToRNBridgeModule.h"
@implementation NativeToRNBridgeModule
RCT_EXPORT_MODULE() //不加参数默认导出本身
- (NSArray<NSString *> *)supportedEvents { //所有需要调用的方法名
return @[@"NativeToRN"];
}
-(void)startObserving
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(emitEventInternal:) name:@"event-emitted" object:nil];
}
-(void)stopObserving
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
//监听通知方法
-(void)emitEventInternal:(NSNotification *)notify
{
//向RN发送消息
if ([notify.object isKindOfClass:[NSDictionary class]]) {
NSDictionary *dic = notify.object;
[self sendEventWithName:@"NativeToRN" body:dic[@"obj"]]; //name 可以自定义,跟js文件及supportedEvents方法里的一致即可
}
}
+(void)emitEventWithName:(NSString *)name andPayload:(NSDictionary *)payload
{
[[NSNotificationCenter defaultCenter] postNotificationName:name object:payload];
}
@end
- 修改index.ios.js文件,实现调用逻辑
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
TouchableOpacity,
NativeModules,
NativeEventEmitter //新增
} from 'react-native';
var RNToNativeBridgeModule = NativeModules.RNToNativeBridgeModule; //对象名称可以自己取,跟下面的一致即可
var NativeToRNBridge = NativeModules.NativeToRNBridgeModule;
const Emitter = new NativeEventEmitter(NativeToRNBridge);
export default class ReactNativeTestDemo extends Component {
render() {
return (
<View style={styles.container}>
<TouchableOpacity activeOpacity={0.5} onPress={() => RNToNativeBridgeModule.RNToNative('测试一下返回功能')}>
<Text style={styles.welcome}>
点我测试RN调Native!
</Text>
</TouchableOpacity>
</View>
)
}
componentWillMount() {
Emitter.addListener('NativeToRN',(body)=>this._getNotice(body));
}
_getNotice (body) {
alert("这是RN弹窗\n" + body);
}
componentWillUnMount() {
this.subScription.remove();
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF'
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
}
});
AppRegistry.registerComponent('ReactNativeTestDemo', () => ReactNativeTestDemo);
- 在项目中编写代码调用emitEventWithName方法,发送消息给RN进行尝试
Codepush热更新相关内容见文档https://www.jianshu.com/p/eda2c131734c
新手上路,参照大神们的文档完成的,有不懂的可以看看原文,😁
参考:
https://www.jianshu.com/p/5111312c57b4
https://www.jianshu.com/p/b1ad255bcf47
网友评论