-
Notifications
You must be signed in to change notification settings - Fork 24.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Summary: React Native on Android has currently been focused and targeted at using an Activity for its main form of instantiation. While this has probably worked for most companies and developers, you lose some of the modularity of a more cohesive application when working in a "brown-field" project that is currently native. This hurts more companies that are looking to adopt React Native and slowly implement it in a fully native application. A lot of developers follow Android's guidelines of using Fragments in their projects, even if it is a debated subject in the Android community, and this addition will allow others to embrace React Native more freely. (I even assume it could help with managing navigation state in applications that contain a decent amount of Native code and would be appreciated in those projects. Such as sharing the Toolbar, TabBar, ViewPager, etc in Native Android) Even with this addition, a developer will still need to host the fragment in an activity, but now that activity can contain native logic like a Drawer, Tabs, ViewPager, etc. Test plan (required) We have been using this class at Hudl for over a couple of months and have found it valuable. If the community agrees on the addition, I can add documentation to the Android sections to include notes about the potential of this Fragment. If the community agrees on the addition, I can update one or more of the examples in the /Examples folder and make use of the Fragment, or even create a new example that uses a native layout manager like Drawer, Tabs, Viewpager, etc) Make sure tests pass on both Travis and Circle CI. _To Note:_ There is also talk of using React Native inside Android Fragment's without any legit documentation, this could help remedy some of that with more documentation included in this PR https://facebook.github.io/react-native/releases/0.26/docs/embedded-app-android.html#sharing-a-reactinstance-across-multiple-activities-fragments-in-your-app Others have also requested something similar and have a half-baked solution as well http://stackoverflow.com/questions/35221447/react-native-inside-a-fragment Release Notes [ANDROID][FEATURE][ReactAndroid/src/main/java/com/facebook/react/ReactFragment.java] - Adds support for Android's Fragment system. This allows for a more hybrid application. Reviewed By: cpojer Differential Revision: D15731340 fbshipit-source-id: 74b7aaedcfd6ad6e074ff911cd7f18a5111caf5c
- Loading branch information
1 parent
5b7be95
commit d0792d4
Showing
3 changed files
with
371 additions
and
54 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
147 changes: 147 additions & 0 deletions
147
ReactAndroid/src/main/java/com/facebook/react/ReactDelegate.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
/** | ||
* Copyright (c) Facebook, Inc. and its affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
package com.facebook.react; | ||
|
||
import android.app.Activity; | ||
import android.content.Intent; | ||
import android.os.Bundle; | ||
import android.view.KeyEvent; | ||
|
||
import com.facebook.infer.annotation.Assertions; | ||
import com.facebook.react.devsupport.DoubleTapReloadRecognizer; | ||
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; | ||
|
||
import javax.annotation.Nullable; | ||
|
||
/** | ||
* A delegate for handling React Application support. This delegate is unaware whether it is used in | ||
* an {@link Activity} or a {@link android.app.Fragment}. | ||
*/ | ||
public class ReactDelegate { | ||
|
||
private final Activity mActivity; | ||
private ReactRootView mReactRootView; | ||
|
||
@Nullable | ||
private final String mMainComponentName; | ||
|
||
@Nullable | ||
private Bundle mLaunchOptions; | ||
|
||
@Nullable | ||
private DoubleTapReloadRecognizer mDoubleTapReloadRecognizer; | ||
|
||
private ReactNativeHost mReactNativeHost; | ||
|
||
|
||
public ReactDelegate(Activity activity, ReactNativeHost reactNativeHost, @Nullable String appKey, @Nullable Bundle launchOptions) { | ||
mActivity = activity; | ||
mMainComponentName = appKey; | ||
mLaunchOptions = launchOptions; | ||
mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer(); | ||
mReactNativeHost = reactNativeHost; | ||
} | ||
|
||
public void onHostResume() { | ||
if (getReactNativeHost().hasInstance()) { | ||
if (mActivity instanceof DefaultHardwareBackBtnHandler) { | ||
getReactNativeHost().getReactInstanceManager().onHostResume(mActivity, (DefaultHardwareBackBtnHandler) mActivity); | ||
} else { | ||
throw new ClassCastException("Host Activity does not implement DefaultHardwareBackBtnHandler"); | ||
} | ||
} | ||
} | ||
|
||
public void onHostPause() { | ||
if (getReactNativeHost().hasInstance()) { | ||
getReactNativeHost().getReactInstanceManager().onHostPause(mActivity); | ||
} | ||
} | ||
|
||
public void onHostDestroy() { | ||
if (mReactRootView != null) { | ||
mReactRootView.unmountReactApplication(); | ||
mReactRootView = null; | ||
} | ||
if (getReactNativeHost().hasInstance()) { | ||
getReactNativeHost().getReactInstanceManager().onHostDestroy(mActivity); | ||
} | ||
} | ||
|
||
public boolean onBackPressed() { | ||
if (getReactNativeHost().hasInstance()) { | ||
getReactNativeHost().getReactInstanceManager().onBackPressed(); | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
public void onActivityResult(int requestCode, int resultCode, Intent data, boolean shouldForwardToReactInstance) { | ||
if (getReactNativeHost().hasInstance() && shouldForwardToReactInstance) { | ||
getReactNativeHost().getReactInstanceManager().onActivityResult(mActivity, requestCode, resultCode, data); | ||
} | ||
} | ||
|
||
public void loadApp() { | ||
loadApp(mMainComponentName); | ||
} | ||
|
||
public void loadApp(String appKey) { | ||
if (mReactRootView != null) { | ||
throw new IllegalStateException("Cannot loadApp while app is already running."); | ||
} | ||
mReactRootView = createRootView(); | ||
mReactRootView.startReactApplication( | ||
getReactNativeHost().getReactInstanceManager(), | ||
appKey, | ||
mLaunchOptions); | ||
|
||
} | ||
|
||
public ReactRootView getReactRootView() { | ||
return mReactRootView; | ||
} | ||
|
||
|
||
protected ReactRootView createRootView() { | ||
return new ReactRootView(mActivity); | ||
} | ||
|
||
/** | ||
* Handles delegating the {@link Activity#onKeyUp(int, KeyEvent)} method to determine whether | ||
* the application should show the developer menu or should reload the React Application. | ||
* | ||
* @return true if we consume the event and either shoed the develop menu or reloaded the application. | ||
*/ | ||
public boolean shouldShowDevMenuOrReload(int keyCode, KeyEvent event) { | ||
if (getReactNativeHost().hasInstance() && getReactNativeHost().getUseDeveloperSupport()) { | ||
if (keyCode == KeyEvent.KEYCODE_MENU) { | ||
getReactNativeHost().getReactInstanceManager().showDevOptionsDialog(); | ||
return true; | ||
} | ||
boolean didDoubleTapR = Assertions.assertNotNull(mDoubleTapReloadRecognizer).didDoubleTapR(keyCode, mActivity.getCurrentFocus()); | ||
if (didDoubleTapR) { | ||
getReactNativeHost().getReactInstanceManager().getDevSupportManager().handleReloadJS(); | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
/** | ||
* Get the {@link ReactNativeHost} used by this app. | ||
*/ | ||
private ReactNativeHost getReactNativeHost() { | ||
return mReactNativeHost; | ||
} | ||
|
||
public ReactInstanceManager getReactInstanceManager() { | ||
return getReactNativeHost().getReactInstanceManager(); | ||
} | ||
|
||
} |
Oops, something went wrong.
d0792d4
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mdvacca I'm not sure exactly why but this broke using a custom RootView using
MainActivity.java