参考文章: 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已经解决该问题,其原理一样。
网友评论