Java tutorial
/* * Copyright (C) 2016 MarkZhai (http://zhaiyifan.cn). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.github.markzhai.react.preloader; import android.annotation.TargetApi; import android.app.Activity; import android.content.Intent; import android.content.MutableContextWrapper; import android.os.Build; import android.os.Bundle; import android.provider.Settings; import android.util.Log; import android.view.KeyEvent; import android.view.ViewGroup; import android.widget.Toast; import com.facebook.common.logging.FLog; import com.facebook.react.ReactApplication; import com.facebook.react.ReactInstanceManager; import com.facebook.react.ReactNativeHost; import com.facebook.react.ReactRootView; import com.facebook.react.common.ReactConstants; import com.facebook.react.devsupport.DoubleTapReloadRecognizer; import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; import com.facebook.react.modules.core.PermissionAwareActivity; import com.facebook.react.modules.core.PermissionListener; import javax.annotation.Nullable; /** * Base Activity for React Native applications. * * @author markzhai on 16/8/20 * @version 0.31.0 */ public abstract class MrReactActivity extends Activity implements DefaultHardwareBackBtnHandler, PermissionAwareActivity { private static final String TAG = "MrReactActivity"; private static final String REDBOX_PERMISSION_MESSAGE = "Overlay permissions needs to be granted in order for react native apps to run in dev mode"; private @Nullable PermissionListener mPermissionListener; private @Nullable ReactInstanceManager mReactInstanceManager; private @Nullable ReactRootView mReactRootView; private DoubleTapReloadRecognizer mDoubleTapReloadRecognizer; private boolean mDoRefresh = false; /** * Returns the launchOptions which will be passed to the {@link ReactInstanceManager} * when the application is started. By default, this will return null and an empty * object will be passed to your top level component as its initial props. * If your React Native application requires props set outside of JS, override * this method to return the Android.os.Bundle of your desired initial props. */ protected @Nullable Bundle getLaunchOptions() { return null; } /** * Returns the name of the main component registered from JavaScript. * This is used to schedule rendering of the component. * e.g. "MoviesApp" */ protected abstract String getMainComponentName(); /** * A subclass may override this method if it needs to use a custom {@link ReactRootView}. */ protected ReactRootView createRootView() { return new ReactRootView(this); } /** * Get the {@link ReactNativeHost} used by this app. By default, assumes {@link #getApplication()} * is an instance of {@link ReactApplication} and calls * {@link ReactApplication#getReactNativeHost()}. Override this method if your application class * does not implement {@code ReactApplication} or you simply have a different mechanism for * storing a {@code ReactNativeHost}, e.g. as a static field somewhere. */ protected ReactNativeHost getReactNativeHost() { return ((ReactApplication) getApplication()).getReactNativeHost(); } /** * Get whether developer support should be enabled or not. By default this delegates to * {@link ReactNativeHost#getUseDeveloperSupport()}. Override this method if your application * class does not implement {@code ReactApplication} or you simply have a different logic for * determining this (default just checks {@code BuildConfig}). */ protected boolean getUseDeveloperSupport() { return BuildConfig.DEBUG; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getUseDeveloperSupport() && Build.VERSION.SDK_INT >= 23) { // Get permission to show redbox in dev builds. if (!Settings.canDrawOverlays(this)) { Intent serviceIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION); startActivity(serviceIntent); FLog.w(ReactConstants.TAG, REDBOX_PERMISSION_MESSAGE); Toast.makeText(this, REDBOX_PERMISSION_MESSAGE, Toast.LENGTH_LONG).show(); } } mReactRootView = ReactPreLoader.getRootView(getReactInfo()); if (mReactRootView != null) { Log.i(TAG, "use pre-load view"); MutableContextWrapper contextWrapper = (MutableContextWrapper) mReactRootView.getContext(); contextWrapper.setBaseContext(this); try { ViewGroup viewGroup = (ViewGroup) mReactRootView.getParent(); if (viewGroup != null) { viewGroup.removeView(mReactRootView); } } catch (Exception exception) { Log.e(TAG, "getParent error", exception); } } else { Log.i(TAG, "createRootView"); mReactRootView = createRootView(); if (mReactRootView != null) { mReactRootView.startReactApplication(getReactNativeHost().getReactInstanceManager(), getMainComponentName(), getLaunchOptions()); } } setContentView(mReactRootView); mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer(); } @Override protected void onPause() { super.onPause(); if (getReactNativeHost().hasInstance()) { getReactNativeHost().getReactInstanceManager().onHostPause(); } } @Override protected void onResume() { super.onResume(); if (getReactNativeHost().hasInstance()) { getReactNativeHost().getReactInstanceManager().onHostResume(this, this); } } @Override protected void onDestroy() { super.onDestroy(); if (mReactRootView != null) { mReactRootView.unmountReactApplication(); mReactRootView = null; ReactPreLoader.onDestroy(getReactInfo()); } // getReactNativeHost().clear(); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (getReactNativeHost().hasInstance()) { getReactNativeHost().getReactInstanceManager().onActivityResult(requestCode, resultCode, data); } } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { if (getReactNativeHost().hasInstance() && getUseDeveloperSupport()) { if (keyCode == KeyEvent.KEYCODE_MENU) { getReactNativeHost().getReactInstanceManager().showDevOptionsDialog(); return true; } if (mDoubleTapReloadRecognizer.didDoubleTapR(keyCode, getCurrentFocus())) { getReactNativeHost().getReactInstanceManager().getDevSupportManager().handleReloadJS(); } } return super.onKeyUp(keyCode, event); } @Override public void onBackPressed() { if (getReactNativeHost().hasInstance()) { getReactNativeHost().getReactInstanceManager().onBackPressed(); } else { super.onBackPressed(); } } @Override public void invokeDefaultOnBackPressed() { super.onBackPressed(); } @Override public void onNewIntent(Intent intent) { if (getReactNativeHost().hasInstance()) { getReactNativeHost().getReactInstanceManager().onNewIntent(intent); } else { super.onNewIntent(intent); } } @TargetApi(Build.VERSION_CODES.M) @Override public void requestPermissions(String[] permissions, int requestCode, PermissionListener listener) { mPermissionListener = listener; requestPermissions(permissions, requestCode); } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { if (mPermissionListener != null && mPermissionListener.onRequestPermissionsResult(requestCode, permissions, grantResults)) { mPermissionListener = null; } } public abstract ReactInfo getReactInfo(); }