美文网首页我爱编程
React-Native操作随笔(一)

React-Native操作随笔(一)

作者: MichaelLedger | 来源:发表于2018-04-16 17:01 被阅读811次

    开发平台:macOS

    搭建开发环境

    • 必需软件

    Homebrew, Mac系统的包管理器,用于安装NodeJS和一些其他必需的工具软件。

    $ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
    

    Node.js,一种javascript的运行环境,能够使得javascript脱离浏览器运行。
    Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。
    Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效。
    Node.js 的包管理器 npm(Node Package Manager),是全球最大的开源库生态系统。

    $ brew install node

    Yarn,Facebook提供的替代npm的工具,可以加速node模块的下载。
    $ brew install yarn$ npm install -g yarn

    react-native-cli,React Native轻量级的命令行工具,用于执行创建、初始化、更新项目、运行打包服务(packager)等任务。
    $ npm install -g react-native-cli

    Xcode7.0 或更高版本

    • 推荐安装

    Watchman是由Facebook提供的监视文件系统变更的工具。安装此工具可以提高开发时的性能(packager可以快速捕捉文件的变化从而实现实时刷新)。译注:此工具官方虽然是推荐安装,但在实践中,我们认为此工具是必须安装,否则可能无法正常开发。
    brew install watchman

    Flow是一个静态的JS类型检查工具。译注:你在很多示例中看到的奇奇怪怪的冒号问号,以及方法参数中像类型一样的写法,都是属于这个flow工具的语法。这一语法并不属于ES标准,只是Facebook自家的代码规范。所以新手可以直接跳过(即不需要安装这一工具,也不建议去费力学习flow相关语法)。
    brew install flow

    Nuclide是由Facebook提供的基于atom的集成开发环境,可用于编写、运行调试React Native应用。
    但是推荐使用WebStormSublime TextVisual Studio Code来编写React Native应用。所有这些开发工具都是跨平台的。其中webstorm是收费的(勤劳的人自然免费了),体量较大,功能较多,基本无需配置,必然是首选。其他工具免费,相对轻量,但或多或少需要下载插件和配置。

    快速创建

    react-native init AwesomeProject
    cd AwesomeProject
    react-native run-ios
    

    可以使用--version参数(注意是两个杠)创建指定版本的项目。例如$ react-native init MyApp --version 0.44.3。注意版本号必须精确到两个小数点。
    可以使用--simulator参数指定模拟器。例如$ react-native run-ios --simulator "iPhone X"

    查看使用帮助:

    $ react-native --help
    Scanning folders for symlinks in /Users/mxr/Desktop/XDS/RN/AwesomeProject/node_modules (12ms)
    
      Usage: react-native [options] [command]
    
      Options:
    
        -V, --version                      output the version number
        -h, --help                         output usage information
    
      Commands:
    
        start [options]                    starts the webserver
        run-ios [options]                  builds your app and starts it on iOS simulator
        run-android [options]              builds your app and starts it on a connected Android emulator or device
        new-library [options]              generates a native library bridge
        bundle [options]                   builds the javascript bundle for offline use
        unbundle [options]                 builds javascript as "unbundle" for offline use
        eject [options]                    Re-create the iOS and Android folders and native code
        link [options] [packageName]       links all native dependencies (updates native build files)
        unlink [options] <packageName>     unlink native dependency
        install [options] <packageName>    install and link native dependencies
        uninstall [options] <packageName>  uninstall and unlink native dependencies
        upgrade [options]                  upgrade your app's template files to the latest version; run this after updating the react-native version in your package.json and running npm install
        log-android [options]              starts adb logcat
        log-ios [options]                  starts iOS device syslog tail
        dependencies [options]             lists dependencies
        info [options]                     Get relevant version info about OS, toolchain and libraries
    
    $ react-native run-ios --help
    Scanning folders for symlinks in /Users/mxr/Desktop/XDS/RN/AwesomeProject/node_modules (12ms)
    
      react-native run-ios [options]
      builds your app and starts it on iOS simulator
    
      Options:
    
        --simulator [string]      Explicitly set simulator to use (default: iPhone 6)
        --configuration [string]  Explicitly set the scheme configuration to use
        --scheme [string]         Explicitly set Xcode scheme to use
        --project-path [string]   Path relative to project root where the Xcode project (.xcodeproj) lives. The default is 'ios'. (default: ios)
        --device [string]         Explicitly set device to use by name.  The value is not required if you have a single device connected.
        --udid [string]           Explicitly set device to use by udid
        --no-packager             Do not launch packager while building
        --verbose                 Do not use xcpretty even if installed
        --port [number]            (default: 8081)
        --config [string]         Path to the CLI configuration file
        -h, --help                output usage information
    
      Example usage:
    
        Run on a different simulator, e.g. iPhone 5: 
        react-native run-ios --simulator "iPhone 5"
    
        Pass a non-standard location of iOS directory: 
        react-native run-ios --project-path "./app/ios"
    
        Run on a connected device, e.g. Max's iPhone: 
        react-native run-ios --device "Max's iPhone"
    
        Run on the AppleTV simulator: 
        react-native run-ios --simulator "Apple TV"  --scheme "helloworld-tvOS"
    
    $ react-native run-android --help
    Scanning folders for symlinks in /Users/mxr/Desktop/XDS/RN/AwesomeProject/node_modules (12ms)
    
      react-native run-android [options]
      builds your app and starts it on a connected Android emulator or device
    
      Options:
    
        --install-debug           
        --root [string]           Override the root directory for the android build (which contains the android directory) (default: )
        --flavor [string]         --flavor has been deprecated. Use --variant instead
        --variant [string]        
        --appFolder [string]      Specify a different application folder name for the android source. (default: app)
        --appId [string]          Specify an applicationId to launch after build. (default: )
        --appIdSuffix [string]    Specify an applicationIdSuffix to launch after build. (default: )
        --main-activity [string]  Name of the activity to start (default: MainActivity)
        --deviceId [string]       builds your app and starts it on a specific device/simulator with the given device id (listed by running "adb devices" on the command line).
        --no-packager             Do not launch packager while building
        --port [number]            (default: 8081)
        --config [string]         Path to the CLI configuration file
        -h, --help                output usage information
    
    Simulator Screen Shot - iPhone X - 2018-04-19 at 14.43.16.png

    集成到现有的原生应用

    • 设置项目目录结构

    首先创建一个空目录用于存放React Native项目
    创建一个/ios子目录,把你现有的iOS项目拷贝到/ios子目录中
    创建一个/android子目录,把你现有的Android项目拷贝到/android子目录中

    |-- AwesomeProject // 根目录
        |-- android // 安卓项目
        |-- ios // iOS项目
        |-- package.json // JavaScript依赖包配置文件
        |-- index.android.js // React Native应用在iOS上的入口文件
        |-- index.ios.js // React Native应用在Android上的入口文件
    
    • 配置package.json
    {
      "name": "MyReactNativeApp",
      "version": "0.0.1",
      "private": true,
      "scripts": {
        "start": "node node_modules/react-native/local-cli/cli.js start"
      },
      "dependencies": {
        "react": "^16.3.1",
        "react-native": "^0.55.3"
      }
    }
    

    示例中的version字段没有太大意义(除非你要把你的项目发布到npm仓库)。
    scripts中是用于启动packager服务的命令($ npm start命令则是启动开发服务器,其实$ react-native start也是一样的)。
    dependencies中的react和react-native的版本取决于你的具体需求。一般来说我们推荐使用最新版本。你可以使用npm info reactnpm info react-native来查看当前的最新版本。

    另外,react-native对react的版本有严格要求,高于或低于某个范围都不可以。
    本文无法在这里列出所有react native和对应的react版本要求,只能提醒读者先尝试执行npm install,然后注意观察安装过程中的报错信息,例如require react@某.某.某版本, but none was installed,然后根据这样的提示,执行npm i -S react@某.某.某版本

    如果你使用多个第三方依赖,可能这些第三方各自要求的react版本有所冲突,此时应优先满足react-native所需要的react版本。其他第三方能用则用,不能用则只能考虑选择其他库。

    • 安装 React & React Native & 第三方依赖

    请打开一个终端/命令提示行,进入到项目目录中(即包含有package.json文件的目录),然后运行下列命令来安装:
    $ npm install$ yarn add react-native
    终端可能会打印类似如下的语句
    react-native@0.54.4 requires a peer of react@^16.3.0-alpha.1 but none was installed.
    只需要安装上述所需的react模块即可:
    $ yarn add react@version_printed_above
    这些模块会被安装到项目根目录下的node_modules/目录中(所有通过npm install命令安装的模块都会放在这个目录中。这个目录我们原则上不复制、不移动、不修改、不上传,随用随装)。通常我们需要将node_modules/添加到.gitignore忽略文件中。

    使用 CocoaPods 导入 React Native

    • 安装CocoaPods

    CocoaPods是针对iOS和Mac开发的包管理工具。我们用它来把React Native框架的代码下载下来并添加到你当前的项目中。 我们建议使用Homebrew来安装CocoaPods。
    $ brew install cocoapods
    从技术上来讲,我们完全可以跳过CocoaPods,但是这样一来我们就需要手工来完成很多配置项。CocoaPods可以帮我们完成这些繁琐的工作。

    • 配置CocoaPods的依赖

    React Native框架整体是作为node模块安装到项目中的。下一步我们需要在CocoaPods的Podfile中指定我们所需要使用的组件。

    在你开始把React Native集成到你的应用中之前,首先要决定具体整合的是React Native框架中的哪些部分。而这就是subspec要做的工作。在创建Podfile文件的时候,需要指定具体安装哪些React Native的依赖库。所指定的每一个库就称为一个subspec

    可用的subspec都列在node_modules/react-native/React.podspec中,基本都是按其功能命名的。一般来说你首先需要添加Core,这一subspec包含了必须的AppRegistryStyleSheetView以及其他的一些React Native核心库。如果你想使用React Native的Text库(即<Text>组件),那就需要添加RCTTextsubspec。同理,Image需要加入RCTImage,等等。

    我们需要在Podfile文件中指定所需的subspec。创建Podfile的最简单的方式就是在/ios子目录中使用CocoaPods的init命令:
    $ pod init
    Podfile会创建在执行命令的目录中。你需要调整其内容以满足你的集成需求。调整后的Podfile的内容看起来类似下面这样:

    # Uncomment the next line to define a global platform for your project
      platform :ios, '8.0'
    
    # The target name is most likely the name of your project.
    target 'NumberTileGame' do
      # Uncomment the next line if you're using Swift or would like to use dynamic frameworks
      # use_frameworks!
    
      # Pods for NumberTileGame
      # Your 'node_modules' directory is probably in the root of your project,
      # but if not, adjust the `:path` accordingly
      pod 'React', :path => '../node_modules/react-native', :subspecs => [
        'Core',
        'CxxBridge', # Include this for RN >= 0.47
        'DevSupport', # Include this to enable In-App Devmenu if RN >= 0.43
        'RCTText',
        'RCTNetwork',
        'RCTWebSocket', # Needed for debugging
        'RCTAnimation', # Needed for FlatList and animations running on native UI thread
        # Add any other subspecs you want to use in your project
      ]
      # Explicitly include Yoga if you are using RN >= 0.42.0
      pod 'yoga', :path => '../node_modules/react-native/ReactCommon/yoga'
    
      # Third party deps podspec link
       pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec'
       pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec'
       pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'
    
      target 'NumberTileGameTests' do
        inherit! :search_paths
        # Pods for testing
      end
    
    end
    
    

    创建好了Podfile后,就可以开始安装React Native的pod包了。
    $ pod install

    常见问题&解决方案

    问题一

    [!] Unable to satisfy the following requirements:
    
    - `React/Core (from `../node_modules/react-native`)` required by `Podfile`
    
    Specs satisfying the `React/Core (from `../node_modules/react-native`)` dependency were found, but they required a higher minimum deployment target.
    

    在Podfile中添加指定最低为8.0的开发版本:platform :ios, '8.0'

    问题二

    [!] Unable to find a specification for `boost-for-react-native` depended upon by `Folly`
    

    执行$ pod update更新pods库即可。

    • pod install & pod update & pod repo update 加速技巧

    使用$ pod repo查看本地的master库

    $ pod repo
    
    aliyun
    - Type: git (master)
    - URL:  https://github.com/aliyun/aliyun-specs.git
    - Path: /Users/MountainX/.cocoapods/repos/aliyun
    
    lunboPodWSpec
    - Type: git (master)
    - URL:  https://github.com/DevaLee/lunboPodWSpec.git
    - Path: /Users/MountainX/.cocoapods/repos/lunboPodWSpec
    
    Specs
    - Type: git (master)
    - URL:  https://github.com/CocoaPods/Specs.git
    - Path: /Users/MountainX/.cocoapods/repos/Specs
    
    3 repos
    

    使用$ pod repo remove NAME来移除不要的master库

    $ pod repo remove master
    $ pod repo add master https://gitcafe.com/akuandev/Specs.git //添加pod的repo源
    $ pod repo update
    

    加速方法:进入到repos目录下,通过git clone直接添加到master库,命令行如下:

    $ cd ~/.cocoapods/repos 
    $ pod repo remove master
    $ git clone https://github.com/CocoaPods/Specs.git master
    

    首先要把本地老的master分支给移除掉,然后使用git clone从github镜像源上clone一份且设置本地master库。这样本地的repo就是最新的了。

    $ git clone https://github.com/CocoaPods/Specs.git master
    
    Cloning into 'master'...
    remote: Counting objects: 2067512, done.
    remote: Compressing objects: 100% (177/177), done.
    remote: Total 2067512 (delta 78), reused 35 (delta 35), pack-reused 2067295
    Receiving objects: 100% (2067512/2067512), 529.53 MiB | 95.00 KiB/s, done.
    Resolving deltas: 100% (1164658/1164658), done.
    Checking out files: 100% (230184/230184), done.
    

    此时再进入到当前工程目录下,执行下面的命令行
    $ pod install --no-repo-update --verbose
    $ pod update --no-repo-update --verbose

    其中--verbose的作用就是打印出执行过程中详细的信息,--no-repo-update的作用就是禁止更新repo,这样就避免执行了git fetch,从而加快速度。

    这样就解决了工程依赖的第三方库版本过低需要更新的问题。

    但是我们在clone github镜像源的时候,发现速度还是比较慢的,这是因为国内访问github的速度不给力,没办法的事情,这个时候可以考虑挂一个VPN或者使用国内一些网站提供的镜像源。
    目前搜集到的可选源有:
    https://gitcafe.com/akuandev/Specs.git
    http://git.oschina.net/akuandev/Specs.git
    https://git.coding.net/hging/Specs.git
    其实就是常见的git托管站

    比如换成coding提供的一个镜像源,命令行如下:

    $ cd ~/.cocoapods/repos 
    $ pod repo remove master
    $ git clone https://git.coding.net/hging/Specs.git master
    

    这样在clone的时候会发现速度很快哈。
    另外,在自己工程中的Podfile文件加入下面一行描述:

    source 'https://git.coding.net/hging/Specs.git'
    

    如果不加这一句话,它默认还是从github镜像源地址去下载的,这个不要给忘记了。

    注意

    • master repo里面存放的是所有第三方库的地址列表,下载第三方库对应的源码还是要到指定的源码存放地址(podspecs中有指定)去下载。更换repo源只是加快了repo的下载速度,并不会加快第三方库源码的下载速度,两者是没有任何关系的。
    • 在工程中尽量避免直接使用pod update、pod install,在后面添加--no-repo-update后使用。
    • 工程中依赖第三方库版本过低,可以先到repos目录下,使用git clone更新master repo,然后在工程中使用pod update --no-repo-update命令。

    上述方案一定程度上加快了CocoaPods的执行速度,但是仍然避免不了要更新全部repo的情况,而实际情况是我们项目当中用到的第三方库大部分只需要十几个,大量的时间被浪费在我们不需要的库上面了。因为CocoaPods是使用中心化的方式来进行管理的,所以当第三方库多起来的时候,就会出现刚才的情况,这个时候可以选择使用Carthage来管理第三方库,它比CocoaPods最大的优势就在于去中心化的方式来管理,不过Carthage的缺点是里面的库还不是很丰富,不过随着时间的推移就不是问题了。

    问题三

    如果集成到原有项目中报错:'folly/folly-config.h' file not found
    则需要更新yarn后重新安装,如果还是无法解决,那就需要回退到稳定版本了。

    • 更新 Yarn

    warning Your current version of Yarn is out of date. The latest version is "1.6.0" while you're on "0.24.5".
    info To upgrade, run the following command:

    $ npm upgrade --global yarn
    

    sudo npm upgrade --global yarn不能更新yarn?

    $ yarn --version
    yarn install v0.24.5
    [1/4] 🔍  Resolving packages...
    success Already up-to-date.
    ✨  Done in 1.01s.
    

    卸了重新安装即可:
    npm uninstall -g yarn && npm install -g yarn

    问题四

    运行.xcworkspace项目后报错:'React/RCTBundleURLProvider.h’ file not found

    解决:Delete node modules, then run npm
    install (or better yet yarn) and after everything has finished downloading, run react-native
    upgrade which should give you the option to replace old files with the template ones, by doing so you re-link your native dependencies in react-native which should fix your problem. Of course don't forget to clean your project in Xcode

    翻译:
    删除node modules文件夹(一般在根目录)$ sudo rm -r -f node_modules/,然后运行 $ npm install(也是在根目录),install 结束后再运行 $ react-native upgrade

    代码集成示例

    现在我们已经准备好了所有依赖,可以开始着手修改原生代码来把React Native真正集成到应用中了。在我们的2048示例中,首先尝试添加一个显示有"High Score"(得分排行榜)的React Native页面。

    1. 创建一个index.ios.js文件

    index.ios.js是React Native应用在iOS上的入口文件。而且它是不可或缺的!它可以是个很简单的文件,简单到可以只包含一行require/import导入语句。

    # 在项目根目录执行以下命令创建文件:
    $ touch index.ios.js
    
    1. 添加你自己的React Native代码

    为了简单示范,把全部的代码都写到了index.ios.js里(当然实际开发中并不推荐这样做)。

    # 进入命令模式
    vim index.ios.js
    # 在命令模式下按下 'i' 进入输入模式
    /*  
    在输入模式中,可以使用以下按键:
    ENTER(回车键)                          换行
    BACK SPACE / Delete (退格键)           删除光标前一个字符
    Fn + BACK SPACE / Delete               删除光标后的一个字符
    方向键                                 在文本中移动光标
    HOME/END                               移动光标到行首/行尾
    Page Up/Page Down                      上/下翻页
    ESC                                    退出输入模式,切换到命令模式
    */
    /*
    在苹果Mac电脑的键盘上没有Home, End, Page UP, Page DOWN这些键,可以通过用Fn键来组合得到同样的功能:
    Home = Fn + 左方向
    End = Fn + 右方向
    Page UP = Fn + 上方向
    Page DOWN = Fn + 下方向
    向前 Delete = Fn + delete键。
    */
    # 在命令模式下按下英文冒号 ':' 就进入了底线命令模式
    /*
    底线命令模式可以输入单个或多个字符的命令,可用的命令非常多。
    在底线命令模式中,基本的命令如下
        :w      将编辑的数据写入硬盘档案中
        :w!     强制将编辑的数据写入硬盘档案中
        :q      离开
        :q!     为强制离开不储存档案
        :wq     储存后离开
        :wq!    强制储存后离开
        :set nu       显示行号,设定之后,会在每一行的前缀显示该行的行号
        :set nonu     取消行号
        按ESC键可随时退出底线命令模式
    */
    

    编辑index.ios.js如下

    //index.ios.js
    '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.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,
      },
    });
    
    // MyReactNativeApp整体js模块的名称
    AppRegistry.registerComponent('MyReactNativeApp', () => RNHighScores);
    
    1. 原生接入RN模块

    现在我们已经在index.ios.js中创建了React Native组件,下一步就是把这个组件添加给一个新的或已有的ViewController。

    首先导入RCTRootView的头文件。

    #import <React/RCTRootView.h>
    

    原生项目中添加跳转React-Native的按钮并定义点击事件如下

    - (IBAction)highScoreButtonPressed:(id)sender {
        NSLog(@"High Score Button Pressed");
        NSURL *jsCodeLocation = [NSURL
                                 URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios"];
        RCTRootView *rootView =
          [[RCTRootView alloc] initWithBundleURL : jsCodeLocation
                               moduleName        : @"MyReactNativeApp"
                               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];
    }
    
    1. Info.plist中添加App Transport Security例外
    <key>NSAppTransportSecurity</key>
    <dict>
        <key>NSExceptionDomains</key>
        <dict>
            <key>localhost</key>
            <dict>
                <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
                <true/>
            </dict>
        </dict>
    </dict>
    
    1. 启动开发服务器
    # 在项目根目录执行:
    $ npm start
    //或者
    $ react-native start
    
    1. 运行应用

    如果你使用的是Xcode,那么照常编译和运行应用即可。
    如果你不想使用Xcode(但是你仍然必须安装Xcode),则可以在命令行中使用以下命令来运行应用:

    # 在项目的根目录中执行:
    $ react-native run-ios
    
    1. 运行结果
      Simulator Screen Shot - iPhone X - 2018-04-19 at 15.35.49.png
      可以直接编辑index.ios.js,保存后在模拟器上Cmd + R(真机可以摇一摇)即可看到及时更新
      Simulator Screen Shot - iPhone X - 2018-04-19 at 15.44.42.png

    Demo下载

    RN_AwesomeProject
    RN_NumberTileGame

    参考:
    React Native - English
    React Native - 中文
    Unable to find a specification for 'boost-for-react-native' depended upon by 'Folly'
    解决CocoaPods慢的小技巧
    解决CocoaPods各种慢的方案(gem换源+pod repo换源)
    Mac终端 vi/vim 的简单使用

    相关文章

      网友评论

        本文标题:React-Native操作随笔(一)

        本文链接:https://www.haomeiwen.com/subject/queskftx.html