This is an automated email from the ASF dual-hosted git repository.

erisu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cordova-ios.git


The following commit(s) were added to refs/heads/master by this push:
     new 0ab311fa feat(statusbar): Simple built-in status bar support (#1523)
0ab311fa is described below

commit 0ab311fafd274047fe98c3e36f95c6c35ce6b6e8
Author: Darryl Pogue <dar...@dpogue.ca>
AuthorDate: Sun Apr 6 21:17:20 2025 -0700

    feat(statusbar): Simple built-in status bar support (#1523)
    
    * fix: Prevent recursion in scrollView monkeypatch
    
    If you call scrollView on a UIView that does not have its own scrollView
    method, this hijack method will keep recursively calling itself until
    you run out of stack space. Try to guard against that by making sure
    that it's not getting called on the same instance multiple times.
    
    TODO: Think about thread safety, but in theory because this is
    view-related stuff it's only safe to run on the main thread.
    
    * feat(statusbar): Simple built-in status bar background
    
    This adds a background behind the status bar automatically when a page
    does not request to extend itself behind the status bar using a meta tag
    with `viewport-fit=cover`. It automatically shows and hides as the value
    of the viewport-fit option changes.
    
    On iOS 16.4 and newer, it will be coloured according to the meta
    `theme-color` tag, and a default colour can be set in the storyboard for
    a CDVViewController.
    
    We expose a very basic JS API hanging off the existing
    `window.statusbar` property that allows controlling the visibility (of
    the status bar contents entirely, not just of the background view) and
    overriding the background colour.
    
    The colour is determined as follows:
      1. Any colour set explicitly with the JS API (if any)
      2. Any colour pulled from the meta tag (iOS 16.4+, if any)
      3. The default colour specified in the storyboard (if any)
      4. The background colour specified in the storyboard (if any)
      5. The default system background colour
    
    Efforts were made to ensure that this does not interfere with the
    existing CDVStatusBar plugin implementation (although maybe this can
    replace it for most common use cases), by making the display of this
    built-in conditional on not having the CDVStatusBar plugin installed.
    
    * feat(statusbar): Hook up StatusBarBackgroundColor
---
 ...VLaunchScreen.m => CDVViewController+Private.h} |  14 +--
 .../Plugins/CDVLaunchScreen/CDVLaunchScreen.m      |   1 +
 .../CDVStatusBarInternal.h}                        |  16 +--
 .../CDVStatusBarInternal/CDVStatusBarInternal.m    |  46 +++++++++
 .../Plugins/CDVWebViewEngine/CDVWebViewEngine.m    |  14 +++
 CordovaLib/Classes/Public/CDVPlugin.m              |  10 +-
 CordovaLib/Classes/Public/CDVViewController.m      | 112 ++++++++++++++++++++-
 CordovaLib/CordovaLib.xcodeproj/project.pbxproj    |  26 +++++
 CordovaLib/include/Cordova/CDVViewController.h     |   7 ++
 cordova-js-src/platform.js                         |   4 +
 cordova-js-src/plugin/ios/statusbar.js             |  78 ++++++++++++++
 lib/prepare.js                                     |  41 ++++++++
 templates/cordova/defaults.xml                     |   4 +
 .../Contents.json                                  |  15 +++
 templates/project/App/Base.lproj/Main.storyboard   |   6 ++
 .../Contents.json                                  |  15 +++
 .../ios-config-xml/App/Base.lproj/Main.storyboard  |   6 ++
 17 files changed, 387 insertions(+), 28 deletions(-)

diff --git 
a/CordovaLib/Classes/Private/Plugins/CDVLaunchScreen/CDVLaunchScreen.m 
b/CordovaLib/Classes/Private/CDVViewController+Private.h
similarity index 75%
copy from CordovaLib/Classes/Private/Plugins/CDVLaunchScreen/CDVLaunchScreen.m
copy to CordovaLib/Classes/Private/CDVViewController+Private.h
index 8c672277..27a907f9 100644
--- a/CordovaLib/Classes/Private/Plugins/CDVLaunchScreen/CDVLaunchScreen.m
+++ b/CordovaLib/Classes/Private/CDVViewController+Private.h
@@ -17,18 +17,12 @@
  under the License.
  */
 
-#import "CDVLaunchScreen.h"
+#import <Cordova/CDVViewController.h>
 
-@implementation CDVLaunchScreen
+@interface CDVViewController (Private)
 
-- (void)show:(CDVInvokedUrlCommand *)command
-{
-    [self.viewController showSplashScreen:YES];
-}
+- (void)setStatusBarWebViewColor:(UIColor *)color;
 
-- (void)hide:(CDVInvokedUrlCommand *)command
-{
-    [self.viewController showSplashScreen:NO];
-}
+- (void)showStatusBar:(BOOL)visible;
 
 @end
diff --git 
a/CordovaLib/Classes/Private/Plugins/CDVLaunchScreen/CDVLaunchScreen.m 
b/CordovaLib/Classes/Private/Plugins/CDVLaunchScreen/CDVLaunchScreen.m
index 8c672277..0609d6f4 100644
--- a/CordovaLib/Classes/Private/Plugins/CDVLaunchScreen/CDVLaunchScreen.m
+++ b/CordovaLib/Classes/Private/Plugins/CDVLaunchScreen/CDVLaunchScreen.m
@@ -18,6 +18,7 @@
  */
 
 #import "CDVLaunchScreen.h"
+#import "CDVViewController+Private.h"
 
 @implementation CDVLaunchScreen
 
diff --git 
a/CordovaLib/Classes/Private/Plugins/CDVLaunchScreen/CDVLaunchScreen.m 
b/CordovaLib/Classes/Private/Plugins/CDVStatusBarInternal/CDVStatusBarInternal.h
similarity index 75%
copy from CordovaLib/Classes/Private/Plugins/CDVLaunchScreen/CDVLaunchScreen.m
copy to 
CordovaLib/Classes/Private/Plugins/CDVStatusBarInternal/CDVStatusBarInternal.h
index 8c672277..08af9c89 100644
--- a/CordovaLib/Classes/Private/Plugins/CDVLaunchScreen/CDVLaunchScreen.m
+++ 
b/CordovaLib/Classes/Private/Plugins/CDVStatusBarInternal/CDVStatusBarInternal.h
@@ -17,18 +17,12 @@
  under the License.
  */
 
-#import "CDVLaunchScreen.h"
+#import <Cordova/CDVPlugin.h>
 
-@implementation CDVLaunchScreen
+@interface CDVStatusBarInternal : CDVPlugin
 
-- (void)show:(CDVInvokedUrlCommand *)command
-{
-    [self.viewController showSplashScreen:YES];
-}
-
-- (void)hide:(CDVInvokedUrlCommand *)command
-{
-    [self.viewController showSplashScreen:NO];
-}
+- (void)setVisible:(CDVInvokedUrlCommand*)command;
+- (void)setBackgroundColor:(CDVInvokedUrlCommand*)command;
 
 @end
+
diff --git 
a/CordovaLib/Classes/Private/Plugins/CDVStatusBarInternal/CDVStatusBarInternal.m
 
b/CordovaLib/Classes/Private/Plugins/CDVStatusBarInternal/CDVStatusBarInternal.m
new file mode 100644
index 00000000..fc6412bd
--- /dev/null
+++ 
b/CordovaLib/Classes/Private/Plugins/CDVStatusBarInternal/CDVStatusBarInternal.m
@@ -0,0 +1,46 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVStatusBarInternal.h"
+#import "CDVViewController+Private.h"
+
+@implementation CDVStatusBarInternal
+
+- (void)setVisible:(CDVInvokedUrlCommand *)command
+{
+    id value = [command argumentAtIndex:0];
+    if (!([value isKindOfClass:[NSNumber class]])) {
+        value = [NSNumber numberWithBool:YES];
+    }
+
+    [self.viewController showStatusBar:[value boolValue]];
+}
+
+- (void)setBackgroundColor:(CDVInvokedUrlCommand *)command
+{
+    NSInteger valueR = [[command argumentAtIndex:0 withDefault:@0] 
integerValue];
+    NSInteger valueG = [[command argumentAtIndex:1 withDefault:@0] 
integerValue];
+    NSInteger valueB = [[command argumentAtIndex:2 withDefault:@0] 
integerValue];
+
+    UIColor *bgColor = [UIColor colorWithRed:valueR/255.f green:valueG/255.f 
blue:valueB/255.f alpha:1.f];
+    [self.viewController setStatusBarBackgroundColor:bgColor];
+}
+
+@end
+
diff --git 
a/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewEngine.m 
b/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewEngine.m
index d2314c82..7100918b 100644
--- a/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewEngine.m
+++ b/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewEngine.m
@@ -22,6 +22,7 @@
 #import "CDVURLSchemeHandler.h"
 #import <Cordova/CDVWebViewProcessPoolFactory.h>
 #import <Cordova/CDVSettingsDictionary.h>
+#import "CDVViewController+Private.h"
 
 #import <objc/message.h>
 
@@ -242,6 +243,8 @@
         wkWebView.customUserAgent = [settings 
cordovaSettingForKey:@"OverrideUserAgent"];
     }
 
+    [wkWebView addObserver:self forKeyPath:@"themeColor" 
options:NSKeyValueObservingOptionInitial context:nil];
+
     self.engineWebView = wkWebView;
 
     if ([self.viewController conformsToProtocol:@protocol(WKUIDelegate)]) {
@@ -477,6 +480,17 @@
     return result;
 }
 
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object 
change:(NSDictionary *)change context:(void *)context
+{
+    if ([keyPath isEqualToString:@"themeColor"]) {
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 150000
+        if (@available(iOS 15.0, *)) {
+            [self.viewController setStatusBarWebViewColor:((WKWebView 
*)self.engineWebView).themeColor];
+        }
+#endif
+    }
+}
+
 #pragma mark - WKScriptMessageHandler implementation
 
 - (void)userContentController:(WKUserContentController*)userContentController 
didReceiveScriptMessage:(WKScriptMessage*)message
diff --git a/CordovaLib/Classes/Public/CDVPlugin.m 
b/CordovaLib/Classes/Public/CDVPlugin.m
index 3eac8209..9b84a458 100644
--- a/CordovaLib/Classes/Public/CDVPlugin.m
+++ b/CordovaLib/Classes/Public/CDVPlugin.m
@@ -28,9 +28,15 @@
 
 - (UIScrollView*)scrollView
 {
-    if ([self respondsToSelector:@selector(scrollView)]) {
-        return [self performSelector:@selector(scrollView)];
+    static UIView *caller = nil;
+
+    if (caller != self && [self respondsToSelector:@selector(scrollView)]) {
+        caller = self;
+        UIScrollView *sv = [self performSelector:@selector(scrollView)];
+        caller = nil;
+        return sv;
     }
+    caller = nil;
     return nil;
 }
 
diff --git a/CordovaLib/Classes/Public/CDVViewController.m 
b/CordovaLib/Classes/Public/CDVViewController.m
index a30671da..5932ea82 100644
--- a/CordovaLib/Classes/Public/CDVViewController.m
+++ b/CordovaLib/Classes/Public/CDVViewController.m
@@ -30,23 +30,27 @@
 #import <Cordova/CDVTimer.h>
 #import "CDVCommandDelegateImpl.h"
 
-static UIColor* defaultBackgroundColor(void) {
+static UIColor *defaultBackgroundColor(void) {
     return UIColor.systemBackgroundColor;
 }
 
-@interface CDVViewController () <CDVWebViewEngineConfigurationDelegate> {
+@interface CDVViewController () <CDVWebViewEngineConfigurationDelegate, 
UIScrollViewDelegate> {
     id <CDVWebViewEngineProtocol> _webViewEngine;
     id <CDVCommandDelegate> _commandDelegate;
     NSMutableDictionary<NSString *, CDVPlugin *> *_pluginObjects;
     NSMutableDictionary<NSString *, NSString *> *_pluginsMap;
     CDVCommandQueue* _commandQueue;
-    UIColor* _backgroundColor;
-    UIColor* _splashBackgroundColor;
+    UIColor *_backgroundColor;
+    UIColor *_splashBackgroundColor;
+    UIColor *_statusBarBackgroundColor;
+    UIColor *_statusBarWebViewColor;
+    UIColor *_statusBarDefaultColor;
     CDVSettingsDictionary* _settings;
 }
 
 @property (nonatomic, readwrite, strong) NSMutableArray* startupPluginNames;
-@property (nonatomic, readwrite, strong) UIView* launchView;
+@property (nonatomic, readwrite, strong) UIView *launchView;
+@property (nonatomic, readwrite, strong) UIView *statusBar;
 @property (readwrite, assign) BOOL initialized;
 
 @end
@@ -60,6 +64,7 @@ static UIColor* defaultBackgroundColor(void) {
 @synthesize webViewEngine = _webViewEngine;
 @synthesize backgroundColor = _backgroundColor;
 @synthesize splashBackgroundColor = _splashBackgroundColor;
+@synthesize statusBarBackgroundColor = _statusBarBackgroundColor;
 @synthesize settings = _settings;
 @dynamic webView;
 @dynamic enumerablePlugins;
@@ -168,11 +173,49 @@ static UIColor* defaultBackgroundColor(void) {
 - (void)setBackgroundColor:(UIColor *)color
 {
     _backgroundColor = color ?: defaultBackgroundColor();
+
+    [self.webView setBackgroundColor:self.backgroundColor];
 }
 
 - (void)setSplashBackgroundColor:(UIColor *)color
 {
     _splashBackgroundColor = color ?: self.backgroundColor;
+
+    [self.launchView setBackgroundColor:self.splashBackgroundColor];
+}
+
+- (UIColor *)statusBarBackgroundColor
+{
+    // If a status bar background color has been explicitly set using the JS 
API, we always use that.
+    // Otherwise, if the webview reports a themeColor meta tag (iOS 15.4+) we 
use that.
+    // Otherwise, we use the status bar background color provided in IB (from 
config.xml).
+    // Otherwise, we use the background color.
+    return _statusBarBackgroundColor ?: _statusBarWebViewColor ?: 
_statusBarDefaultColor ?: self.backgroundColor;
+}
+
+- (void)setStatusBarBackgroundColor:(UIColor *)color
+{
+    // We want the initial value from IB to set the statusBarDefaultColor and
+    // then all future changes to set the statusBarBackgroundColor.
+    //
+    // The reason for this is that statusBarBackgroundColor is treated like a
+    // forced override when it is set, and we don't want that for the initial
+    // value from config.xml set via IB.
+
+    if (!_statusBarBackgroundColor && !_statusBarWebViewColor && 
!_statusBarDefaultColor) {
+        _statusBarDefaultColor = color;
+    } else {
+        _statusBarBackgroundColor = color;
+    }
+
+    [self.statusBar setBackgroundColor:self.statusBarBackgroundColor];
+}
+
+- (void)setStatusBarWebViewColor:(UIColor *)color
+{
+    _statusBarWebViewColor = color;
+
+    [self.statusBar setBackgroundColor:self.statusBarBackgroundColor];
 }
 
 // Only for testing
@@ -320,6 +363,11 @@ static UIColor* defaultBackgroundColor(void) {
         [self createGapView];
     }
 
+    // Instantiate the status bar
+    if (!self.statusBar) {
+        [self createStatusBarView];
+    }
+
     // /////////////////
 
     if ([self.startupPluginNames count] > 0) {
@@ -358,6 +406,7 @@ static UIColor* defaultBackgroundColor(void) {
 
     [self.webView setBackgroundColor:self.backgroundColor];
     [self.launchView setBackgroundColor:self.splashBackgroundColor];
+    [self.statusBar setBackgroundColor:self.statusBarBackgroundColor];
 
     if (self.showInitialSplashScreen) {
         [self.launchView setAlpha:1];
@@ -525,6 +574,11 @@ static UIColor* defaultBackgroundColor(void) {
 {
     self.webView.hidden = NO;
 
+    if ([self.webView respondsToSelector:@selector(scrollView)]) {
+        UIScrollView *scrollView = [self.webView 
performSelector:@selector(scrollView)];
+        [self scrollViewDidChangeAdjustedContentInset:scrollView];
+    }
+
     if ([self.settings cordovaBoolSettingForKey:@"AutoHideSplashScreen" 
defaultValue:YES]) {
         CGFloat splashScreenDelaySetting = [self.settings 
cordovaFloatSettingForKey:@"SplashScreenDelay" defaultValue:0];
 
@@ -541,6 +595,23 @@ static UIColor* defaultBackgroundColor(void) {
     }
 }
 
+- (void)scrollViewDidChangeAdjustedContentInset:(UIScrollView *)scrollView
+{
+    if (self.webView.hidden) {
+        self.statusBar.hidden = true;
+        return;
+    }
+
+    self.statusBar.hidden = (scrollView.contentInsetAdjustmentBehavior == 
UIScrollViewContentInsetAdjustmentNever);
+}
+
+- (BOOL)prefersStatusBarHidden
+{
+    // The CDVStatusBar plugin overrides this in a category extension, and
+    // should bypass this implementation entirely
+    return self.statusBar.alpha < 0.0001f;
+}
+
 #pragma mark - View Setup
 
 - (void)loadSettings
@@ -667,6 +738,31 @@ static UIColor* defaultBackgroundColor(void) {
 
     [self.view addSubview:view];
     [self.view sendSubviewToBack:view];
+
+    if ([self.webView respondsToSelector:@selector(scrollView)]) {
+        UIScrollView *scrollView = [self.webView 
performSelector:@selector(scrollView)];
+        scrollView.delegate = self;
+    }
+}
+
+- (void)createStatusBarView
+{
+    // If cordova-plugin-statusbar is loaded, we'll let it handle the status
+    // bar to avoid introducing conflict
+    if (NSClassFromString(@"CDVStatusBar") != nil)
+        return;
+
+    self.statusBar = [[UIView alloc] init];
+    self.statusBar.translatesAutoresizingMaskIntoConstraints = NO;
+
+    [self.view addSubview:self.statusBar];
+
+    [self.statusBar.leadingAnchor 
constraintEqualToAnchor:self.view.leadingAnchor].active = YES;
+    [self.statusBar.trailingAnchor 
constraintEqualToAnchor:self.view.trailingAnchor].active = YES;
+    [self.statusBar.topAnchor 
constraintEqualToAnchor:self.view.topAnchor].active = YES;
+    [self.statusBar.bottomAnchor 
constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor].active = YES;
+
+    self.statusBar.hidden = YES;
 }
 
 #pragma mark CordovaCommands
@@ -783,6 +879,12 @@ static UIColor* defaultBackgroundColor(void) {
     }];
 }
 
+- (void)showStatusBar:(BOOL)visible
+{
+    [self.statusBar setAlpha:(visible ? 1 : 0)];
+    [self setNeedsStatusBarAppearanceUpdate];
+}
+
 - (void)parseSettingsWithParser:(id <NSXMLParserDelegate>)delegate
 {
     [CDVConfigParser parseConfigFile:self.configFilePath 
withDelegate:delegate];
diff --git a/CordovaLib/CordovaLib.xcodeproj/project.pbxproj 
b/CordovaLib/CordovaLib.xcodeproj/project.pbxproj
index 14e66bea..3b292627 100644
--- a/CordovaLib/CordovaLib.xcodeproj/project.pbxproj
+++ b/CordovaLib/CordovaLib.xcodeproj/project.pbxproj
@@ -81,6 +81,12 @@
                7ED95D581AB9029B008C4574 /* NSDictionary+CordovaPreferences.m 
in Sources */ = {isa = PBXBuildFile; fileRef = 7ED95D321AB9029B008C4574 /* 
NSDictionary+CordovaPreferences.m */; };
                7ED95D591AB9029B008C4574 /* NSMutableArray+QueueAdditions.h in 
Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D331AB9029B008C4574 /* 
NSMutableArray+QueueAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; };
                7ED95D5A1AB9029B008C4574 /* NSMutableArray+QueueAdditions.m in 
Sources */ = {isa = PBXBuildFile; fileRef = 7ED95D341AB9029B008C4574 /* 
NSMutableArray+QueueAdditions.m */; };
+               90227B4C2D499A1B005DB74E /* CDVViewController+Private.h in 
Headers */ = {isa = PBXBuildFile; fileRef = 90227B4B2D499A1B005DB74E /* 
CDVViewController+Private.h */; };
+               90227B4D2D499A1B005DB74E /* CDVViewController+Private.h in 
Headers */ = {isa = PBXBuildFile; fileRef = 90227B4B2D499A1B005DB74E /* 
CDVViewController+Private.h */; };
+               90227B512D49A042005DB74E /* CDVStatusBarInternal.h in Headers 
*/ = {isa = PBXBuildFile; fileRef = 90227B4E2D49A042005DB74E /* 
CDVStatusBarInternal.h */; };
+               90227B522D49A042005DB74E /* CDVStatusBarInternal.m in Sources 
*/ = {isa = PBXBuildFile; fileRef = 90227B4F2D49A042005DB74E /* 
CDVStatusBarInternal.m */; };
+               90227B532D49A042005DB74E /* CDVStatusBarInternal.h in Headers 
*/ = {isa = PBXBuildFile; fileRef = 90227B4E2D49A042005DB74E /* 
CDVStatusBarInternal.h */; };
+               90227B542D49A042005DB74E /* CDVStatusBarInternal.m in Sources 
*/ = {isa = PBXBuildFile; fileRef = 90227B4F2D49A042005DB74E /* 
CDVStatusBarInternal.m */; };
                902B30742C6C5A7E00C6804C /* CordovaLib.docc in Sources */ = 
{isa = PBXBuildFile; fileRef = 902B30732C6C5A7E00C6804C /* CordovaLib.docc */; 
};
                902B30752C6C5A7E00C6804C /* CordovaLib.docc in Sources */ = 
{isa = PBXBuildFile; fileRef = 902B30732C6C5A7E00C6804C /* CordovaLib.docc */; 
};
                9036843D2C6EB06500A3338C /* CDVAllowList.h in Headers */ = {isa 
= PBXBuildFile; fileRef = 9036843B2C6EB06500A3338C /* CDVAllowList.h */; };
@@ -194,6 +200,9 @@
                7ED95D321AB9029B008C4574 /* NSDictionary+CordovaPreferences.m 
*/ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = 
sourcecode.c.objc; path = "NSDictionary+CordovaPreferences.m"; sourceTree = 
"<group>"; };
                7ED95D331AB9029B008C4574 /* NSMutableArray+QueueAdditions.h */ 
= {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = 
sourcecode.c.h; path = "NSMutableArray+QueueAdditions.h"; sourceTree = 
"<group>"; };
                7ED95D341AB9029B008C4574 /* NSMutableArray+QueueAdditions.m */ 
= {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = 
sourcecode.c.objc; path = "NSMutableArray+QueueAdditions.m"; sourceTree = 
"<group>"; };
+               90227B4B2D499A1B005DB74E /* CDVViewController+Private.h */ = 
{isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = 
"CDVViewController+Private.h"; sourceTree = "<group>"; };
+               90227B4E2D49A042005DB74E /* CDVStatusBarInternal.h */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.c.h; path = 
CDVStatusBarInternal.h; sourceTree = "<group>"; };
+               90227B4F2D49A042005DB74E /* CDVStatusBarInternal.m */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = 
CDVStatusBarInternal.m; sourceTree = "<group>"; };
                902B30732C6C5A7E00C6804C /* CordovaLib.docc */ = {isa = 
PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = 
CordovaLib.docc; sourceTree = "<group>"; };
                902D0BC12AEB64EB009C68E5 /* PrivacyInfo.xcprivacy */ = {isa = 
PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; 
sourceTree = "<group>"; };
                9036843B2C6EB06500A3338C /* CDVAllowList.h */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CDVAllowList.h; 
sourceTree = "<group>"; };
@@ -300,6 +309,7 @@
                                7ED95CF31AB9028C008C4574 /* CDVJSON_private.h 
*/,
                                7ED95CF41AB9028C008C4574 /* CDVJSON_private.m 
*/,
                                7ED95CF51AB9028C008C4574 /* CDVPlugin+Private.h 
*/,
+                               90227B4B2D499A1B005DB74E /* 
CDVViewController+Private.h */,
                                7ED95CF61AB9028C008C4574 /* Plugins */,
                        );
                        name = Private;
@@ -309,6 +319,7 @@
                7ED95CF61AB9028C008C4574 /* Plugins */ = {
                        isa = PBXGroup;
                        children = (
+                               90227B502D49A042005DB74E /* 
CDVStatusBarInternal */,
                                4E714D3123F5356700A321AF /* CDVLaunchScreen */,
                                4E23F8F423E16D30006CD852 /* CDVWebViewEngine */,
                                28BFF9111F355A1D00DDF01A /* CDVLogger */,
@@ -349,6 +360,15 @@
                        path = Classes/Public;
                        sourceTree = "<group>";
                };
+               90227B502D49A042005DB74E /* CDVStatusBarInternal */ = {
+                       isa = PBXGroup;
+                       children = (
+                               90227B4E2D49A042005DB74E /* 
CDVStatusBarInternal.h */,
+                               90227B4F2D49A042005DB74E /* 
CDVStatusBarInternal.m */,
+                       );
+                       path = CDVStatusBarInternal;
+                       sourceTree = "<group>";
+               };
                9064EF5E26FAB74200C9D65B /* include */ = {
                        isa = PBXGroup;
                        children = (
@@ -401,6 +421,7 @@
                        buildActionMask = 2147483647;
                        files = (
                                C0C01EB61E3911D50056E6CB /* Cordova.h in 
Headers */,
+                               90227B4C2D499A1B005DB74E /* 
CDVViewController+Private.h in Headers */,
                                C0C01EBB1E39131A0056E6CB /* CDV.h in Headers */,
                                C0C01EBC1E39131A0056E6CB /* CDVAppDelegate.h in 
Headers */,
                                9068B5332C6DFE2000B13532 /* 
CDVSettingsDictionary.h in Headers */,
@@ -432,6 +453,7 @@
                                9052DE8E2150D06B008E83D4 /* 
CDVIntentAndNavigationFilter.h in Headers */,
                                9052DE8F2150D06B008E83D4 /* CDVHandleOpenURL.h 
in Headers */,
                                9047732F2C7A57E900373636 /* 
CDVURLSchemeHandler.h in Headers */,
+                               90227B532D49A042005DB74E /* 
CDVStatusBarInternal.h in Headers */,
                                2FCCEA18247E7366007276A8 /* CDVLaunchScreen.h 
in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
@@ -441,6 +463,7 @@
                        buildActionMask = 2147483647;
                        files = (
                                7ED95D351AB9029B008C4574 /* CDV.h in Headers */,
+                               90227B4D2D499A1B005DB74E /* 
CDVViewController+Private.h in Headers */,
                                7ED95D361AB9029B008C4574 /* CDVAppDelegate.h in 
Headers */,
                                7ED95D381AB9029B008C4574 /* CDVAvailability.h 
in Headers */,
                                9068B5342C6DFE2000B13532 /* 
CDVSettingsDictionary.h in Headers */,
@@ -472,6 +495,7 @@
                                3093E2231B16D6A3003F381A /* 
CDVIntentAndNavigationFilter.h in Headers */,
                                7E7F69B91ABA3692007546F4 /* CDVHandleOpenURL.h 
in Headers */,
                                904773312C7A57E900373636 /* 
CDVURLSchemeHandler.h in Headers */,
+                               90227B512D49A042005DB74E /* 
CDVStatusBarInternal.h in Headers */,
                                4E714D3623F535B500A321AF /* CDVLaunchScreen.h 
in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
@@ -568,6 +592,7 @@
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               90227B542D49A042005DB74E /* 
CDVStatusBarInternal.m in Sources */,
                                9052DE712150D040008E83D4 /* CDVAppDelegate.m in 
Sources */,
                                9052DE722150D040008E83D4 /* 
CDVCommandDelegateImpl.m in Sources */,
                                9052DE732150D040008E83D4 /* CDVCommandQueue.m 
in Sources */,
@@ -600,6 +625,7 @@
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               90227B522D49A042005DB74E /* 
CDVStatusBarInternal.m in Sources */,
                                7ED95D371AB9029B008C4574 /* CDVAppDelegate.m in 
Sources */,
                                7ED95D3C1AB9029B008C4574 /* 
CDVCommandDelegateImpl.m in Sources */,
                                7ED95D3E1AB9029B008C4574 /* CDVCommandQueue.m 
in Sources */,
diff --git a/CordovaLib/include/Cordova/CDVViewController.h 
b/CordovaLib/include/Cordova/CDVViewController.h
index 434a085f..fa934eae 100644
--- a/CordovaLib/include/Cordova/CDVViewController.h
+++ b/CordovaLib/include/Cordova/CDVViewController.h
@@ -187,6 +187,13 @@ NS_ASSUME_NONNULL_BEGIN
  */
 @property (nonatomic, null_resettable, copy) IBInspectable UIColor 
*splashBackgroundColor;
 
+/**
+ The color drawn behind the status bar.
+
+ This can be set in the storyboard file as a view controller attribute.
+ */
+@property (nonatomic, null_resettable, copy) IBInspectable UIColor 
*statusBarBackgroundColor;
+
 - (UIView*)newCordovaViewWithFrame:(CGRect)bounds;
 
 /**
diff --git a/cordova-js-src/platform.js b/cordova-js-src/platform.js
index 83868c81..b3d729f1 100644
--- a/cordova-js-src/platform.js
+++ b/cordova-js-src/platform.js
@@ -34,6 +34,10 @@ module.exports = {
         // see the file under plugin/ios/launchscreen.js
         
require('cordova/modulemapper').clobbers('cordova/plugin/ios/launchscreen', 
'navigator.splashscreen');
 
+        // Attach the internal statusBar utility to window.statusbar
+        // see the file under plugin/ios/statusbar.js
+        
require('cordova/modulemapper').clobbers('cordova/plugin/ios/statusbar', 
'window.statusbar');
+
         require('cordova/channel').onNativeReady.fire();
     }
 };
diff --git a/cordova-js-src/plugin/ios/statusbar.js 
b/cordova-js-src/plugin/ios/statusbar.js
new file mode 100644
index 00000000..8fcc3f6e
--- /dev/null
+++ b/cordova-js-src/plugin/ios/statusbar.js
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+var exec = require('cordova/exec');
+
+var statusBarVisible = true;
+var statusBar = {};
+
+Object.defineProperty(statusBar, 'visible', {
+    configurable: false,
+    enumerable: true,
+    get: function () {
+        if (window.StatusBar) {
+            // Let the CDVStatusBar plugin handle it
+            return window.StatusBar.isVisible;
+        }
+
+        return statusBarVisible;
+    },
+    set: function (value) {
+        if (window.StatusBar) {
+            // Let the CDVStatusBar plugin handle it
+            if (value) {
+                window.StatusBar.show();
+            } else {
+                window.StatusBar.hide();
+            }
+        } else {
+            statusBarVisible = value;
+            exec(null, null, 'StatusBarInternal', 'setVisible', [!!value]);
+        }
+    }
+});
+
+Object.defineProperty(statusBar, 'setBackgroundColor', {
+    configurable: false,
+    enumerable: false,
+    writable: false,
+    value: function (value) {
+        var script = document.querySelector('script[src$="cordova.js"]');
+        script.style.color = value;
+        var rgbStr = window.getComputedStyle(script).getPropertyValue('color');
+
+        if (!rgbStr.match(/^rgb/)) {
+            return;
+        }
+
+        var rgbVals = rgbStr.match(/\d+/g).map(function (v) { return 
parseInt(v, 10); });
+        if (rgbVals.length < 3) {
+            return;
+        }
+
+        if (window.StatusBar) {
+            window.StatusBar.backgroundColorByHexString('#' + 
rgbVals[0].toString(16).padStart(2, '0') + rgbVals[1].toString(16).padStart(2, 
'0') + rgbVals[2].toString(16).padStart(2, '0'));
+        } else {
+            exec(null, null, 'StatusBarInternal', 'setBackgroundColor', 
rgbVals);
+        }
+    }
+});
+
+module.exports = statusBar;
diff --git a/lib/prepare.js b/lib/prepare.js
index 54ca51fe..10e1e06d 100644
--- a/lib/prepare.js
+++ b/lib/prepare.js
@@ -614,6 +614,21 @@ function getSplashScreenBackgroundColorDir (projectRoot, 
platformProjDir) {
     }
 }
 
+/**
+ * Returns the directory for the StatusBarBackgroundColor.colorset asset, or
+ * null if no xcassets exist.
+ *
+ * @param  {string} projectRoot        The project's root directory
+ * @param  {string} platformProjDir    The platform's project directory
+ */
+function getStatusBarBackgroundColorDir (projectRoot, platformProjDir) {
+    if (folderExists(path.join(projectRoot, platformProjDir, 
'Assets.xcassets/'))) {
+        return path.join(platformProjDir, 'Assets.xcassets', 
'StatusBarBackgroundColor.colorset');
+    } else {
+        return null;
+    }
+}
+
 function colorPreferenceToComponents (pref) {
     if (!pref || 
!pref.match(/^(#[0-9A-Fa-f]{3}|(0x|#)([0-9A-Fa-f]{2})?[0-9A-Fa-f]{6})$/)) {
         return {
@@ -668,6 +683,7 @@ function updateBackgroundColor (cordovaProject, locations) {
 
     const pref = cordovaProject.projectConfig.getPreference('BackgroundColor', 
'ios') || '';
     const splashPref = 
cordovaProject.projectConfig.getPreference('SplashScreenBackgroundColor', 
'ios') || pref;
+    const statusBarPref = 
cordovaProject.projectConfig.getPreference('StatusBarBackgroundColor', 'ios') 
|| pref;
 
     const backgroundColorDir = getBackgroundColorDir(cordovaProject.root, 
platformProjDir);
     if (backgroundColorDir) {
@@ -704,6 +720,24 @@ function updateBackgroundColor (cordovaProject, locations) 
{
         fs.writeFileSync(path.join(cordovaProject.root, 
splashBackgroundColorDir, 'Contents.json'),
             JSON.stringify(contentsJSON, null, 2));
     }
+
+    const statusBarBackgroundColorDir = 
getStatusBarBackgroundColorDir(cordovaProject.root, platformProjDir);
+    if (statusBarBackgroundColorDir) {
+        const contentsJSON = {
+            colors: [{
+                idiom: 'universal',
+                color: colorPreferenceToComponents(statusBarPref)
+            }],
+            info: {
+                author: 'Xcode',
+                version: 1
+            }
+        };
+
+        events.emit('verbose', 'Updating Status Bar Background Color color set 
Contents.json');
+        fs.writeFileSync(path.join(cordovaProject.root, 
statusBarBackgroundColorDir, 'Contents.json'),
+            JSON.stringify(contentsJSON, null, 2));
+    }
 }
 
 /**
@@ -740,6 +774,13 @@ function cleanBackgroundColor (projectRoot, projectConfig, 
locations) {
         fs.writeFileSync(path.join(projectRoot, splashBackgroundColorDir, 
'Contents.json'),
             JSON.stringify(contentsJSON, null, 2));
     }
+
+    const statusBarBackgroundColorDir = 
getStatusBarBackgroundColorDir(projectRoot, platformProjDir);
+    if (statusBarBackgroundColorDir) {
+        events.emit('verbose', 'Cleaning Status Bar Background Color color set 
Contents.json');
+        fs.writeFileSync(path.join(projectRoot, statusBarBackgroundColorDir, 
'Contents.json'),
+            JSON.stringify(contentsJSON, null, 2));
+    }
 }
 
 function updateFileResources (cordovaProject, locations) {
diff --git a/templates/cordova/defaults.xml b/templates/cordova/defaults.xml
index e7f2776d..98eafe9a 100644
--- a/templates/cordova/defaults.xml
+++ b/templates/cordova/defaults.xml
@@ -56,5 +56,9 @@
         <param name="ios-package" value="CDVGestureHandler"/>
         <param name="onload" value="true"/>
     </feature>
+    <feature name="StatusBarInternal">
+        <param name="ios-package" value="CDVStatusBarInternal"/>
+        <param name="onload" value="true"/>
+    </feature>
 
 </widget>
diff --git 
a/templates/project/App/Assets.xcassets/StatusBarBackgroundColor.colorset/Contents.json
 
b/templates/project/App/Assets.xcassets/StatusBarBackgroundColor.colorset/Contents.json
new file mode 100644
index 00000000..462830f8
--- /dev/null
+++ 
b/templates/project/App/Assets.xcassets/StatusBarBackgroundColor.colorset/Contents.json
@@ -0,0 +1,15 @@
+{
+  "colors" : [
+    {
+      "color" : {
+        "platform" : "ios",
+        "reference" : "systemBackgroundColor"
+      },
+      "idiom" : "universal"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/templates/project/App/Base.lproj/Main.storyboard 
b/templates/project/App/Base.lproj/Main.storyboard
index 0655267c..3372d5d2 100644
--- a/templates/project/App/Base.lproj/Main.storyboard
+++ b/templates/project/App/Base.lproj/Main.storyboard
@@ -42,6 +42,9 @@
                             <color key="value" 
name="SplashScreenBackgroundColor"/>
                         </userDefinedRuntimeAttribute>
                         <userDefinedRuntimeAttribute type="boolean" 
keyPath="showSplashScreen" value="YES"/>
+                        <userDefinedRuntimeAttribute type="color" 
keyPath="statusBarBackgroundColor">
+                            <color key="value" 
name="StatusBarBackgroundColor"/>
+                        </userDefinedRuntimeAttribute>
                     </userDefinedRuntimeAttributes>
                 </viewController>
                 <placeholder placeholderIdentifier="IBFirstResponder" 
id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
@@ -55,6 +58,9 @@
         <namedColor name="SplashScreenBackgroundColor">
             <color white="1" alpha="1" colorSpace="custom" 
customColorSpace="genericGamma22GrayColorSpace"/>
         </namedColor>
+        <namedColor name="StatusBarBackgroundColor">
+            <color white="1" alpha="1" colorSpace="custom" 
customColorSpace="genericGamma22GrayColorSpace"/>
+        </namedColor>
     </resources>
 </document>
 
diff --git 
a/tests/spec/unit/fixtures/ios-config-xml/App/Assets.xcassets/StatusBarBackgroundColor.colorset/Contents.json
 
b/tests/spec/unit/fixtures/ios-config-xml/App/Assets.xcassets/StatusBarBackgroundColor.colorset/Contents.json
new file mode 100644
index 00000000..462830f8
--- /dev/null
+++ 
b/tests/spec/unit/fixtures/ios-config-xml/App/Assets.xcassets/StatusBarBackgroundColor.colorset/Contents.json
@@ -0,0 +1,15 @@
+{
+  "colors" : [
+    {
+      "color" : {
+        "platform" : "ios",
+        "reference" : "systemBackgroundColor"
+      },
+      "idiom" : "universal"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git 
a/tests/spec/unit/fixtures/ios-config-xml/App/Base.lproj/Main.storyboard 
b/tests/spec/unit/fixtures/ios-config-xml/App/Base.lproj/Main.storyboard
index 0655267c..3372d5d2 100644
--- a/tests/spec/unit/fixtures/ios-config-xml/App/Base.lproj/Main.storyboard
+++ b/tests/spec/unit/fixtures/ios-config-xml/App/Base.lproj/Main.storyboard
@@ -42,6 +42,9 @@
                             <color key="value" 
name="SplashScreenBackgroundColor"/>
                         </userDefinedRuntimeAttribute>
                         <userDefinedRuntimeAttribute type="boolean" 
keyPath="showSplashScreen" value="YES"/>
+                        <userDefinedRuntimeAttribute type="color" 
keyPath="statusBarBackgroundColor">
+                            <color key="value" 
name="StatusBarBackgroundColor"/>
+                        </userDefinedRuntimeAttribute>
                     </userDefinedRuntimeAttributes>
                 </viewController>
                 <placeholder placeholderIdentifier="IBFirstResponder" 
id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
@@ -55,6 +58,9 @@
         <namedColor name="SplashScreenBackgroundColor">
             <color white="1" alpha="1" colorSpace="custom" 
customColorSpace="genericGamma22GrayColorSpace"/>
         </namedColor>
+        <namedColor name="StatusBarBackgroundColor">
+            <color white="1" alpha="1" colorSpace="custom" 
customColorSpace="genericGamma22GrayColorSpace"/>
+        </namedColor>
     </resources>
 </document>
 


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@cordova.apache.org
For additional commands, e-mail: commits-h...@cordova.apache.org


Reply via email to