Skip to content

fix(SystemBars): defer safe area CSS injection until the document exists - #8636

Open
kttalley wants to merge 1 commit into
ionic-team:mainfrom
kttalley:fix/android-safe-area-css-before-document
Open

kttalley wants to merge 1 commit into
ionic-team:mainfrom
kttalley:fix/android-safe-area-css-before-document

Conversation

@kttalley

Copy link
Copy Markdown

The window insets listener can fire before the WebView has a document (first layout, or when the host app calls requestApplyInsets early). At that point document.documentElement is null, so the script injected by injectSafeAreaCSS() throws and logs this on startup:

E Capacitor/Console: File:  - Line 6 - Msg: Error injecting safe area CSS: TypeError: Cannot read properties of null (reading 'style')

This change applies the --safe-area-inset-* values right away when document.documentElement exists, which is the same as before. If it doesn't exist yet, the values are applied once on DOMContentLoaded instead. If several calls come in before the document is ready, only one listener is added and it uses the most recent values. If a later call finds the document and applies values first, the pending ones are dropped, so older insets can't overwrite newer ones. Errors from setProperty are still caught and logged as before.

Closes #8530

Testing

  • ./gradlew build test -b capacitor/build.gradle (same as npm run verify in android/) passes with JDK 21, including lint. Prettier (prettier-plugin-java with @ionic/prettier-config) reports no changes for the file.
  • Minimal Capacitor 8.5.2 app (its SystemBars.java is identical to main), viewport-fit=cover, default insetsHandling, on an API 36 arm64 emulator with WebView 133:
    • Without the patch: the error was logged 3 times per cold start on 4 of 5 launches.
    • With the patch: 0 errors over 8 cold starts, and the CSS variables had the same values (all 0px, since WebView < 140 takes the native padding path here).
    • A debug build with temporary console.logs showed both paths working. Most launches applied the values immediately. On one launch the first three calls were deferred, then the values were applied once on DOMContentLoaded (on https://localhost/), followed by the normal call after onPageCommitVisible.
  • I ran the injected script in Node against a stubbed document to check: document present (applied immediately), document missing (no error, one DOMContentLoaded listener), repeated calls before the document exists (latest values win), a deferred call followed by an immediate one (stale values not applied), and setProperty throwing (still logged).

I couldn't test the pass-through branch with non-zero values on a real device (it needs WebView 140+), but that branch uses the same script.

The same script is on next (where insetsHandling now defaults to native, but css still uses it), and this patch applies there cleanly. iOS doesn't inject these variables, so it has no equivalent issue.

The window insets listener can fire before the WebView has a document,
so `document.documentElement` is null and the injected script logs
"Cannot read properties of null (reading 'style')" on startup.

Apply the values immediately when `document.documentElement` exists,
otherwise apply the most recent values once on `DOMContentLoaded`.

Closes ionic-team#8530

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SystemBars: safe area CSS injection throws "Cannot read properties of null" on startup (Android 16)

1 participant