Skip to content

Commit

Permalink
refactor!: Add CDVSettingsDictionary class (#1458)
Browse files Browse the repository at this point in the history
This will replace the extension category on NSDictionary, which has
always felt a little bit hacky and has caused issues in weird
circumstances due to requiring special build flags to work properly.
  • Loading branch information
dpogue authored Aug 20, 2024
1 parent 98cca7f commit 3a426fd
Show file tree
Hide file tree
Showing 16 changed files with 627 additions and 20 deletions.
2 changes: 1 addition & 1 deletion CordovaLib/Classes/Private/CDVCommandDelegateImpl.m
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ - (void)runInBackground:(void (^)(void))block
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block);
}

- (NSDictionary*)settings
- (CDVSettingsDictionary*)settings
{
return _viewController.settings;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Licensed to the Apache Software Foundation (ASF) under one
#import "CDVWebViewEngine.h"
#import "CDVWebViewUIDelegate.h"
#import <Cordova/CDVWebViewProcessPoolFactory.h>
#import <Cordova/NSDictionary+CordovaPreferences.h>
#import <Cordova/CDVSettingsDictionary.h>
#import <Cordova/CDVURLSchemeHandler.h>

#import <objc/message.h>
Expand Down Expand Up @@ -75,7 +75,7 @@ - (nullable instancetype)initWithFrame:(CGRect)frame
return [self initWithFrame:frame configuration:nil];
}

- (WKWebViewConfiguration*) createConfigurationFromSettings:(NSDictionary*)settings
- (WKWebViewConfiguration*) createConfigurationFromSettings:(CDVSettingsDictionary*)settings
{
WKWebViewConfiguration* configuration;
if (_configuration) {
Expand Down Expand Up @@ -170,7 +170,7 @@ - (void)pluginInitialize
{
// viewController would be available now. we attempt to set all possible delegates to it, by default
CDVViewController* vc = (CDVViewController*)self.viewController;
NSDictionary* settings = self.commandDelegate.settings;
CDVSettingsDictionary* settings = self.commandDelegate.settings;

NSString *scheme = [settings cordovaSettingForKey:@"scheme"];

Expand Down Expand Up @@ -365,7 +365,7 @@ - (BOOL) canLoadRequest:(NSURLRequest*)request
return YES;
}

- (void)updateSettings:(NSDictionary*)settings
- (void)updateSettings:(CDVSettingsDictionary*)settings
{
WKWebView* wkWebView = (WKWebView*)_engineWebView;

Expand Down Expand Up @@ -410,7 +410,7 @@ - (void)updateSettings:(NSDictionary*)settings
- (void)updateWithInfo:(NSDictionary*)info
{
NSDictionary* scriptMessageHandlers = [info objectForKey:kCDVWebViewEngineScriptMessageHandlers];
NSDictionary* settings = [info objectForKey:kCDVWebViewEngineWebViewPreferences];
id settings = [info objectForKey:kCDVWebViewEngineWebViewPreferences];
id navigationDelegate = [info objectForKey:kCDVWebViewEngineWKNavigationDelegate];
id uiDelegate = [info objectForKey:kCDVWebViewEngineWKUIDelegate];

Expand All @@ -435,8 +435,10 @@ - (void)updateWithInfo:(NSDictionary*)info
wkWebView.UIDelegate = uiDelegate;
}

if (settings && [settings isKindOfClass:[NSDictionary class]]) {
if (settings && [settings isKindOfClass:[CDVSettingsDictionary class]]) {
[self updateSettings:settings];
} else if (settings && [settings isKindOfClass:[NSDictionary class]]) {
[self updateSettings:[[CDVSettingsDictionary alloc] initWithDictionary:settings]];
}
}

Expand Down
159 changes: 159 additions & 0 deletions CordovaLib/Classes/Public/CDVSettingsDictionary.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
/*
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 <Cordova/CDVSettingsDictionary.h>

@interface CDVSettingsDictionary () {
// Ideally this should not be mutable, but we've got legacy API that allows
// plugins to set values in here, so this is the world we have to live in
NSMutableDictionary *_dict;
}
@end

@implementation CDVSettingsDictionary

- (instancetype)init
{
return [self initWithDictionary:@{}];
}

- (instancetype)initWithDictionary:(NSDictionary *)dict
{
self = [super init];
if (self != nil) {
if ([dict isKindOfClass:[NSMutableDictionary class]]) {
_dict = (NSMutableDictionary *)dict;
} else {
_dict = [NSMutableDictionary dictionaryWithDictionary:dict];
}
}
return self;
}

- (instancetype)initWithObjects:(const id _Nonnull [ _Nullable ])objects forKeys:(const id <NSCopying> _Nonnull [ _Nullable ])keys count:(NSUInteger)cnt
{
self = [self init];
if (self != nil) {
_dict = [NSMutableDictionary dictionaryWithObjects:objects forKeys:keys count:cnt];
}
return self;
}

- (instancetype)initWithCoder:(NSCoder *)coder
{
NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithCoder:coder];

if (dict != nil) {
self = [self initWithDictionary:dict];
} else {
self = [self initWithDictionary:@{}];
}
return self;
}

+ (BOOL)supportsSecureCoding
{
return YES;
}

- (Class)classForCoder
{
return [self class];
}

- (id)forwardingTargetForSelector:(SEL)selector
{
return _dict;
}

- (NSUInteger)count
{
return _dict.count;
}

- (id)objectForKey:(NSString *)key
{
return [_dict objectForKey:[key lowercaseString]];
}

- (NSEnumerator *)keyEnumerator
{
return [_dict keyEnumerator];
}

- (id)cordovaSettingForKey:(NSString *)key
{
return [self objectForKey:key];
}

- (BOOL)cordovaBoolSettingForKey:(NSString *)key defaultValue:(BOOL)defaultValue
{
BOOL value = defaultValue;

id prefObj = [self objectForKey:key];
if (prefObj == nil) {
#ifdef DEBUG
NSLog(@"The preference key \"%@\" is not defined and will default to \"%@\"", key, (defaultValue ? @"TRUE" : @"FALSE"));
#endif
return value;
}

if ([prefObj isKindOfClass:NSString.class]) {
prefObj = [prefObj lowercaseString];

if ([prefObj isEqualToString:@"true"] || [prefObj isEqualToString:@"1"] || [prefObj isEqualToString:@"yes"]) {
return YES;
} else if ([prefObj isEqualToString:@"false"] || [prefObj isEqualToString:@"0"] || [prefObj isEqualToString:@"no"]) {
return NO;
}
} else if ([prefObj isKindOfClass:NSNumber.class] && ([prefObj isEqual:@YES] || [prefObj isEqual:@NO])) {
return [prefObj isEqual:@YES];
}

return value;
}

- (CGFloat)cordovaFloatSettingForKey:(NSString *)key defaultValue:(CGFloat)defaultValue
{
CGFloat value = defaultValue;

id prefObj = [self objectForKey:key];
if (prefObj != nil) {
value = [prefObj floatValue];
}

return value;
}

- (void)setObject:(id)value forKey:(NSString *)key
{
[_dict setObject:value forKey:[key lowercaseString]];
}

- (void)setObject:(id)value forKeyedSubscript:(NSString *)key
{
[_dict setObject:value forKey:[key lowercaseString]];
}

- (void)setCordovaSetting:(id)value forKey:(NSString *)key
{
[self setObject:value forKey:key];
}

@end
5 changes: 3 additions & 2 deletions CordovaLib/Classes/Public/CDVViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Licensed to the Apache Software Foundation (ASF) under one
#import <Cordova/CDVPlugin.h>
#import "CDVPlugin+Private.h"
#import <Cordova/CDVConfigParser.h>
#import <Cordova/CDVSettingsDictionary.h>
#import <Cordova/NSDictionary+CordovaPreferences.h>
#import "CDVCommandDelegateImpl.h"

Expand All @@ -49,7 +50,7 @@ @interface CDVViewController () <CDVWebViewEngineConfigurationDelegate> {
}

@property (nonatomic, readwrite, strong) NSXMLParser* configParser;
@property (nonatomic, readwrite, strong) NSMutableDictionary* settings;
@property (nonatomic, readwrite, strong) CDVSettingsDictionary* settings;
@property (nonatomic, readwrite, strong) NSMutableDictionary* pluginObjects;
@property (nonatomic, readwrite, strong) NSMutableArray* startupPluginNames;
@property (nonatomic, readwrite, strong) NSDictionary* pluginsMap;
Expand Down Expand Up @@ -178,7 +179,7 @@ - (void)loadSettings
// Get the plugin dictionary, allowList and settings from the delegate.
self.pluginsMap = delegate.pluginsDict;
self.startupPluginNames = delegate.startupPluginNames;
self.settings = delegate.settings;
self.settings = [[CDVSettingsDictionary alloc] initWithDictionary:delegate.settings];

// And the start folder/page.
if(self.wwwFolderName == nil){
Expand Down
2 changes: 2 additions & 0 deletions CordovaLib/Classes/Public/NSDictionary+CordovaPreferences.m
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ Licensed to the Apache Software Foundation (ASF) under one

@import Foundation;

#define __CORDOVA_SILENCE_HEADER_DEPRECATIONS
#import <Cordova/NSDictionary+CordovaPreferences.h>
#undef __CORDOVA_SILENCE_HEADER_DEPRECATIONS

@implementation NSDictionary (CordovaPreferences)

Expand Down
15 changes: 15 additions & 0 deletions CordovaLib/CordovaLib.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@
9052DE8E2150D06B008E83D4 /* CDVIntentAndNavigationFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 3093E2211B16D6A3003F381A /* CDVIntentAndNavigationFilter.h */; };
9052DE8F2150D06B008E83D4 /* CDVHandleOpenURL.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95CF81AB9028C008C4574 /* CDVHandleOpenURL.h */; };
9059F51C26F2CE2400B3B2B7 /* CDVURLSchemeHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F4D42BA23F218BA00501999 /* CDVURLSchemeHandler.h */; settings = {ATTRIBUTES = (Public, ); }; };
9068B5332C6DFE2000B13532 /* CDVSettingsDictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = 9068B5322C6DFE2000B13532 /* CDVSettingsDictionary.h */; settings = {ATTRIBUTES = (Public, ); }; };
9068B5342C6DFE2000B13532 /* CDVSettingsDictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = 9068B5322C6DFE2000B13532 /* CDVSettingsDictionary.h */; settings = {ATTRIBUTES = (Public, ); }; };
9068B5362C6E007400B13532 /* CDVSettingsDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = 9068B5352C6E007400B13532 /* CDVSettingsDictionary.m */; };
9068B5372C6E007400B13532 /* CDVSettingsDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = 9068B5352C6E007400B13532 /* CDVSettingsDictionary.m */; };
90B382512AEB72DD00F3F4D7 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 902D0BC12AEB64EB009C68E5 /* PrivacyInfo.xcprivacy */; };
90DE61742B8F11D300810C2E /* Cordova.h in Headers */ = {isa = PBXBuildFile; fileRef = C0C01EB41E3911D50056E6CB /* Cordova.h */; settings = {ATTRIBUTES = (Public, ); }; };
A3B082D41BB15CEA00D8DC35 /* CDVGestureHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = A3B082D21BB15CEA00D8DC35 /* CDVGestureHandler.h */; };
Expand Down Expand Up @@ -193,6 +197,8 @@
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>"; };
9036843C2C6EB06500A3338C /* CDVAllowList.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CDVAllowList.m; sourceTree = "<group>"; };
9068B5322C6DFE2000B13532 /* CDVSettingsDictionary.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CDVSettingsDictionary.h; sourceTree = "<group>"; };
9068B5352C6E007400B13532 /* CDVSettingsDictionary.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CDVSettingsDictionary.m; sourceTree = "<group>"; };
A3B082D21BB15CEA00D8DC35 /* CDVGestureHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVGestureHandler.h; sourceTree = "<group>"; };
A3B082D31BB15CEA00D8DC35 /* CDVGestureHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVGestureHandler.m; sourceTree = "<group>"; };
C0C01EB21E3911D50056E6CB /* Cordova.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Cordova.framework; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -326,6 +332,7 @@
7ED95D1E1AB9029B008C4574 /* CDVPlugin+Resources.m */,
7ED95D201AB9029B008C4574 /* CDVPlugin.m */,
7ED95D221AB9029B008C4574 /* CDVPluginResult.m */,
9068B5352C6E007400B13532 /* CDVSettingsDictionary.m */,
7ED95D251AB9029B008C4574 /* CDVTimer.m */,
4E23F8F523E16E96006CD852 /* CDVWebViewProcessPoolFactory.m */,
7ED95D2B1AB9029B008C4574 /* CDVViewController.m */,
Expand Down Expand Up @@ -361,6 +368,7 @@
7ED95D1F1AB9029B008C4574 /* CDVPlugin.h */,
7ED95D211AB9029B008C4574 /* CDVPluginResult.h */,
7ED95D231AB9029B008C4574 /* CDVScreenOrientationDelegate.h */,
9068B5322C6DFE2000B13532 /* CDVSettingsDictionary.h */,
7ED95D241AB9029B008C4574 /* CDVTimer.h */,
7ED95D2A1AB9029B008C4574 /* CDVViewController.h */,
4E23F8F923E16E96006CD852 /* CDVWebViewProcessPoolFactory.h */,
Expand Down Expand Up @@ -391,6 +399,7 @@
C0C01EB61E3911D50056E6CB /* Cordova.h in Headers */,
C0C01EBB1E39131A0056E6CB /* CDV.h in Headers */,
C0C01EBC1E39131A0056E6CB /* CDVAppDelegate.h in Headers */,
9068B5332C6DFE2000B13532 /* CDVSettingsDictionary.h in Headers */,
C0C01EBD1E39131A0056E6CB /* CDVAvailability.h in Headers */,
C0C01EBE1E39131A0056E6CB /* CDVAvailabilityDeprecated.h in Headers */,
C0C01EBF1E39131A0056E6CB /* CDVCommandDelegate.h in Headers */,
Expand Down Expand Up @@ -430,6 +439,7 @@
7ED95D351AB9029B008C4574 /* CDV.h in Headers */,
7ED95D361AB9029B008C4574 /* CDVAppDelegate.h in Headers */,
7ED95D381AB9029B008C4574 /* CDVAvailability.h in Headers */,
9068B5342C6DFE2000B13532 /* CDVSettingsDictionary.h in Headers */,
7ED95D391AB9029B008C4574 /* CDVAvailabilityDeprecated.h in Headers */,
7ED95D3A1AB9029B008C4574 /* CDVCommandDelegate.h in Headers */,
7ED95D3B1AB9029B008C4574 /* CDVCommandDelegateImpl.h in Headers */,
Expand Down Expand Up @@ -506,6 +516,7 @@
0867D690FE84028FC02AAC07 /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1010;
TargetAttributes = {
C0C01EB11E3911D50056E6CB = {
Expand Down Expand Up @@ -559,6 +570,7 @@
9052DE742150D040008E83D4 /* CDVConfigParser.m in Sources */,
9052DE752150D040008E83D4 /* CDVInvokedUrlCommand.m in Sources */,
9052DE762150D040008E83D4 /* CDVPlugin+Resources.m in Sources */,
9068B5362C6E007400B13532 /* CDVSettingsDictionary.m in Sources */,
9052DE772150D040008E83D4 /* CDVPlugin.m in Sources */,
9052DE782150D040008E83D4 /* CDVPluginResult.m in Sources */,
9036843F2C6EB06500A3338C /* CDVAllowList.m in Sources */,
Expand Down Expand Up @@ -589,6 +601,7 @@
7ED95D401AB9029B008C4574 /* CDVConfigParser.m in Sources */,
7ED95D421AB9029B008C4574 /* CDVInvokedUrlCommand.m in Sources */,
7ED95D441AB9029B008C4574 /* CDVPlugin+Resources.m in Sources */,
9068B5372C6E007400B13532 /* CDVSettingsDictionary.m in Sources */,
2F4D42BD23F218BA00501999 /* CDVURLSchemeHandler.m in Sources */,
7ED95D461AB9029B008C4574 /* CDVPlugin.m in Sources */,
9036843E2C6EB06500A3338C /* CDVAllowList.m in Sources */,
Expand Down Expand Up @@ -638,6 +651,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
Expand Down Expand Up @@ -708,6 +722,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
Expand Down
5 changes: 5 additions & 0 deletions CordovaLib/include/Cordova/CDV.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
under the License.
*/

#define __CORDOVA_SILENCE_HEADER_DEPRECATIONS

#import <Cordova/CDVAvailability.h>
#import <Cordova/CDVAvailabilityDeprecated.h>
#import <Cordova/CDVAppDelegate.h>
Expand All @@ -28,10 +30,13 @@
#import <Cordova/CDVConfigParser.h>
#import <Cordova/CDVInvokedUrlCommand.h>
#import <Cordova/CDVPlugin+Resources.h>
#import <Cordova/CDVSettingsDictionary.h>
#import <Cordova/CDVWebViewEngineProtocol.h>
#import <Cordova/CDVWebViewProcessPoolFactory.h>
#import <Cordova/NSDictionary+CordovaPreferences.h>
#import <Cordova/NSMutableArray+QueueAdditions.h>
#import <Cordova/CDVScreenOrientationDelegate.h>
#import <Cordova/CDVTimer.h>
#import <Cordova/CDVURLSchemeHandler.h>

#undef __CORDOVA_SILENCE_HEADER_DEPRECATIONS
3 changes: 2 additions & 1 deletion CordovaLib/include/Cordova/CDVCommandDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@

@class CDVPlugin;
@class CDVPluginResult;
@class CDVSettingsDictionary;

typedef NSURL* (^ UrlTransformerBlock)(NSURL*);

@protocol CDVCommandDelegate <NSObject>

@property (nonatomic, readonly) NSDictionary* settings;
@property (nonatomic, readonly) CDVSettingsDictionary* settings;
@property (nonatomic, copy) UrlTransformerBlock urlTransformer;

- (NSString*)pathForResource:(NSString*)resourcepath;
Expand Down
1 change: 1 addition & 0 deletions CordovaLib/include/Cordova/CDVPlugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#import <Cordova/CDVPluginResult.h>
#import <Cordova/NSMutableArray+QueueAdditions.h>
#import <Cordova/CDVCommandDelegate.h>
#import <Cordova/CDVSettingsDictionary.h>
#import <Cordova/CDVViewController.h>
#import <Cordova/CDVWebViewEngineProtocol.h>

Expand Down
Loading

0 comments on commit 3a426fd

Please sign in to comment.