[Bug]: SystemBars shrinks the WebView twice for the keyboard on Android 10 (API 29) when WebView >= 140 and viewport-fit=cover

Open Beginner friendly
#8,601 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
78/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
android, java
Domain
mobile

Research direction

Start in android/capacitor/src/main/java/com/getcapacitor/plugin/SystemBars.java, at initWindowInsetsListener and the shouldPassthroughInsets branch. Reproduce with the Android 10 emulator setup described, using viewport-fit=cover and a text input. Done means the WebView keeps the framework-resized height while the keyboard is open on API 29, with Android 30+ and Android 9/13 behavior unchanged.

Written by the indexing model from the issue text.

Description

triage
Capacitor Version
@capacitor/android 8.5.1 (the affected code is unchanged in 8.5.2 and on `main`:
android/capacitor/src/main/java/com/getcapacitor/plugin/SystemBars.java, `initWindowInsetsListener`)
@capacitor/core 8.5.1
@capacitor/keyboard 8.0.5
Other API Details
Node 22.23.2, npm 10
Android: compileSdk/targetSdk 36, minSdk 26, AGP 8.13.0
Affected device: Zebra TC21, Android 10 (API 29), Android System WebView >= 140 (Play-updated)
Not affected: DT50 Android 9 (WebView provider is Chrome 138, the last for Android 9), DT50 Android 13 (WebView 151), Pixel Android 16/17
Page uses <meta name="viewport" content="viewport-fit=cover, ...">
capacitor.config.json: "SystemBars": { "style": "DARK" } (insetsHandling default "css"), no Keyboard config
Platforms Affected
  • iOS
  • Android
  • Web
Current Behavior

On Android 10 (API 29) with a current WebView (>= 140) and a page that declares viewport-fit=cover, opening the soft keyboard on any text field shrinks the WebView by the keyboard height twice. On a phone-sized screen the entire WebView disappears and only the window background is visible for as long as the keyboard is up (see the customer video description below: the login page turns into a solid colour when the username field is tapped, and comes back when the keyboard closes). Typing still goes into the invisible field.

Root cause, as far as I can tell from SystemBars.initWindowInsetsListener:

boolean shouldPassthroughInsets = getWebViewMajorVersion() >= WEBVIEW_VERSION_WITH_SAFE_AREA_FIX && hasViewportCover;
...
if (shouldPassthroughInsets) {
    // We need to correct for a possible shown IME
    v.setPadding(0, 0, 0, keyboardVisible ? imeInsets.bottom : 0);
  • On API < 30 the activity uses adjustResize, so the framework has already resized the window for the IME by the time this listener runs.
  • On API < 30 WindowInsetsCompat.Type.ime() is the AndroidX compat approximation (system window inset minus stable inset), which still reports the full keyboard height even though the window no longer overlaps the IME.
  • The passthrough branch then pads the WebView's parent by that height again. Net effect: WebView height = screen - 2 x keyboard.

On API 30+ ime() is the real overlap, which is 0 once the window has been resized, so the same line is harmless there. On WebView < 140 the passthrough branch is never taken, so the bug only appears once a device's WebView updates past 140, i.e. it is showing up in the field now on Android 10 devices with Play services, while Android 9 devices (capped at Chrome/WebView 138) never hit it.

Expected Behavior

The WebView keeps the framework-resized height when the keyboard opens on Android 10, exactly as it does on Android 9 (non-passthrough branch) and Android 11+.

Fix that works for us (shipped as a patch-package patch):

             if (shouldPassthroughInsets) {
-                // We need to correct for a possible shown IME
-                v.setPadding(0, 0, 0, keyboardVisible ? imeInsets.bottom : 0);
+                // On API < 30 the window is already resized for the IME (adjustResize) and the
+                // compat ime() inset still reports the keyboard height, so padding again shrinks
+                // the WebView twice. Only pad on API 30+, where ime() is the real overlap.
+                boolean padForIme = keyboardVisible && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R;
+                v.setPadding(0, 0, 0, padForIme ? imeInsets.bottom : 0);

Happy to open a PR with this if you agree with the approach.

Project Reproduction

No public repo yet (I can put one together if needed). Steps, ~10 minutes with an emulator:

  1. npm init @capacitor/app@latest, add Android, keep the default viewport-fit=cover meta. Add a text <input> to the page; make <body> a colour different from the window background so the effect is obvious.
  2. Emulator: system-images;android-29;default;arm64-v8a (Android 10, ships WebView 74). Because that WebView is < 140, temporarily set WEBVIEW_VERSION_WITH_SAFE_AREA_FIX = 0 in node_modules/@capacitor/android/.../SystemBars.java to take the passthrough branch (that is what a real Android 10 device with WebView >= 140 does).
  3. Run, tap the input. The WebView loses twice the keyboard height: on a 1080x2280 emulator ~26% of the page is left above a blank band the size of the keyboard; on a 720x1280 device (Zebra TC21) nothing is left.
  4. Apply the diff above: the WebView keeps the framework-resized height and the input stays visible.
  5. Same build on an Android 16 emulator and on Android 9/13 devices: unchanged.
Additional Information
  • Also transpiling for old WebViews and the WEBVIEW_VERSION_WITH_SAFE_AREA_KEYBOARD_FIX path are unrelated; the issue is purely the API < 30 double shrink.
  • Field impact: rugged Android 10 handhelds (Zebra TC21/TC26 etc.) are common in logistics; as their WebView updates past 140, every Capacitor 8.5 app with viewport-fit=cover will start losing its page whenever the keyboard opens.
Dominant language
TypeScript
Stars
16.7k
Forks
1.3k
Avg merge
3d 10h
Merged PRs (30d)
10

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from ionic-team/capacitor

All issues in ionic-team/capacitor

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.