React-Native技术调研
0.前提:
搭建环境:https://reactnative.cn/docs/getting-started/,
分mac/win/linux,平台分android/ios。
1.创建一个新项目
使用rn创建一个项目和把rn技术集成到一个现有的原生项目是有差别的。
//创建和运行一个rn项目:
react-native init AwesomeProject
cd AwesomeProject
react-native run-ios
编译和运行需要一段时间...耐心等待..根据rn版本的不同,ios虚拟机也不不同,比如最新的0.57版本的是iphoneX,低版本的rn默认创造的ios虚拟机就老一点。
注意官网中特别提到:
!!!注意!!!:init 命令默认会创建最新的版本,而目前最新的 0.45 及以上版本需要下载 boost
等几个第三方库编译。这些库在国内即便翻墙也很难下载成功,导致很多人无法运行iOS项目!!!中文网在论坛中提供了这些库的国内下载链接。如果你嫌麻烦,又没有对新版本的需求,那么可以暂时创建0.44.3的版本。
我在rn版本0.57.5,react-cli版本2.0.1直接init创建项目没有遇到以上问题。
几个常用操作
- cmd+r 刷新,可配置热更新,调出菜单enable liveload
- cmd+d 调出菜单
2.试着用RN写一个静态页面
https://github.com/ZhangMingZhao1/react-native-pratice/tree/master/earphone_guide
3.集成到一个原生项目
这里以一个rn集成到ios object-c为例,现实中这种情况可能也更多一些。
a.
用xcode新建一个单页面应用,语言选择object-c,名字为ReactNativeDemo,在项目根目录下,新建ReactNative文件夹,用于存放跟reactnative相关文件。(后面简称rn)
b.
在rn文件夹中新建一个package.json,内容为:
{
"name": "ReactNativeDemo",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start"
},
"dependencies": {
"react": "16.0.0",
"react-native": "0.51.0"
}
}
注意版本严格规定
c.
进入rn文件夹,npm install,在rn文件夹新建index.js,以前版本是inex.ios.js。
内容为:
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
class ScoresView extends React.Component {
render() {
var contents = this.props['scores'].map((score) => (
<Text key={score.name}>
{score.name}:{score.value}
{'
'}
</Text>
));
return (
<View style={styles.container}>
<Text style={styles.highScoresTitle}>2048 High Scores!</Text>
<Text style={styles.scores}>{contents}</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#FFFFFF',
},
highScoresTitle: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
scores: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
// 注册组件,程序入口
// 第一个参数:注册模块名称,这里亲测不和项目名一致也可以,但是好多资料说名字要和项目名一致
// 第二个参数:函数,此函数返回组件类名,程序启动就会自动去加载这个组件
AppRegistry.registerComponent('App', () => ScoresView);
d.
进入项目根目录,安装cocoapods,
brew install cocoapods
我的mac下会报个错,在一个文件下没有权限写入,而homebrew现在禁止使用sudo执行,根据提示的指令可以收回那个文件的权限,复制粘贴执行就好。
安装好后,在根目录使用pod init,在生成的Podfile中内容改为:
source 'https://github.com/CocoaPods/Specs.git'
react_native_path = './ReactNative/node_modules/react-native'
platform :ios, ‘9.0’
use_frameworks!
target 'ReactNativeDemo' do
# 'node_modules'目录一般位于根目录中
# 但是如果你的结构不同,那你就要根据实际路径修改下面的`:path`
pod 'React', :path => react_native_path, :subspecs => [
'Core',
#'BatchedBridge', # 0.45 版本以后需要添加
'CxxBridge',
'DevSupport', # 如果RN版本 >= 0.43,则需要加入此行才能开启开发者菜单
'RCTText',
'RCTImage',
'RCTNetwork',
'RCTWebSocket', # 这个模块是用于调试功能的
# 在这里继续添加你所需要的模块
]
# 如果你的RN版本 >= 0.42.0,则加入下面这行
pod 'yoga', :path => react_native_path + '/ReactCommon/yoga'
# Third party deps
pod 'DoubleConversion', :podspec => react_native_path + '/third-party-podspecs/DoubleConversion.podspec'
pod 'GLog', :podspec => react_native_path + '/third-party-podspecs/GLog.podspec'
pod 'Folly', :podspec => react_native_path + '/third-party-podspecs/Folly.podspec'
end
这个文件类似npm的package.json,记录了所需文件的依赖,所以下一步就是
pod install
e.
在总ios项目中修改http的安全策略,在info.plist加上:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
f.
用xcode打开项目,在Main.storyboard拖入一个按钮,在ViewController.m中加入头文件:
#import <React/RCTRootView.h>
再增加一个按钮的跳转方法:
- (IBAction)pushToReactNativeView:(id)sender {
NSURL *jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.bundle?platform=ios"];
RCTRootView *rootView =
[[RCTRootView alloc] initWithBundleURL: jsCodeLocation
moduleName: @"App"
initialProperties:
@{
@"scores" : @[
@{
@"name" : @"Alex",
@"value": @"42"
},
@{
@"name" : @"Joel",
@"value": @"10"
}
]
}
launchOptions: nil];
UIViewController *vc = [[UIViewController alloc] init];
vc.view = rootView;
[self presentViewController:vc animated:YES completion:nil];
}
可能会出现加载出错,这是因为pod install安装的文件没有加载进来,重启xcode项目,重新打开项目即可。
然后把ViewController.m文件中的#import <fishhook/fishhook.h> 改为 #import "fishhook.h",不然后面运行可能会报错。
g.
给这个按钮和这个方法绑定起来,进入keyboard,按住 ctrl,点击按钮会出现一个箭头,指向左上角的ViewContrller,可出现一个框,选择刚才写的pushToReactNativeView方法,会在右下角看到关联了。
这部可详见iOS学习之基础控件添加和事件绑定,推荐一个链接:https://www.jianshu.com/p/6eb302a62956
h.
进入到rn文件夹,npm start 启动node服务器,这时会进入dev状态,动态打包。回到xcode,运行项目,点击按钮,就会看到跳转到rn写的页面。
4.RN打包给原生项目使用
a.
在rn项目根目录中创建release_ios 文件夹,(打包必须创建文件夹)具体可以自己命名,作为资源目标的输出文件目录。
在根目录下执行打包命令:
react-native bundle --entry-file index.js --platform ios --dev false --bundle-output release_ios/main.jsbundle --assets-dest release_ios/
会看到release_ios下多出assets文件夹(如果有图片),和两个jsbindle文件.
b.
将main.jsbundle和assets拖入Xcode的项目导航面板中,选择默认导入即可(位置和里面的文件夹同级)
修改上面的ViewController,m,
将端口动态引入改为本地,让React Native去使用我们刚才导入的jsbundle,这样以来我们就摆脱了对本地nodejs服务器的依赖。当然也可以将jsbundle 放到自己的远程服务器中,更换远程的服务器文件就可以加载jsbundle,为了提高性能我们可以在本地做一次缓存。@后面是自己打包文件的名字不加后缀。
c.
ios app的打包就可以看官网了:https://developer.apple.com/support/app-store-connect/
5.留下的疑问,待继续研究
- npm start后打包的文件是在哪里放着的,找了一下没找到,难道和webpack dev一样使用了memory-fs-js,把临时打包文件动态写进了内存里吗?
- 大家可以补充..etc