美文网首页
React Native 启动白屏问题(Android)

React Native 启动白屏问题(Android)

作者: boyrt | 来源:发表于2018-03-23 17:01 被阅读0次

    参考文章: https://blog.csdn.net/fengyuzhengfan/article/details/52712829
    本文主要是针对Android白屏问题,记录解决方案。IOS传送阵

    出现白屏的原因是js.bundle文件未加载完。解决的思路:通过原生代码实现白屏上显示一个Dialog,当js.bundle文件加载完后,在JS代码中将Dialog隐藏。

    原生部分

    原生部分主要是实现Dialog,显示Dialog和JS调用Dialog隐藏的桥接。原生部分项目结构如下图:


    image.png

    SplashScreen:创建Diaolg,当白屏的时候显示用。
    SplashScreenModule、SplashScreenReactPackage:Dialog关闭的桥接,需要在MainApplication中注册。
    welcome.png:Dialog布局文件显示的图片
    splash.xml:Dialog加载的布局文件

    SplashScreen.java

    public class SplashScreen {
    
        private static int NULL_ID = 0;
        private static Dialog mSplashDialog;
        private static WeakReference<Activity> mActivity;
    
        /**
         * 打开启动屏
         */
        public static void show(final Activity activity, final boolean fullScreen, final int themeResId){
            if (activity==null) return;
            mActivity = new WeakReference<Activity>(activity);
            activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if (!activity.isFinishing()) {
                        mSplashDialog = new Dialog(
                                activity,
                                themeResId !=NULL_ID ? themeResId
                                        : fullScreen ? R.style.SplashScreen_Fullscreen
                                        : R.style.SplashScreen_SplashTheme
    
                        );
                        mSplashDialog.setContentView(R.layout.splash);
                        mSplashDialog.setCancelable(false);
                        if (!mSplashDialog.isShowing()) {
                            mSplashDialog.show();
                        }
                    }
                }
            });
        }
    
        /**
         * 打开启动屏
         */
        public static void show(final Activity activity, final boolean fullScreen) {
            show(activity, fullScreen, 0);
        }
    
        /**
         * 打开启动屏
         */
        public static void show(final Activity activity) {
            show(activity, false);
        }
    
        /**
         * 关闭启动屏
         */
        public static void hide(Activity activity) {
            if (activity == null) {
                if (mActivity == null) {
                    return;
                }
                activity = mActivity.get();
            }
            if (activity == null) return;
    
            activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if (mSplashDialog != null && mSplashDialog.isShowing()) {
                        mSplashDialog.dismiss();
                        mSplashDialog = null;
                    }
                }
            });
        }
    
    }
    

    SplashScreenModule.java

    public class SplashScreenModule extends ReactContextBaseJavaModule {
        public SplashScreenModule(ReactApplicationContext reactContext) {
            super(reactContext);
        }
    
        @Override
        public String getName() {
            return "SplashScreen";
        }
    
        /**
         * 打开启动屏
         */
        @ReactMethod
        public void show() {
            SplashScreen.show(getCurrentActivity());
        }
    
        /**
         * 关闭启动屏
         */
        @ReactMethod
        public void hide() {
            SplashScreen.hide(getCurrentActivity());
        }
    
        /**
         * 退出程序
         */
        @ReactMethod
        public void exit() {
            if (getCurrentActivity() != null)
                getCurrentActivity().finish();
            System.exit(0);
        }
    
    }
    

    styles.xml

    <resources>
    
        <!-- Base application theme. -->
        <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
            <!-- Customize your theme here. -->
        </style>
    
        <style name="SplashScreen_SplashAnimation">
            <item name="android:windowExitAnimation">@android:anim/fade_out</item>
        </style>
    
        <style name="SplashScreen_SplashTheme" parent="Theme.AppCompat.NoActionBar">
            <item name="android:windowAnimationStyle">@style/SplashScreen_SplashAnimation</item>
        </style>
        <style name="SplashScreen_Fullscreen" parent="SplashScreen_SplashTheme">
            <item name="android:windowFullscreen">true</item>
        </style>
    
    </resources>
    

    MainActivity.java
    关键代码:SplashScreen.show(this,true),并且必须在super.onCreate(savedInstanceState)之前调用。

    public class MainActivity extends ReactActivity {
    
        @Override
        protected String getMainComponentName() {
            return "PushDemo";
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            SplashScreen.show(this,true);//显示Dialog
            super.onCreate(savedInstanceState);
            //解决应用程序多次重启问题
            if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0){
                finish();
                return;
            }
        }
    }
    

    JS部分

    该部分比较简单,直接上代码
    SplashNative.js

    import {NativeModules, Platform} from 'react-native';
    
    const splash = (Platform.OS === "android") ? NativeModules.SplashScreen : {};
    
    export default splash;
    

    关键点是何时隐藏dialog
    在js的第一个页面的componentDidMount方法中调用

        import SplashScreen from '../native/SplashNative'     
        ...
        componentDidMount() {
            if(Platform.OS === 'android') {
                SplashScreen.hide();
            }
        }
    

    到此,就完成了白屏问题的解决。

    注:原来npm库中react-native-splash-screen已经解决该问题,其原理一样。

    相关文章

      网友评论

          本文标题:React Native 启动白屏问题(Android)

          本文链接:https://www.haomeiwen.com/subject/osyxcftx.html