An open API service indexing awesome lists of open source software.

https://github.com/younatics/react-native-integration-with-existing-app

React Native Integration with existing app
https://github.com/younatics/react-native-integration-with-existing-app

integration react reactnative

Last synced: 5 months ago
JSON representation

React Native Integration with existing app

Awesome Lists containing this project

README

          

# React Native [0.45.1] Integration with the existing apps

## Purpose
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](http://facebook.github.io/react-native/releases/next/docs/integration-with-existing-apps.html#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.

## Develop Enviroment
This document is based on below version. React Native currently changes a lot, so be careful.

```javascript
"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.

## Getting started
### Step 1. Install tools and init project
#### Install tools
you can also see this in [Getting Started](http://facebook.github.io/react-native/releases/next/docs/getting-started.html)
```
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.
```javascript
{
"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.

---
### Step 2. Add postinstall in package.json
```javascript
{
"name": "ReactProject",
"version": "0.0.1",
"private": true,
"scripts": {
"postinstall": "sed -i '' 's/#import /#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 `. You need to change it to `#import "RCTValueAnimatedNode.h`. So use `postinstall`

---
### Step 3. Git clone your iOS and Android Project
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]
```

---
### Step4. Modify iOS project
You can do this step easily with the iOS depedency tool `cocoapods`. Add libraries in `Podfile` and `pod install`
```ruby
#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`
```Swift
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.
```Swift
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`
```Swift
@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
```Swift
#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
```

---
### Step4. Modify Android project

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

```Java
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
```Java
@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

```Java
class ReactManagerBridge() : ReactPackage {

override fun createJSModules(): List> {
return emptyList()
}

override fun createViewManagers(reactContext: ReactApplicationContext): List> {
val modules = ArrayList>()
return modules
}

override fun createNativeModules(reactContext: ReactApplicationContext): List {
val modules = ArrayList()

modules.add(ReactManager(reactContext))
return modules
}

}
```

Add reactmanager to call method

```Java
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!