react-native-navigation的迁移库

BaseReactActivity.java 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. package com.reactnativenavigation.activities;
  2. import android.content.Intent;
  3. import android.os.Build;
  4. import android.os.Bundle;
  5. import android.os.Handler;
  6. import android.provider.Settings;
  7. import android.support.annotation.CallSuper;
  8. import android.support.v7.app.AppCompatActivity;
  9. import android.util.Log;
  10. import android.view.KeyEvent;
  11. import android.view.Menu;
  12. import android.view.MenuItem;
  13. import android.widget.EditText;
  14. import android.widget.Toast;
  15. import com.facebook.common.logging.FLog;
  16. import com.facebook.react.LifecycleState;
  17. import com.facebook.react.ReactInstanceManager;
  18. import com.facebook.react.ReactPackage;
  19. import com.facebook.react.ReactRootView;
  20. import com.facebook.react.bridge.Arguments;
  21. import com.facebook.react.bridge.WritableMap;
  22. import com.facebook.react.common.ReactConstants;
  23. import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
  24. import com.facebook.react.shell.MainReactPackage;
  25. import com.reactnativenavigation.BuildConfig;
  26. import com.reactnativenavigation.core.RctManager;
  27. import com.reactnativenavigation.core.objects.Button;
  28. import com.reactnativenavigation.core.objects.Screen;
  29. import com.reactnativenavigation.packages.RnnPackage;
  30. import com.reactnativenavigation.utils.ContextProvider;
  31. import com.reactnativenavigation.views.RnnToolBar;
  32. import java.util.Arrays;
  33. import java.util.List;
  34. import javax.annotation.Nullable;
  35. /**
  36. * Base Activity for React Native applications.
  37. */
  38. public abstract class BaseReactActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler {
  39. private static final String TAG = "BaseReactActivity";
  40. private static final String REDBOX_PERMISSION_MESSAGE =
  41. "Overlay permissions needs to be granted in order for react native apps to run in dev mode";
  42. private static final String EVENT_TOOLBAR_BUTTON_CLICKED = "OnToolbarButtonClicked";
  43. @Nullable
  44. protected ReactInstanceManager mReactInstanceManager;
  45. private LifecycleState mLifecycleState = LifecycleState.BEFORE_RESUME;
  46. private boolean mDoRefresh = false;
  47. private Menu mMenu;
  48. protected RnnToolBar mToolbar;
  49. /**
  50. * Returns the name of the bundle in assets. If this is null, and no file path is specified for
  51. * the bundle, the app will only work with {@code getUseDeveloperSupport} enabled and will
  52. * always try to load the JS bundle from the packager server.
  53. * e.g. "index.android.bundle"
  54. */
  55. @Nullable
  56. protected String getBundleAssetName() {
  57. return "index.android.bundle";
  58. }
  59. /**
  60. * Returns a custom path of the bundle file. This is used in cases the bundle should be loaded
  61. * from a custom path. By default it is loaded from Android assets, from a path specified
  62. * by {getBundleAssetName}.
  63. * e.g. "file://sdcard/myapp_cache/index.android.bundle"
  64. */
  65. @Nullable
  66. protected String getJSBundleFile() {
  67. return null;
  68. }
  69. /**
  70. * Returns the name of the main module. Determines the URL used to fetch the JS bundle
  71. * from the packager server. It is only used when dev support is enabled.
  72. * This is the first file to be executed once the {@link ReactInstanceManager} is created.
  73. * e.g. "index.android"
  74. */
  75. protected String getJSMainModuleName() {
  76. return "index.android";
  77. }
  78. /**
  79. * Returns the launchOptions which will be passed to the {@link ReactInstanceManager}
  80. * when the application is started. By default, this will return null and an empty
  81. * object will be passed to your top level component as its initial props.
  82. * If your React Native application requires props set outside of JS, override
  83. * this method to return the Android.os.Bundle of your desired initial props.
  84. */
  85. @Nullable
  86. protected Bundle getLaunchOptions() {
  87. return null;
  88. }
  89. /**
  90. * Returns the name of the main component registered from JavaScript.
  91. * This is used to schedule rendering of the component.
  92. * e.g. "MoviesApp"
  93. */
  94. protected String getMainComponentName() {
  95. return "";
  96. }
  97. /**
  98. * Returns whether dev mode should be enabled. This enables e.g. the dev menu.
  99. */
  100. protected boolean getUseDeveloperSupport() {
  101. return BuildConfig.DEBUG;
  102. }
  103. /**
  104. * Returns a list of {@link ReactPackage} used by the app.
  105. * You'll most likely want to return at least the {@code MainReactPackage}.
  106. * If your app uses additional views or modules besides the default ones,
  107. * you'll want to include more packages here.
  108. */
  109. protected List<ReactPackage> getPackages() {
  110. return Arrays.asList(
  111. new MainReactPackage(),
  112. new RnnPackage()
  113. );
  114. }
  115. /**
  116. * A subclass may override this method if it needs to use a custom {@link ReactRootView}.
  117. */
  118. protected ReactRootView createRootView() {
  119. return new ReactRootView(this);
  120. }
  121. @Override
  122. protected void onCreate(Bundle savedInstanceState) {
  123. super.onCreate(savedInstanceState);
  124. mReactInstanceManager = createReactInstanceManager();
  125. handleOnCreate();
  126. }
  127. /**
  128. * A subclass may override this method if it needs to use a custom instance.
  129. */
  130. protected ReactInstanceManager createReactInstanceManager() {
  131. return getReactInstanceManager();
  132. }
  133. protected ReactInstanceManager getReactInstanceManager() {
  134. RctManager rctManager = RctManager.getInstance();
  135. if (!rctManager.isInitialized()) {
  136. rctManager.init(getApplicationContext(), getMainComponentName(), getPackages());
  137. }
  138. return rctManager.getReactInstanceManager();
  139. }
  140. protected void handleOnCreate() {
  141. if (getUseDeveloperSupport() && Build.VERSION.SDK_INT >= 23) {
  142. // Get permission to show redbox in dev builds.
  143. if (!Settings.canDrawOverlays(this)) {
  144. Intent serviceIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
  145. startActivity(serviceIntent);
  146. FLog.w(ReactConstants.TAG, REDBOX_PERMISSION_MESSAGE);
  147. Toast.makeText(this, REDBOX_PERMISSION_MESSAGE, Toast.LENGTH_LONG).show();
  148. }
  149. }
  150. ReactRootView mReactRootView = createRootView();
  151. mReactRootView.startReactApplication(mReactInstanceManager, getMainComponentName(), getLaunchOptions());
  152. setContentView(mReactRootView);
  153. }
  154. @Override
  155. protected void onResume() {
  156. super.onResume();
  157. ContextProvider.setActivityContext(this);
  158. mLifecycleState = LifecycleState.RESUMED;
  159. if (mReactInstanceManager != null) {
  160. mReactInstanceManager.onResume(this, this);
  161. }
  162. }
  163. @Override
  164. protected void onPause() {
  165. super.onPause();
  166. mLifecycleState = LifecycleState.BEFORE_RESUME;
  167. if (mReactInstanceManager != null) {
  168. mReactInstanceManager.onPause();
  169. }
  170. ContextProvider.clearActivityContext();
  171. }
  172. @Override
  173. protected void onDestroy() {
  174. super.onDestroy();
  175. // Destroy react instance manager only if there are no resumed react activities
  176. BaseReactActivity activity = ContextProvider.getActivityContext();
  177. if (mReactInstanceManager != null && (activity == null || activity.isFinishing())) {
  178. Log.i(TAG, "Destroying ReactInstanceManager");
  179. mReactInstanceManager.onDestroy();
  180. } else {
  181. Log.d(TAG, "Not destroying ReactInstanceManager");
  182. }
  183. }
  184. @CallSuper
  185. public void push(Screen screen) {
  186. if (mToolbar != null &&
  187. getCurrentNavigatorId().equals(screen.navigatorId) &&
  188. getScreenStackSize() >= 1) {
  189. mToolbar.showBackButton();
  190. }
  191. }
  192. @CallSuper
  193. public Screen pop(String navigatorId) {
  194. if (mToolbar != null &&
  195. getCurrentNavigatorId().equals(navigatorId) &&
  196. getScreenStackSize() <= 2) {
  197. mToolbar.hideBackButton();
  198. }
  199. return null;
  200. }
  201. protected abstract String getCurrentNavigatorId();
  202. protected abstract Screen getCurrentScreen();
  203. public abstract int getScreenStackSize();
  204. @Override
  205. public boolean onCreateOptionsMenu(Menu menu) {
  206. mMenu = menu;
  207. return super.onCreateOptionsMenu(menu);
  208. }
  209. @Override
  210. public boolean onOptionsItemSelected(MenuItem item) {
  211. if (item.getItemId() == android.R.id.home) {
  212. onBackPressed();
  213. } else {
  214. String eventId = Button.getButtonEventId(item);
  215. assert eventId != null;
  216. WritableMap params = Arguments.createMap();
  217. RctManager.getInstance().sendEvent(eventId, getCurrentScreen(), params);
  218. }
  219. return super.onOptionsItemSelected(item);
  220. }
  221. public Menu getMenu() {
  222. return mMenu;
  223. }
  224. @Override
  225. public void onActivityResult(int requestCode, int resultCode, Intent data) {
  226. if (mReactInstanceManager != null) {
  227. mReactInstanceManager.onActivityResult(requestCode, resultCode, data);
  228. }
  229. }
  230. @Override
  231. public boolean onKeyUp(int keyCode, KeyEvent event) {
  232. if (mReactInstanceManager != null &&
  233. mReactInstanceManager.getDevSupportManager().getDevSupportEnabled()) {
  234. if (keyCode == KeyEvent.KEYCODE_MENU) {
  235. mReactInstanceManager.showDevOptionsDialog();
  236. return true;
  237. }
  238. if (keyCode == KeyEvent.KEYCODE_R && !(getCurrentFocus() instanceof EditText)) {
  239. // Enable double-tap-R-to-reload
  240. if (mDoRefresh) {
  241. mReactInstanceManager.getDevSupportManager().handleReloadJS();
  242. mDoRefresh = false;
  243. } else {
  244. mDoRefresh = true;
  245. new Handler().postDelayed(
  246. new Runnable() {
  247. @Override
  248. public void run() {
  249. mDoRefresh = false;
  250. }
  251. },
  252. 200);
  253. }
  254. }
  255. }
  256. return super.onKeyUp(keyCode, event);
  257. }
  258. @Override
  259. public void onBackPressed() {
  260. if (getScreenStackSize() > 1) {
  261. pop(getCurrentNavigatorId());
  262. } else {
  263. if (mReactInstanceManager != null) {
  264. mReactInstanceManager.onBackPressed();
  265. } else {
  266. super.onBackPressed();
  267. }
  268. }
  269. }
  270. @Override
  271. public void invokeDefaultOnBackPressed() {
  272. super.onBackPressed();
  273. }
  274. }