跨平台

React Native之集成到现有原生应用中(iOS)

2019-02-11  本文已影响3人  平安喜乐698
目录


1. iOS

<1>创建目录

首先创建一个空目录(根目录)用于存放 React Native 项目;
然后在其中创建一个ios子目录,把现有的 iOS 项目拷贝到ios子目录中;

<2>安装React 和 React Native 模块

在根目录下创建一个名为package.json的空文本文件,然后填入以下内容:
  {
    "name": "MyReactNativeApp",
    "version": "0.0.1",
    "private": true,
    "scripts": {
      "start": "node node_modules/react-native/local-cli/cli.js start"
    }
  }
用 yarn 或 npm(两者都是 node 的包管理器)来安装 React 和 React Native 模块。(所有 JavaScript 依赖模块都会被安装到根目录下的node_modules目录中)
  yarn add react-native 或 yarn add react@16.2.0

<3>配置CocoaPods,并安装

可用的subspec都列在node_modules/react-native/React.podspec中
  必要的Core(含了必须的AppRegistry、StyleSheet、View以及其他的一些 React Native 核心库);
  想使用 Text,则加入RCTText;
  想使用 Image,则加入RCTImage;
  等等

Podfile示例如下:

# platform :ios, '9.0'

target '项目名' do
  # use_frameworks!

  # 'node_modules'目录一般位于根目录中
  # 但是如果你的结构不同,那你就要根据实际路径修改下面的`:path`
  pod 'React', :path => '../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 => '../node_modules/react-native/ReactCommon/yoga'

  # 如果RN版本 >= 0.45则加入下面三个第三方编译依赖
  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'

end

<4>项目根目录下创建index.js

import React, { Component } 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,
  },
});

AppRegistry.registerComponent('RNHighScores', () => RNHighScores);

<5>ViewController中

#import <React/RCTRootView.h>


    NSURL *jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.bundle?platform=ios"];
    // moduleName和js组件名要一致
    // initialProperties可以在js组件this.props['scores']获取,这一字典参数会在内部被转化为一个可供 JS 组件调用的 JSON 对象
    RCTRootView *rootView =
    [[RCTRootView alloc] initWithBundleURL: jsCodeLocation
                                moduleName: @"RNHighScores"
                         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];
其他(略过)

rootView.appProperties = @{@"images" : @[@"",@""]};
  1、设置appProperties之后,React Native 应用将会根据新的属性重新渲染(仅当新旧属性不一样时)。
  2、必须在主线程中设置
  3、如果在 bridge 还没初始化完成前就设置 appProperties,设置可能会无效
  4、componentWillReceiveProps和componentWillUpdateProps方法在属性更新后不会触发。但可以通过componentWillMount访问新的属性值


rootView.delegate = self;
rootView.sizeFlexibility = RCTRootViewSizeFlexibilityHeight;
#pragma mark - RCTRootViewDelegate
- (void)rootViewDidChangeIntrinsicSize:(RCTRootView *)rootView{
  CGRect newFrame = rootView.frame;
  newFrame.size = rootView.intrinsicContentSize;
  rootView.frame = newFrame;
}
/*
  在 JS 和原生中都设置弹性尺寸可能导致不确定的行为。
  改变根视图的弹性模式将会导致布局的重新计算,并且在重新量出内容尺寸时会调用rootViewDidChangeIntrinsicSize方法
  RCTRootView支持 4 种不同的弹性布局模式。
  typedef NS_ENUM(NSInteger, RCTRootViewSizeFlexibility) {
    RCTRootViewSizeFlexibilityNone = 0,  默认值
    RCTRootViewSizeFlexibilityWidth,
    RCTRootViewSizeFlexibilityHeight,
    RCTRootViewSizeFlexibilityWidthAndHeight,
  };
 React Native 布局是通过一个特殊的线程进行计算,而原生 UI 视图是通过主线程更新。这可能导致短暂的原生端和 React Native 端的不一致。
*/

<6>info.plist中加

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

<7>运行应用

项目根目录下

npm start
启动开发服务器(即 Packager,它负责实时监测 js 文件的变动并实时打包,输出给客户端运行)

react-native run-ios
运行应用
上一篇下一篇

猜你喜欢

热点阅读