capacitor-plugins icon indicating copy to clipboard operation
capacitor-plugins copied to clipboard

@capacitor/splash-screen: Calling SplashScreen.hide() in background on Android causes crash

Open jmartycak-rbi opened this issue 8 months ago • 7 comments

Bug Report

Plugin(s)

@capacitor/splash-screen

Capacitor Version

💊   Capacitor Doctor  💊 

Latest Dependencies:

  @capacitor/cli: 5.5.0
  @capacitor/core: 5.5.0
  @capacitor/android: 5.5.0
  @capacitor/ios: 5.5.0

Installed Dependencies:

  @capacitor/cli: 5.3.0
  @capacitor/core: 5.3.0
  @capacitor/android: 5.3.0
  @capacitor/ios: 5.3.0

[info] Using Gemfile: RubyGems bundle installed
[success] iOS looking great! 👌
[success] Android looking great! 👌

Platform(s)

Android

Current Behavior

We've started seeing a couple of splash screen related crash reports in Firebase Crashlytics after a recent update to Capacitor 5. Our investigation revealed it's related to the @capacitor/splash-screen package. The problem manifests itself when the app is backgrounded when the splash screen is still visible, and later the hide method is called in the background. Looking up the error message revealed the same issue was present in react-native-bootsplash package. You can see this issue for additional technical details and applied fix.

Also it seems it's happening only for a specific subset of devices: Snímek obrazovky 2023-10-24 v 10 56 31

Stacktrace:

Fatal Exception: java.lang.NullPointerException
Attempt to invoke direct method 'void android.view.SurfaceControl.checkNotReleased()' on a null object reference
  android.view.SurfaceControl.-$$Nest$mcheckNotReleased
  android.view.SurfaceControl$Transaction.checkPreconditions (SurfaceControl.java:2798)
  android.view.SurfaceControl$Transaction.hide (SurfaceControl.java:2950)
  android.app.ActivityThread.syncTransferSplashscreenViewTransaction (ActivityThread.java:4200)
  android.app.ActivityThread.-$$Nest$msyncTransferSplashscreenViewTransaction
  android.app.ActivityThread$1.onDraw (ActivityThread.java:4177)
  android.view.ViewTreeObserver.dispatchOnDraw (ViewTreeObserver.java:1132)
  android.view.ViewRootImpl.draw (ViewRootImpl.java:4585)
  android.view.ViewRootImpl.performDraw (ViewRootImpl.java:4368)
  android.view.ViewRootImpl.performTraversals (ViewRootImpl.java:3595)
  android.view.ViewRootImpl.doTraversal (ViewRootImpl.java:2354)
  android.view.ViewRootImpl$TraversalRunnable.run (ViewRootImpl.java:9078)
  android.view.Choreographer$CallbackRecord.run (Choreographer.java:1346)
  android.view.Choreographer$CallbackRecord.run (Choreographer.java:1354)
  android.view.Choreographer.doCallbacks (Choreographer.java:1005)
  android.view.Choreographer.doFrame (Choreographer.java:936)
  android.view.Choreographer$FrameDisplayEventReceiver.run (Choreographer.java:1322)
  android.os.Handler.handleCallback (Handler.java:942)
  android.os.Handler.dispatchMessage (Handler.java:99)
  android.os.Looper.loopOnce (Looper.java:227)
  android.os.Looper.loop (Looper.java:327)
  android.app.ActivityThread.main (ActivityThread.java:7995)
  java.lang.reflect.Method.invoke (Method.java)
  com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:548)
  com.android.internal.os.ZygoteInit.main (ZygoteInit.java:942)

Expected Behavior

The app doesn't crash when splash screen hide method is called in the background

Code Reproduction

https://github.com/jmartycak-rbi/capacitor-splash-screen-bug

Steps to reproduce in readme

Other Technical Details

n/a

Additional Context

https://github.com/zoontek/react-native-bootsplash/issues/381

jmartycak-rbi avatar Oct 24 '23 08:10 jmartycak-rbi

This issue needs more information before it can be addressed. In particular, the reporter needs to provide a minimal sample app that demonstrates the issue. If no sample app is provided within 15 days, the issue will be closed.

Please see the Contributing Guide for how to create a Sample App.

Thanks! Ionitron 💙

Ionitron avatar Oct 24 '23 10:10 Ionitron

Consider calling the hide method within the callback of platform.ready. You can refer to the following link for an example: GitHub - Ionic Conference App.

LennonReid avatar Nov 01 '23 13:11 LennonReid

It also happens with the launchAutoHide option and not explicitly calling the .hide() method

    SplashScreen: {
      launchAutoHide: true,
      launchShowDuration: 2000,
      backgroundColor: "#F6F8F8",
      androidScaleType: "CENTER_CROP",
      splashFullScreen: true,
    },

selcuk-sahin avatar Nov 12 '23 13:11 selcuk-sahin

I tested the demo you provided on three different Android devices, and it performed well on all of them. To expedite the resolution of the issue you're encountering, it would be helpful if you could provide the Logcat log specific to the device where the problem occurs. This is especially important considering that not all development teams may have the OnePlus device for testing physical phones.

LennonReid avatar Nov 12 '23 15:11 LennonReid

This is an Android 12 OS bug that was supposedly fixed on Android 13, but for some reason some devices with Android 13 (mostly Oppo/Oneplus) are still affected.

What react-native-bootsplash has done is to remove the compatibility library, which is something we don't plan to do. There must be something else I'm missing because the issue is on the OS, not on the compatibility library, so removing the compat library should not make any effect on Android 13 devices. I've created a sample native app with just the splash code and no compatibility library and it still crash on Oppo devices.

The only thing I've found that makes the app to not crash is to not call setOnExitAnimationListener, which will then disable the splash fade animation.

So we can add a feature to allow users to prevent the setOnExitAnimationListener code from running if configured to do so, that will remove the animation but will prevent the crash on some devices.

jcesarmobile avatar Nov 20 '23 19:11 jcesarmobile

in my react project:

capacitor.config.json

"plugins": {
    "SplashScreen": {
      "launchAutoHide": false
    },
  }

App.tsx

const timer = setTimeout(()=>{
  SplashScreen.hide().catch((error) => console.error(error));
  clearTimeout(timer);
},3000)

const App: React.FC = () => {
...
}

I only use it to avoid errors caused by Splash.hide().

CodeIceCream avatar Dec 04 '23 08:12 CodeIceCream

@jcesarmobile Hi, react-native-bootsplash maintainer here.

The issue is caused by how they implement the way to keep the splash screen on screen.

They basically freeze the UI updates during the whole time the splash screen is visible.

Another thing you can try: Just after the splash screen is shown (with the AndroidX lib), try to lock the phone screen and unlock (put a timeout at 10s to hide the splash screen) 😅

zoontek avatar Dec 20 '23 08:12 zoontek