[Bug]: SystemBars shrinks the WebView twice for the keyboard on Android 10 (API 29) when WebView >= 140 and viewport-fit=cover
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 78/100
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
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.
- Dominant language
- TypeScript
- Stars
- 16.7k
- Forks
- 1.3k
- Avg merge
- 3d 10h
- Merged PRs (30d)
- 10
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from ionic-team/capacitor
-
triage
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
ionic-team/capacitor#8616 ·
-
triage
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
ionic-team/capacitor#8574 ·
-
SystemBars: safe area CSS injection throws "Cannot read properties of null" on startup (Android 16) Opentriage
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
ionic-team/capacitor#8530 · 2 comments ·
-
triage
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
ionic-team/capacitor#8529 ·
-
needs reproduction
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
ionic-team/capacitor#8472 · 2 comments · 1 reaction ·
All issues in ionic-team/capacitor
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
Eynzof/Hermes-CN-Desktop#610 ·
-
bug clawsweeper:linked-pr-open clawsweeper:needs-live-repro clawsweeper:no-new-fix-pr impact:message-loss issue-rating: 🐚 platinum hermit P2 regression
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
-
enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
-
calcite-components needs triage refactor
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
Esri/calcite-design-system#15203 ·
-
Difficulty 1/5 Under an hour Newbie friendliness 78/100
fullcalendar/fullcalendar#8106 ·