Skip to content

Conversation

@theproducer
Copy link
Contributor

@theproducer theproducer commented Oct 3, 2025

This PR introduces a new core plugin, System Bars, designed to be a modern take on the Status Bar plugin, managing Android System Bars, the iOS status bar, and fix issues related to broken safe area insets on Android.

@pauldemarco
Copy link

This looks great, what more is needed before merge?

@pauldemarco
Copy link

pauldemarco commented Oct 15, 2025

I am noticing that currently, without this plugin, the safe area and the status bar are working great on iOS -- it even changes the status bar text depending on light or dark mode when I toggle dark on the root: document.documentElement.classList.toggle('dark')

I am noticing this PR includes some styling on the status bar. Is there any way to have Android act like the iOS and have it "just work"?

I also want to make sure this won't break what we have working fine on iOS.

@tafelnl
Copy link

tafelnl commented Oct 16, 2025

I am noticing this PR includes some styling on the status bar. Is there any way to have Android act like the iOS and have it "just work"?

I also want to make sure this won't break what we have working fine on iOS.

I am not sure if you have a correct understanding of this "inject css variables" thing. It doesn't inject env css variables, as that isn't possible. It detects the safe area insets in a best effort and injects them as custom var css variables. That means that you will have to change code to make it work on both iOS and Android. That's exactly one of the reasons I'm advocating for a native approach

@tafelnl
Copy link

tafelnl commented Oct 16, 2025

I'd like to add that as of November 1st (actually earlier, but Google granted an extension to developers that depend on older SDKs) no one will be able to publish a release to the play store if they're not supporting edge-to-edge. So I think this should be given the utmost priority by the Capacitor team

@pauldemarco
Copy link

I am noticing this PR includes some styling on the status bar. Is there any way to have Android act like the iOS and have it "just work"?
I also want to make sure this won't break what we have working fine on iOS.

I am not sure if you have a correct understanding of this "inject css variables" thing. It doesn't inject env css variables, as that isn't possible. It detects the safe area insets in a best effort and injects them as custom var css variables. That means that you will have to change code to make it work on both iOS and Android. That's exactly one of the reasons I'm advocating for a native approach

I just discovered all of this was only a problem with an Android Medium emulator. I just tried the Pixel 9 emulator and safe area is working great without any plugins.

@theproducer
Copy link
Contributor Author

theproducer commented Oct 20, 2025

Hello everyone! Stay tuned, I'm on the verge of getting this past the finish line, The plan is to make some final changes and wrap this up this week.

@theproducer
Copy link
Contributor Author

I am noticing this PR includes some styling on the status bar. Is there any way to have Android act like the iOS and have it "just work"?

By "just work", you're expecting just the default status bar, without the fullscreen / transparent status bar style, correct?

@tafelnl
Copy link

tafelnl commented Oct 21, 2025

I'm curious which approach you've chosen to go with. I'm still advocating for going the native route. To demonstrate how that would work I made a simple demo proof of concept. Mind you that I've created this in like 5 minutes, so it's still not perfect, but you will get the main idea.

Demo: https://github.com/tafelnl/capacitor-demo
The magic happens in this file: https://github.com/tafelnl/capacitor-demo/blob/main/android/app/src/main/java/com/example/demo/EdgeToEdgePlugin.kt

I also commented some todos which I haven't done because it's a proof of concept.

@pauldemarco
Copy link

I am noticing this PR includes some styling on the status bar. Is there any way to have Android act like the iOS and have it "just work"?

By "just work", you're expecting just the default status bar, without the fullscreen / transparent status bar style, correct?

As of right now on iOS, without this plugin, the status bar is transparent and switches the text color automatically to the right color when I set the root html class to dark mode and light mode. Not sure how this is working.

Copy link
Member

@markemer markemer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, but needs an npm run fmt

@markemer
Copy link
Member

Kicked off an update to see if that would clear the fmt issue, since you clearly ran it as the last step.

@tafelnl
Copy link

tafelnl commented Nov 11, 2025

Hey @tafelnl, thanks for all the discussion here! We're discussing your approach internally, and are considering making it an available option (in addition to the approach we're taking in this PR) in a future version of Capacitor.

Thanks, sounds promising! Which approach are you referring to exactly? I proposed several changes. Among which were the keyboard fix, adjustMarginsForEdgeToEdge and viewport-fit=cover

@tafelnl
Copy link

tafelnl commented Nov 12, 2025

IMO the safe area workaround and styling of system bars are two different feature sets. To me it would make more sense to include the workaround in the core. Then deprecate/remove the @capacitor/status-bar plugin in favor of a new @capacitor/system-bars (as I think renaming would be justified) plugin and include the styling functionality there. Additionally the keyboard workaround can then be moved into the core and removed from the keyboard plugin

@theproducer theproducer merged commit a32216a into main Nov 12, 2025
6 checks passed
@theproducer theproducer deleted the RDMR-902 branch November 12, 2025 19:16
zoomableWebView = JSONUtils.getBoolean(configJSON, "android.zoomEnabled", JSONUtils.getBoolean(configJSON, "zoomEnabled", false));
resolveServiceWorkerRequests = JSONUtils.getBoolean(configJSON, "android.resolveServiceWorkerRequests", true);
adjustMarginsForEdgeToEdge = JSONUtils.getString(configJSON, "android.adjustMarginsForEdgeToEdge", "disable");
adjustMarginsForEdgeToEdge = JSONUtils.getString(configJSON, "android.adjustMarginsForEdgeToEdge", "auto");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think adjustMarginsForEdgeToEdge can be removed?

private void initSystemBars() {
String style = getConfig().getString("style", STYLE_DEFAULT).toUpperCase(Locale.US);
boolean hidden = getConfig().getBoolean("hidden", false);
boolean disableCSSInsets = getConfig().getBoolean("disableInsets", false);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With a naming like disableInsets I would expect that either 1) insets are disabled entirely (similar to adjustMarginsForEdgeToEdge: force) or 2) that the injection of custom vars is disabled. Both isn't true. I think it makes sense to include a config var like insetsCorrectionBehavior that is an enum with the following values:

  • disabled: this entirely disables the logic here
  • fallbackToInjection: this enables the logic and also enables injection for older webviews
  • fallbackToMargins: this enables the logic and for older webviews falls back to shrinking the webview using margins (IMO this should be the default as discussed before)

Right now this PR makes it quite hard to override this behavior if a developer is - for whatever reason - looking to change the core behavior (for example by installing a plugin that has a different philosophy about this).

On another note: the disableCSSInsets is checked inside the evaluateJavascript callback. But - with the current logic - it can be lifted to check it before initSystemBars is called

});
}

@PluginMethod
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The swift equivalents of the plugin methods here are annotated with a returnType: none. Would it make sense to change it to @PluginMethod(returnType = PluginMethod.RETURN_NONE)?

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.

9 participants