> 以下内容都是以 iOS 平台的角度来说的，相应的第三方库，安卓需要按照官网进行与安卓原生的集成。

# **react-native项目说明**

1. [react-native 官网](http://facebook.github.io/react-native/)
2. [react-native 中文网](https://reactnative.cn/)
3. [react-native github](https://github.com/facebook/react-native)
4. [react-native guide](https://github.com/reactnativecn/react-native-guide)
5. [react-native awesome](https://github.com/jondot/awesome-react-native)
6. [typescript 中文网](https://www.tslang.cn/docs/home.html)
7. [storybook 官网](https://storybook.js.org/docs/basics/writing-stories/)
8. [react 中文官网](https://react.docschina.org/docs/hello-world.html)
9. [redux 官网](http://cn.redux.js.org/)
10. [code-push 官网](https://appcenter.ms/apps)

### 原生端（iOS、android）需要集成的第三方库

1. [React](https://reactnative.cn/docs/integration-with-existing-apps/)
2. [react-navigation](https://reactnavigation.org/docs/en/getting-started.html)
3. [code-push(ios)](https://github.com/microsoft/react-native-code-push/blob/master/docs/setup-ios.md)
4. [code-push(android)](https://github.com/microsoft/react-native-code-push/blob/master/docs/setup-android.md)
5. [react-natvie-linear-gradient](https://github.com/react-native-community/react-native-linear-gradient)
6. [react-native-charts-wrapper](https://github.com/wuxudong/react-native-charts-wrapper/blob/master/installation_guide/README.md)

### 一. react-native 集成到iOS项目中

> 官网上给的[文档](https://reactnative.cn/docs/integration-with-existing-apps/)是以 react-native 项目为主目录，把 ios/android 项目为子目录。我这里的做法是以 ios 项目为主目录，react-native 项目为子目录，做法稍有不同。

1.  以我们 FHT 项目为例，目录名称为 iOS
2.  在 iOS 目录下建立 reactnative 文件夹，以后所有的 react-native 相关文件都放在 reactnative 中
3.  在 reactnative 目录下创建 package.json，并写入以下内容，name 要 version 可以任意填

    ```
    {
    	  "name": "FHTReactNativeApp",
    	  "version": "1.0.0",
    	  "private": true,
    	  "scripts": {
    	    "start": "node node_modules/react-native/local-cli/cli.js start"
    	  }
    }
    ```

4.  使用 yarn 添加 react-native

    `yarn add react-native`

5.  根据上一步给出的警告信息，添加对应版本的 react

    `yarn add react@version`

6.  进入到 demo 目录下，在 Podfile 文件中加入以下内容

    ```
    # 'node_modules'目录一般位于根目录中
    # 但是如果你的结构不同，那你就要根据实际路径修改下面的`:path`
    pod 'React', :path => './reactnative/node_modules/react-native', :subspecs => [
        'Core',
        'CxxBridge', # 如果 RN 版本 >= 0.47 则加入此行
        'DevSupport', # 如果 RN 版本 >= 0.43，则需要加入此行才能开启开发者菜单
        'RCTText',
        'RCTNetwork',
        'RCTWebSocket', # 调试功能需要此模块
        'RCTAnimation', # FlatList 和原生动画功能需要此模块
        # 在这里继续添加你所需要的其他 RN 模块
    ]

    # 如果你的 RN 版本 >= 0.42.0，则加入下面这行
    pod 'yoga', :path => './reactnative/node_modules/react-native/ReactCommon/yoga'
    
    # 如果 RN 版本 >= 0.45 则加入下面三个第三方编译依赖
    pod 'DoubleConversion', :podspec => './reactnative/node_modules/react-native/third-party-podspecs/DoubleConversion.podspec'
    pod 'glog', :podspec => './reactnative/node_modules/react-native/third-party-podspecs/glog.podspec'
    pod 'Folly', :podspec => './reactnative/node_modules/react-native/third-party-podspecs/Folly.podspec'
    ```

7. 执行 pod 命令安装依赖

    `pod install`

8. 接着配置 typescript 的支持，可参照[微软的配置方案](https://github.com/Microsoft/TypeScript-React-Native-Starter)。进入到 reactnative 目录下，执行以下命令

    ```
    yarn add --dev typescript
    yarn add --dev react-native-typescript-transformer
    yarn tsc --init --pretty --jsx react
    touch rn-cli.config.js
    yarn add --dev @types/react @types/react-native

    ```

9. 根据需要在 tsconfig.json 配置相关内容
10. 打开 rn-cli.config.js，并加入以下内容

    ```
    module.exports = {
    	getTransformModulePath() {
    		return require.resolve("react-native-typescript-transformer");
    	},
    	getSourceExts() {
    		return ["ts", "tsx"];
    	}
    };
    ```

11. 在 iOS 中需要接入 react-native 的 viewController 中加入以下代码，注意 moduleName 与 react-native 中导出的模块名称要一致

    ```
    NSURL *bundleUrl = [NSURL URLWithString:@"http://192.168.0.198:8081/index.bundle?platform=ios"];
    RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:bundleUrl moduleName:@"FHTTrafficStatistics" initialProperties:@{} launchOptions:@{}];
    rootView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:rootView];

    // 需要设置rootView的上下左右约束
    ```

12. 创建以.ts/.tsx 为后缀的文件，编写业务代码
13. 创建 index.js 入口文件，并加入以下代码

    ```
    import {AppRegistry} from 'react-native';
    import TrafficStatisticsContainer from './TrafficStatistics/Container';
    AppRegistry.registerComponent("FHTTrafficStatistics", () => TrafficStatisticsContainer);
    ```

14. 开启 node 服务

    `npm start`

15. 运行 iOS 项目，进入到加入了 react-native 项目的页面，可以看到运行的效果。

### 二. 对项目目录的解释

![项目目录](./readme/dir.png)

1. **_api.ts_**：所有的 api，由 swagger_gen.sh 脚本生成
2. **_Base_**：放置一些公共的.ts/.tsx 文件
3. **_images_**：资源文件
4. **_index.js_**：react-native 项目入口文件
5. **_node_modules_**：依赖包
6. **_package-lock.json_**：记录依赖包的相关信息，如版本等
7. **_package.json_**：依赖包配置文件
8. **_rn-cli.config_**：配置 typescript 支持时创建的文件
9. **_swagger_gen.sh_**：生成 api.ts 的脚本
10. **_TrafficStatistics_**：流量统计相关页面
11. **_tsconfig.json_**：typescripe 配置文件

### 三. 对 FHTNativeModules.ts 文件的解释

> 文件在./Utils/FHTNativeModules.ts

**_是模块的声明文件，模块是指原生（iOS/android）项目暴露给 react-native 项目的模块。_**

**先看一下 iOS 端写的要导出的模块有哪些：**

![iOS暴露的模块](./readme/ios_module.png)

1. **_FHTRNEventEmitManager_**：负责发送事件到 react-native
2. **_FHTRNEventHandleManager_**：负责处理 react-native 的事件，比如点击
3. **_FHTRNMethodManager_**：负责导出方法供 react-native 使用
4. **_FHTRNConstManager_**：负责导出常量供 react-native 使用

**以 FHTRNConstManager 为例进行解释**

下图红色字体表示的为 iOS 端导出的常量名称
![FHTRNConstManager](./readme/const_manager.png)

**不创建 FHTNativeModules.ts 时的使用方式**

使用过程中是完全没有提示的
![FHTRNConstManager](./readme/old_use.png)

**创建 FHTNativeModules.ts 后的使用方式**

先看看 FHTNativeModules.ts 的内容
![FHTRNConstManager](./readme/native_modules.png)

使用过程中会有提示
![FHTRNConstManager](./readme/new_use.png)

**_需要注意的是，每当原生端有新的模块导出，都要在 FHTNativeModules.ts 中增加对应的声明_**

### 四. 对 Color.ts 的解释

> 文件在./Const/Color.ts

**_导出的一个字符串枚举，枚举内容为 16 进制颜色字符串，这么做的目的是可以方便有提示的使用颜色。对前端理解不深，不知道正常应该如何处理，这是我自己的想法_**

Color.ts 文件的内容
![FHTRNConstManager](./readme/color.png)

**没有 Color.ts 使用颜色时，且没有提示**

````

...
backgroundColor: '#FC3A0D',
...

```

\***\*有 Color.ts 使用颜色时，且有提示\*\***

```

import Color from './Color'

...
backgroundColor: Color.cf03ad,
...

```

### 五. 对 NetworkTool.ts 的解释

> 文件在./Tool/NetworkTool.ts

**_包装一下请求，对每个请求加入我们自己的 headers，比如 Authorization 等等_**

NetworkTool.ts 文件的内容
![NetworkTool](./readme/network_tool.png)

使用方法

```

import NetworkTool from './NetworkTool'
import \* as Api from './api'

...
getMobileProductVisitDetail = async () => {
const api = await NetworkTool.restfulApi(Api.StatisticsApiApi);
const result = await api.statisticsApiMobileProductVisitStatistics({timeRange: 'Today', size: 50});
}
...

```

### 六. 导航器的选择

由于 react-native 官网推荐使用**_react-navigation_**，所以我选择使用了 react-navigation 作为我们 react-native 项目的导航

[react-navigation 官网](https://reactnavigation.org/)

### 七. chart 的选择

在 github 上找了几个跨平台的画图的库

1. [react-native-chart](https://github.com/tomauty/react-native-chart)
2. [victory-native](https://github.com/FormidableLabs/victory-native)
3. [react-native-charts-wrapper](https://github.com/wuxudong/react-native-charts-wrapper)
4. [react-native-svg-charts](https://github.com/JesperLekland/react-native-svg-charts)
5. [react-native-pathjs-charts](https://github.com/capitalone/react-native-pathjs-charts)

简单的使用过以后，综合考虑易用性、库本身是否维护、文档等，最终选择了`react-native-charts-wrapper`做为我们项目中使用的库。

### 八. 热更新服务

> 热更新服务简单点说就是一个云服务器，用于存放 reactnative 代码打包后的 bundle 包，供原生端去下载。

目前比较常用的热更新服务

1. [微软热更新服务](https://github.com/Microsoft/react-native-code-push)
2. [react-native 中文网热更新服务](https://github.com/reactnativecn/react-native-pushy)

也可以自己搭建热更新服务器

1. [搭建自己的 react-native 热更新服务](https://www.jianshu.com/p/8e08c7661275)

我首先尝试了中文网提供的热更新服务，按照其[github](https://github.com/Microsoft/react-native-code-push)上的教程集成时（因为我们是在原有项目基础上集成，所以只能手动集成），结果失败了；后来通过自己创建 RCTHotUpdate.podspec 文件才算集成成功，使用后发现并不是那么好用，所以最终选择了微软提供的热更新服务。

**_微软热更新 code-push 账号密码_**

```

userName: fht360@fht360.com

password: Jshh@2019

token: 721d409405487a0b34f652f5c321e0cf0fadf603

ios debug deployment key: 7ylaRW6bwG1v6p3SlRnJfgrP1UM61f2f4ca3-0c1e-4e1d-9d6a-9c67f52f7f5d

ios staging deployment key:
qhiSHyePpdC_HLCMTQyAiV46zuDq1f2f4ca3-0c1e-4e1d-9d6a-9c67f52f7f5d

ios production deployment key: oa3Z3NcrvO5f4P9h_IJMFomflrPY1f2f4ca3-0c1e-4e1d-9d6a-9c67f52f7f5d

android debug deployment key:
l_Hb724-ufwCtWfoX_gI7ux30TBF1f2f4ca3-0c1e-4e1d-9d6a-9c67f52f7f5d

android staging deployment key:
bm2zjkxNB559CjQVP4JtIJt6sNW21f2f4ca3-0c1e-4e1d-9d6a-9c67f52f7f5d

android production deployment key: SK7jlDMneJIhpIB8TsrXwiXLgKgK1f2f4ca3-0c1e-4e1d-9d6a-9c67f52f7f5d

```

### 九、Android 引入 node_modules 中库时需注意的点

1、使用时需在项目根目录 setting.gradle 中配置引入的 module 名称，例如：
include ':app',':react-native-code-push'
project(':react-native-code-push').projectDir = new File(rootProject.projectDir, FHT_REACT_NODE_MODULE_PATH + 'react-native-code-push/android/app')

（1）第一行 include 表示 app 下 build.gradle 中引入该 module 的别名，implementation project(':react-native-code-push')
（2）第二行表示引入的 module 的名称及其 android 项目路径，所选择路径为 src 文件夹的上一级路径；

2、fht 项目 buildType 有三种，所以引入 module 时需检查该 module 的 build.gradle 是否也配置了，如果未配置，则需手动添加
buildTypes {
release {}
dev {}
debug {}
}

备注：
方式(1)：使用fht/fix_react_native_lib_build_gradle.js配置node_modules下的相关库【该方式已废弃，建议使用方式（2）】
方式(2)：使用fht-react-native/fix_module_lib_build_gradle.js配置nodules下的相关库

3、由于项目已迁移至Androidx,fht-react-native中引入的库react-native-gesture-handler、react-native-charts-wrapper、
react-native-code-push以及react-native-linear-gradient中的部分文件中android.support.xxxx的引用需要修改至androidx引用，这个每次node_modules重新生成的时候需要检查下文件是否正确（目前node_modules生成后运行项目会因这个问题报错）
// TODO nodejs 脚本检测库引用中android.support.xxx的引用并替换为androidx功能

4、node_modules 下的库引用时，大部分 module 都会从根目录中获取 compileSdkVersion 等信息，项目配置时最好能在根目录
的 build.gradle 中配置全局变量：
ext {
compileSdkVersion = 28
buildToolsVersion = "28.0.3"
minSdkVersion = 19
targetSdkVersion = 28
}


4、【重要】每次重新 npm install or yarn install 后需重新检查 setting.gradle 中引入的 node_modules 下的对应的 module 的
build.gradle 是否仍然是添加注意点 2 中的 buildType...
```


5、【重要】
1、@zhangmenglai windows上 目前只能使用node 10运行react(index_android_bundle包也需要使用node 10),node 12及以上暂时用不了,调试及打包时
需要注意node版本切换；
2、@zhangmenglai windows上不要使用cnpm install安装包，会出现打包失败情况，错误很奇葩，使用npm install;
3、
