react-native-navigation的迁移库

BaseReactActivity.java 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. package com.reactnativenavigation.activities;
  2. import android.content.BroadcastReceiver;
  3. import android.content.Context;
  4. import android.content.Intent;
  5. import android.content.IntentFilter;
  6. import android.content.res.Configuration;
  7. import android.os.Build;
  8. import android.os.Bundle;
  9. import android.os.Handler;
  10. import android.provider.Settings;
  11. import android.support.annotation.CallSuper;
  12. import android.support.v4.widget.DrawerLayout;
  13. import android.support.v7.app.ActionBarDrawerToggle;
  14. import android.support.v7.app.AppCompatActivity;
  15. import android.util.Log;
  16. import android.view.KeyEvent;
  17. import android.view.Menu;
  18. import android.view.MenuItem;
  19. import android.widget.EditText;
  20. import android.widget.FrameLayout;
  21. import android.widget.Toast;
  22. import com.facebook.common.logging.FLog;
  23. import com.facebook.react.ReactInstanceManager;
  24. import com.facebook.react.ReactPackage;
  25. import com.facebook.react.ReactRootView;
  26. import com.facebook.react.bridge.Arguments;
  27. import com.facebook.react.bridge.ReadableMap;
  28. import com.facebook.react.bridge.WritableMap;
  29. import com.facebook.react.common.ReactConstants;
  30. import com.facebook.react.devsupport.DevServerHelper;
  31. import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
  32. import com.facebook.react.shell.MainReactPackage;
  33. import com.reactnativenavigation.BuildConfig;
  34. import com.reactnativenavigation.controllers.ModalController;
  35. import com.reactnativenavigation.core.RctManager;
  36. import com.reactnativenavigation.core.objects.Button;
  37. import com.reactnativenavigation.core.objects.Drawer;
  38. import com.reactnativenavigation.core.objects.Screen;
  39. import com.reactnativenavigation.modal.RnnModal;
  40. import com.reactnativenavigation.packages.RnnPackage;
  41. import com.reactnativenavigation.utils.ContextProvider;
  42. import com.reactnativenavigation.utils.StyleHelper;
  43. import com.reactnativenavigation.views.RnnToolBar;
  44. import com.reactnativenavigation.views.ScreenStack;
  45. import java.util.Arrays;
  46. import java.util.List;
  47. import javax.annotation.Nullable;
  48. public abstract class BaseReactActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler {
  49. protected static final String KEY_ANIMATED = "animated";
  50. protected static final String KEY_BADGE = "badge";
  51. protected static final String KEY_HIDDEN = "hidden";
  52. protected static final String KEY_SIDE = "side";
  53. protected static final String KEY_TAB_INDEX = "tabIndex";
  54. protected static final String KEY_TITLE = "title";
  55. protected static final String KEY_TO = "to";
  56. private static final String TAG = "BaseReactActivity";
  57. private static final String REDBOX_PERMISSION_MESSAGE =
  58. "Overlay permissions needs to be granted in order for react native apps to run in dev mode";
  59. @Nullable
  60. protected ReactInstanceManager mReactInstanceManager;
  61. private boolean mDoRefresh = false;
  62. private Menu mMenu;
  63. protected RnnToolBar mToolbar;
  64. protected ActionBarDrawerToggle mDrawerToggle;
  65. protected DrawerLayout mDrawerLayout;
  66. protected ScreenStack mDrawerStack;
  67. /**
  68. * Returns the name of the bundle in assets. If this is null, and no file path is specified for
  69. * the bundle, the app will only work with {@code getUseDeveloperSupport} enabled and will
  70. * always try to load the JS bundle from the packager server.
  71. * e.g. "index.android.bundle"
  72. */
  73. @Nullable
  74. public String getBundleAssetName() {
  75. return "index.android.bundle";
  76. }
  77. /**
  78. * Returns a custom path of the bundle file. This is used in cases the bundle should be loaded
  79. * from a custom path. By default it is loaded from Android assets, from a path specified
  80. * by {getBundleAssetName}.
  81. * e.g. "file://sdcard/myapp_cache/index.android.bundle"
  82. */
  83. @Nullable
  84. public String getJSBundleFile() {
  85. return null;
  86. }
  87. /**
  88. * Returns the name of the main module. Determines the URL used to fetch the JS bundle
  89. * from the packager server. It is only used when dev support is enabled.
  90. * This is the first file to be executed once the {@link ReactInstanceManager} is created.
  91. * e.g. "index.android"
  92. */
  93. public String getJSMainModuleName() {
  94. return "index.android";
  95. }
  96. /**
  97. * Returns the launchOptions which will be passed to the {@link ReactInstanceManager}
  98. * when the application is started. By default, this will return null and an empty
  99. * object will be passed to your top level component as its initial props.
  100. * If your React Native application requires props set outside of JS, override
  101. * this method to return the Android.os.Bundle of your desired initial props.
  102. */
  103. @Nullable
  104. protected Bundle getLaunchOptions() {
  105. return null;
  106. }
  107. /**
  108. * Returns the name of the main component registered from JavaScript.
  109. * This is used to schedule rendering of the component.
  110. * e.g. "MoviesApp"
  111. */
  112. protected String getMainComponentName() {
  113. return "";
  114. }
  115. /**
  116. * Returns whether dev mode should be enabled. This enables e.g. the dev menu.
  117. */
  118. public boolean getUseDeveloperSupport() {
  119. return BuildConfig.DEBUG;
  120. }
  121. /**
  122. * Returns a list of {@link ReactPackage} used by the app.
  123. * You'll most likely want to return at least the {@code MainReactPackage}.
  124. * If your app uses additional views or modules besides the default ones,
  125. * you'll want to include more packages here.
  126. */
  127. public List<ReactPackage> getPackages() {
  128. return Arrays.asList(
  129. new MainReactPackage(),
  130. new RnnPackage()
  131. );
  132. }
  133. /**
  134. * A subclass may override this method if it needs to use a custom {@link ReactRootView}.
  135. */
  136. protected ReactRootView createRootView() {
  137. return new ReactRootView(this);
  138. }
  139. @Override
  140. protected void onCreate(Bundle savedInstanceState) {
  141. super.onCreate(savedInstanceState);
  142. ContextProvider.setActivityContext(this);
  143. mReactInstanceManager = createReactInstanceManager();
  144. handleOnCreate();
  145. }
  146. /**
  147. * A subclass may override this method if it needs to use a custom instance.
  148. */
  149. protected ReactInstanceManager createReactInstanceManager() {
  150. return getReactInstanceManager();
  151. }
  152. protected ReactInstanceManager getReactInstanceManager() {
  153. RctManager rctManager = RctManager.getInstance();
  154. if (!rctManager.isInitialized()) {
  155. rctManager.init(this);
  156. }
  157. return rctManager.getReactInstanceManager();
  158. }
  159. @CallSuper
  160. protected void handleOnCreate() {
  161. permissionToShowRedboxIfNeeded();
  162. }
  163. private void permissionToShowRedboxIfNeeded() {
  164. if (getUseDeveloperSupport() && Build.VERSION.SDK_INT >= 23 && !Settings.canDrawOverlays(this)) {
  165. Intent serviceIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
  166. startActivity(serviceIntent);
  167. FLog.w(ReactConstants.TAG, REDBOX_PERMISSION_MESSAGE);
  168. Toast.makeText(this, REDBOX_PERMISSION_MESSAGE, Toast.LENGTH_LONG).show();
  169. }
  170. }
  171. @Override
  172. protected void onResume() {
  173. super.onResume();
  174. ContextProvider.setActivityContext(this);
  175. if (mReactInstanceManager != null) {
  176. mReactInstanceManager.onHostResume(this, this);
  177. }
  178. }
  179. @Override
  180. protected void onPause() {
  181. super.onPause();
  182. if (mReactInstanceManager != null) {
  183. mReactInstanceManager.onHostPause();
  184. }
  185. ContextProvider.clearActivityContext();
  186. }
  187. @Override
  188. protected void onDestroy() {
  189. super.onDestroy();
  190. // Destroy react instance manager only if there are no resumed react activities
  191. BaseReactActivity activity = ContextProvider.getActivityContext();
  192. if (mReactInstanceManager != null && (activity == null || activity.isFinishing())) {
  193. Log.i(TAG, "Destroying ReactInstanceManager");
  194. mReactInstanceManager.onHostDestroy();
  195. RctManager.getInstance().onDestroy();
  196. } else {
  197. Log.d(TAG, "Not destroying ReactInstanceManager");
  198. }
  199. }
  200. @CallSuper
  201. public void push(Screen screen) {
  202. StyleHelper.updateStyles(mToolbar, screen);
  203. if (mToolbar != null) {
  204. mToolbar.update(screen);
  205. if (getCurrentNavigatorId().equals(screen.navigatorId) &&
  206. getScreenStackSize() >= 1) {
  207. mToolbar.setNavUpButton(screen);
  208. }
  209. }
  210. }
  211. @CallSuper
  212. public Screen pop(String navigatorId) {
  213. if (mToolbar != null &&
  214. getCurrentNavigatorId().equals(navigatorId) &&
  215. getScreenStackSize() <= 2) {
  216. mToolbar.setNavUpButton();
  217. }
  218. return null;
  219. }
  220. @CallSuper
  221. public Screen popToRoot(String navigatorId) {
  222. if (mToolbar != null) {
  223. mToolbar.setNavUpButton();
  224. }
  225. return null;
  226. }
  227. @CallSuper
  228. public Screen resetTo(Screen screen) {
  229. StyleHelper.updateStyles(mToolbar, screen);
  230. if (mToolbar != null) {
  231. mToolbar.setNavUpButton();
  232. }
  233. return null;
  234. }
  235. protected abstract String getCurrentNavigatorId();
  236. @CallSuper
  237. public Screen getCurrentScreen() {
  238. ModalController modalController = ModalController.getInstance();
  239. if (modalController.isModalDisplayed()) {
  240. RnnModal modal = modalController.get();
  241. assert modal != null;
  242. return modal.getCurrentScreen();
  243. }
  244. return null;
  245. }
  246. public abstract int getScreenStackSize();
  247. @Override
  248. public void onConfigurationChanged(Configuration newConfig) {
  249. super.onConfigurationChanged(newConfig);
  250. if (mDrawerToggle != null) {
  251. mDrawerToggle.onConfigurationChanged(newConfig);
  252. }
  253. }
  254. @Override
  255. public boolean onCreateOptionsMenu(Menu menu) {
  256. mMenu = menu;
  257. Screen currentScreen = getCurrentScreen();
  258. if (mToolbar != null && currentScreen != null) {
  259. mToolbar.setupToolbarButtonsAsync(currentScreen);
  260. }
  261. return super.onCreateOptionsMenu(menu);
  262. }
  263. @Override
  264. public boolean onOptionsItemSelected(MenuItem item) {
  265. if (mDrawerToggle != null &&
  266. getScreenStackSize() == 1 &&
  267. mDrawerToggle.onOptionsItemSelected(item)) {
  268. return true;
  269. }
  270. if (item.getItemId() == android.R.id.home) {
  271. onBackPressed();
  272. } else {
  273. String eventId = Button.getButtonEventId(item);
  274. assert eventId != null;
  275. WritableMap params = Arguments.createMap();
  276. RctManager.getInstance().sendEvent(eventId, getCurrentScreen(), params);
  277. }
  278. return super.onOptionsItemSelected(item);
  279. }
  280. @Override
  281. public void onPostCreate(Bundle savedInstanceState) {
  282. super.onPostCreate(savedInstanceState);
  283. if (mDrawerToggle != null) {
  284. mDrawerToggle.syncState();
  285. }
  286. }
  287. public Menu getMenu() {
  288. return mMenu;
  289. }
  290. @Override
  291. public void onActivityResult(int requestCode, int resultCode, Intent data) {
  292. if (mReactInstanceManager != null) {
  293. mReactInstanceManager.onActivityResult(requestCode, resultCode, data);
  294. }
  295. }
  296. @Override
  297. public boolean onKeyUp(int keyCode, KeyEvent event) {
  298. if (mReactInstanceManager != null &&
  299. mReactInstanceManager.getDevSupportManager().getDevSupportEnabled()) {
  300. if (keyCode == KeyEvent.KEYCODE_MENU) {
  301. mReactInstanceManager.showDevOptionsDialog();
  302. return true;
  303. }
  304. if (keyCode == KeyEvent.KEYCODE_R && !(getCurrentFocus() instanceof EditText)) {
  305. // Enable double-tap-R-to-reload
  306. if (mDoRefresh) {
  307. mReactInstanceManager.getDevSupportManager().handleReloadJS();
  308. mDoRefresh = false;
  309. } else {
  310. mDoRefresh = true;
  311. new Handler().postDelayed(
  312. new Runnable() {
  313. @Override
  314. public void run() {
  315. mDoRefresh = false;
  316. }
  317. },
  318. 200);
  319. }
  320. }
  321. }
  322. return super.onKeyUp(keyCode, event);
  323. }
  324. /**
  325. * Called after bundle was reloaded. This is a good chance to clean up previously connected react views.
  326. */
  327. public void onJSBundleReloaded() {
  328. removeAllReactViews();
  329. }
  330. protected abstract void removeAllReactViews();
  331. @Override
  332. public void onBackPressed() {
  333. if (getScreenStackSize() > 1) {
  334. pop(getCurrentNavigatorId());
  335. } else {
  336. if (mReactInstanceManager != null) {
  337. mReactInstanceManager.onBackPressed();
  338. } else {
  339. super.onBackPressed();
  340. }
  341. }
  342. }
  343. @Override
  344. public void invokeDefaultOnBackPressed() {
  345. super.onBackPressed();
  346. }
  347. protected void setupDrawer(Screen screen, Drawer drawer, int drawerFrameId, int drawerLayoutId) {
  348. if (drawer == null || drawer.left == null) {
  349. return;
  350. }
  351. mDrawerStack = new ScreenStack(this);
  352. FrameLayout drawerFrame = (FrameLayout) findViewById(drawerFrameId);
  353. drawerFrame.addView(mDrawerStack);
  354. mDrawerStack.push(drawer.left);
  355. mDrawerLayout = (DrawerLayout) findViewById(drawerLayoutId);
  356. mDrawerToggle = mToolbar.setupDrawer(mDrawerLayout, drawer.left, screen);
  357. }
  358. public void setNavigationButtons(ReadableMap buttons) {
  359. if (mToolbar == null) {
  360. return;
  361. }
  362. getCurrentScreen().setButtons(buttons);
  363. mToolbar.setupToolbarButtonsAsync(getCurrentScreen());
  364. }
  365. public void setNavigationTitle(ReadableMap title) {
  366. if (mToolbar == null) {
  367. return;
  368. }
  369. mToolbar.setTitle(title.getString(KEY_TITLE));
  370. }
  371. public void toggleNavigationBar(ReadableMap params) {
  372. if (mToolbar == null) {
  373. return;
  374. }
  375. boolean hide = params.getBoolean(KEY_HIDDEN);
  376. boolean animated = params.getBoolean(KEY_ANIMATED);
  377. if (hide) {
  378. mToolbar.hideToolbar(animated);
  379. } else {
  380. mToolbar.showToolbar(animated);
  381. }
  382. }
  383. public void toggleDrawer(ReadableMap params) {
  384. if (mToolbar == null || mDrawerToggle == null) {
  385. return;
  386. }
  387. boolean animated = params.getBoolean(KEY_ANIMATED);
  388. String side = params.getString(KEY_SIDE);
  389. String to = params.getString(KEY_TO);
  390. switch (to) {
  391. case "open":
  392. mToolbar.showDrawer(animated);
  393. break;
  394. case "closed":
  395. mToolbar.hideDrawer(animated);
  396. break;
  397. default:
  398. mToolbar.toggleDrawer(animated);
  399. break;
  400. }
  401. }
  402. }