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