Repository navigation
[Bug]: SystemBars shrinks the WebView twice for the keyboard on Android 10 (API 29) when WebView >= 140 and viewport-fit=cover #8601
Description
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:
npm init @capacitor/app@latest, add Android, keep the defaultviewport-fit=covermeta. Add a text<input>to the page; make<body>a colour different from the window background so the effect is obvious.- Emulator:
system-images;android-29;default;arm64-v8a(Android 10, ships WebView 74). Because that WebView is < 140, temporarily setWEBVIEW_VERSION_WITH_SAFE_AREA_FIX = 0innode_modules/@capacitor/android/.../SystemBars.javato take the passthrough branch (that is what a real Android 10 device with WebView >= 140 does). - 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.
- Apply the diff above: the WebView keeps the framework-resized height and the input stays visible.
- 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_FIXpath 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=coverwill start losing its page whenever the keyboard opens.
Activity
chbrecht commentedon Oct 14, 2026
We hit this in production as well and can confirm the analysis and the fix.
Field reports (after shipping Capacitor 8): Users on Android 10 devices with a Play-updated WebView could no longer type in our app. Example: Huawei P20 Pro, EMUI 12 / Android 10, WebView 153, SwiftKey. A second user had a Samsung device with Samsung Keyboard. As soon as the keyboard opened, the whole page turned blank. On the Samsung device, typed text ended up in the field in reverse order once the keyboard was closed. On smaller screens nothing of the page remains visible. The keyboard app makes no difference: we reproduced it with SwiftKey and with Gboard.
Reproduction:
@capacitor/android8.5.1,viewport-fit=cover, defaultinsetsHandling(css), no Keyboard plugin config.system-images;android-29;google_apis_playstore;arm64-v8a. The stock image ships WebView 91, so the passthrough branch is not taken until you update "Android System WebView" via the Play Store (we got 154).imeVisible=true imeBottom=817while the parent shrinks from2065to1380px (adjustResize). The extrasetPadding(0, 0, 0, imeInsets.bottom)then removes the keyboard height a second time.adb shell wm size), the entire page disappears, which matches the field reports.Fix: We gate the IME padding in the passthrough branch on
Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM(same gate as #8528) and ship it viapatch-package. Verified on the API 29 emulator with SwiftKey and Gboard; behaviour on Android 17 is unchanged. #8606 (gate at API 30) should fix the API 29 case just as well.Note:
@capacitor/android8.5.3 still contains the unguarded line, so this is not fixed in the latest release yet. It would be great to get #8606 (or an equivalent fix) merged.