Capacitor/Cordova Splash Screen delay?

Hi, I’m experiencing issues with boot time in Capacitor.

I’ve read that Capacitor handles splashscreen differently than Cordova, which first shows a grey window and then it is filled with the real splash screen. It can be programmatically hide calling splashScreen.hide() as soon as the platform is ready.

Capacitor is smarter, it shows the real SplashScreen already during the first phase.
We can hide the splash screen in Capacitor calling Plugins.SplashScreen.hide().

I hope I understood how these 2 work.

Now, I’ve created a Capacitor 2.0 app, it works perfectly but I’m experiencing a long boot time during first phase with an Android device, it takes ~3 seconds for phase 1(static full screen image), then it shows the spinning loader for ~2 second and then the app is finally ready. During transition between phase 1 and phase 2 it blinks and with “darkish” splashscreen it is too noticeable. (Note: I’ve tried with a blank new app and it still blinks).

I’m already calling the Plugin.SplashScreen.hide in app.component and I’ve built the app with --prod flag.

The only “weird” thing is I’m using a Cordova plugin in my project and I’ve used Cordova-res to create icon and splashscreen.
The app boots in less than 3 seconds in total in Emulator Nexus 5X Api 26 and ~5 seconds in physical Device (Huawei Y6 Android 9). Is that my fault or it just does not fit for cheap android devices?

Thanks so much!
Niccolò

@mhartington

My environment:

Ionic:

Ionic CLI : 6.6.0 (/usr/local/lib/node_modules/@ionic/cli)
Ionic Framework : @ionic/angular 5.0.7
@angular-devkit/build-angular : 0.803.26
@angular-devkit/schematics : 8.3.26
@angular/cli : 8.3.26
@ionic/angular-toolkit : 2.2.0

Capacitor:

Capacitor CLI : 2.1.0
@capacitor/core : 2.0.1

Cordova:

Cordova CLI : 9.0.0 (cordova-lib@9.0.1)
Cordova Platforms : none
Cordova Plugins : no whitelisted plugins (2 plugins total)

Utility:

cordova-res : 0.14.0
native-run : 1.0.0

System:

Android SDK Tools : 26.1.1 (/Users/simoncini/Library/Android/sdk)
ios-deploy : 1.9.4
NodeJS : v12.16.1 (/usr/local/bin/node)
npm : 6.14.4
OS : macOS Mojave
Xcode : Xcode 11.3.1 Build version 11C504

Can you share some code or a demo app?

1 Like

Hi Mike!
Here’s the GitHub repository with a blank new app.

I’ve set the dark theme to create more contrast and a dark blue splashscreen.
I’ve used cordova-res to create icon and splashscreen.

I reduced the boot time adding:
“plugins”: {
“SplashScreen”: {
“launchShowDuration”: 0
}
}

and removing the spinning from capacitor-config.json but I still have the white blinking.
(SplashScreen(dark blue) -> White Screen -> App Loaded(dark grey) )

Thanks so much!
Niccolò

1 Like

So I wasn’t really able to replicate this in my test with your project.

2020-05-15 10:14:52.316673-0400 App[28467:1623497] WF: === Starting WebFilter logging for process App
2020-05-15 10:14:52.316855-0400 App[28467:1623497] WF: _userSettingsForUser : (null)
2020-05-15 10:14:52.317042-0400 App[28467:1623497] WF: _WebFilterIsActive returning: NO
Loading network plugin
2020-05-15 10:14:52.370565-0400 App[28467:1623497] CAPKeyboard: resize mode - native
⚡️  Loading app at capacitor://localhost...
Reachable via WiFi
APP ACTIVE
⚡️  WebView loaded
⚡️  [log] - Ionic Native: deviceready event fired after 54 ms
⚡️  [warn] - Native: tried calling StatusBar.styleDefault, but the StatusBar plugin is not installed.
⚡️  [warn] - Install the StatusBar plugin: 'ionic cordova plugin add cordova-plugin-statusbar'
⚡️  [warn] - Native: tried calling SplashScreen.hide, but the SplashScreen plugin is not installed.
⚡️  [warn] - Install the SplashScreen plugin: 'ionic cordova plugin add cordova-plugin-splashscreen'
⚡️  To Native ->  App addListener 53029944

Though I will note a few things. You shouldn’t use the cordova API for interacting with splashscreen and statusbar. Use the built in APIs for that. This will result in even faster starter up time.

import { Component } from '@angular/core';
import { Plugins } from '@capacitor/core';
@Component({
  selector: 'app-root',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.scss']
})
export class AppComponent {

  ngOnInit() {
    const { SplashScreen } = Plugins
    SplashScreen.hide();
  }
}

I’ve been working on it for last few days, I’ll post a demo of what I mean. I must say that Capacitor app are very fast on my iOS device and in Android Emulator and they perform “bad” on my android device (which is very cheap but I use it as a benchmark).

I created a project from scratch and now the app.component.ts is just like the one you kindly suggested here. I used css to customize the app and make the “delay” more clear.

Here’s my capacitor.config.json (which is the only file with app.component.ts that I modified from the brand new project).

Maybe this device is just too bad for an hybrid app but apparently Cordova’s app doesn’t have the “white” screen between the actual splash screen and the loaded app (see gif)

{
  "appId": "io.ionic.starter",
  "appName": "BlankCapacitor",
  "bundledWebRuntime": false,
  "npmClient": "npm",
  "webDir": "www",
  "plugins": {
    "SplashScreen": {
      "launchShowDuration": 0,
      "launchAutoHide": false,
      "showSpinner": true
    }
  },
  "cordova": {}
}

And here’s the demo:

ezgif.com-video-to-gif-2

Are you doing a production build of your app? Honestly this looks like your app taking a bit to startup vs capacitor being slow.

Yes, I do this

ionic build --prod && npx cap copy && npx cap sync && npx cap open android

and I clean the project from Android studio every time.

in fact I get this:

> ng run app:build:production
Generating ES5 bundles for differential loading...
ES5 bundle generation complete.

The weird thing is that the SAME blank app behave differently with Cordova, it starts with a grey container but does not have the white page in between the splash and the app.
I’m losing my mind :slight_smile:

Well the webview in native land is configured differently, so I’d expect that to happen. look a the background color option in the config for capacitor.

Already tried going like this but it went differently than I expected

"plugins": {
    "SplashScreen": {
      "launchShowDuration": 0,
      "launchAutoHide": false,
      "backgroundColor": "#42d77d", (that's the ion-color-success, a light green)
      "showSpinner": true
    }
  },

the only thing that changed was this:

and the white “transition” page stayed white :frowning:

1 Like

I created another repo with the latest changes just in case someone else wanna try on his/her device:

One last thing and then I will just resign myself :frowning:

Here’s the log of the app(the exact source you can find in the repointing just posted) in Android Studio if can be helpful, I’m posting so much just in case it could somehow improve Capacitor in low performance devices…

I’d like to say thanks one more time for your help and patience @mhartington, really thanks!

05/15 22:06:08: Launching 'app' on HUAWEI MRD-LX1.
$ adb shell am start -n "io.ionic.starter/io.ionic.starter.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Connected to process 6869 on device 'huawei-mrd_lx1-5WH6R19422014318'.
Capturing and displaying logcat messages from application. This behavior can be disabled in the "Logcat output" section of the "Debugger" settings page.
I/HwApiCacheMangerEx: apicache path=/storage/emulated/0 state=mounted key=io.ionic.starter#10350#256
I/HwApiCacheMangerEx: apicache path=/storage/emulated/0 state=mounted key=io.ionic.starter#10350#0
W/FirebaseApp: Default FirebaseApp failed to initialize because no default options were found. This usually means that com.google.gms:google-services was not applied to your gradle project.
I/FirebaseInitProvider: FirebaseApp initialization unsuccessful
D/ZrHung.AppEyeUiProbe: notify runnable to start.
D/ZrHung.AppEyeUiProbe: Runnable thread started.
I/AwareBitmapCacher: init processName:io.ionic.starter pid=6869 uid=10350
E/MemoryLeakMonitorManager: MemoryLeakMonitor.jar is not exist!
V/ActivityThread: Skipping new config:{1.0 ?mcc?mnc [it_IT,en_IT,de_DE,es_IT,pt_IT] ldltr sw360dp w360dp h711dp 320dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 0, 0) mAppBounds=Rect(0, 54 - 720, 1476) mWindowingMode=fullscreen mActivityType=undefined} nonFullScreen=0 suim:1 s.16}, config:{1.0 ?mcc?mnc [it_IT,en_IT,de_DE,es_IT,pt_IT] ldltr sw360dp w360dp h711dp 320dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 0, 0) mAppBounds=Rect(0, 54 - 720, 1476) mWindowingMode=fullscreen mActivityType=undefined} nonFullScreen=0 suim:1 s.16} for app:io.ionic.starter
V/HwPolicyFactory: : success to get AllImpl object and return....
V/ActivityThread: callActivityOnCreate
W/o.ionic.starte: Accessing hidden method Landroid/graphics/drawable/Drawable;->getOpticalInsets()Landroid/graphics/Insets; (light greylist, linking)
    Accessing hidden field Landroid/graphics/Insets;->left:I (light greylist, linking)
W/o.ionic.starte: Accessing hidden field Landroid/graphics/Insets;->right:I (light greylist, linking)
    Accessing hidden field Landroid/graphics/Insets;->top:I (light greylist, linking)
    Accessing hidden field Landroid/graphics/Insets;->bottom:I (light greylist, linking)
E/o.ionic.starte: Invalid ID 0x00000000.
    Invalid ID 0x00000000.
I/HwApsImpl: APS: new HwApsImpl created
V/HwWidgetFactory: : successes to get AllImpl object and return....
I/HwPhoneWindow: updateLayoutParamsColor false mSpecialSet=false, mForcedNavigationBarColor=false, navigationBarColor=0, mNavBarShow=false, mIsFloating=false
I/HwPhoneWindow: updateLayoutParamsColor true mSpecialSet=true, mForcedNavigationBarColor=false, navigationBarColor=fffcfcfc, mNavBarShow=false, mIsFloating=false
W/o.ionic.starte: Accessing hidden method Landroid/view/View;->getAccessibilityDelegate()Landroid/view/View$AccessibilityDelegate; (light greylist, linking)
W/o.ionic.starte: Accessing hidden method Landroid/view/View;->computeFitSystemWindows(Landroid/graphics/Rect;Landroid/graphics/Rect;)Z (light greylist, reflection)
W/o.ionic.starte: Accessing hidden method Landroid/view/ViewGroup;->makeOptionalFitsSystemWindows()V (light greylist, reflection)
I/WebViewFactory: Loading com.android.chrome version 81.0.4044.138 (code 404413820)
E/o.ionic.starte: Invalid ID 0x00000000.
E/o.ionic.starte: Invalid ID 0x00000000.
I/chatty: uid=10350(io.ionic.starter) identical 1 line
E/o.ionic.starte: Invalid ID 0x00000000.
I/cr_LibraryLoader: Loaded native library version number "81.0.4044.138"
W/o.ionic.starte: Accessing hidden method Landroid/content/Context;->bindServiceAsUser(Landroid/content/Intent;Landroid/content/ServiceConnection;ILandroid/os/Handler;Landroid/os/UserHandle;)Z (light greylist, reflection)
E/: [ZeroHung]zrhung_get_config: Get config failed for wp[0x0008]
I/o.ionic.starte: Background concurrent copying GC freed 43505(11MB) AllocSpace objects, 5(100KB) LOS objects, 87% free, 1693KB/13MB, paused 198us total 156.077ms
D/HwCustConnectivityManagerImpl: isBlockNetworkRequestByNonAis, INVALID_SUBSCRIPTION_ID
D/ConnectivityManager: requestNetwork and the calling app is: io.ionic.starter
D/HwCustConnectivityManagerImpl: isBlockNetworkRequestByNonAis, INVALID_SUBSCRIPTION_ID
D/Capacitor: Starting BridgeActivity
D/Capacitor: Registering plugin: App
D/Capacitor: Registering plugin: Accessibility
D/Capacitor: Registering plugin: BackgroundTask
D/Capacitor: Registering plugin: Browser
D/Capacitor: Registering plugin: Camera
D/Capacitor: Registering plugin: Clipboard
D/Capacitor: Registering plugin: Device
D/Capacitor: Registering plugin: LocalNotifications
D/Capacitor: Registering plugin: Filesystem
D/Capacitor: Registering plugin: Geolocation
D/Capacitor: Registering plugin: Haptics
D/Capacitor: Registering plugin: Keyboard
D/Capacitor: Registering plugin: Modals
D/Capacitor: Registering plugin: Network
D/Capacitor: Registering plugin: Permissions
D/Capacitor: Registering plugin: Photos
D/Capacitor: Registering plugin: PushNotifications
D/Capacitor: Registering plugin: Share
D/Capacitor: Registering plugin: SplashScreen
D/Capacitor: Registering plugin: StatusBar
D/Capacitor: Registering plugin: Storage
D/Capacitor: Registering plugin: Toast
D/Capacitor: Registering plugin: WebView
E/Capacitor: Unable to read file at path public/plugins
D/Capacitor: Loading app at http://localhost
W/o.ionic.starte: Accessing hidden method Landroid/media/AudioManager;->getOutputLatency(I)I (light greylist, reflection)
I/HwSecImmHelper: mSecurityInputMethodService is null
D/Capacitor/LN: LocalNotification received: null
D/Capacitor/LN: Activity started without notification attached
V/AudioManager: isWiredHeadsetOn...
W/cr_media: Requires BLUETOOTH permission
D/ActivityThread: add activity client record, r= ActivityRecord{488e6de token=android.os.BinderProxy@9e2e9 {io.ionic.starter/io.ionic.starter.MainActivity}} token= android.os.BinderProxy@9e2e9
D/Capacitor: App started
D/ZrHung.AppEyeUiProbe: notify runnable to start.
E/GED: Failed to get GED Log Buf, err(0)
D/Capacitor/App: Firing change: true
I/ConfigStore: android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasWideColorDisplay retrieved: 0
I/ConfigStore: android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasHDRDisplay retrieved: 0
V/Capacitor/App: Notifying listeners for event appStateChange
D/Capacitor/App: No listeners found for event appStateChange
I/iGraphics: [0020080c] pn: io.ionic.starter, p: 6869
    Not kirin platform
D/Capacitor: App resumed
D/OpenGLRenderer: Skia GL Pipeline
D/HwAppInnerBoostImpl: set config for io.ionic.starter BOOST_FLAG=true REPORT_DURATION_CLICK=1000 REPORT_TIMES_CLICK=3 REPORT_DURATION_SLIDE=5000 REPORT_TIMES_SLIDE=16
D/OpenGLRenderer:   HWUI Binary is  enabled
D/HwCustConnectivityManagerImpl: isBlockNetworkRequestByNonAis, INVALID_SUBSCRIPTION_ID
D/ConnectivityManager: requestNetwork and the calling app is: io.ionic.starter
D/HwCustConnectivityManagerImpl: isBlockNetworkRequestByNonAis, INVALID_SUBSCRIPTION_ID
D/Capacitor: Handling local request: http://localhost/
W/HiTouch_HiTouchSensor: depended package hiTouch does n't exist!
I/HiTouch_HiTouchSensor: HiTouch restricted: system app HiTouch don't exist.
D/HiTouch_PressGestureDetector: onAttached, package=io.ionic.starter, windowType=1, mHiTouchRestricted=true
I/HwPhoneWindow: updateLayoutParamsColor true mSpecialSet=true, mForcedNavigationBarColor=false, navigationBarColor=fffcfcfc, mNavBarShow=true, mIsFloating=false
W/VideoCapabilities: Unrecognized profile 4 for video/hevc
W/VideoCapabilities: Unrecognized profile/level 1/32 for video/mp4v-es
    Unrecognized profile/level 32768/2 for video/mp4v-es
    Unrecognized profile/level 32768/64 for video/mp4v-es
W/VideoCapabilities: Unsupported mime video/xvid
I/OpenGLRenderer: Initialized EGL, version 1.4, mEglDisplay 0x1
D/OpenGLRenderer: Swap behavior 2
W/BinaryProgramHWUI: check gpuassistant service fail!
W/BinaryProgramHWUI: check gpuassistant service fail!
    get GpuAssistant service fail! 
W/VideoCapabilities: Unrecognized profile/level 1/32 for video/mp4v-es
I/VideoCapabilities: Unsupported profile 4 for video/mp4v-es
E/GED: Failed to get GED Log Buf, err(0)
V/Capacitor/Network: Notifying listeners for event networkStatusChange
D/Capacitor/Network: No listeners found for event networkStatusChange
D/OpenGLRenderer:   HWUI Binary is  enabled
D/Capacitor: Handling local request: http://localhost/styles.422ed6fc60f0620c5097.css
D/Capacitor: Handling local request: http://localhost/runtime-es2015.b562b3280a89a29679d9.js
D/Capacitor: Handling local request: http://localhost/polyfills-es2015.f4d09162f068ef1dd55d.js
I/ViewRootImpl: jank_removeInvalidNode jank list is null
W/InputMethodManager: startInputReason = 1
D/Capacitor: Handling local request: http://localhost/main-es2015.46284695edf0f08172ea.js
W/InputMethodManager: startInputReason = 5
E/GED: Failed to get GED Log Buf, err(0)
V/Capacitor/Plugin: To native (Capacitor plugin): callbackId: 125095544, pluginId: SplashScreen, methodName: hide
V/Capacitor: callback: 125095544, pluginId: SplashScreen, methodName: hide, methodData: {}
D/Capacitor: Handling local request: http://localhost/common-es2015.1178e06efeed6c43358b.js
D/Capacitor: Handling local request: http://localhost/25-es2015.e8f19df9a6da3da168eb.js
I/Capacitor/Console: File: http://localhost/main-es2015.46284695edf0f08172ea.js - Line 1 - Msg: Ionic Native: deviceready event fired after 389 ms
D/Capacitor: Handling local request: http://localhost/19-es2015.385dc906f92566d537e3.js
D/Capacitor: Handling local request: http://localhost/2-es2015.726ea1b29f00ba6afd0a.js
D/Capacitor: Handling local request: http://localhost/16-es2015.e43d43498167909375bd.js
D/Capacitor: Handling local request: http://localhost/8-es2015.23ea3396a104c741af73.js
D/Capacitor: Handling local request: http://localhost/6-es2015.0435464cb0954a713d1d.js
V/Capacitor/Plugin: To native (Capacitor plugin): callbackId: 125095545, pluginId: App, methodName: addListener
V/Capacitor: callback: 125095545, pluginId: App, methodName: addListener, methodData: {"eventName":"backButton"}
D/Capacitor: Handling local request: http://localhost/4-es2015.ee94eebe0ddb4f57e28c.js
D/Capacitor: Handling local request: http://localhost/3-es2015.16bf19d5b67382ee913e.js
D/Capacitor: Handling local request: http://localhost/87-es2015.0d8463589227b2eeafd8.js
D/Capacitor: Handling local request: http://localhost/33-es2015.ce788fa1aee02f16515d.js
D/Capacitor: Handling local request: http://localhost/53-es2015.d140fe39d8c53b9f36b5.js
D/Capacitor: Handling local request: http://localhost/svg/triangle.svg
D/Capacitor: Handling local request: http://localhost/svg/ellipse.svg
D/Capacitor: Handling local request: http://localhost/svg/square.svg
D/Capacitor: Handling local request: http://localhost/73-es2015.24f236b947c335d054d8.js
D/Capacitor: Handling local request: http://localhost/assets/icon/favicon.png
D/AwareBitmapCacher: handleInit switch not opened pid=6869

Have you tried dismissing the splash screen in your actual page ionViewWillEnter, within a 100ms setTimeout function, instead of the app.component.ts?

That might do the trick. Otherwise, take a look at my blog post, which also references a thread here. It ‘fixed’ the issue of the splash not being correctly sized and also the white/grey flash for me.

Note: I am manually dismissing the splash screen with a setTimeout of 100ms when ready, having also set the splash timeout in the config file to something like 30000 so it doesn’t disappear before I’ve done my stuff)

1 Like

Hi Dave, thanks for your help!

I did not solve the problem but your fix has improved the situation. Now I do not have a long white screen after the splash screen but I have SplashScreen -> blink of white screen -> SplashScreen with loading spinner and then the app finally load.

If only I could remove that annoying white screen in between the first static splash and the second with loading spinner, it would be finally fixed.

That’s probably caused but low performance phones because my iPhone X loads this app even faster than a “native” app so it must be hardware related. ( I just bought a new android phone though so I will make another test today/tomorrow).

Thanks for your help btw , it improved the quality of the loading significantly!

1 Like

I have the same problem with a new brand Ionic5 app with Capacitor

  constructor(
    private router: Router,
    private platform: Platform,
    private statusBar: StatusBar,
....
  ) {
    this.initializeApp();
  }

  initializeApp() {
    this.platform.ready().then(() => {
      console.log('@@@ initializeApp @@@');
      this.statusBar.styleDefault();
      this.splashScreen.hide();

The white screen remains for two or three seconds.

I remember that in the config.xml generated by Cordova there were some options to change the splash screen behavior, does it exists something of similar with Capacitor?

    <preference name="AutoHideSplashScreen" value="false" />
    <preference name="SplashScreen" value="screen" />
    <preference name="SplashScreenDelay" value="15000" />
    <preference name="FadeSplashScreenDuration" value="1500" />
    <preference name="FadeSplashScreen" value="true" />
    <preference name="SplashScreen" value="screen" />

I don’t understand how to change fadeOutDuration of the splash screen:

https://capacitor.ionicframework.com/docs/apis/splash-screen/

Great!! Works fine for me! thanks

This Work perfectly for me:

remove this line: "launchShowDuration": 0 from capacitor.config.json

In your app.ts make this changes:

import { timer } from 'rxjs';
import { Plugins } from '@capacitor/core';
const { SplashScreen } = Plugins;

constructor(){
    this.initializeApp();
}

initializeApp() {
  this.platform.ready().then(() => {
      timer(1000).subscribe(()=> 
      SplashScreen.hide();
    )
  })
}
1 Like

Having the same problem… i even tried the 9-patch splash screen image but nothing. I have this issue with every new ionic angular and capacitor project…

The thing i noticed is that the behaviour change one u change the android:theme="@style/AppTheme.NoActionBarLaunch" in the AndroidManifest.xml with something different.

You can even comment Splash.showOnLaunch(this, bridge.getConfig()); this out in the BridgeActivity.java so you have just the blank page followed by your main page

1 Like


Work around with launch duration 3000ms. It work for me.