做過(guò) RN 項(xiàng)目的童鞋應(yīng)該都知道 RN 項(xiàng)目啟動(dòng)之后有一個(gè)短暫的白屏,調(diào)試階段這個(gè)白屏的時(shí)間較長(zhǎng),大概3-5秒,打正式包后這個(gè)白屏?xí)r間會(huì)大大縮短,大多時(shí)候都是一閃而過(guò),所以稱之為『閃白』。

雖然說(shuō)時(shí)間很短,但是只要能被用戶察覺(jué),都是屬于 Bug
為什么會(huì)有白屏
在iOS App 中有 啟動(dòng)圖(LaunchImage),啟動(dòng)圖結(jié)束后才會(huì)出現(xiàn)上述的閃白,這個(gè)過(guò)程是 JS 解釋的過(guò)程,JS 解釋完畢之前沒(méi)有內(nèi)容,所以才表現(xiàn)出白屏,那么解決的方法就是在啟動(dòng)圖結(jié)束后,JS 解釋完成前,做一些處理
-
啟動(dòng)圖結(jié)束的時(shí)間
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions; -
JS解釋完畢
可以大致確定在項(xiàng)目第一個(gè)頁(yè)面加載完畢,注意是第一個(gè)頁(yè)面,不一定是 app 的『首頁(yè)』
componentDidMount() { }
解決思路
- 啟動(dòng)圖結(jié)束后通過(guò)原生代碼加載一張全屏占位圖片,跟啟動(dòng)圖一樣的圖片,混淆視聽(tīng)『欺騙用戶』
- JS解釋完畢后通知原生可以移除占位圖
- 收到 JS 發(fā)來(lái)的可以移除占位圖的通知,移除占位圖
實(shí)現(xiàn)
-
SplashScreen 用來(lái)接收 JS 發(fā)來(lái)的『移除占位圖』的消息
SplashScreen.h
#import <Foundation/Foundation.h> #import "RCTBridgeModule.h" @interface SplashScreen : NSObject<RCTBridgeModule> @endSplashScreen.m
#import "SplashScreen.h" @implementation SplashScreen RCT_EXPORT_MODULE(); RCT_EXPORT_METHOD(close){ [[NSNotificationCenter defaultCenter] postNotificationName:@"Notification_CLOSE_SPLASH_SCREEN" object:nil]; } @end -
AppDelegate.m
@interface AppDelegate () { UIImageView *splashImage; } @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(closeSplashImage) name:"Notification_CLOSE_SPLASH_SCREEN" object:nil]; ... [self autoSplashScreen];//寫(xiě)在 return YES 之前,其他代碼之后 return YES; } -(void)autoSplashScreen { if (!splashImage) { splashImage = [[UIImageView alloc]initWithFrame:[UIScreen mainScreen].bounds]; } if (IPHONESCREEN3p5) { [splashImage setImage:[UIImage imageNamed:@"launch4"]]; }else if (IPHONESCREEN4){ [splashImage setImage:[UIImage imageNamed:@"launch5"]]; }else if (IPHONESCREEN4p7){ [splashImage setImage:[UIImage imageNamed:@"launch6"]]; }else if (IPHONESCREEN5p5){ [splashImage setImage:[UIImage imageNamed:@"launch7"]]; } [self.window addSubview:splashImage]; } -(void)closeSplashImage { dispatch_sync(dispatch_get_main_queue(), ^{ [UIView animateWithDuration:0.5 animations:^{ splashImage.alpha = 0; } completion:^(BOOL finished){ [splashImage removeFromSuperview]; }]; }); } -
JS中選擇合適的時(shí)機(jī)調(diào)用關(guān)閉方法
if (Platform.OS === 'ios') { NativeModules.SplashScreen.close(); };
GitHub上有一套統(tǒng)一兩個(gè)平臺(tái)的代碼,有興趣的可以去看看,
https://github.com/crazycodeboy/react-native-splash-screen/blob/master/README.zh.md