react-native-navigation的迁移库

BaseReactActivity.java 10KB

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