Skip to content

Commit

Permalink
Initial Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
avishayil committed Jul 17, 2016
0 parents commit a2e8a51
Show file tree
Hide file tree
Showing 18 changed files with 840 additions and 0 deletions.
41 changes: 41 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Numerous always-ignore extensions
*.diff
*.err
*.orig
*.log
*.rej
*.swo
*.swp
*.vi
*~
*.sass-cache

# OS or Editor folders
.DS_Store
.cache
.project
.settings
.tags
.tmproj
.iml
nbproject
Thumbs.db
tags

# NPM packages folder.
node_modules/

# Brunch folder for temporary files.
tmp/

# Brunch output folder.
public/

# Bower stuff.
bower_components/

# API Docs
docs/api/

# DotEnv
.env
1 change: 1 addition & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
examples
22 changes: 22 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
The MIT License (MIT)

Copyright (c) 2016 Avishay Bar

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

142 changes: 142 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# React Native Restart

Restart Your React Native Project

[![npm version](https://img.shields.io/npm/v/react-native-restart.svg?style=flat-square)](https://www.npmjs.com/package/react-native-restart)
[![npm downloads](https://img.shields.io/npm/dm/react-native-restart.svg?style=flat-square)](https://www.npmjs.com/package/react-native-restart)

<!-- TOC depthFrom:1 depthTo:6 withLinks:1 updateOnSave:1 orderedList:0 -->

- [React Native Restart](#react-native-restart)
- [Installation](#installation)
- [Android Installation](#android-installation)
- [RN < 0.29](#rn-029)
- [RN >= 0.29](#rn-029)
- [iOS Installation](#ios-installation)
- [Importing The Library](#importing-the-library)
- [Adding the Code](#adding-the-code)
- [Usage](#usage)
- [CREDITS](#credits)
- [TODO](#todo)

<!-- /TOC -->

## Installation
`npm install react-native-restart --save`

## Android Installation

In `android/settings.gradle`
```gradle
...
include ':react-native-restart'
project(':react-native-restart').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-restart/android')
```

In `android/app/build.gradle`

```gradle
...
dependencies {
...
compile project(':react-native-restart')
}
```

### RN < 0.29

Register module (in `MainActivity.java`)

```java
import com.avishayil.rnrestart.ReactNativeRestartPackage; // <--- Import

public class MainActivity extends ReactActivity {
......

/**
* A list of packages used by the app. If the app uses additional views
* or modules besides the default ones, add more packages here.
*/
@Override
protected List<ReactPackage> getPackages() {
...
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new ReactNativeRestartPackage() // Add this line
);
}
......

}
```

### RN >= 0.29

Register module (in `MainApplication.java`)

```java
import com.avishayil.rnrestart.ReactNativeRestartPackage; // <--- Import

public class MainApplication extends Application implements ReactApplication {

private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
......

/**
* A list of packages used by the app. If the app uses additional views
* or modules besides the default ones, add more packages here.
*/
@Override
protected List<ReactPackage> getPackages() {
...
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new ReactNativeRestartPackage() // Add this line
);
}
};
......
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
};

```

## iOS Installation

### Importing The Library

* Drag the file `RCTRestart.xcodeproj` from `/node_modules/react-native-restart/ios` into the `Libraries` group in the Project navigator. Ensure that `Copy items if needed` is UNCHECKED!

![Add Files To...](http://i.imgur.com/puxHiIg.png)

![Library Imported Successfully](http://i.imgur.com/toZUWg5.png)

* Ensure that `libRCTRestart.a` is linked through `Link Binary With Libraries` on `Build Phases`:

![Library Linked](http://i.imgur.com/Sm1birt.png)

* Ensure that `Header Search Paths` on `Build Settings` has the path `$(SRCROOT)/../node_modules/react-native-restart` set to `recursive`:

* You're All Set!


## Usage

```javascript
import RNRestart from 'react-native-restart'; // Import package from node modules

// Immediately reload the React Native Bundle
RNRestart.Restart();
```

## CREDITS
Thanks to Microsoft CodePush library. I simply extracted the code from their library's logic to reload the React Native Bundle.

## TODO
* [ ] Tell me?
34 changes: 34 additions & 0 deletions android/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
buildscript {
repositories {
jcenter()
}

dependencies {
classpath 'com.android.tools.build:gradle:2.1.0'
}
}

apply plugin: 'com.android.library'

android {
compileSdkVersion 23
buildToolsVersion "23.0.1"

defaultConfig {
minSdkVersion 16
targetSdkVersion 22
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}

dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.facebook.react:react-native:+'
}
17 changes: 17 additions & 0 deletions android/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /usr/local/Cellar/android-sdk/24.4.1_1/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# Add any project specific keep options here:

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
3 changes: 3 additions & 0 deletions android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.avishayil.rnrestart">
</manifest>
117 changes: 117 additions & 0 deletions android/src/main/java/com/avishayil/rnrestart/ReactNativeRestart.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package com.avishayil.rnrestart;

import android.app.Activity;

import com.facebook.react.ReactActivity;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
* Created by Avishay on 7/17/16.
*/
public class ReactNativeRestart extends ReactContextBaseJavaModule {

private static final String REACT_APPLICATION_CLASS_NAME = "com.facebook.react.ReactApplication";
private static final String REACT_NATIVE_HOST_CLASS_NAME = "com.facebook.react.ReactNativeHost";


public ReactNativeRestart(ReactApplicationContext reactContext) {
super(reactContext);
}

private void loadBundleLegacy(final Activity currentActivity) {
currentActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
currentActivity.recreate();
}
});
}

private void loadBundle() {
final Activity currentActivity = getCurrentActivity();

if (currentActivity == null) {
// The currentActivity can be null if it is backgrounded / destroyed, so we simply
// no-op to prevent any null pointer exceptions.
return;
} else if (!ReactActivity.class.isInstance(currentActivity)) {
// Our preferred reload logic relies on the user's Activity inheriting
// from the core ReactActivity class, so if it doesn't, we fallback
// early to our legacy behavior.
loadBundleLegacy(currentActivity);
} else {
try {
ReactActivity reactActivity = (ReactActivity)currentActivity;
ReactInstanceManager instanceManager;

// #1) Get the ReactInstanceManager instance, which is what includes the
// logic to reload the current React context.
try {
// In RN 0.29, the "mReactInstanceManager" field yields a null value, so we try
// to get the instance manager via the ReactNativeHost, which only exists in 0.29.
Method getApplicationMethod = ReactActivity.class.getMethod("getApplication");
Object reactApplication = getApplicationMethod.invoke(reactActivity);
Class<?> reactApplicationClass = tryGetClass(REACT_APPLICATION_CLASS_NAME);
Method getReactNativeHostMethod = reactApplicationClass.getMethod("getReactNativeHost");
Object reactNativeHost = getReactNativeHostMethod.invoke(reactApplication);
Class<?> reactNativeHostClass = tryGetClass(REACT_NATIVE_HOST_CLASS_NAME);
Method getReactInstanceManagerMethod = reactNativeHostClass.getMethod("getReactInstanceManager");
instanceManager = (ReactInstanceManager)getReactInstanceManagerMethod.invoke(reactNativeHost);
} catch (Exception e) {
// The React Native version might be older than 0.29, so we try to get the
// instance manager via the "mReactInstanceManager" field.
Field instanceManagerField = ReactActivity.class.getDeclaredField("mReactInstanceManager");
instanceManagerField.setAccessible(true);
instanceManager = (ReactInstanceManager)instanceManagerField.get(reactActivity);
}

// #3) Get the context creation method and fire it on the UI thread (which RN enforces)
final Method recreateMethod = instanceManager.getClass().getMethod("recreateReactContextInBackground");

final ReactInstanceManager finalizedInstanceManager = instanceManager;
reactActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
try {
recreateMethod.invoke(finalizedInstanceManager);
}
catch (Exception e) {
// The recreation method threw an unknown exception
// so just simply fallback to restarting the Activity
loadBundleLegacy(currentActivity);
}
}
});
} catch (Exception e) {
// Our reflection logic failed somewhere
// so fall back to restarting the Activity
loadBundleLegacy(currentActivity);
}
}
}

private Class tryGetClass(String className) {
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
return null;
}
}

@ReactMethod
public void Restart() {
loadBundle();
}

@Override
public String getName() {
return "RNRestart";
}

}
Loading

0 comments on commit a2e8a51

Please sign in to comment.