React Native简介:

React-Native 是由Facebook出品的一款可以使用JavaScript来编写原生app的框架,官方说明是:A framework for building native app with React(一个使用React来编写原生app的框架),然而这个React也是由该公司出品的一款可以用来编写用户界面的JS库。二者的出现,以其强大的功能和便捷的使用方式迅速被广大开发者使用,并在各大平台的应用研发中占据了自己的一席之地。




集成

本文主要讲解的是在现有项目中如何集成React-Native框架,其他操作请自行查阅官网。

当然集成步骤官网上也有详细说明,传送门:中文版英文版


OK, let's do this...

准备工作:

  1. 搭建基本的React-Native开发环境,请参考这里
  2. 安装cocoapods,如果没有请参考官网。之后的操作是建立在已安装cocoapods,并且项目中已有podfile文件的情况下。
  3. 准备一个好用的文本编译器,用于编译.json文件和.js文件。

开始集成:




首先需要调整一下目录结构,方便管理,虽然官网推荐的是新建文件夹,并建ios子目录,然后将项目放入。但这并不是我们想干的,我们还是习惯根目录下面是原生的东西。我的建议是,在项目根目录中创建一个文件夹,自定义名称,用于放置所有与React-Native相关文件和文件夹。




然后,打开该文件夹,在文件夹中创建一个package.json的文件,该文件将作为React-Native的配置文件存在。并在文件中加入以下内容


{
  "name": "YouProjectName",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node node_modules/react-native/local-cli/cli.js start"
  },
  "dependencies": {
    "react": "16.0.0-alpha.12",
    "react-native": "0.47.1"
  }
}

注:请将name后面替换为自己的项目的名称,另外,react和React-Native版本请查阅官网确定是最新版本。


创建该文件最快的方法是,打开终端,cd到你创建的文件夹下,并输入


$touch package.json

再使用文本编译器来编辑即可。



$ npm install

等待终端执行完毕后,该文件夹下会多出一个node_modules的文件夹,里面是所有React 和React-Native相关模块。



cocoapods终于要上场了,安装依赖库的之前必须要使用node_modules下的相关配置文件,所有要先安装模块,导入库。


打开podfile,并在其中加入如下代码:


pod 'React', :path => './YourReactNativeFolder/node_modules/react-native', :subspecs => [
    'Core',             #核心库
    'BatchedBridge',    #RN版本高于0.45之后必须导入
    'DevSupport',       # 如果RN版本 >= 0.43,则需要加入此行才能开启开发者菜单
    'ART',
    'RCTActionSheet',
    'RCTAdSupport',
    'RCTAnimation',
    'RCTCameraRoll',
    'RCTGeolocation',
    'RCTImage',
    'RCTNetwork',
    'RCTPushNotification',
    'RCTSettings',
    'RCTText',
    'RCTVibration',
    'RCTWebSocket',     # 这个模块是用于调试功能的
    'RCTLinkingIOS'
  ]
  # 如果你的RN版本 >= 0.42.0,则加入下面这行
  pod 'Yoga', :path => './YourReactNativeFolder/node_modules/react-native/ReactCommon/yoga'





保存之后,执行pod install命令即可。



成功之后,回来先编译一下程序,如没有报错,说明集成成功。




页面嵌入


集成之后,当然是怎么在现有项目中使用了。




首先需要创建React-Native框架的iOS入口文件,即index.ios.js。


据官方介绍该文件是必须创建的,作为入口存在,可以很简单,但必须有。


创建方法推荐在使用touch命令,即在终端进入package.json所在文件夹,输入命令


$ touch index.ios.js

之后用文本编译器打开,写入以下代码作为测试使用:


'use strict';

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View
} from 'react-native';
//{'\n'}换行符
export default class ReactPage extends Component {
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>
          这就是所谓的{'\n'}
          React Native 
        </Text>
        <Text style={styles.instructions}>
       模拟器中cmd+R刷新页面,cmd+D调出调试菜单
        </Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F2F2F2',
  },
  welcome: {
    fontSize: 24,
    textAlign: 'center',
    margin: 10,
  },
  instructions: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5,
  },
});

AppRegistry.registerComponent('YourProjectName', () => ReactPage);



注:请将最后的YourProjectName替换成你项目的名称。




然后就是在项目代码中调用React-Native页面了,这里需要做的就是先找到需要调用React-Native页面的位置,在页面中引入头文件:


#import <React/RCTRootView.h>

然后在事件处理方法中添加如下代码:


NSURL *jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"];
    
    RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation moduleName:@"AiFlow" initialProperties:nil launchOptions:nil];
    rootView.backgroundColor = [UIColor colorWithHexString:@"#F2F2F2"];
    
    UIViewController *vc = [[UIViewController alloc] init];
    vc.view = rootView;
    
    [self presentViewController:vc animated:YES completion:nil];

完成后,即可点击运行,以模拟器打开。


但,如果现在触发该事件,则无法展示页面,因为React-Native的服务端并未启动,因此在触发事件之前,需要先打开终端,进入package.json文件所在目录,并执行:


$ npm start

等待服务器启动后,便可触发该事件,等待页面加载即可。

好了,至此,集成加运行调试结束,可以愉快地修改index.ios.js文件里的代码玩耍吧。





是的,坑就是坑,永远在那里,不管你踩不踩。




1.  很多同学纠结于目录结构,生怕如果不按照官网的步骤进行就无法集成成功,其实不然,目录是死的,人是活的,只要将需要设置路径的地方设置正确就不会有影响,比如podfile中的path。路径的写法中 ./ 代表的是该文件所在目录,../ 代表的是该文件所在上级目录,因此官网的写法是 ../,因为按照他所创建的文件结构,node_modules文件夹就是在podfile的上级目录。如果pod install命令报错,先检查cocoapods的版本,需要1.2.0以上版本,再检查path路径是否写的正确。




2.  巨坑:关于podfile中React库的subspecs该引入哪些组件的问题。先说一下我集成时遇到的情况,我在按照官网的集成方法做完之后,信心满满的点了一下运行,结果您猜怎么着,Xcode编译报错了。。。是的,不是React-Native报错,是Xcode报错,错误类型是Undefined symbols 错误指引告诉我说要添加类库libReact.a。好吧,我就加咯,加了之后编译,仍然报错。我就奇怪了,于是开始查资料,但貌似根本没有类似于我这样的情况出现。怎么办呢,整整一天时间,我都在研究到底哪里出了问题,直到看到了 这篇文章 ,豁然开朗。。。


所谓的未找到libReact.a的错误仅仅是因为我少导入了一个组件,这个组件的名字叫 BatchedBridge,该组件是React-Native0.45版本以后需要添加的依赖库,但官 网的代码中的代码是酱紫的:


pod 'React', :path => '../node_modules/react-native', :subspecs => [
    'Core',
    'DevSupport', # 如果RN版本 >= 0.43,则需要加入此行才能开启开发者菜单
    'RCTText',
    'RCTNetwork',
    'RCTWebSocket', # 这个模块是用于调试功能的
    # 在这里继续添加你所需要的模块
  ]




所以解决办法就是多引入一个'BatchedBridge'。呵呵哒,一天的时间就这么白白搭进去了,所以同学们注意了,只要出现跟libReact.a相关的错误,一定不是因为未找到该库,


而是缺少了上述依赖组件。


3. 出现与http请求相关的错误时,需在info.plist文件中设置App Transport Security允许http请求,并设置localhost字段,即在info.plist文件中加入:


<key>NSAppTransportSecurity</key>
	<dict>
		<key>NSAllowsArbitraryLoads</key>
		<true/>
		<key>NSExceptionDomains</key>
		<dict>
			<key>localhost</key>
			<dict>
				<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
				<true/>
			</dict>
		</dict>
	</dict>


OK就这些。