1. 程式人生 > >React Native 啟動白屏問題解決方案,教程

React Native 啟動白屏問題解決方案,教程

問題描述:

用React Native架構的無論是Android APP還是iOS APP,在啟動時都出現白屏現象,時間大概1~3s(根據手機或模擬器的效能不同而不同)。

問題分析:

為什麼會產生白屏?

React Native應用在啟動時會將js bundle讀取到記憶體中,並完成渲染。這期間由於js bundle還沒有完成裝載並渲染,所以介面顯示的是白屏。

白屏給人的感覺很不友好,那有沒有辦法不顯示白屏呢?

上文解釋了:為什麼React Native應用會在啟動的時候顯示一會白屏。既然知道了出現問題的原因,那麼離解決問題也不遠了。市場上大部分APP在啟動的時候都會有個啟動屏,啟動屏對於使用者是比較友好的,一來展示歡迎資訊,二來顯示一些產品資訊或一些廣告,啟動頁對於程式來說,是為程式完成初始化載入資料,做一些初始化工作的所保留的時間,啟動屏等待的時間可長可短,具體根據業務而定。

下面我就教大家如何給React Native 應用新增啟動屏,並解決啟動白屏的問題。

Android啟動白屏解決方案

我們可以通過為React Native Android應用新增啟動屏的方式,來解決啟動白屏的問題。我在《React Native Android啟動屏,啟動白屏,閃現白屏》一文中介紹過一種為React Native Android應用新增啟動屏的方法, 不過那種方法雖好,但牽扯到對React Native 原始碼的修改,如果React Native 版本有更新還需要對原始碼做一些處理,所以以後維護起來不是很方便。

下面就向大家介紹另外一種為React Native Android應用新增啟動屏的方案。

《React Native Android啟動屏,啟動白屏,閃現白屏》一文中 我們使用的是在根檢視容器上新增一個檢視作為啟動屏,當js bundle載入並渲染完成後,再將新增的檢視從根檢視上移除。在根檢視上新增一個檢視的方式其實就是為了遮擋白屏,既然是遮擋白屏,我們是不是可以彈出一個對話方塊呢?

小夥伴們肯定會說,對話方塊也不是全屏啊,主題也不一樣啊,不過沒關係,既然我們可以新增對話方塊,那麼我們就可以修改對話方塊的樣式來達到我們需要的效果。

要達到啟動屏的效果,我們需要一個什麼樣效果的對話方塊呢?

  1. 在APP啟動的時候顯示;
  2. 在js bundle載入並渲染完成後消失;
  3. 全屏顯示;
  4. 顯示的內容可以通過 layout xml 進行修改;

上述是我們對這個對話方塊的基本需求,現在就讓我們來實現這一需求:

為滿足上述需求,對話方塊元件需要提供下面兩個方法:

1.顯示對話方塊的方法:

/**
 * 開啟啟動屏
 */
public static void show(final Activity activity,final boolean fullScreen) {
    if (activity == null) return;
    mActivity = new WeakReference<Activity>(activity);
    activity.runOnUiThread(new Runnable() {
        @Override
        public void run() {
            if (!activity.isFinishing()) {

                mSplashDialog = new Dialog(activity,fullScreen? R.style.SplashScreen_Fullscreen:R.style.SplashScreen_SplashTheme);
                mSplashDialog.setContentView(R.layout.launch_screen);
                mSplashDialog.setCancelable(false);

                if (!mSplashDialog.isShowing()) {
                    mSplashDialog.show();
                }
            }
        }
    });
} 

為了Activity被銷燬的時候,持有的Activity能被及時的回收,這裡我們通過new WeakReference<Activity>(activity);建立了一個Activity的弱引用。

另外,因為在Android中所有的有關UI操作都必須在主執行緒,所有我們通過activity.runOnUiThread(new Runnable()...,將對話方塊的顯示放在了主執行緒處理。

然後,我們可以在MainActivity.javaonCreate方法中調void show(final Activity activity,final boolean fullScreen)方法來顯示啟動屏。

@Override
protected void onCreate(Bundle savedInstanceState) {
    SplashScreen.show(this,true);
    super.onCreate(savedInstanceState);
}

提示:SplashScreen.show(this,true);放在super.onCreate(savedInstanceState);之前的位置效果會更好。

2.關閉對話方塊的方法:

/**
 * 關閉啟動屏
 */
public static void hide(Activity activity) {
    if (activity == null) activity = mActivity.get();
    if (activity == null) return;

    activity.runOnUiThread(new Runnable() {
        @Override
        public void run() {
            if (mSplashDialog != null && mSplashDialog.isShowing()) {
                mSplashDialog.dismiss();
            }
        }
    });
}

上述程式碼中,我們提供了關閉啟動屏的方法。那麼如何才能讓JS模組呼叫void hide(Activity activity)來關閉啟動屏呢?

因為我們需要在js中呼叫hide方法還控制啟動屏的關閉。js不能直接調Java,所有我們需要為他們搭建一個橋樑(Native Modules)。

首先,建立一個ReactContextBaseJavaModule型別的類,供js呼叫。

/**
 * SplashScreenModule
 * 出自:http://www.devio.org
 * GitHub:https://github.com/crazycodeboy
 * Eamil:[email protected]
 */
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());
    }
}

其次,建立一個ReactPackage型別的類,用於向React Native註冊我們的SplashScreenModule元件。

/**
 * SplashScreenReactPackage
 * 出自:http://www.devio.org
 * GitHub:https://github.com/crazycodeboy
 * Eamil:[email protected]
 */
public class SplashScreenReactPackage implements ReactPackage {

    @Override
    public List<Class<? extends JavaScriptModule>> createJSModules() {
        return Collections.emptyList();
    }

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }

    @Override
    public List<NativeModule> createNativeModules(
            ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();
        modules.add(new SplashScreenModule(reactContext));
        return modules;
    }
}

再次,在MainApplication中註冊SplashScreenModule元件。

@Override
protected List<ReactPackage> getPackages() {
    return Arrays.<ReactPackage>asList(
            new MainReactPackage(),
            new SplashScreenReactPackage()
    );
}

準備工作,做好之後,下面我們就可以在JS中呼叫hide方法來關閉啟動屏了。

第三步:在JS模組中控制啟動屏的關閉

/**
 * SplashScreen
 * 啟動屏
 * 出自:http://www.devio.org
 * GitHub:https://github.com/crazycodeboy
 * Eamil:[email protected]
 * @flow
 */
'use strict';

import { NativeModules } from 'react-native';
module.exports = NativeModules.SplashScreen;

然後,我們可以在js中呼叫SplashScreen的hide()方法來關閉啟動屏了。

componentDidMount() {
    SplashScreen.hide();
}

不要忘記在使用SplashScreen的js檔案中匯入它哦import SplashScreen from './SplashScreen

iOS啟動白屏解決方案

在iOS中,iOS支援為程式設定一個Launch Image或Launch Screen File來作為啟動屏,當程式被開啟的時候,首先顯示的便是設定的這個啟動屏了。

那麼小夥伴會問了,這個啟動螢幕什麼時候會消失呢?

AppDelegate如下方法:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

該方法返回一個 BOOL型別的值,當系統呼叫該方並返回值之後,標誌著APP啟動載入已經完成,系統會將啟動屏給關掉。

所以如果我們控制了這個啟動螢幕讓它在js bundle載入並渲染完成之後再關閉不就解決了iOS 啟動白屏了嗎?

上面已經說到,- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions方法執行完成之後,啟動屏會被關掉。

所以我們就想辦法控制該方實行的時間。

第一步:建立一個名為SplashScreen的Object-C檔案

在SplashScreen.h檔案中新增如下程式碼:

//
//  SplashScreen.h
//  SplashScreen
//  出自:http://www.devio.org
//  GitHub:https://github.com/crazycodeboy
//  Eamil:[email protected]


#import "RCTBridgeModule.h"

@interface SplashScreen : NSObject<RCTBridgeModule>
+ (void)show;
@end

在SplashScreen.m中新增如下程式碼:

//  SplashScreen
//  出自:http://www.devio.org
//  GitHub:https://github.com/crazycodeboy
//  Eamil:[email protected]

#import "SplashScreen.h"

static bool waiting = true;

@implementation SplashScreen
- (dispatch_queue_t)methodQueue{
    return dispatch_get_main_queue();
}
RCT_EXPORT_MODULE()

+ (void)show {
    while (waiting) {
        NSDate* later = [NSDate dateWithTimeIntervalSinceNow:0.1];
        [[NSRunLoop mainRunLoop] runUntilDate:later];
    }
}

RCT_EXPORT_METHOD(hide) {
    dispatch_async(dispatch_get_main_queue(),
                   ^{
                       waiting = false;
                   });
}
@end

在上述程式碼中,我們通過[[NSRunLoop mainRunLoop] runUntilDate:later];來控制- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions方法執行的時間, 主執行緒會每隔0.1s阻塞一次,直到waiting變數為true,然後我們就可以通過暴露給JS模組的hide方法來控制waiting變數的值,繼而達到控制啟動螢幕的關閉。

第二步:在JS模組中控制啟動屏的關閉

通過第一步我們已經向JS模組暴露了hide方法,然我們就可以在JS模組中通過hide方法來關閉啟動螢幕。 由於iOS在JS模組中控制啟動屏的關閉的方法和Android中第三步:在JS模組中控制啟動屏的關閉的方法是一樣的,這裡就不再介紹了。

開源庫

為了方便大家使用和解決React Native應用啟動白屏的問題,我已經將上述方案做成React Native元件react-native-splash-screen, 開源在了GitHub上,小夥伴們可以下載使用。

相關推薦

React Native 啟動問題解決方案,教程

問題描述: 用React Native架構的無論是Android APP還是iOS APP,在啟動時都出現白屏現象,時間大概1~3s(根據手機或模擬器的效能不同而不同)。 問題分析: 為什麼會產生白屏? React Native應用在啟動時會將js bundle

android 啟動解決方案

最近在做專案的時候,突然遇到啟動頁白屏不顯示的問題,首先想到的就是圖片大小,仔細檢視 果然,美工給了我一張超大的圖片,我也沒細看就替換上去了,汗! 好吧,既然發現了問題,果斷替換掉圖片,但是,特麼還是白屏(你特麼在逗我!),幾番百度,谷歌,得到如下解決方案:

android App啟動解決方案

App啟動白屏/黑屏產生原因:      進入到Activity,但是未載入到佈局檔案,就先顯示來windows視窗的背景。黑屏/白屏就是顯示的windows背景(這個就是theme的設定)。     on

vue 項目解決方案

sset 運營商 assets 基礎 tsp pack path try 分析 在做的項目是使用 vue-cli 腳手架為基礎的,只能使用微信瀏覽器打開的。在某次更新功能代碼後,被反饋在一些手機上會出現白屏。經過一番探索,多管齊下解決了問題 白屏可能的原因: es6 代碼

Android中WebView顯示flash閃解決方案

播放flash(.swf格式)檔案通常有兩種方式:SWF播放器,WebView,以下僅討論WebView播放flash的情況: 使用場景:需要對UI做定製,明顯,自己寫個flash播放器工作量太大,WebView輕巧多了。步驟如下: 1.安裝Adobe的flash外掛

Ubuntu啟動解決方案

在啟動Ubuntu的時候出現黑屏的情況,是因為升級了核心導致顯示卡不相容,啟動的時候應該告訴核心不要載入顯示卡: sudo vi /etc/default/grub 找到quiet splash

[React Native] Android 優化

APP是原生嵌入一個React Native介面 背景 按官方例項集成了一個React Native介面,但每次開啟都感覺等待時間有點長,會有白屏狀態。這對於強迫症來說簡直不能忍。於是決定優化。 效果 優化前的效果,白屏時間較長。

vue 路由切換解決方案

out 期望 n) his http 方案 return code load 關於vue 路由切換的白屏,事實上在開發的過程中,我一直沒有遇到過。 我有個哥們遇到這個問題,問我怎麽解決的, 我暈了,我沒遇到這樣的問題啊,我怎麽解決啊啊啊啊。。 事實上是遇到過一回的。 場景一

react native 新增啟動頁並解決啟動問題

我們之所以設定啟動頁,很大一部分原因是在啟動頁顯示的背後可以利用寶貴的時間來初始化我們的應用,啟動頁消失後,初始化的工作就應該做完。因此,使用開源RN元件是比較靠譜的,閒言少敘,直奔主題! 安裝 npm install --save rn-splash-screen連線 react-native l

12月11日,發生大面積的包含 react-native-image-picker 的安卓專案啟動崩潰現象解決方案。(我的已經解決

12月11日,發生大面積的包含 react-native-image-picker 的安卓專案啟動崩潰現象。疑似原因為maven源丟失。解決方案見github:https://github.com/react-native-community/react-native-image-picke

react native Android啟動頁面、修改圖示、修改名字、修復啟動

給Android新增啟動頁 實現啟動頁基本有三種思路: 使用RN開源元件;原生java編寫;模擬啟動頁,這種方法基本就是replace路由棧;http://www.jianshu.com/p/da658aceeb44 我們之所以設定啟動頁,很大一部分原因是在啟動頁顯示

Flutter Android端啟動問題的解決

Flutter 應用在 Android 端上啟動時會有一段很明顯的白屏現象,白屏的時長由裝置的效能決定,裝置效能越差,白屏時間越長。這篇文章主要介紹了Flutter Android端啟動白屏問題的解決。感興趣的小夥伴們可以參考一下 問題描述 Flutter 應用在 Android 端上

Android啟動問題完美解決

在開發過程中我們經常會遇到點選啟動App的時候有短暫的白屏出現,怎麼避免這種情況呢?提供倆種解決思路 1、設定透明的介面來完成 在你的style裡面加這倆行程式碼 <item name="android:windowIsTranslucent">true&l

(原創)解決APP啟動的問題

APP啟動時需要大量的時間進行初始化操作,包括application的初始化以及MainActivity的初始化 在這個過程中,可能會出現白屏的情況 也就是使用者點選啟動圖示後 首先看到的是一片白色的螢幕 這樣的體驗肯定是不好的 而且如果設定了Splash頁面,進入

解決Android app啟動問題

1.解決app啟動白屏問題 介紹兩種方式 載入首頁頁面前,進行頁面或者顏色過渡,使用者體驗感好 第一步設定一下主題色為透明 <!-- 應用啟動頁(StartingWindow)的theme --> <style name="AppTheme.Startin

android activtiy 啟動原因還有解決方法

在啟動android 程式的時候,經常會遇到啟動的時候螢幕會顯示白色的內容,原因是: Android中Activity啟動的時候實際上建立了兩個Window物件,第一個叫做PreviewWindow,是為了避免真正的視窗沒有及時加載出來,但是又不想讓使用者等待才引入了這個windo

解決啟動問題

一般情況下 我們在啟動APP的時候,螢幕會出現一段時間的白屏或者黑屏,不同的裝置可能白屏黑屏顯示的時間長短不同,裝置硬體較差的時間都會比較長,這顯然影

Android冷啟動解析,帶你一步步分析和解決問題

本文同步發表於我的微信公眾號,掃一掃文章底部的二維碼或在微信搜尋 郭霖 即可關注,每天都有文章更新。 寫在前面 記得在本月初,我發表了一篇文章叫《 Android Studio新功能解析,你真的瞭解Instant Run嗎?》,裡面詳細講解了

解決APP啟動或者黑閃現的問題

解決辦法,自定義Theme,有兩種方法,第一種Theme就是設定一張背景圖。當程式啟動時,首先顯示這張背景圖,避免出現黑屏。第二種Theme是把樣式設定為透明,程式啟動後不會黑屏而是整個透明瞭,等到介面初始化完才一次性顯示出來。 //1、設定背景圖Them

解決開啟應用啟動幾秒問題

只要修改style.xml,就可以完美解決。<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">