Écran noir au lancement : la fenêtre n'était jamais rendue visible

La première version conditionnait la création de la fenêtre à `window == nil`,
par prudence : le manifeste déclarant UISceneStoryboardFile = Main, je
supposais qu'UIKit avait déjà monté la fenêtre depuis le storyboard et qu'il
ne fallait pas l'écraser.

Sur appareil, le résultat est un écran noir permanent, sans erreur, sans log,
sans crash. UIKit fournit bien un objet fenêtre, mais ne le rend pas visible à
notre place : la garde sautait donc makeKeyAndVisible() et rien ne s'affichait
jamais. Le fond noir de capacitor.config.ts rendait le symptôme indiscernable
d'un écran d'attente.

Le template de Capacitor crée la fenêtre sans condition. C'est le chemin
éprouvé, et s'en écarter « par sécurité » aura coûté un aller-retour de build.
Le seul écart qui reste nécessaire est MainViewController au lieu d'un
CAPBridgeViewController nu : notre sous-classe enregistre les neuf plugins
in-app dans capacitorDidLoad(), et ne dépend de rien du storyboard.

⚠️ À retenir pour la suite : sur ce chemin, une garde défensive ne protège de
rien et masque le défaut qu'elle prétend éviter. La condition de succès était
observable (une fenêtre visible), pas déductible.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sylvain Bettinelli
2026-09-22 09:16:08 +00:00
parent 157250b3eb
commit adb8177f2f

View File

@@ -33,21 +33,24 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
options connectionOptions: UIScene.ConnectionOptions) { options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = scene as? UIWindowScene else { return } guard let windowScene = scene as? UIWindowScene else { return }
// Le manifeste déclare `UISceneStoryboardFile = Main` : UIKit a donc // ⚠️ Ne PAS conditionner cette création à `window == nil`.
// déjà chargé Main.storyboard et instancié `MainViewController`, qui
// porte l'enregistrement des plugins natifs et la config WKWebView.
// //
// Le template de Capacitor pose ici un `CAPBridgeViewController()` nu. // C'était ma première version, par prudence : le manifeste déclarant
// L'appliquer tel quel remplacerait notre sous-classe et ferait perdre // `UISceneStoryboardFile = Main`, je supposais qu'UIKit avait déjà
// cette configuration **sans erreur visible**. On ne crée donc la // monté la fenêtre et qu'il ne fallait pas l'écraser. Résultat sur
// fenêtre que si le storyboard ne l'a pas fait, et avec notre // appareil : **écran noir permanent, sans la moindre erreur**. UIKit
// contrôleur. // fournit bien une fenêtre, mais ne la rend pas visible à notre place ;
if window == nil { // la garde sautait donc `makeKeyAndVisible()` et rien ne s'affichait.
//
// Le template de Capacitor crée la fenêtre sans condition, et c'est le
// chemin éprouvé. Le seul écart nécessaire est `MainViewController` au
// lieu d'un `CAPBridgeViewController` nu : notre sous-classe enregistre
// les neuf plugins in-app dans `capacitorDidLoad()`. Elle ne dépend de
// rien du storyboard, donc l'instancier ici est sans perte.
let fenetre = UIWindow(windowScene: windowScene) let fenetre = UIWindow(windowScene: windowScene)
fenetre.rootViewController = MainViewController() fenetre.rootViewController = MainViewController()
window = fenetre window = fenetre
fenetre.makeKeyAndVisible() fenetre.makeKeyAndVisible()
}
SceneDelegateProxy.shared.scene(scene, willConnectTo: session, options: connectionOptions) SceneDelegateProxy.shared.scene(scene, willConnectTo: session, options: connectionOptions)
} }