capacitor-plugin-status-bar 2.0.1 → 2.0.3

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.
package/README.md CHANGED
@@ -137,7 +137,7 @@ getSafeAreaInsets() => Promise<SafeAreaInsets>
137
137
 
138
138
  Get the safe area insets.
139
139
  Returns the insets for status bar, navigation bar, and notch areas.
140
- Values are in pixels on Android and points on iOS.
140
+ Values are in CSS pixels (dp) on all platforms.
141
141
 
142
142
  **Returns:** <code>Promise&lt;<a href="#safeareainsets">SafeAreaInsets</a>&gt;</code>
143
143
 
@@ -21,7 +21,6 @@ import androidx.core.view.WindowInsetsCompat;
21
21
 
22
22
  import com.getcapacitor.Plugin;
23
23
 
24
- import java.util.Objects;
25
24
 
26
25
  /**
27
26
  * Android Status Bar utilities with Android 10-15+ (API 29-35+) support.
@@ -43,62 +42,65 @@ public class StatusBar extends Plugin {
43
42
  private int currentStatusBarColor = Color.BLACK;
44
43
  private int currentNavBarColor = Color.BLACK;
45
44
 
46
- @Override
47
- public void load() {
48
- super.load();
49
- setupEdgeToEdgeBehavior();
50
- }
51
-
52
- private void setupEdgeToEdgeBehavior() {
53
- Activity activity = getActivity();
54
- if (activity == null)
55
- return;
56
-
57
- Window window = activity.getWindow();
58
- View decorView = window.getDecorView();
59
-
60
- WindowCompat.setDecorFitsSystemWindows(window, false);
61
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { // Android 14+
62
- ViewCompat.setOnApplyWindowInsetsListener(decorView, (v, insets) -> {
63
- ViewCompat.onApplyWindowInsets(v, insets);
64
- return insets;
65
- });
66
- }
67
- }
45
+ // Note: load() is not called since StatusBar is instantiated via new StatusBar()
46
+ // from StatusBarPlugin, not registered as a Capacitor plugin itself.
47
+ // All initialization happens via ensureEdgeToEdgeConfigured() called from StatusBarPlugin.load().
68
48
 
69
49
  /**
70
50
  * Ensures edge-to-edge is properly configured for Android 15+.
71
- * This fixes the keyboard extra space issue by properly handling IME insets
72
- * using the modern WindowInsets API instead of deprecated soft input modes.
51
+ * Sets up a unified insets listener on the decorView that handles both
52
+ * IME insets and overlay view sizing.
73
53
  *
74
54
  * @param activity The activity to configure
75
55
  */
76
56
  public void ensureEdgeToEdgeConfigured(Activity activity) {
77
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) { // Android 15 (API 35)
78
- Window window = activity.getWindow();
79
- View decorView = window.getDecorView();
57
+ Window window = activity.getWindow();
58
+ View decorView = window.getDecorView();
80
59
 
81
- // Enable edge-to-edge mode for Android 15+
82
- WindowCompat.setDecorFitsSystemWindows(window, false);
60
+ // Enable edge-to-edge for ALL API levels.
61
+ // window.setStatusBarColor() is unreliable on many devices/OEMs,
62
+ // so we use overlay views to control bar colors consistently.
63
+ WindowCompat.setDecorFitsSystemWindows(window, false);
83
64
 
84
- ViewCompat.setOnApplyWindowInsetsListener(decorView, (v, insets) -> {
85
- androidx.core.graphics.Insets imeInsets = insets.getInsets(WindowInsetsCompat.Type.ime());
86
- androidx.core.graphics.Insets systemBarsInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars());
65
+ // Make native bar colors transparent so our overlays are the sole color source
66
+ window.setStatusBarColor(Color.TRANSPARENT);
67
+ window.setNavigationBarColor(Color.TRANSPARENT);
68
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
69
+ window.setStatusBarContrastEnforced(false);
70
+ window.setNavigationBarContrastEnforced(false);
71
+ }
87
72
 
88
- boolean isKeyboardVisible = imeInsets.bottom > 0;
89
- Log.d(TAG, "ensureEdgeToEdgeConfigured: IME visible=" + isKeyboardVisible
90
- + ", IME bottom=" + imeInsets.bottom
91
- + ", system bars bottom=" + systemBarsInsets.bottom);
73
+ // Single unified insets listener on decorView for overlay sizing
74
+ ViewCompat.setOnApplyWindowInsetsListener(decorView, (v, insets) -> {
75
+ // Size status bar overlay
76
+ int top = insets.getInsets(WindowInsetsCompat.Type.statusBars()).top;
77
+ View statusOverlay = ((ViewGroup) v).findViewWithTag(STATUS_BAR_OVERLAY_TAG);
78
+ if (statusOverlay != null) {
79
+ ViewGroup.LayoutParams params = statusOverlay.getLayoutParams();
80
+ if (params.height != top) {
81
+ params.height = top;
82
+ statusOverlay.setLayoutParams(params);
83
+ Log.d(TAG, "insetsListener: status bar overlay height=" + top);
84
+ }
85
+ }
92
86
 
93
- ViewCompat.onApplyWindowInsets(v, insets);
94
- return insets;
95
- });
87
+ // Size navigation bar overlay
88
+ int bottom = insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom;
89
+ View navOverlay = ((ViewGroup) v).findViewWithTag(NAV_BAR_OVERLAY_TAG);
90
+ if (navOverlay != null) {
91
+ ViewGroup.LayoutParams params = navOverlay.getLayoutParams();
92
+ if (params.height != bottom) {
93
+ params.height = bottom;
94
+ navOverlay.setLayoutParams(params);
95
+ Log.d(TAG, "insetsListener: nav bar overlay height=" + bottom);
96
+ }
97
+ }
96
98
 
97
- Log.d(TAG,
98
- "ensureEdgeToEdgeConfigured: Edge-to-edge enabled with WindowInsets API for Android 15+ (API 35+)");
99
- } else {
100
- Log.d(TAG, "ensureEdgeToEdgeConfigured: Android < 15, no action needed");
101
- }
99
+ ViewCompat.onApplyWindowInsets(v, insets);
100
+ return insets;
101
+ });
102
+
103
+ Log.d(TAG, "ensureEdgeToEdgeConfigured: edge-to-edge with overlay views, API=" + Build.VERSION.SDK_INT);
102
104
  }
103
105
 
104
106
  public void setOverlaysWebView(Activity activity, boolean overlay) {
@@ -196,11 +198,6 @@ public class StatusBar extends Plugin {
196
198
  Log.d(TAG, "setStyle: style=" + style + ", colorHex=" + colorHex);
197
199
  Window window = activity.getWindow();
198
200
 
199
- // Enable drawing of system bar backgrounds (required for color changes)
200
- window.addFlags(android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
201
- window.clearFlags(android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
202
- window.clearFlags(android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
203
-
204
201
  // Store the current style and color for later reapplication
205
202
  currentStyle = style;
206
203
  currentColorHex = colorHex;
@@ -279,60 +276,45 @@ public class StatusBar extends Plugin {
279
276
  * Returns the insets for status bar, navigation bar, and notch areas.
280
277
  *
281
278
  * @param activity The activity to get the insets from
282
- * @return A map containing top, bottom, left, and right inset values in pixels
279
+ * @return A map containing top, bottom, left, and right inset values in dp (density-independent pixels)
283
280
  */
284
281
  public java.util.Map<String, Integer> getSafeAreaInsets(Activity activity) {
285
282
  Log.d(TAG, "getSafeAreaInsets");
286
283
  java.util.Map<String, Integer> insets = new java.util.HashMap<>();
284
+ float density = activity.getResources().getDisplayMetrics().density;
287
285
 
288
- Window window = activity.getWindow();
289
- View decorView = window.getDecorView();
290
-
291
- WindowInsets windowInsets = decorView.getRootWindowInsets();
292
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
293
- // API 30+ (Android 11+) - Use WindowInsets API
294
- if (windowInsets != null) {
295
- android.graphics.Insets systemBarsInsets = windowInsets.getInsets(WindowInsets.Type.systemBars());
296
- android.graphics.Insets displayCutoutInsets = windowInsets.getInsets(WindowInsets.Type.displayCutout());
297
-
298
- // Combine system bars and display cutout insets (use maximum of both)
299
- insets.put("top", Math.max(systemBarsInsets.top, displayCutoutInsets.top));
300
- insets.put("bottom", Math.max(systemBarsInsets.bottom, displayCutoutInsets.bottom));
301
- insets.put("left", Math.max(systemBarsInsets.left, displayCutoutInsets.left));
302
- insets.put("right", Math.max(systemBarsInsets.right, displayCutoutInsets.right));
303
-
304
- Log.d(TAG, "getSafeAreaInsets (API 30+): top=" + insets.get("top")
305
- + ", bottom=" + insets.get("bottom")
306
- + ", left=" + insets.get("left")
307
- + ", right=" + insets.get("right"));
308
- } else {
309
- // Fallback to zero insets
310
- insets.put("top", 0);
311
- insets.put("bottom", 0);
312
- insets.put("left", 0);
313
- insets.put("right", 0);
314
- Log.w(TAG, "getSafeAreaInsets: windowInsets is null");
315
- }
286
+ View decorView = activity.getWindow().getDecorView();
287
+ WindowInsetsCompat windowInsets = ViewCompat.getRootWindowInsets(decorView);
288
+
289
+ if (windowInsets != null) {
290
+ // Use WindowInsetsCompat for accurate, type-specific insets across all API levels
291
+ androidx.core.graphics.Insets statusBars = windowInsets.getInsets(WindowInsetsCompat.Type.statusBars());
292
+ androidx.core.graphics.Insets navBars = windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars());
293
+ androidx.core.graphics.Insets displayCutout = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout());
294
+
295
+ int topPx = Math.max(statusBars.top, displayCutout.top);
296
+ int bottomPx = Math.max(navBars.bottom, displayCutout.bottom);
297
+ int leftPx = Math.max(navBars.left, displayCutout.left);
298
+ int rightPx = Math.max(navBars.right, displayCutout.right);
299
+
300
+ // Convert physical pixels to dp (CSS pixels) for the WebView layer
301
+ insets.put("top", Math.round(topPx / density));
302
+ insets.put("bottom", Math.round(bottomPx / density));
303
+ insets.put("left", Math.round(leftPx / density));
304
+ insets.put("right", Math.round(rightPx / density));
305
+
306
+ Log.d(TAG, "getSafeAreaInsets: topPx=" + topPx + " bottomPx=" + bottomPx
307
+ + " density=" + density
308
+ + " -> top=" + insets.get("top") + "dp"
309
+ + " bottom=" + insets.get("bottom") + "dp"
310
+ + " left=" + insets.get("left") + "dp"
311
+ + " right=" + insets.get("right") + "dp");
316
312
  } else {
317
- // API 29 (Android 10) - Use deprecated system window insets
318
- if (windowInsets != null) {
319
- insets.put("top", windowInsets.getSystemWindowInsetTop());
320
- insets.put("bottom", windowInsets.getSystemWindowInsetBottom());
321
- insets.put("left", windowInsets.getSystemWindowInsetLeft());
322
- insets.put("right", windowInsets.getSystemWindowInsetRight());
323
-
324
- Log.d(TAG, "getSafeAreaInsets (API 29): top=" + insets.get("top")
325
- + ", bottom=" + insets.get("bottom")
326
- + ", left=" + insets.get("left")
327
- + ", right=" + insets.get("right"));
328
- } else {
329
- // Fallback to zero insets
330
- insets.put("top", 0);
331
- insets.put("bottom", 0);
332
- insets.put("left", 0);
333
- insets.put("right", 0);
334
- Log.w(TAG, "getSafeAreaInsets: windowInsets is null");
335
- }
313
+ insets.put("top", 0);
314
+ insets.put("bottom", 0);
315
+ insets.put("left", 0);
316
+ insets.put("right", 0);
317
+ Log.w(TAG, "getSafeAreaInsets: windowInsets is null");
336
318
  }
337
319
 
338
320
  return insets;
@@ -400,16 +382,14 @@ public class StatusBar extends Plugin {
400
382
 
401
383
  private void applyStatusBarBackground(Activity activity, @ColorInt int color) {
402
384
  Log.d(TAG, "applyStatusBarBackground: color=#" + Integer.toHexString(color) + ", API=" + Build.VERSION.SDK_INT);
403
- // Use overlay approach for all API levels since edge-to-edge mode
404
- // (setDecorFitsSystemWindows=false) makes window.setStatusBarColor() ineffective
385
+ // Use overlay views for all API levels for consistent behavior
405
386
  ensureStatusBarOverlay(activity, color);
406
387
  }
407
388
 
408
389
  private void applyNavigationBarBackground(Activity activity, @ColorInt int color) {
409
390
  Log.d(TAG, "applyNavigationBarBackground: color=#" + Integer.toHexString(color) + ", API="
410
391
  + Build.VERSION.SDK_INT);
411
- // Use overlay approach for all API levels since edge-to-edge mode
412
- // (setDecorFitsSystemWindows=false) makes window.setNavigationBarColor() ineffective
392
+ // Use overlay views for all API levels for consistent behavior
413
393
  ensureNavBarOverlay(activity, color);
414
394
  }
415
395
 
@@ -417,41 +397,38 @@ public class StatusBar extends Plugin {
417
397
  Log.d(TAG, "ensureStatusBarOverlay: color=#" + Integer.toHexString(color));
418
398
  ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
419
399
  View existing = decorView.findViewWithTag(STATUS_BAR_OVERLAY_TAG);
400
+
401
+ // Get current status bar height synchronously for immediate sizing
402
+ int initialHeight = 0;
403
+ WindowInsetsCompat rootInsets = ViewCompat.getRootWindowInsets(decorView);
404
+ if (rootInsets != null) {
405
+ initialHeight = rootInsets.getInsets(WindowInsetsCompat.Type.statusBars()).top;
406
+ }
407
+
420
408
  if (existing == null) {
421
- Log.d(TAG, "ensureStatusBarOverlay: creating new overlay");
409
+ Log.d(TAG, "ensureStatusBarOverlay: creating new overlay, initialHeight=" + initialHeight);
422
410
  View overlay = new View(activity);
423
411
  overlay.setTag(STATUS_BAR_OVERLAY_TAG);
424
412
  overlay.setBackgroundColor(color);
425
413
 
426
414
  FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
427
415
  ViewGroup.LayoutParams.MATCH_PARENT,
428
- 0);
429
- lp.topMargin = 0;
416
+ initialHeight);
430
417
  overlay.setLayoutParams(lp);
431
418
 
432
- // Add to the top of the decor view
433
419
  decorView.addView(overlay);
434
-
435
- // Apply correct height from insets
436
- ViewCompat.setOnApplyWindowInsetsListener(overlay, (v, windowInsets) -> {
437
- int top;
438
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
439
- top = Objects.requireNonNull(windowInsets.toWindowInsets())
440
- .getInsets(WindowInsets.Type.statusBars()).top;
441
- } else {
442
- top = Objects.requireNonNull(windowInsets.toWindowInsets()).getSystemWindowInsetTop();
443
- }
444
- ViewGroup.LayoutParams params = v.getLayoutParams();
445
- params.height = top;
446
- v.setLayoutParams(params);
447
- // Don't set color here - it's set before listener and should not be overridden
448
- return windowInsets;
449
- });
450
- overlay.requestApplyInsets();
420
+ // Sizing updates are handled by the unified listener in ensureEdgeToEdgeConfigured
421
+ decorView.requestApplyInsets();
451
422
  } else {
452
423
  Log.d(TAG, "ensureStatusBarOverlay: updating existing overlay");
453
424
  existing.setBackgroundColor(color);
454
- existing.requestApplyInsets();
425
+ // Update height if it was 0 (listener hadn't fired yet)
426
+ ViewGroup.LayoutParams params = existing.getLayoutParams();
427
+ if (params.height == 0 && initialHeight > 0) {
428
+ params.height = initialHeight;
429
+ existing.setLayoutParams(params);
430
+ Log.d(TAG, "ensureStatusBarOverlay: fixed height to " + initialHeight);
431
+ }
455
432
  }
456
433
  }
457
434
 
@@ -469,39 +446,39 @@ public class StatusBar extends Plugin {
469
446
  Log.d(TAG, "ensureNavBarOverlay: color=#" + Integer.toHexString(color));
470
447
  ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
471
448
  View existing = decorView.findViewWithTag(NAV_BAR_OVERLAY_TAG);
449
+
450
+ // Get current nav bar height synchronously for immediate sizing
451
+ int initialHeight = 0;
452
+ WindowInsetsCompat rootInsets = ViewCompat.getRootWindowInsets(decorView);
453
+ if (rootInsets != null) {
454
+ initialHeight = rootInsets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom;
455
+ }
456
+
472
457
  if (existing == null) {
473
- Log.d(TAG, "ensureNavBarOverlay: creating new overlay");
458
+ Log.d(TAG, "ensureNavBarOverlay: creating new overlay, initialHeight=" + initialHeight);
474
459
  View overlay = new View(activity);
475
460
  overlay.setTag(NAV_BAR_OVERLAY_TAG);
476
461
  overlay.setBackgroundColor(color);
477
462
 
478
463
  FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
479
464
  ViewGroup.LayoutParams.MATCH_PARENT,
480
- 0);
465
+ initialHeight);
481
466
  lp.gravity = Gravity.BOTTOM;
482
467
  overlay.setLayoutParams(lp);
483
468
 
484
469
  decorView.addView(overlay);
485
-
486
- ViewCompat.setOnApplyWindowInsetsListener(overlay, (v, windowInsets) -> {
487
- int bottom;
488
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
489
- bottom = Objects.requireNonNull(windowInsets.toWindowInsets())
490
- .getInsets(WindowInsets.Type.navigationBars()).bottom;
491
- } else {
492
- bottom = Objects.requireNonNull(windowInsets.toWindowInsets()).getSystemWindowInsetBottom();
493
- }
494
- ViewGroup.LayoutParams params = v.getLayoutParams();
495
- params.height = bottom;
496
- v.setLayoutParams(params);
497
- // Don't set color here - it's set before listener and should not be overridden
498
- return windowInsets;
499
- });
500
- overlay.requestApplyInsets();
470
+ // Sizing updates are handled by the unified listener in ensureEdgeToEdgeConfigured
471
+ decorView.requestApplyInsets();
501
472
  } else {
502
473
  Log.d(TAG, "ensureNavBarOverlay: updating existing overlay");
503
474
  existing.setBackgroundColor(color);
504
- existing.requestApplyInsets();
475
+ // Update height if it was 0 (listener hadn't fired yet)
476
+ ViewGroup.LayoutParams params = existing.getLayoutParams();
477
+ if (params.height == 0 && initialHeight > 0) {
478
+ params.height = initialHeight;
479
+ existing.setLayoutParams(params);
480
+ Log.d(TAG, "ensureNavBarOverlay: fixed height to " + initialHeight);
481
+ }
505
482
  }
506
483
  }
507
484
 
@@ -527,18 +504,15 @@ public class StatusBar extends Plugin {
527
504
  */
528
505
  private void makeStatusBarBackgroundTransparent(Activity activity) {
529
506
  Log.d(TAG, "makeStatusBarBackgroundTransparent: API=" + Build.VERSION.SDK_INT);
530
- Window window = activity.getWindow();
507
+ ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
531
508
 
532
- // Make overlay views transparent (used for all API levels)
533
- ViewGroup decorView = (ViewGroup) window.getDecorView();
534
509
  View statusBarOverlay = decorView.findViewWithTag(STATUS_BAR_OVERLAY_TAG);
535
- View navBarOverlay = decorView.findViewWithTag(NAV_BAR_OVERLAY_TAG);
536
-
537
510
  if (statusBarOverlay != null) {
538
511
  statusBarOverlay.setBackgroundColor(Color.TRANSPARENT);
539
512
  Log.d(TAG, "makeStatusBarBackgroundTransparent: status bar overlay made transparent");
540
513
  }
541
514
 
515
+ View navBarOverlay = decorView.findViewWithTag(NAV_BAR_OVERLAY_TAG);
542
516
  if (navBarOverlay != null) {
543
517
  navBarOverlay.setBackgroundColor(Color.TRANSPARENT);
544
518
  Log.d(TAG, "makeStatusBarBackgroundTransparent: navigation bar overlay made transparent");
package/dist/docs.json CHANGED
@@ -150,7 +150,7 @@
150
150
  "parameters": [],
151
151
  "returns": "Promise<SafeAreaInsets>",
152
152
  "tags": [],
153
- "docs": "Get the safe area insets.\nReturns the insets for status bar, navigation bar, and notch areas.\nValues are in pixels on Android and points on iOS.",
153
+ "docs": "Get the safe area insets.\nReturns the insets for status bar, navigation bar, and notch areas.\nValues are in CSS pixels (dp) on all platforms.",
154
154
  "complexTypes": [
155
155
  "SafeAreaInsets"
156
156
  ],
@@ -90,7 +90,7 @@ export interface StatusBarPlugin {
90
90
  /**
91
91
  * Get the safe area insets.
92
92
  * Returns the insets for status bar, navigation bar, and notch areas.
93
- * Values are in pixels on Android and points on iOS.
93
+ * Values are in CSS pixels (dp) on all platforms.
94
94
  */
95
95
  getSafeAreaInsets(): Promise<SafeAreaInsets>;
96
96
  }
@@ -1 +1 @@
1
- {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,KAIX;AAJD,WAAY,KAAK;IACf,wBAAe,CAAA;IACf,sBAAa,CAAA;IACb,0BAAiB,CAAA;AACnB,CAAC,EAJW,KAAK,KAAL,KAAK,QAIhB;AAWD,MAAM,CAAN,IAAY,kBAIX;AAJD,WAAY,kBAAkB;IAC5B,mCAAa,CAAA;IACb,mCAAa,CAAA;IACb,qCAAe,CAAA;AACjB,CAAC,EAJW,kBAAkB,KAAlB,kBAAkB,QAI7B","sourcesContent":["export enum Style {\n LIGHT = 'LIGHT',\n DARK = 'DARK',\n CUSTOM = 'CUSTOM',\n}\n\n/**\n * Full HEX color format only (6 or 8 digits).\n * - 6 digits: #RRGGBB (e.g., #FFFFFF, #000000, #FF5733)\n * - 8 digits: #RRGGBBAA with alpha channel (e.g., #FFFFFF00, #FF5733CC)\n *\n * Note: Short 3-digit format (#FFF) is NOT supported.\n */\nexport type StatusBarColor = `#${string}`;\n\nexport enum StatusBarAnimation {\n NONE = 'none',\n FADE = 'fade',\n SLIDE = 'slide',\n}\n\ntype StatusBarStyleNoDefaultOptions = {\n style: Style;\n};\n\ntype StatusBarStyleOptions =\n | StatusBarStyleNoDefaultOptions\n | {\n style: Style.CUSTOM;\n color: StatusBarColor;\n };\n\nexport type StatusBarOptions = StatusBarStyleOptions;\n\nexport type StatusBarShowOptions = {\n animated: boolean;\n};\n\nexport type StatusBarHideOptions = {\n /**\n * The animation type for hiding the status bar.\n * - 'fade': Makes the background transparent without removing the status bar and navigation bar.\n * - 'slide': Hides the status bar and navigation bar completely (default behavior).\n */\n animation: StatusBarAnimation;\n};\n\nexport type StatusBarSetOverlaysWebViewOptions = {\n value: boolean;\n};\n\nexport type StatusBarSetBackgroundOptions = {\n color: StatusBarColor;\n};\n\nexport type SafeAreaInsets = {\n top: number;\n bottom: number;\n left: number;\n right: number;\n};\n\nexport interface StatusBarPlugin {\n /**\n * Set the status bar and navigation bar style and color.\n * @param options - The options to set the status bar style and color.\n * @param options.style - The style of the status bar.\n * @param options.color - The color of the status bar.\n */\n setStyle(options: StatusBarOptions): Promise<void>;\n /**\n * Show the status bar.\n * @param options - The options to show the status bar.\n * @param options.animated - Whether to animate the status bar.\n */\n show(options: StatusBarShowOptions): Promise<void>;\n /**\n * Hide the status bar.\n * @param options - The options to hide the status bar.\n * @param options.animation - The animation type: 'fade' makes background transparent, 'slide' hides bars completely.\n */\n hide(options: StatusBarHideOptions): Promise<void>;\n /**\n * Set whether the status bar overlays the web view.\n *\n * **iOS only** - On Android this is a no-op (resolves without error).\n *\n * - `true`: Web content extends behind the status bar (transparent background),\n * allowing content to be visible through the status bar area on scroll.\n * - `false`: Restores the status bar background to the color set by `setStyle`\n * or falls back to the default style from Capacitor config.\n *\n * @param options - The options to set the status bar overlays web view.\n * @param options.value - Whether the status bar overlays the web view (required).\n */\n setOverlaysWebView(options: StatusBarSetOverlaysWebViewOptions): Promise<void>;\n /**\n * Set the window background color.\n * @param options - The options to set the window background color.\n * @param options.color - The background color in HEX format.\n */\n setBackground(options: StatusBarSetBackgroundOptions): Promise<void>;\n /**\n * Get the safe area insets.\n * Returns the insets for status bar, navigation bar, and notch areas.\n * Values are in pixels on Android and points on iOS.\n */\n getSafeAreaInsets(): Promise<SafeAreaInsets>;\n}\n"]}
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,KAIX;AAJD,WAAY,KAAK;IACf,wBAAe,CAAA;IACf,sBAAa,CAAA;IACb,0BAAiB,CAAA;AACnB,CAAC,EAJW,KAAK,KAAL,KAAK,QAIhB;AAWD,MAAM,CAAN,IAAY,kBAIX;AAJD,WAAY,kBAAkB;IAC5B,mCAAa,CAAA;IACb,mCAAa,CAAA;IACb,qCAAe,CAAA;AACjB,CAAC,EAJW,kBAAkB,KAAlB,kBAAkB,QAI7B","sourcesContent":["export enum Style {\n LIGHT = 'LIGHT',\n DARK = 'DARK',\n CUSTOM = 'CUSTOM',\n}\n\n/**\n * Full HEX color format only (6 or 8 digits).\n * - 6 digits: #RRGGBB (e.g., #FFFFFF, #000000, #FF5733)\n * - 8 digits: #RRGGBBAA with alpha channel (e.g., #FFFFFF00, #FF5733CC)\n *\n * Note: Short 3-digit format (#FFF) is NOT supported.\n */\nexport type StatusBarColor = `#${string}`;\n\nexport enum StatusBarAnimation {\n NONE = 'none',\n FADE = 'fade',\n SLIDE = 'slide',\n}\n\ntype StatusBarStyleNoDefaultOptions = {\n style: Style;\n};\n\ntype StatusBarStyleOptions =\n | StatusBarStyleNoDefaultOptions\n | {\n style: Style.CUSTOM;\n color: StatusBarColor;\n };\n\nexport type StatusBarOptions = StatusBarStyleOptions;\n\nexport type StatusBarShowOptions = {\n animated: boolean;\n};\n\nexport type StatusBarHideOptions = {\n /**\n * The animation type for hiding the status bar.\n * - 'fade': Makes the background transparent without removing the status bar and navigation bar.\n * - 'slide': Hides the status bar and navigation bar completely (default behavior).\n */\n animation: StatusBarAnimation;\n};\n\nexport type StatusBarSetOverlaysWebViewOptions = {\n value: boolean;\n};\n\nexport type StatusBarSetBackgroundOptions = {\n color: StatusBarColor;\n};\n\nexport type SafeAreaInsets = {\n top: number;\n bottom: number;\n left: number;\n right: number;\n};\n\nexport interface StatusBarPlugin {\n /**\n * Set the status bar and navigation bar style and color.\n * @param options - The options to set the status bar style and color.\n * @param options.style - The style of the status bar.\n * @param options.color - The color of the status bar.\n */\n setStyle(options: StatusBarOptions): Promise<void>;\n /**\n * Show the status bar.\n * @param options - The options to show the status bar.\n * @param options.animated - Whether to animate the status bar.\n */\n show(options: StatusBarShowOptions): Promise<void>;\n /**\n * Hide the status bar.\n * @param options - The options to hide the status bar.\n * @param options.animation - The animation type: 'fade' makes background transparent, 'slide' hides bars completely.\n */\n hide(options: StatusBarHideOptions): Promise<void>;\n /**\n * Set whether the status bar overlays the web view.\n *\n * **iOS only** - On Android this is a no-op (resolves without error).\n *\n * - `true`: Web content extends behind the status bar (transparent background),\n * allowing content to be visible through the status bar area on scroll.\n * - `false`: Restores the status bar background to the color set by `setStyle`\n * or falls back to the default style from Capacitor config.\n *\n * @param options - The options to set the status bar overlays web view.\n * @param options.value - Whether the status bar overlays the web view (required).\n */\n setOverlaysWebView(options: StatusBarSetOverlaysWebViewOptions): Promise<void>;\n /**\n * Set the window background color.\n * @param options - The options to set the window background color.\n * @param options.color - The background color in HEX format.\n */\n setBackground(options: StatusBarSetBackgroundOptions): Promise<void>;\n /**\n * Get the safe area insets.\n * Returns the insets for status bar, navigation bar, and notch areas.\n * Values are in CSS pixels (dp) on all platforms.\n */\n getSafeAreaInsets(): Promise<SafeAreaInsets>;\n}\n"]}
@@ -230,13 +230,19 @@ import Capacitor
230
230
 
231
231
  if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
232
232
  let window = windowScene.windows.first {
233
+ // Use statusBarManager for accurate status bar height
234
+ let statusBarHeight = windowScene.statusBarManager?.statusBarFrame.height ?? 0
233
235
  let safeAreaInsets = window.safeAreaInsets
234
- insets["top"] = safeAreaInsets.top
236
+
237
+ // top: status bar height specifically
238
+ insets["top"] = statusBarHeight
239
+ // bottom: home indicator / navigation bar area
235
240
  insets["bottom"] = safeAreaInsets.bottom
241
+ // left/right: safe area for landscape / display cutouts
236
242
  insets["left"] = safeAreaInsets.left
237
243
  insets["right"] = safeAreaInsets.right
238
244
 
239
- print("StatusBar: getSafeAreaInsets - top=\(safeAreaInsets.top), bottom=\(safeAreaInsets.bottom), left=\(safeAreaInsets.left), right=\(safeAreaInsets.right)")
245
+ print("StatusBar: getSafeAreaInsets - top=\(statusBarHeight), bottom=\(safeAreaInsets.bottom), left=\(safeAreaInsets.left), right=\(safeAreaInsets.right)")
240
246
  } else {
241
247
  print("StatusBar: getSafeAreaInsets - Unable to get window, returning zero insets")
242
248
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "capacitor-plugin-status-bar",
3
- "version": "2.0.1",
3
+ "version": "2.0.3",
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",