React Native でアプリ起動の際に`Error: No native splash screen registered for given view controller.`のアラートが出る現象の解決2021/11/11

React Native でアプリ起動の際に`Error: No native splash screen registered for given view controller.`のアラートが出る現象の解決

React Native + Expo でアプリ開発時に、アプリ起動後スプラッシュが消えるタイミングで以下のアラートが出ていました。

[Unhandled promise rejection: Error: No native splash screen registered for given view controller. Call 'SplashScreen.show' for given view controller first.]
at node_modules/react-native/Libraries/BatchedBridge/NativeModules.js:103:50 in promiseMethodWrapper
at node_modules/@unimodules/react-native-adapter/build/NativeModulesProxy.native.js:15:23 in moduleName.methodInfo.name
at node_modules/expo-splash-screen/build/SplashScreen.js:23:17 in hideAsync
at node_modules/expo-splash-screen/build/SplashScreen.js:19:7 in hideAsync

この現象についての原因調査と解決方法のメモです。

結論を先に言うと

AppLoading でアプリ起動時のアセットの読み込みなどを行っていました。このコンポーネントの audoHideSplash の機能が原因でした。 デフォルトは有効になっているので、false を渡して機能を無効化することで解決できました。

import AppLoading from "expo-app-loading";

~~~

    <AppLoading
      ~~~
      autoHideSplash={false}
    />

概要

  • 使用しているライブラリ
  • エラーの内容を読む
  • SplashScreen.hideAsync() を取り除いてみる
  • 他の何かが hideAsync しようとしている?
  • SplashScreen のサンプルソースを見ると怪しいものを発見

使用しているライブラリ

今回の現象に関連しているのは以下のライブラリでした。

  • expo-splash-screen
    アプリ起動時のスプラッシュ画面の表示に使っています。
  • expo-app-loading
    アプリ起動時のアセット呼び出しやデータ準備などに使っています。

エラーの内容を読む

エラーの内容を見ると、スプラッシュスクリーンが登録されていないと言われています。 SplachScreen.show を最初に呼び出してほしいとのことです。

たしかに、アセットのロードが終わるタイミングで以下を実行して、明示的にスプラッシュを非表示にしています。
この時にスプラッシュがすでに存在しなくなっているのかなと考えられます。

import * as SplashScreen from "expo-splash-screen";

~~~

    await SplashScreen.hideAsync();

しかし、これよりも先にスプラッシュ画面の呼び出しは行っているので、スプラッシュは存在しているはずです。実際に画面にもスプラッシュ画面が表示されていますしね。

    await SplashScreen.preventAutoHideAsync();

SplashScreen.hideAsync() を取り除いてみる

仮説として、hideAsync が不要なのではないかと考え、この行を削除してみました。

結果、スプラッシュスクリーンは表示されたままになり、ホーム画面を表示できない現象が発生。 スプラッシュを隠す hideAsync は必要で、ちゃんと動作していた様子です。

この仮説はハズレでした。

他の何かが hideAsync しようとしている?

仮説として、明示的に hideAsync を記述しているところ以外で、スプラッシュを非表示にする処理が動いているのではと考えました。

何となく怪しいのは、ホーム画面の描写で上書きしているとか、AppLoading の起動時のアセット読み込みなどを管理するコンポーネントなどが考えられます。

SplashScreen のサンプルソースを見ると怪しいものを発見

スプラッシュの実装はドキュメントにも記載されているものを使っているので、それほどおかしいところはないはず。 サンプルのコードがあったので覗いてみました。

https://github.com/expo/examples/tree/master/with-splash-screen https://github.com/expo/examples/blob/master/with-splash-screen/App.js

私の実装と同じようにAppLoading を使っていますが、サンプルではautoHideSplash という引数を渡しています。

      <AppLoading
        // Instruct SplashScreen not to hide yet, we want to do this manually
        autoHideSplash={false}
        startAsync={startAsync}
        onError={console.error}
        onFinish={onFinish}
      />

AppLoading には確かにautoHideSplash というパラメータを渡すことができ、デフォルトでは true となっています。 https://docs.expo.dev/versions/v43.0.0/sdk/app-loading/

AppLoading コンポーネントのアンマウント時にスプラッシュ画面を非表示にしようとします。

これが原因ではと考え、autoHideSplash にfalse を渡すように修正したところ、問題のアラートが表示されなくなりました。 スプラッシュもしっかりと非表示になり、問題が解決できました。

    <AppLoading
      ~~~
      autoHideSplash={false}
    />

おわりに

エラーではなくアラートがログに出るだけなので、放置してもアプリの動作には問題ないはずです。 しかし、こういったものが積み重なると気持ち悪いですし、もっと大きな問題の検知の遅れになったりしてしまいます。

できるだけ細かいアラートなども見逃さずメモしておいたり、コストやスケジュールを考慮して対応するタイミングを作れると良いです。

基本的には AppLoading の使い方の問題でした。サンプルみたりすると解決のヒントがあるのでとても助かりますね。 またバージョン更新によって動作が変わることもあるので、都度対応していければ考えています。

  • このエントリーをはてなブックマークに追加