This repository was made for React Natvie users who want to integrate RN[0.45.1] to the existing application using Swift3, Obbjective-C, JAVA, Kotlin. Integration with existing apps is well documented, but I wanted to make it more easy. This document was recorded after the recent test. Feel free to make Pull Request. Thanks.
This document is based on below version. React Native currently changes a lot, so be careful.
"dependencies": {
"react": "16.0.0-alpha.12",
"react-native": "0.45.1"
}
If you have iOS
and Android
application independently, this will be the perfect guide for you. Please follow these steps.
you can also see this in Getting Started
brew install node
brew install watchman
npm install -g react-native-cli
If you are all done with the above, init your project.
react-native init ReactProject
In your ReactProject
directory, you can find package.json
. this should look like this.
{
"name": "ReactProject",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"test": "jest"
},
"dependencies": {
"react": "16.0.0-alpha.6",
"react-native": "0.44.0"
},
"devDependencies": {
"babel-jest": "20.0.3",
"babel-preset-react-native": "1.9.2",
"jest": "20.0.4",
"react-test-renderer": "16.0.0-alpha.6"
},
"jest": {
"preset": "react-native"
}
}
you can't use
expo
when you integrate with existing apps.
{
"name": "ReactProject",
"version": "0.0.1",
"private": true,
"scripts": {
"postinstall": "sed -i '' 's/#import <RCTAnimation\\/RCTValueAnimatedNode.h>/#import \"RCTValueAnimatedNode.h\"/' ./node_modules/react-native/Libraries/NativeAnimation/RCTNativeAnimatedNodesManager.h",
"start": "node node_modules/react-native/local-cli/cli.js start",
"test": "jest"
},
"dependencies": {
"react": "16.0.0-alpha.12",
"react-native": "0.45.1"
},
"devDependencies": {
"babel-jest": "20.0.3",
"babel-preset-react-native": "2.0.0",
"jest": "20.0.4",
"react-test-renderer": "16.0.0-alpha.12"
},
"jest": {
"preset": "react-native"
}
}
Currently, RN 0.45.1 have a problem in iOS - #import <RCTAnimation\\/RCTValueAnimatedNode.h>
. You need to change it to #import "RCTValueAnimatedNode.h
. So use postinstall
Main purpose of this step is to make a structure for configuration management. You can just copy and paste to /android
directory and /iOS
directory. or git clone
to make a structure as below.
[React native repository]
|
|- /android [Android repository]
|- /ios [iOS repository]
You can do this step easily with the iOS depedency tool cocoapods
. Add libraries in Podfile
and pod install
#React Native
pod 'React', :path => '../node_modules/react-native', :subspecs => [
'Core',
'RCTText',
'RCTNetwork',
'RCTImage',
'RCTWebSocket',
'DevSupport',
'BatchedBridge',
'RCTAnimation'
]
pod 'Yoga', :path => '../node_modules/react-native/ReactCommon/yoga'
Make UIViewController
to present React Native view
import UIKit
import React
import SnapKit
class ReactViewController: UIViewController, ZBAnSimPopupDelegate {
var reactView: RCTRootView!
var item_id: Int?
override func loadView() {
super.loadView()
guard let id = item_id else { return }
let mockData = ["item_id": "\(id)"]
self.reactView = ReactBridge.shared.viewForModule("ReactProject", initialProperties: mockData)
self.view.addSubview(self.reactView)
self.reactView.snp.makeConstraints { (m) in
m.edges.equalTo(self.view)
}
}
}
Add React Bridge
to communicate with index.ios.js
<-> UIViewController
. forHotReloading
flag is for compile bundle or localhost.
let localUrl = "http://localhost:8081/index.ios.bundle?platform=ios&dev=true"
let forHotReloading = false
class ReactBridge: NSObject {
static let shared = ReactBridge()
}
extension ReactBridge: RCTBridgeDelegate {
func sourceURL(for bridge: RCTBridge!) -> URL! {
return URL(string: localUrl)
}
func createBridgeIfNeeded() -> RCTBridge {
let bridge = RCTBridge.init(delegate: self, launchOptions: nil)
return bridge ?? RCTBridge()
}
func viewForModule(_ moduleName: String, initialProperties: [String : Any]?) -> RCTRootView {
if forHotReloading {
let viewBridge = createBridgeIfNeeded()
let rootView: RCTRootView = RCTRootView(
bridge: viewBridge,
moduleName: moduleName,
initialProperties: initialProperties)
return rootView
} else {
if let iosBundle = Bundle.main.url(forResource: "main", withExtension: "jsbundle") {
guard let bundleRootView = RCTRootView(bundleURL: iosBundle, moduleName: moduleName, initialProperties: initialProperties, launchOptions: nil) else { return RCTRootView() }
return bundleRootView
}
}
return RCTRootView()
}
}
Add ReactManager.swift
to call method with Native
<-> React-Native
@objc(ReactManager) class ReactManager: NSObject {
var bridge: RCTBridge!
@objc func back(_ reactTag: NSNumber) {
DispatchQueue.main.async {
if let view = self.bridge.uiManager.view(forReactTag: reactTag) {
let presentedViewController = view.reactViewController()
presentedViewController?.navigationController?.pop(animated: true)
}
}
}
}
We need an addtional Objective-C file
beacuse React
uses macro. Add ReactManagerBridge.m
file like this
#import "ReactManagerBridge.h"
#import "zigbang-Swift.h"
@implementation ReactManagerBridge
RCT_EXPORT_MODULE(ReactManager);
RCT_EXPORT_METHOD(back:(nonnull NSNumber *)reactTag) {
ReactManager* reactManager = [[ReactManager alloc] init];
reactManager.bridge = _bridge;
[reactManager back:reactTag];
}
@end
add dependency in build.gradle
allprojects {
repositories {
mavenLocal()
jcenter()
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url "$rootDir/../node_modules/react-native/android"
}
}
}
in your app.gradle
. I added exclude
becuase it conflicts with existing dependecies
compile ("com.facebook.react:react-native:+") {
exclude group:'com.facebook.stetho', module:'stetho'
}
Add ReactInstanceManager
to use it in React Native
. I recommend to make an instance in Mainapplication
because it takes some time to generate an instance
public static ReactInstanceManager react;
this.react = ReactInstanceManager.builder()
.setApplication(this)
.setBundleAssetName("index.android.bundle")
.setJSMainModuleName("index.android")
.addPackage(new MainReactPackage())
.addPackage(new ReactManagerBridge())
.setUseDeveloperSupport(BuildConfig.DEBUG)
.setInitialLifecycleState(LifecycleState.RESUMED)
.build();
Modify your ReactRootView
where you want to use. Also, add props to pass parameter
@BindView(R.id.container)
ReactRootView container;
react = MainApplication.react;
Bundle props = new Bundle();
props.putString("items", new Gson().toJson(response));
container.startReactApplication(react, "ReactProject", props);
Add bridge to communicate with Native
class ReactManagerBridge() : ReactPackage {
override fun createJSModules(): List<Class<out JavaScriptModule>> {
return emptyList()
}
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
val modules = ArrayList<ViewManager<*, *>>()
return modules
}
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
val modules = ArrayList<NativeModule>()
modules.add(ReactManager(reactContext))
return modules
}
}
Add reactmanager to call method
class ReactManager(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
fun ReactManager(reactContext: ReactApplicationContext) {
super.getReactApplicationContext()
}
override fun getName(): String {
return "ReactManager"
}
@ReactMethod
fun alert(message: String) {
Toast.makeText(getReactApplicationContext(), message, Toast.LENGTH_LONG).show()
}
}
This is all about setting your react native to existing application!