Blank screen on Android/iOS after capacitor build when calling SplashScreen in ngOnInit
0 reputation · 16 May 2023, 18:40 UTC
0 reputation · 16 May 2023, 18:40 UTC
The goal is to ensure that Capacitor plugin invocations (e.g., SplashScreen, StatusBar, Network) execute successfully both during local development with ionic serve and in production builds generated by ionic capacitor build android or ios.
When such plugins are called in the root component’s ngOnInit or constructor, the calls succeed in the browser because the web runtime mocks the plugin layer, but they fail in native builds where the Capacitor platform is not yet initialized, often resulting in an undefined plugin object, a blank screen, or an uncaught promise rejection.
It remains unclear where plugin initialization should be placed for root components versus lazy‑loaded modules, whether relying on the @capacitor/app ready event is sufficient for all plugins or if the Ionic Angular Platform service should be preferred, and how to verify plugin readiness without introducing runtime errors in either environment.
Where should plugin initialization be located for root components versus lazy‑loaded modules to guarantee the Capacitor platform is ready?
Is the @capacitor/app ready event adequate for all plugins, or should the Ionic Angular Platform service be used instead?
How can plugin readiness be verified safely in both web and native contexts?
In a native build the Capacitor runtime is not yet initialized when Angular’s ngOnInit runs. If SplashScreen.show() is executed at that moment it can block the UI thread (especially on Android) and the native splash image never hides, leaving a blank screen. The same applies to any plugin that depends on the Capacitor bridge.
Place them in the constructor *or* inside an explicit Platform.ready() callback. The constructor runs before the Angular view is rendered, but Platform.ready() guarantees the Capacitor bridge is active.
Call plugins inside ngAfterViewInit or a service that subscribes to Platform.ready(). Avoid ngOnInit for native plugin usage.
Yes, App.addListener('appStateChange', …) or App.addListener('pause', …) fire only after the platform is ready. However, for early initialization Ionic’s Platform.ready() is more idiomatic because it also works in the browser and provides a Promise that resolves when the bridge is available.
import { Component, OnInit } from '@angular/core';
import { Platform } from '@ionic/angular';
import { SplashScreen } from '@capacitor/splash-screen';
@Component({
selector: 'app-root',
templateUrl: 'app.component.html'
})
export class AppComponent implements OnInit {
constructor(private platform: Platform) {}
async ngOnInit() {
await this.platform.ready(); // guarantees Capacitor bridge
SplashScreen.hide(); // hide native splash
}
}
Do not call SplashScreen.show() here unless you also call hide() later. The Capacitor runtime automatically shows the splash on launch; manual show() is only needed for custom behavior.
npx cap sync to ensure assets are copied.ionic capacitor build android or ionic capacitor build ios.adb logcat (Android) or Xcode console (iOS) for SplashScreen.hide() logs.android/app/src/main/res and ios/Runner/Assets.xcassets and follow Capacitor naming conventions.What is the exact error in the device logs when the blank screen appears? Knowing whether it’s a “SplashScreen not found” or a “platform not ready” message will pinpoint the missing step.
Use comments to ask for clarification. Post a solution as an answer.
32,275 reputation · 17 May 2023, 02:53 UTC
One nuance worth adding to the Platform.ready() pattern already described: SplashScreen.hide() called the instant the promise resolves can race the first Angular render, so users see a white flash instead of the intended handoff. A common workaround is to hide the splash after the initial route has finished activating, e.g. by listening for the first NavigationEnd from the Angular router, or by adding a small delay after platform.ready().
For the web/native verification question, Capacitor.isPluginAvailable('SplashScreen') combined with Capacitor.isNativePlatform() is a safer gate than assuming ionic serve mocks everything — some plugins ship no web implementation and throw not implemented on web rather than silently succeeding. Guarding with these checks lets one code path run in both environments without try/catch noise.
Also note the blank screen may not be plugin timing at all: a wrong base href or a JS bundle error produces the same symptom. Before restructuring initialization, attach chrome://inspect (Android) or Safari Web Inspector (iOS) and confirm an actual unhandled rejection from the plugin call. Behavior varies across Capacitor major versions, so verify against the installed @capacitor/core.