capacitor-plugin-status-bar 2.0.10 → 2.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -21,7 +21,6 @@ import androidx.core.view.WindowInsetsCompat;
21
21
 
22
22
  import com.getcapacitor.Plugin;
23
23
 
24
-
25
24
  /**
26
25
  * Android Status Bar utilities with Android 10-15+ (API 29-35+) support.
27
26
  * Supports:
@@ -42,39 +41,39 @@ public class CapacitorStatusBar extends Plugin {
42
41
  private int currentStatusBarColor = Color.BLACK;
43
42
  private int currentNavBarColor = Color.BLACK;
44
43
 
45
- // Note: load() is not called since CapacitorStatusBar is instantiated via new CapacitorStatusBar()
44
+ // Note: load() is not called since CapacitorStatusBar is instantiated via new
45
+ // CapacitorStatusBar()
46
46
  // from CapacitorStatusBarPlugin, not registered as a Capacitor plugin itself.
47
- // All initialization happens via ensureEdgeToEdgeConfigured() called from CapacitorStatusBarPlugin.load().
47
+ // All initialization happens via ensureEdgeToEdgeConfigured() called from
48
+ // CapacitorStatusBarPlugin.load().
48
49
 
49
50
  /**
50
- * Ensures edge-to-edge is properly configured for Android 15+.
51
- * Sets up a unified insets listener on the decorView that handles both
52
- * IME insets and overlay view sizing.
51
+ * Ensures edge-to-edge is properly configured for Android 12+.
52
+ * Sets up a unified insets listener on the decorView that handles
53
+ * overlay view sizing and WebView padding so content stays within
54
+ * the safe area.
53
55
  *
54
56
  * @param activity The activity to configure
57
+ * @param webView The Capacitor WebView to apply safe-area padding to (may be null)
55
58
  */
56
- public void ensureEdgeToEdgeConfigured(Activity activity) {
59
+ public void ensureEdgeToEdgeConfigured(Activity activity, @Nullable View webView) {
57
60
  Window window = activity.getWindow();
58
61
  View decorView = window.getDecorView();
59
62
 
60
63
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
61
- // Android 12+ (API 31+): enable edge-to-edge layout.
62
- // The nav bar uses overlay views because gesture navigation ignores setNavigationBarColor().
63
- // The status bar still uses setStatusBarColor() reliably on API 31–34;
64
- // overlay is only needed on API 35+ where edge-to-edge is enforced and the native API is a no-op.
65
64
  WindowCompat.setDecorFitsSystemWindows(window, false);
66
65
 
67
- // Set a transparent baseline; setStyle() will apply the actual color via setStatusBarColor()
68
- // (API 31-34) or the status bar overlay (API 35+).
69
66
  window.setStatusBarColor(Color.TRANSPARENT);
70
67
  window.setNavigationBarColor(Color.TRANSPARENT);
71
68
  window.setStatusBarContrastEnforced(false);
72
69
  window.setNavigationBarContrastEnforced(false);
73
70
 
74
- // Single unified insets listener on decorView for overlay sizing
75
71
  ViewCompat.setOnApplyWindowInsetsListener(decorView, (v, insets) -> {
76
- // Size status bar overlay
77
72
  int top = insets.getInsets(WindowInsetsCompat.Type.statusBars()).top;
73
+ int navBottom = insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom;
74
+ boolean imeVisible = insets.isVisible(WindowInsetsCompat.Type.ime());
75
+
76
+ // Size status bar overlay
78
77
  View statusOverlay = ((ViewGroup) v).findViewWithTag(STATUS_BAR_OVERLAY_TAG);
79
78
  if (statusOverlay != null) {
80
79
  ViewGroup.LayoutParams params = statusOverlay.getLayoutParams();
@@ -85,27 +84,49 @@ public class CapacitorStatusBar extends Plugin {
85
84
  }
86
85
  }
87
86
 
88
- // Size navigation bar overlay
89
- int bottom = insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom;
87
+ // Size navigation bar overlay — collapse it when the keyboard is
88
+ // open since the nav bar is hidden behind the IME.
89
+ int overlayBottom = imeVisible ? 0 : navBottom;
90
90
  View navOverlay = ((ViewGroup) v).findViewWithTag(NAV_BAR_OVERLAY_TAG);
91
91
  if (navOverlay != null) {
92
92
  ViewGroup.LayoutParams params = navOverlay.getLayoutParams();
93
- if (params.height != bottom) {
94
- params.height = bottom;
93
+ if (params.height != overlayBottom) {
94
+ params.height = overlayBottom;
95
95
  navOverlay.setLayoutParams(params);
96
- Log.d(TAG, "insetsListener: nav bar overlay height=" + bottom);
96
+ Log.d(TAG, "insetsListener: nav bar overlay height=" + overlayBottom
97
+ + " (imeVisible=" + imeVisible + ")");
97
98
  }
98
99
  }
99
100
 
100
- ViewCompat.onApplyWindowInsets(v, insets);
101
- return insets;
101
+ // Inset the WebView via layout margins so it never renders behind
102
+ // system bars. When the keyboard is open the nav bar is behind the
103
+ // IME, so drop the bottom margin to avoid a gap above the keyboard.
104
+ if (webView != null
105
+ && webView.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
106
+ ViewGroup.MarginLayoutParams mlp =
107
+ (ViewGroup.MarginLayoutParams) webView.getLayoutParams();
108
+ int left = insets.getInsets(WindowInsetsCompat.Type.systemBars()).left;
109
+ int right = insets.getInsets(WindowInsetsCompat.Type.systemBars()).right;
110
+ int bottomMargin = imeVisible ? 0 : navBottom;
111
+ if (mlp.topMargin != top || mlp.bottomMargin != bottomMargin
112
+ || mlp.leftMargin != left || mlp.rightMargin != right) {
113
+ mlp.topMargin = top;
114
+ mlp.bottomMargin = bottomMargin;
115
+ mlp.leftMargin = left;
116
+ mlp.rightMargin = right;
117
+ webView.setLayoutParams(mlp);
118
+ Log.d(TAG, "insetsListener: webView margins t=" + top
119
+ + " b=" + bottomMargin + " l=" + left + " r=" + right
120
+ + " (imeVisible=" + imeVisible + ")");
121
+ }
122
+ }
123
+
124
+ return WindowInsetsCompat.CONSUMED;
102
125
  });
103
126
 
127
+ decorView.requestApplyInsets();
104
128
  Log.d(TAG, "ensureEdgeToEdgeConfigured: edge-to-edge with overlay views, API=" + Build.VERSION.SDK_INT);
105
129
  } else {
106
- // Android < 12 (API < 31): Only disable contrast enforcement.
107
- // Do NOT call setDecorFitsSystemWindows(false), create overlay views, or set insets listener.
108
- // This avoids conflicts with plugins like @capawesome/capacitor-android-edge-to-edge-support.
109
130
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
110
131
  window.setStatusBarContrastEnforced(false);
111
132
  window.setNavigationBarContrastEnforced(false);
@@ -157,57 +178,42 @@ public class CapacitorStatusBar extends Plugin {
157
178
  showNavigationBar(activity, true);
158
179
  }
159
180
 
160
- public void hideStatusBar(Activity activity, String animation) {
161
- Log.d(TAG, "hideStatusBar: animation=" + animation + ", API=" + Build.VERSION.SDK_INT);
181
+ public void hideStatusBar(Activity activity) {
162
182
  Window window = activity.getWindow();
163
183
  View decorView = window.getDecorView();
164
184
 
165
- String animationType = animation != null ? animation.toLowerCase() : "slide";
166
-
167
- if ("fade".equals(animationType)) {
168
- // Fade mode: Make background transparent without removing status bar and
169
- // navigation bar
170
- Log.d(TAG, "hideStatusBar: fade mode - making backgrounds transparent");
171
- makeStatusBarBackgroundTransparent(activity);
172
- hideNavigationBar(activity, "fade");
173
- } else if ("slide".equals(animationType)) {
174
- // Slide mode: Hide status bar and navigation bar completely (current behavior)
175
- Log.d(TAG, "hideStatusBar: slide mode - hiding bars completely");
185
+ // Slide mode: Hide status bar and navigation bar completely (current behavior)
186
+ Log.d(TAG, "hideStatusBar: slide mode - hiding bars completely");
176
187
 
177
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
178
- // API 30+ (Android 11+) - Use WindowInsetsController
179
- WindowInsetsController controller = window.getInsetsController();
180
- if (controller != null) {
181
- Log.d(TAG, "hideStatusBar: hiding system bars (API 30+)");
182
- // Hide both status and navigation bars together
183
- controller.hide(WindowInsets.Type.systemBars());
184
- // Set behavior for immersive mode (user can swipe to reveal temporarily)
185
- controller.setSystemBarsBehavior(
186
- WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);
187
- } else {
188
- Log.w(TAG, "hideStatusBar: WindowInsetsController is null");
189
- }
188
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
189
+ // API 30+ (Android 11+) - Use WindowInsetsController
190
+ WindowInsetsController controller = window.getInsetsController();
191
+ if (controller != null) {
192
+ Log.d(TAG, "hideStatusBar: hiding system bars (API 30+)");
193
+ // Hide both status and navigation bars together
194
+ controller.hide(WindowInsets.Type.systemBars());
195
+ // Set behavior for immersive mode (user can swipe to reveal temporarily)
196
+ controller.setSystemBarsBehavior(
197
+ WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);
190
198
  } else {
191
- // API 29 (Android 10) - Use system UI visibility flags (deprecated but
192
- // necessary)
193
- Log.d(TAG, "hideStatusBar: hiding using system UI flags (API 29)");
194
- // Use immersive sticky mode with proper layout flags for Android 10
195
- decorView.setSystemUiVisibility(
196
- View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
197
- | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
198
- | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
199
- | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
200
- | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
201
- | View.SYSTEM_UI_FLAG_FULLSCREEN);
199
+ Log.w(TAG, "hideStatusBar: WindowInsetsController is null");
202
200
  }
203
-
204
- // Make the overlay backgrounds transparent so content shows through
205
- makeStatusBarBackgroundTransparent(activity);
206
201
  } else {
207
- // Unknown animation type, default to slide
208
- Log.w(TAG, "hideStatusBar: unknown animation type '" + animationType + "', defaulting to slide");
209
- hideStatusBar(activity, "slide");
202
+ // API 29 (Android 10) - Use system UI visibility flags (deprecated but
203
+ // necessary)
204
+ Log.d(TAG, "hideStatusBar: hiding using system UI flags (API 29)");
205
+ // Use immersive sticky mode with proper layout flags for Android 10
206
+ decorView.setSystemUiVisibility(
207
+ View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
208
+ | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
209
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
210
+ | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
211
+ | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
212
+ | View.SYSTEM_UI_FLAG_FULLSCREEN);
210
213
  }
214
+
215
+ // Make the overlay backgrounds transparent so content shows through
216
+ makeStatusBarBackgroundTransparent(activity);
211
217
  }
212
218
 
213
219
  public void setStyle(Activity activity, String style, @Nullable String colorHex) {
@@ -262,7 +268,8 @@ public class CapacitorStatusBar extends Plugin {
262
268
  }
263
269
 
264
270
  // Set icon appearance AFTER background operations.
265
- // On Android 13 (API 33), applyStatusBarBackground triggers requestApplyInsets()
271
+ // On Android 13 (API 33), applyStatusBarBackground triggers
272
+ // requestApplyInsets()
266
273
  // which causes the WindowInsetsController to reset setSystemBarsAppearance.
267
274
  // Calling setLightStatusBarIcons last ensures the icon style is not overridden.
268
275
  setLightStatusBarIcons(window, lightBackground);
@@ -291,7 +298,8 @@ public class CapacitorStatusBar extends Plugin {
291
298
  * Returns the insets for status bar, navigation bar, and notch areas.
292
299
  *
293
300
  * @param activity The activity to get the insets from
294
- * @return A map containing top, bottom, left, and right inset values in dp (density-independent pixels)
301
+ * @return A map containing top, bottom, left, and right inset values in dp
302
+ * (density-independent pixels)
295
303
  */
296
304
  public java.util.Map<String, Integer> getSafeAreaInsets(Activity activity) {
297
305
  Log.d(TAG, "getSafeAreaInsets");
@@ -302,10 +310,12 @@ public class CapacitorStatusBar extends Plugin {
302
310
  WindowInsetsCompat windowInsets = ViewCompat.getRootWindowInsets(decorView);
303
311
 
304
312
  if (windowInsets != null) {
305
- // Use WindowInsetsCompat for accurate, type-specific insets across all API levels
313
+ // Use WindowInsetsCompat for accurate, type-specific insets across all API
314
+ // levels
306
315
  androidx.core.graphics.Insets statusBars = windowInsets.getInsets(WindowInsetsCompat.Type.statusBars());
307
316
  androidx.core.graphics.Insets navBars = windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars());
308
- androidx.core.graphics.Insets displayCutout = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout());
317
+ androidx.core.graphics.Insets displayCutout = windowInsets
318
+ .getInsets(WindowInsetsCompat.Type.displayCutout());
309
319
 
310
320
  int topPx = Math.max(statusBars.top, displayCutout.top);
311
321
  int bottomPx = Math.max(navBars.bottom, displayCutout.bottom);
@@ -499,12 +509,12 @@ public class CapacitorStatusBar extends Plugin {
499
509
 
500
510
  private void applyStatusBarBackground(Activity activity, @ColorInt int color) {
501
511
  Log.d(TAG, "applyStatusBarBackground: color=#" + Integer.toHexString(color) + ", API=" + Build.VERSION.SDK_INT);
502
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
503
- // Android 15+ (API 35+): edge-to-edge is enforced, setStatusBarColor() is a no-op
512
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
513
+ // API 31+: edge-to-edge is enabled, setStatusBarColor() is unreliable.
514
+ // Use an overlay View drawn on top of the status bar area.
504
515
  ensureStatusBarOverlay(activity, color);
505
516
  } else {
506
- // API 29–34: setStatusBarColor() works reliably for the status bar on all navigation modes.
507
- // Note: gesture navigation only ignores setNavigationBarColor(), not setStatusBarColor().
517
+ // API 29–30: no edge-to-edge, native API works reliably.
508
518
  activity.getWindow().setStatusBarColor(color);
509
519
  }
510
520
  }
@@ -512,13 +522,13 @@ public class CapacitorStatusBar extends Plugin {
512
522
  private void applyNavigationBarBackground(Activity activity, @ColorInt int color) {
513
523
  Log.d(TAG, "applyNavigationBarBackground: color=#" + Integer.toHexString(color) + ", API="
514
524
  + Build.VERSION.SDK_INT);
515
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
516
- // Android 15+ (API 35+): edge-to-edge enforced, setNavigationBarColor() is a no-op
525
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
526
+ // API 31+: edge-to-edge is enabled, setNavigationBarColor() is unreliable
527
+ // (especially gesture navigation which ignores it entirely).
528
+ // Use an overlay View drawn at the bottom of the screen.
517
529
  ensureNavBarOverlay(activity, color);
518
530
  } else {
519
- // API 29–34: setNavigationBarColor() works for button navigation.
520
- // Gesture navigation ignores it (system enforces transparency for gesture handles),
521
- // but in that case there is no visible nav bar to color anyway.
531
+ // API 29–30: no edge-to-edge, native API works for button navigation.
522
532
  activity.getWindow().setNavigationBarColor(color);
523
533
  }
524
534
  }
@@ -547,7 +557,8 @@ public class CapacitorStatusBar extends Plugin {
547
557
  overlay.setLayoutParams(lp);
548
558
 
549
559
  decorView.addView(overlay);
550
- // Sizing updates are handled by the unified listener in ensureEdgeToEdgeConfigured
560
+ // Sizing updates are handled by the unified listener in
561
+ // ensureEdgeToEdgeConfigured
551
562
  decorView.requestApplyInsets();
552
563
  } else {
553
564
  Log.d(TAG, "ensureStatusBarOverlay: updating existing overlay");
@@ -597,7 +608,8 @@ public class CapacitorStatusBar extends Plugin {
597
608
  overlay.setLayoutParams(lp);
598
609
 
599
610
  decorView.addView(overlay);
600
- // Sizing updates are handled by the unified listener in ensureEdgeToEdgeConfigured
611
+ // Sizing updates are handled by the unified listener in
612
+ // ensureEdgeToEdgeConfigured
601
613
  decorView.requestApplyInsets();
602
614
  } else {
603
615
  Log.d(TAG, "ensureNavBarOverlay: updating existing overlay");
@@ -623,9 +635,9 @@ public class CapacitorStatusBar extends Plugin {
623
635
  }
624
636
 
625
637
  private void applyWindowBackground(Activity activity, @ColorInt int color) {
626
- Log.d(TAG, "applyWindowBackground: color=#" + Integer.toHexString(color));
638
+ Log.d(TAG, "applyWindowBackground: body is always transparent; status/nav bars use overlays/native APIs");
627
639
  View decorView = activity.getWindow().getDecorView();
628
- decorView.setBackgroundColor(color);
640
+ decorView.setBackgroundColor(Color.TRANSPARENT);
629
641
  }
630
642
 
631
643
  /**
@@ -637,8 +649,8 @@ public class CapacitorStatusBar extends Plugin {
637
649
  Window window = activity.getWindow();
638
650
  ViewGroup decorView = (ViewGroup) window.getDecorView();
639
651
 
640
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
641
- // Android 15+: both bars use overlay views
652
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
653
+ // API 31+: edge-to-edge uses overlay views for both bars
642
654
  View statusBarOverlay = decorView.findViewWithTag(STATUS_BAR_OVERLAY_TAG);
643
655
  if (statusBarOverlay != null) {
644
656
  statusBarOverlay.setBackgroundColor(Color.TRANSPARENT);
@@ -650,7 +662,7 @@ public class CapacitorStatusBar extends Plugin {
650
662
  Log.d(TAG, "makeStatusBarBackgroundTransparent: nav bar overlay made transparent");
651
663
  }
652
664
  } else {
653
- // API 29–34: both bars use native window API
665
+ // API 29–30: no edge-to-edge, native window API
654
666
  window.setStatusBarColor(Color.TRANSPARENT);
655
667
  window.setNavigationBarColor(Color.TRANSPARENT);
656
668
  Log.d(TAG, "makeStatusBarBackgroundTransparent: set native bar colors to transparent");
@@ -1,12 +1,7 @@
1
1
  package com.cap.plugins.statusbar;
2
2
 
3
- import android.os.Build;
4
3
  import android.view.View;
5
4
 
6
- import androidx.core.graphics.Insets;
7
- import androidx.core.view.ViewCompat;
8
- import androidx.core.view.WindowInsetsCompat;
9
-
10
5
  import com.getcapacitor.Plugin;
11
6
  import com.getcapacitor.PluginCall;
12
7
  import com.getcapacitor.PluginMethod;
@@ -19,21 +14,10 @@ public class CapacitorStatusBarPlugin extends Plugin {
19
14
  @Override
20
15
  public void load() {
21
16
  super.load();
22
- // Apply default style based on system theme on plugin load
23
17
  getActivity().runOnUiThread(() -> {
24
- implementation.ensureEdgeToEdgeConfigured(getActivity());
18
+ View webView = getBridge().getWebView();
19
+ implementation.ensureEdgeToEdgeConfigured(getActivity(), webView);
25
20
  implementation.applyDefaultStyle(getActivity());
26
-
27
- // On Android 15+ (API 35+), edge-to-edge is enforced and the WebView content
28
- // extends under system bars. Apply padding so Ionic content stays in the safe area.
29
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
30
- View webView = getBridge().getWebView();
31
- ViewCompat.setOnApplyWindowInsetsListener(webView, (v, insets) -> {
32
- Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
33
- v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
34
- return insets;
35
- });
36
- }
37
21
  });
38
22
  }
39
23
 
@@ -71,7 +55,7 @@ public class CapacitorStatusBarPlugin extends Plugin {
71
55
  public void hide(PluginCall call) {
72
56
  try {
73
57
  getActivity().runOnUiThread(() -> {
74
- implementation.hideStatusBar(getActivity(), "slide");
58
+ implementation.hideStatusBar(getActivity());
75
59
  call.resolve();
76
60
  });
77
61
  } catch (Exception e) {
@@ -227,8 +227,8 @@ import Capacitor
227
227
  return
228
228
  }
229
229
 
230
- window.backgroundColor = color
231
- print("CapacitorStatusBar: setBackground - Set window background to \(colorHex)")
230
+ window.backgroundColor = .clear
231
+ print("CapacitorStatusBar: setBackground - Body is always transparent; status/nav bars use overlays/native APIs")
232
232
  }
233
233
  }
234
234
 
@@ -237,20 +237,15 @@ import Capacitor
237
237
  var insets: [String: CGFloat] = ["top": 0, "bottom": 0, "left": 0, "right": 0]
238
238
 
239
239
  if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
240
- let window = windowScene.windows.first {
241
- // Use statusBarManager for accurate status bar height
242
- let statusBarHeight = windowScene.statusBarManager?.statusBarFrame.height ?? 0
240
+ let window = windowScene.windows.first(where: { $0.isKeyWindow }) ?? windowScene.windows.first {
243
241
  let safeAreaInsets = window.safeAreaInsets
244
242
 
245
- // top: status bar height specifically
246
- insets["top"] = statusBarHeight
247
- // bottom: home indicator / navigation bar area
248
- insets["bottom"] = safeAreaInsets.bottom
249
- // left/right: safe area for landscape / display cutouts
250
- insets["left"] = safeAreaInsets.left
251
- insets["right"] = safeAreaInsets.right
243
+ insets["top"] = self.sanitizedInsetValue(safeAreaInsets.top)
244
+ insets["bottom"] = 0
245
+ insets["left"] = 0
246
+ insets["right"] = 0
252
247
 
253
- print("CapacitorStatusBar: getSafeAreaInsets - top=\(statusBarHeight), bottom=\(safeAreaInsets.bottom), left=\(safeAreaInsets.left), right=\(safeAreaInsets.right)")
248
+ print("CapacitorStatusBar: getSafeAreaInsets - top=\(safeAreaInsets.top), bottom=\(safeAreaInsets.bottom), left=\(safeAreaInsets.left), right=\(safeAreaInsets.right)")
254
249
  } else {
255
250
  print("CapacitorStatusBar: getSafeAreaInsets - Unable to get window, returning zero insets")
256
251
  }
@@ -399,6 +394,12 @@ import Capacitor
399
394
  return (0.299 * red + 0.587 * green + 0.114 * blue)
400
395
  }
401
396
 
397
+ /// Guard against non-finite/negative inset values before bridging to JS.
398
+ private func sanitizedInsetValue(_ value: CGFloat) -> CGFloat {
399
+ guard value.isFinite else { return 0 }
400
+ return max(0, value)
401
+ }
402
+
402
403
  private func isSystemInDarkMode() -> Bool {
403
404
  guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
404
405
  let window = windowScene.windows.first else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "capacitor-plugin-status-bar",
3
- "version": "2.0.10",
3
+ "version": "2.0.12",
4
4
  "description": "Capacitor plugin for managing the status bar style, visibility, and color on iOS and Android. Control overlay modes, background colors, and appearance for native mobile applications.",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",