From e007fafb754d98b47a5315e4e5b53fda17ff5a4b Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Mon, 27 Jan 2025 17:20:36 -0800 Subject: [PATCH] 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. --- .../Private/CDVViewController+Private.h | 28 +++++ .../Plugins/CDVLaunchScreen/CDVLaunchScreen.m | 1 + .../CDVStatusBarInternal.h | 28 +++++ .../CDVStatusBarInternal.m | 46 +++++++ .../CDVWebViewEngine/CDVWebViewEngine.m | 12 ++ CordovaLib/Classes/Public/CDVViewController.m | 112 +++++++++++++++++- .../CordovaLib.xcodeproj/project.pbxproj | 26 ++++ .../include/Cordova/CDVViewController.h | 7 ++ cordova-js-src/platform.js | 4 + cordova-js-src/plugin/ios/statusbar.js | 78 ++++++++++++ templates/cordova/defaults.xml | 4 + 11 files changed, 341 insertions(+), 5 deletions(-) create mode 100644 CordovaLib/Classes/Private/CDVViewController+Private.h create mode 100644 CordovaLib/Classes/Private/Plugins/CDVStatusBarInternal/CDVStatusBarInternal.h create mode 100644 CordovaLib/Classes/Private/Plugins/CDVStatusBarInternal/CDVStatusBarInternal.m create mode 100644 cordova-js-src/plugin/ios/statusbar.js diff --git a/CordovaLib/Classes/Private/CDVViewController+Private.h b/CordovaLib/Classes/Private/CDVViewController+Private.h new file mode 100644 index 0000000000..27a907f968 --- /dev/null +++ b/CordovaLib/Classes/Private/CDVViewController+Private.h @@ -0,0 +1,28 @@ +/* + 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 + +@interface CDVViewController (Private) + +- (void)setStatusBarWebViewColor:(UIColor *)color; + +- (void)showStatusBar:(BOOL)visible; + +@end diff --git a/CordovaLib/Classes/Private/Plugins/CDVLaunchScreen/CDVLaunchScreen.m b/CordovaLib/Classes/Private/Plugins/CDVLaunchScreen/CDVLaunchScreen.m index 8c672277fd..0609d6f4b7 100644 --- a/CordovaLib/Classes/Private/Plugins/CDVLaunchScreen/CDVLaunchScreen.m +++ b/CordovaLib/Classes/Private/Plugins/CDVLaunchScreen/CDVLaunchScreen.m @@ -18,6 +18,7 @@ Licensed to the Apache Software Foundation (ASF) under one */ #import "CDVLaunchScreen.h" +#import "CDVViewController+Private.h" @implementation CDVLaunchScreen diff --git a/CordovaLib/Classes/Private/Plugins/CDVStatusBarInternal/CDVStatusBarInternal.h b/CordovaLib/Classes/Private/Plugins/CDVStatusBarInternal/CDVStatusBarInternal.h new file mode 100644 index 0000000000..08af9c89e9 --- /dev/null +++ b/CordovaLib/Classes/Private/Plugins/CDVStatusBarInternal/CDVStatusBarInternal.h @@ -0,0 +1,28 @@ +/* + 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 + +@interface CDVStatusBarInternal : CDVPlugin + +- (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 0000000000..fc6412bda3 --- /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 d2314c82e4..a39bba23a9 100644 --- a/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewEngine.m +++ b/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewEngine.m @@ -22,6 +22,7 @@ Licensed to the Apache Software Foundation (ASF) under one #import "CDVURLSchemeHandler.h" #import #import +#import "CDVViewController+Private.h" #import @@ -242,6 +243,8 @@ - (void)pluginInitialize 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,15 @@ - (CDVWebViewPermissionGrantType)parsePermissionGrantType:(NSString*)optionStrin return result; } +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context +{ + if ([keyPath isEqualToString:@"themeColor"]) { + if (@available(iOS 15.0, *)) { + [self.viewController setStatusBarWebViewColor:((WKWebView *)self.engineWebView).themeColor]; + } + } +} + #pragma mark - WKScriptMessageHandler implementation - (void)userContentController:(WKUserContentController*)userContentController didReceiveScriptMessage:(WKScriptMessage*)message diff --git a/CordovaLib/Classes/Public/CDVViewController.m b/CordovaLib/Classes/Public/CDVViewController.m index a30671da0a..5932ea82c7 100644 --- a/CordovaLib/Classes/Public/CDVViewController.m +++ b/CordovaLib/Classes/Public/CDVViewController.m @@ -30,23 +30,27 @@ Licensed to the Apache Software Foundation (ASF) under one #import #import "CDVCommandDelegateImpl.h" -static UIColor* defaultBackgroundColor(void) { +static UIColor *defaultBackgroundColor(void) { return UIColor.systemBackgroundColor; } -@interface CDVViewController () { +@interface CDVViewController () { id _webViewEngine; id _commandDelegate; NSMutableDictionary *_pluginObjects; NSMutableDictionary *_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 @@ @implementation CDVViewController @synthesize webViewEngine = _webViewEngine; @synthesize backgroundColor = _backgroundColor; @synthesize splashBackgroundColor = _splashBackgroundColor; +@synthesize statusBarBackgroundColor = _statusBarBackgroundColor; @synthesize settings = _settings; @dynamic webView; @dynamic enumerablePlugins; @@ -168,11 +173,49 @@ - (void)setWwwFolderName:(NSString *)name - (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 @@ - (void)viewDidLoad [self createGapView]; } + // Instantiate the status bar + if (!self.statusBar) { + [self createStatusBarView]; + } + // ///////////////// if ([self.startupPluginNames count] > 0) { @@ -358,6 +406,7 @@ - (void)viewDidLoad [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 @@ - (void)onWebViewPageDidLoad:(NSNotification*)notification { 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 @@ - (void)onWebViewPageDidLoad:(NSNotification*)notification } } +- (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 @@ - (void)createGapView [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 @@ - (void)showSplashScreen:(BOOL)visible }]; } +- (void)showStatusBar:(BOOL)visible +{ + [self.statusBar setAlpha:(visible ? 1 : 0)]; + [self setNeedsStatusBarAppearanceUpdate]; +} + - (void)parseSettingsWithParser:(id )delegate { [CDVConfigParser parseConfigFile:self.configFilePath withDelegate:delegate]; diff --git a/CordovaLib/CordovaLib.xcodeproj/project.pbxproj b/CordovaLib/CordovaLib.xcodeproj/project.pbxproj index 14e66bea44..3b292627d5 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 = ""; }; 7ED95D331AB9029B008C4574 /* NSMutableArray+QueueAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMutableArray+QueueAdditions.h"; sourceTree = ""; }; 7ED95D341AB9029B008C4574 /* NSMutableArray+QueueAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMutableArray+QueueAdditions.m"; sourceTree = ""; }; + 90227B4B2D499A1B005DB74E /* CDVViewController+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "CDVViewController+Private.h"; sourceTree = ""; }; + 90227B4E2D49A042005DB74E /* CDVStatusBarInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CDVStatusBarInternal.h; sourceTree = ""; }; + 90227B4F2D49A042005DB74E /* CDVStatusBarInternal.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CDVStatusBarInternal.m; sourceTree = ""; }; 902B30732C6C5A7E00C6804C /* CordovaLib.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = CordovaLib.docc; sourceTree = ""; }; 902D0BC12AEB64EB009C68E5 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; 9036843B2C6EB06500A3338C /* CDVAllowList.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CDVAllowList.h; sourceTree = ""; }; @@ -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 = ""; }; + 90227B502D49A042005DB74E /* CDVStatusBarInternal */ = { + isa = PBXGroup; + children = ( + 90227B4E2D49A042005DB74E /* CDVStatusBarInternal.h */, + 90227B4F2D49A042005DB74E /* CDVStatusBarInternal.m */, + ); + path = CDVStatusBarInternal; + sourceTree = ""; + }; 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 434a085f41..fa934eae77 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 83868c81b4..b3d729f191 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 0000000000..a8e324c691 --- /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) + rgbVals[1].toString(16) + rgbVals[2].toString(16)); + } else { + exec(null, null, 'StatusBarInternal', 'setBackgroundColor', rgbVals); + } + } +}); + +module.exports = statusBar; diff --git a/templates/cordova/defaults.xml b/templates/cordova/defaults.xml index e7f2776d51..98eafe9afa 100644 --- a/templates/cordova/defaults.xml +++ b/templates/cordova/defaults.xml @@ -56,5 +56,9 @@ + + + +