现有原生iOS和安卓项目集成React-Native

一、创建工程
到自己创建项目的文件夹下输入命令:

react-native init 项目名

当然如果你想指定安装react-native版本的话你也可以这样
后面的0.57.1可以自定义成自己的版本

react-native init 项目名 --version 0.57.1

目录结构还这样的


现有原生iOS和安卓项目集成React-Native_第1张图片
image.png

这里android和ios 文件夹你可以删掉换成自己的现有iOS和安卓项目.
删掉android和iOS文件夹后
添加React Native所需要的依赖
目录结构如下

RN项目
├── Android项目
├── iOS项目
├── package.json
├── node_modules
└── .gitignore

我们来先说安卓怎么配置

第一步:配置maven

接下来我们需要为已经存在的RN项目添加 React Native依赖,在RN项目/Android项目/app/build.gradle文件中添加如下

dependencies {
    compile 'com.android.support:appcompat-v7:+'
    ...
    compile "com.facebook.react:react-native:+" // From node_modules
}
现有原生iOS和安卓项目集成React-Native_第2张图片
image.png

然后,我们为RN项目配置使用的本地React Native maven目录,在RN项目/Android项目/build.gradle文件中添加如下代码:

allprojects {
    repositories {
        mavenLocal()
        maven {
            // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
            url "$rootDir/../node_modules/react-native/android"
        }
        ...
    }
    ...
}

现有原生iOS和安卓项目集成React-Native_第3张图片
image.png

这里需要注意的是url "$rootDir/../node_modules/react-native/android"路径的问题
如果你是把package.json文件放在Android项目目录下的话
也就是说RN项目/Android项目/package.json
那么这里你要这么写提示:为确保你配置的目录正确,可以通过在Android Studio中运行Gradle sync 看是否有 “Failed to resolve: com.facebook.react:react-native:0.x.x” 的错误出现,没有错误则说明配置正确,否则说明配置路由有问题。

url "$rootDir/node_modules/react-native/android

第二步:配置权限

接下来我们为APP运行配置所需要的权限:检查你项目中的AndroidManifest.xml文件中看是否有如下权限:

另外,如果你需要用到RN的Dev Settings功能:

现有原生iOS和安卓项目集成React-Native_第4张图片
image.png

则需要在AndroidManifest.xml文件中添加如下代码:

上面这些Android就简单的配置完成了
然后修改RN项目的index.js文件
如果你项目比较老的话,那么这个文件将是index.ios.js和index.android.js请自行选择

有些同学不会导入包裹
import { AppRegistry } from 'react-native';
import App from './App';

AppRegistry.registerComponent('App1', () => App);

App1就是以后你要跳转到的RN 项目的页面
另外,在上述代码中我们引用了一个App.js文件

import React, { Component } from 'react';
import {
  Platform,
  StyleSheet,
  Text,
  View
} from 'react-native';

type Props = {};
export default class App extends Component {
  render() {
    return (
      
        
          我是RN页面
        
      
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  }
 });
为React Native创建一个Activity来作为容器

创建RNPageActivity
首先我们需要创建一个Activity来作为React Native的容器,

//有些同学不知道包名是什么这里我都直接导入复制进来
import android.app.Activity;
import android.databinding.Bindable;
import android.os.Bundle;
import android.view.KeyEvent;

import com.facebook.react.ReactActivity;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactRootView;
import com.facebook.react.common.LifecycleState;
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
import com.facebook.react.shell.MainReactPackage;
import com.lanto.goodfix.base.SimpleActivity;
public class RNPageActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler {
    private ReactRootView mReactRootView;
    private ReactInstanceManager mReactInstanceManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mReactRootView = new ReactRootView(this);
        mReactInstanceManager = ReactInstanceManager.builder()
            .setApplication(getApplication())
            .setBundleAssetName("index.android.bundle")
            .setJSMainModulePath("index")
            .addPackage(new MainReactPackage())
            .setUseDeveloperSupport(BuildConfig.DEBUG)
            .setInitialLifecycleState(LifecycleState.RESUMED)
            .build();
        // 这个"App1"名字一定要和我们在index.js中注册的名字保持一致AppRegistry.registerComponent()
        mReactRootView.startReactApplication(mReactInstanceManager, "App1", null);

        setContentView(mReactRootView);
    }

    @Override
    public void invokeDefaultOnBackPressed() {
        super.onBackPressed();
    }
}
//为ReactInstanceManager添加Activity的生命周期回调
//一个 ReactInstanceManager可以被多个activities或fragments共享,
//所以我们需要在Activity的//生命周期中回调ReactInstanceManager的对于的方法。
@Override
protected void onPause() {
    super.onPause();

    if (mReactInstanceManager != null) {
        mReactInstanceManager.onHostPause(this);
    }
}

@Override
protected void onResume() {
    super.onResume();

    if (mReactInstanceManager != null) {
        mReactInstanceManager.onHostResume(this, this);
    }
}

@Override
public void onBackPressed() {
    if (mReactInstanceManager != null) {
        mReactInstanceManager.onBackPressed();
    } else {
        super.onBackPressed();
    }
}

@Override
protected void onDestroy() {
    super.onDestroy();

    if (mReactInstanceManager != null) {
        mReactInstanceManager.onHostDestroy(this);
    }
    if (mReactRootView != null) {
        mReactRootView.unmountReactApplication();
    }
}
@Override
public void invokeDefaultOnBackPressed() {
    super.onBackPressed();
}
public boolean onKeyUp(int keyCode, KeyEvent event) {
    if (getUseDeveloperSupport()) {
        if (keyCode == KeyEvent.KEYCODE_MENU) {//Ctrl + M 打开RN开发者菜单
            mReactInstanceManager.showDevOptionsDialog();
            return true;
        }
    }
    return super.onKeyUp(keyCode, event);
}

参数说明

setBundleAssetName:打包时放在assets目录下的JS bundle包的名字,App release之后会从该目录下加载JS bundle;
setJSMainModulePath:JS bundle中主入口的文件名,也就是我们上文中创建的那个index.js文件;
addPackage:向RN添加Native Moudle,在上述代码中我们添加了new MainReactPackage()这个是必须的,另外,如果我们创建一些其他的Native Moudle也需要通过addPackage的方式将其注册到RN中。需要指出的是RN除了这个方法外,也提供了一个addPackages方法用于批量向RN添加Native Moudle;
setUseDeveloperSupport:设置RN是否开启开发者模式(debugging,reload,dev memu),比如我们常用开发者弹框;
setInitialLifecycleState:通过这个方法来设置RN初始化时所处的生命周期状态,一般设置成LifecycleState.RESUMED就行,和下文讲的Activity容器的生命周期状态关联;
mReactRootView.startReactApplication:它的第一个参数是mReactInstanceManager,第二个参数是我们在index.js中注册的组件的名字,第三个参数接受一个Bundle来作为RN初始化时传递给JS的初始化数据
在中AndroidManifest.xml注册一个RNPageActivity

运行React Native

找到你package.json的所在文件夹输入
npm start
然后我们打开AndroidStudio,点击运行按钮或者通过快捷键Ctrl+R来将项目安装到模拟器上:

现有原生iOS和安卓项目集成React-Native_第5张图片
image.png

添加更多React Native的组件

import { AppRegistry } from 'react-native';
import App from './App';
import App2 from './App2';

AppRegistry.registerComponent('App1', () => App);
AppRegistry.registerComponent('App2', () => App);
//这里可以添加多个,只要对应就可以了
//目前这种方法是可以自定义比较灵活的一种集成方式
//祝大家好运,到此安卓就集成完成了

下面再说几句
如果你是在模拟器上运行,那么这样就可以了
如果是真机,你要这样输入
先安装index.android.bundle

//先创建下面路径的assets文件夹
react-native bundle --platform android --dev false --entry-file index.js --bundle-output 安卓项目名/app/src/main/assets/index.android.bundle --assets-dest app/src/main/res/

//一定要注意你的路径

//然后终端输入
adb reverse tcp:8081 tcp:8081
npm start

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^分割线^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

下面就是iOS项目的集成了

iOS项目我们采用pod来集成,相对简单,不会出现各种添加错误的问题

首先在pod Podfile文件中添加
这里需要主语rn_path 路径问题,写你自己的路径

rn_path = '../node_modules/react-native'
    pod 'React', :path => '../node_modules/react-native', :subspecs => [
    'Core',
    'ART',
    'CxxBridge',
    'RCTActionSheet',
    'RCTGeolocation',
    'RCTImage',
    'RCTAnimation’,
    'RCTNetwork',
    'RCTPushNotification',
    'RCTSettings',
    'RCTText',
    'RCTVibration',
    'RCTWebSocket',
    'RCTLinkingIOS',
    'DevSupport'
    ]
    pod 'yoga', path: "#{rn_path}/ReactCommon/yoga"
    pod 'glog', :podspec => "#{rn_path}/third-party-podspecs/glog.podspec"
#
    # React Native third party dependencies podspecs
    pod 'DoubleConversion', :podspec => "#{rn_path}/third-party-podspecs/DoubleConversion.podspec"
    pod 'Folly', :podspec => "#{rn_path}/third-party-podspecs/Folly.podspec"

然后到podfile所在文件夹 再次
pod install

如果运行起来后报这个错误的话


现有原生iOS和安卓项目集成React-Native_第6张图片
image.png

请用以下解决
在podfile 文件中添加如下代码

def change_lines_in_file(file_path, &change)
    print "Fixing #{file_path}...\n"
    
    contents = []
    
    file = File.open(file_path, 'r')
    file.each_line do | line |
        contents << line
    end
    file.close
    
    File.open(file_path, 'w') do |f|
        f.puts(change.call(contents))
    end
end

post_install do |installer|
    # https://github.com/facebook/yoga/issues/711#issuecomment-381098373
    change_lines_in_file('./Pods/Target Support Files/yoga/yoga-umbrella.h') do |lines|
        lines.reject do | line |
            [
            '#import "Utils.h"',
            '#import "YGLayout.h"',
            '#import "YGNode.h"',
            '#import "YGNodePrint.h"',
            '#import "YGStyle.h"',
            '#import "Yoga-internal.h"',
            ].include?(line.strip)
        end
    end
    
    # https://github.com/facebook/yoga/issues/711#issuecomment-374605785
    change_lines_in_file('../node_modules/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceSizeMeasureMode.h') do |lines|
        unless lines[27].include?("#ifdef __cplusplus")
            lines.insert(27, "#ifdef __cplusplus")
            lines.insert(34, "#endif")
        end
        lines
    end
    
    # https://github.com/facebook/react-native/issues/13198
    change_lines_in_file('../node_modules/react-native/Libraries/NativeAnimation/RCTNativeAnimatedNodesManager.h') do |lines|
        lines.map { |line| line.include?("#import ") ? '#import "RCTValueAnimatedNode.h"' : line }
    end
    
    # https://github.com/facebook/react-native/issues/16039
    change_lines_in_file('../node_modules/react-native/Libraries/WebSocket/RCTReconnectingWebSocket.m') do |lines|
        lines.map { |line| line.include?("#import ") ? '#import "fishhook.h"' : line }
    end
end

接下来你需要配置index.js文件 这里就省略了 同安卓那边的,可以自己看
也就是这步

import { AppRegistry } from 'react-native';
import App from './App';
import App2 from './App2';

AppRegistry.registerComponent('App1', () => App);
AppRegistry.registerComponent('App2', () => App);

接下来在你需要跳转的地方OC代码里加入

 NSURL *jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
        
        
        RCTRootView *rootView =
        
        [[RCTRootView alloc] initWithBundleURL: jsCodeLocation
                                    moduleName: @"QiXiu"
                             initialProperties:
         @{
           @"name" : @[
                   @{
                       @"name" : @"Alex",
                       @"value": @"42"
                       },
                   @{
                       @"name" : @"Joel",
                       @"value": @"10"
                       }
                   ]
           }
                                 launchOptions: nil];
        UIViewController *vc = [[SHCustomerViewController alloc] init];
        vc.view = rootView;
        //[self presentViewController:vc animated:YES completion:nil];
        [self.navigationController pushViewController:vc animated:nil];
        vc.title = @"我是RN页面";

注意这行代码[[RCTRootView alloc] initWithBundleURL: jsCodeLocation moduleName: @"App1" initialProperties:
这里的 App1 就是你配置的页面

你可能感兴趣的:(现有原生iOS和安卓项目集成React-Native)