1. 安装环境,仅以mac为例
- 如果需要iOS与Android同时开发运行,必须使用装有macOS的电脑,请知悉
1.1 首先安装homebrew(mac系统下的包管理器)
-
首先查看是否安装了homebrew 输入:
brew -v
-
如果没有安装,需要安装
输入:/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
如果不是管理员账户,会遇到权限问题
输入:
sudo chown -R `whoami` /usr/local
1.2 安装node.js
-
使用homebrew 安装 node 输入:
brew install node
-
修改源,或者科学上网法(翻墙)
npm config set registry https://registry.npm.taobao.org --global
npm config set disturl https://npm.taobao.org/dist --global
-
注意: 合理可以使用cnpm 来代替npm提高运行效率
1.3 安装yarn(代替npm加快node module下载速度)以及react-native-cli(RN的编译打包工具)
- 输入代码
npm install -g yarn react-native-cli
- 修改源
yarn config set registry https://registry.npm.taobao.org --global
yarn config set disturl https://npm.taobao.org/dist --global
1.4 推荐安装watchman, Flow 不推荐!
watchman 能够实时刷新,所见即所得!
1.5 安装Sublime 开发 以及 如何使用package control安装IDE
- 首先按照https://packagecontrol.io/installation#st3 安装package control,注意自己sublime的版本,
- 安装成功后,到preference 里面的package control 中输入install package,等候一小会儿,
- loading结束后出现输入框,输入需要安装的插件
推荐使用的插件 : ReactJS Emmet Terminal react-native-snippets
2 纯RN语法项目,以项目名称MyApp为例
2.1 创建项目,初始化npm,node.js服务器配置等一系列操作
终端 运行 react-native init MyApp --version 0.44.3
-
注意事项,我们这里指定版本
0.44.3
,如果没有版本,运行时会提示错误Print: Entry, ":CFBundleIdentifier", Does Not Exist
或者Command /bin/sh failed with exit code 1
让人难以理解,主要是新版本没有有效的支持,出现这两个错误,请重新创建项目!!! -
具体原因已经发现!!!! ,查看package.json 的dependencies 依赖中,
react
依赖的版本是alpha 版本,我们需要替换成稳定版本!!
2.2 到MyApp的目录下,直接运行
cd MyApp && react-native run-ios
2.3 简单修改和运行的大致步骤
- RN 程序启动在ios工程中的 main.m中,循环调用appDelegate 代理,代理中某些方法会一直执行,某些方法只会执行一次
- appDelegate 中
- (BOOL)application: didFinishLaunchingWithOptions:
是程序启动的入口,仅仅调用一次 . OC代码通过寻找到js文件里的模块具体加载,所以OC调用的js文件名称必须与文件夹里的文件名称一致,模块名称必须和js文件里注册模块名保持一致 - js文件中最后一句代码是注册,即注册js中的某个模块,执行js中的某个类,告诉OC 该运行哪个模块
- 简单修改下
AppDelegate中修改
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"myAPP" fallbackResource:nil];
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName:@"module1"
initialProperties:nil
launchOptions:launchOptions];
JS文件中修改
AppRegistry.registerComponent('module1', () => clas1);
export default class clas1 extends Component
3 iOS向现有的项目集成RN代码
创建工程,并且将工程纳入pod 管理下,
3.1 在工程的根目录下创建文件夹,随意取名,比如RNComponent
- 进入
RNComponent
目录,创建package.json文件
名称,版本和依赖会变化,注意!
{
"name": "appTest",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start"
},
"dependencies": {
"react": "16.0.0-alpha.6",
"react-native": "0.44.3"
}
}
- 安装node 依赖包库 推荐
npm install
,如果错误试试cnpm install
,需要一段时间,耐心等待 - 在package.json同级目录下,创建一个文件,比如index.ios.js
内容为要创建的页面的内容,获取原生页面传过来的score,并且显示
'use strict';
import React from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
class RNHighScores extends React.Component {
render() {
var contents = this.props["scores"].map(
score => <Text key={score.name}>{score.name}:{score.value}{"\n"}</Text>
);
return (
<View style={styles.container}>
<Text style={styles.highScoresTitle}>
2048 High Scores!
</Text>
<Text style={styles.highScoresTitle}>
30000000
</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,
},
});
// 整体js模块的名称,注册名称是ssss
AppRegistry.registerComponent('ssss', () => RNHighScores);
3.2 原生工程的集成
- podfile 中 加入下面的依赖库,注意依赖的路径选择,path是实际路径
# 'node_modules'目录一般位于根目录中
# 但是如果你的结构不同,那你就要根据实际路径修改下面的`:path`
pod 'React', :path => './RNComponent/node_modules/react-native', :subspecs => [
'Core',
# 'CxxBridge', # 如果RN版本 >= 0.47则加入此行
'DevSupport', # 如果RN版本 >= 0.43,则需要加入此行才能开启开发者菜单
'RCTText',
'RCTNetwork',
'RCTWebSocket', # 这个模块是用于调试功能的
# 在这里继续添加你所需要的模块
'ART',
'RCTActionSheet',
'RCTAdSupport',
'RCTGeolocation',
'RCTImage',
'RCTPushNotification',
'RCTSettings',
'RCTVibration',
'RCTLinkingIOS',
]
# 如果你的RN版本 >= 0.42.0,请加入下面这行
pod "Yoga", :path => "./RNComponent/node_modules/react-native/ReactCommon/yoga"
- 安装依赖
pod install
3.3 RN的js代码最终替代的是MVC中的View,所以我们用view来接收RN的代码
func doSome() {
// 这里如果是要求真机运行,请务必将真机的ip修改到这里来,如果是127.0.0.1或者localhost ,只能模拟器访问 , 平台是ios,开发模式下
let jsPath = URL(string: "http://172.29.164.9:8081/index.ios.bundle?platform=ios&dev=true")
// 传递的数据,以字典形式传递
let metaData: Dictionary = ["scores":
[
["name":"william", "value":"42"],
["name":"ssss", "value":"10"]
]
]
// 这里的ssss是js中注册的名称,会找到index.ios.js中的ssss模块
let rootView = RCTRootView(bundleURL: jsPath, moduleName: "ssss", initialProperties: metaData, launchOptions: nil)
// 设置view
let vc = UIViewController()
vc.view = rootView
self.present(vc, animated: true, completion: nil)
}
3.4 启动npm服务,运行项目
npm start
3.5 运行项目即可
- 可以通过修改index.ios.js 来改变页面,模拟器上使用command + R 来重新编译加载RN 的内容, 真机使用摇一摇呼出开发选项,选择reload即可
- 如果运行时,工程有长连接的保活 打印,有时候会感觉很烦
找到edit scheme 中的envirment variables ,添加键值对 OS_ACTIVITY_MODE
disable
3.6 但是目前有一个问题,一旦远程npm没有启动,就会导致连接失败
如何摆脱node服务器?
-
在json.package 目录下创建release_ios 文件夹
-
然后通过react-natice 命令创建 main.jsbunlde文件夹
react-native bundle --entry-file index.ios.js --platform ios --dev false --bundle-output release_ios/main.jsbundle --assets-dest release_ios/
- 生成的文件夹中可能有main.jsbundle,main.jsbundle.meta,asset等,将main.jsbundle 以及asset拖到工程的目录中
这里遇到一个BUG,就是swift4.0 如果直接拖到目录,然后拖到工程目录,会导致找不到文件...,只能直接拖到工程目录中!!
还有个问题,如果遇到多个js文件,那怎么批量处理,待续
4 语法分析
4.1 JS 语法
// 从'react'中引入组件
import React, {
Component,
} from 'react';
// 从react-native 中引入各个单一的组件名称
import {
TabBarIOS,
NavigatorIOS
} from 'react-native';
//对工程扩展组件
class App extends Component {
render() {
return (
<TabBarIOS>
<TabBarIOS.Item title="React Native" selected={true}>
<NavigatorIOS initialRoute={{ title: 'React Native' }} />
</TabBarIOS.Item>
</TabBarIOS>
);
}
}
几个关键字:export,default,extends关键字
4.2 样式表
var styles = StyleSheet.create({
row: { flexDirection: 'row', margin: 40 },
image: { width: 40, height: 40, marginRight: 10 },
text: { flex: 1, justifyContent: 'center'},
title: { fontSize: 11, fontWeight: 'bold' },
subtitle: { fontSize: 10 },
});
这里通过创建一个变量 的样式类 来管理所有的样式
4.3 最重要的,入口文件必须要加,其他文件不必加
// 注意,这里用引号括起来的'HelloWorldApp'必须和你init创建的项目名一致
AppRegistry.registerComponent('HelloWorldApp', () => HelloWorldApp);
程序入口文件必须要进行注册,ios才能识别到这个js文件,从这个入口进
5. 技巧
5.1 使用导航控制器以及tab切换控制器
参照 http://www.jianshu.com/p/7d435e199c96
- 修改8081 端口,有时候8081被占用等
- (1)启动项目时react-native start --port 8083
- (2) 手动修改项目下的node_modules\react-native\local-cli\server\server.js下的方法server.js文件,default:8081 改掉
- (3) lsof -n -i4TCP:8081 查找到占用8081的应用的pid, kill -9 pid 杀死应用
6. 遇到的BUG
前言: 解决BUG说实话还是Stack overflow 靠谱,其他都一般
React Native 真是一堆坑,至少中文网站上一堆坑
-
如果xxx文件找不到,或者输入npm xxx save 之后报错,
npm install
npm 是重新下载node_module文件依赖 -
使用
npm xxx save
下载某些新的组件报错? npm 5 貌似有很大的问题!,换成yarn install xxx
试试...如果npm下载之后发现什么都没干就直接报错了??因为npm5 这个坑货下一个删一个,把之前有用的给删了,请先npm install
,然后改用yarn install xxx
-
不想在xcode 里面一直提示
__nw_connection_get_connected_socket_block_invoke XX Connection has no connected handler
,在edit scheme 里面找到environment variables 设置key 是OS_ACTIVITY_MODE
,value 是disable
-
模拟器运行过程中,突然 ⌘ + R 没反应了!!, 但是command + 1有反应,原因是我不小心按了shift ⌘ + K ,关闭了键盘!!
-
自定义模块,但是每次运行都会报错
Expected a component class got [objesc Object]
,解决方法,所有的自定义组件首字母都必须大写... -
出现
RCTFatal
是语法错误了,一般是少些() ; {} 等 -
单独说一次! 下载安装新的组件时,不要使用npm ,报错不说,还一堆问题,使用
yarn add xxx
例如:yarn add react-navigation
-
使用最新的react-navigation 中的StackNavigator ,提示错误:
Route 'xxx' should declare a screen, for example: import xxx ...
这种错误,明明写了,但是要我声明screen,原因是因为调用顺序的问题,需要把定义的screen 放在代码最前面....网上某些'大神'真是够了,废话连篇,不讲重点
6. 使用优缺点介绍
优点 :
- 方便前端人员快速构建APP
- RN 在
一套代码,多个领域
上一直在改进,以后安卓iOS 可以做大绝大多数通用 - RN 运行效率和iOS 原生相差无几,运行流畅
缺点 :
- 学习成本高
- 发布还是需要了解iOS发布知识,依赖于Xcode
- 不适合复杂需求下的开发
- 有时会有莫名其妙的BUG
- 解决问题困难,提示有限
- App性能损耗,内存占用过大,内部运行了JavaScriptCore 造成的
总结 : 如果是一线开发人员作为附加技能来说,收益是极高的,但是如果作为主职就会有很多局限性.无论是RN还是swift 或者kotlin,未来的方向是增加通用性,swift 开发服务器,swift 开发Android也有人在研究,swift web开发也已经提出.
网友评论