Activity布局以组件形式加载React Native



一、需求分析


前几篇博客中,和大家分享了关于React Native For Android 的一系列内容,以及React Native第三方库的使用技巧。今天和大家分享内容可以算是React Native基于最新版本实现JsBundle预加载,界面秒开优化延伸。

本篇博客内容围绕的依然是如何加载RN界面,在JsBundle加载优化这篇博客中,我们从源码角度分析了如何实现快速加载RN界面,RN界面的加载在ReactActivity的onCreate中完成,实则是通过ReactDelegate委托类的onCreate来实现。在ReactDelegate的onCreate方法中,系统调用loadApp来加载RN根视图,在loadApp方法中通过createRootView创建视图(new ReactRootView()),并启动设置到Activity的ContentView(DecoerView)上。



二、功能实现


上面我们分析了整个RN视图加载的流程,那么如何在现有Activity布局中加载RN界面呢?原理依然要从创建设置ReactRootView来解决。RN的新版本对设置创建ReactRootView进行了封装,使得我们只需要重写getMainComponentName方法返回RN注册名称即可。这就使得我们不能直接控制ReactRootView的创建和设置。所以依然要采用重写ReactDelegate的方式来解决

    public class MyReactDelegate {  
      
        private final Activity mActivity;  
        private ReactRootView mReactRootView;  
        private Callback mPermissionsCallback;  
        private final String mMainComponentName;  
        private PermissionListener mPermissionListener;  
        private final int REQUEST_OVERLAY_PERMISSION_CODE = 1111;  
        private DoubleTapReloadRecognizer mDoubleTapReloadRecognizer;  
      
        public PreLoadReactDelegate(Activity activity,@Nullable String mainComponentName) {  
            this.mActivity = activity;  
            this.mMainComponentName = mainComponentName;  
        }  
      
        public void onCreate() {  
            boolean needsOverlayPermission = false;  
            if (getReactNativeHost().getUseDeveloperSupport() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {  
                // Get permission to show redBox in dev builds.  
                if (!Settings.canDrawOverlays(mActivity)) {  
                    needsOverlayPermission = true;  
                    Intent serviceIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,Uri.parse("package:" + mActivity.getPackageName()));  
                    mActivity.startActivityForResult(serviceIntent,REQUEST_OVERLAY_PERMISSION_CODE);  
                }  
            }  
      
            if (mMainComponentName != null && !needsOverlayPermission) {  

                  mReactRootView = new ReactRootView(mActivity);  
                  mReactRootView.startReactApplication(  
                            getReactInstanceManager(),mMainComponentName,null);  
                }  
               // 3.将RootView设置到Activity布局
  mActivity.setContentView(R.layout.acty_rn);
  ((FrameLayout)mActivity.findViewById(R.id.rn_contaner)).addView(mReactRootView);
            }  
      
            mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer();  
        }  
      
        public void onResume() {  
            if (getReactNativeHost().hasInstance()) {  
                getReactInstanceManager().onHostResume(mActivity,(DefaultHardwareBackBtnHandler)mActivity);  
            }  
            if (mPermissionsCallback != null) {  
                mPermissionsCallback.invoke();  
                mPermissionsCallback = null;  
            }  
        }  
      
        public void onPause() {  
            if (getReactNativeHost().hasInstance()) {  
                getReactInstanceManager().onHostPause(mActivity);  
            }  
        }  
      
        public void onDestroy() {  
      
            if (mReactRootView != null) {  
                mReactRootView.unmountReactApplication();  
                mReactRootView = null;  
            }  
            if (getReactNativeHost().hasInstance()) {  
                getReactInstanceManager().onHostDestroy(mActivity);  
            }  
      
            
        }  
      
        public boolean onNewIntent(Intent intent) {  
            if (getReactNativeHost().hasInstance()) {  
                getReactInstanceManager().onNewIntent(intent);  
                return true;  
            }  
            return false;  
        }  
      
        public void onActivityResult(int requestCode,int resultCode,Intent data) {  
            if (getReactNativeHost().hasInstance()) {  
                getReactInstanceManager().onActivityResult(mActivity,requestCode,resultCode,data);  
            } else {  
                // Did we request overlay permissions?  
                if (requestCode == REQUEST_OVERLAY_PERMISSION_CODE && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {  
                    if (Settings.canDrawOverlays(mActivity)) {  
                        if (mMainComponentName != null) {  
                            if (mReactRootView != null) {  
                                throw new IllegalStateException("Cannot loadApp while app is already running.");  
                            }  
                            mReactRootView = new ReactRootView(mActivity);  
                            mReactRootView.startReactApplication(  
                                    getReactInstanceManager(),null);  
                            mActivity.setContentView(mReactRootView);  
                        }  
                    }  
                }  
            }  
        }  
      
        public boolean onBackpressed() {  
            if (getReactNativeHost().hasInstance()) {  
                getReactInstanceManager().onBackpressed();  
                return true;  
            }  
            return false;  
        }  
      
        public boolean onRNKeyUp(int keyCode) {  
            if (getReactNativeHost().hasInstance() && getReactNativeHost().getUseDeveloperSupport()) {  
                if (keyCode == KeyEvent.KEYCODE_MENU) {  
                    getReactInstanceManager().showDevOptionsDialog();  
                    return true;  
                }  
                boolean didDoubleTapR = Assertions.assertNotNull(mDoubleTapReloadRecognizer)  
                        .didDoubleTapR(keyCode,mActivity.getCurrentFocus());  
                if (didDoubleTapR) {  
                    getReactInstanceManager().getDevSupportManager().handleReloadJS();  
                    return true;  
                }  
            }  
            return false;  
        }  
      
        public void requestPermissions(String[] permissions,int requestCode,PermissionListener listener) {  
            mPermissionListener = listener;  
            mActivity.requestPermissions(permissions,requestCode);  
        }  
      
        public void onRequestPermissionsResult(final int requestCode,final String[] permissions,final int[] grantResults) {  
            mPermissionsCallback = new Callback() {  
                @Override  
                public void invoke(Object... args) {  
                    if (mPermissionListener != null && mPermissionListener.onRequestPermissionsResult(requestCode,permissions,grantResults)) {  
                        mPermissionListener = null;  
                    }  
                }  
            };  
        }  
      
        /** 
         * 获取 Application中 ReactNativeHost 
         * @return 
         */  
        private ReactNativeHost getReactNativeHost() {  
            return MainApplication.getInstance().getReactNativeHost();  
        }  
      
        /** 
         * 获取 ReactInstanceManager 
         * @return 
         */  
        private ReactInstanceManager getReactInstanceManager() {  
            return getReactNativeHost().getReactInstanceManager();  
        }  
    }  

核心依然是修改了onCreate中方法,我们在设置根布局时,不是直接设置ReactRootView,而是加载我们自己的Activity布局,然后将RN布局作为子布局添加到Activity布局,这样就可以实现在现有Activity布局中嵌入RN布局了。



三、效果


点击查看源码

相关文章

一、前言 在组件方面react和Vue一样的,核心思想玩的就是组件...
前言: 前段时间学习完react后,刚好就接到公司一个react项目...
前言: 最近收到组长通知我们项目组后面新开的项目准备统一技...
react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom...