You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by dp...@apache.org on 2021/10/01 07:38:16 UTC

[cordova-ios] branch master updated: feat: add CDVWebViewEngineConfigurationDelegate (#1050)

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

dpogue 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 4c81363  feat: add CDVWebViewEngineConfigurationDelegate (#1050)
4c81363 is described below

commit 4c8136345ae9622646ee7e4eb60ba2b37ad44fbe
Author: Michael Tamburro <61...@users.noreply.github.com>
AuthorDate: Fri Oct 1 03:38:10 2021 -0400

    feat: add CDVWebViewEngineConfigurationDelegate (#1050)
    
    * feat: add CDVWebViewEngineConfigurationDelegate to fully expose WKWebView configuration (#900)
    
    * fix: update the existing tests of the default behavior
    
    * chore: bring back initWithFrame, as existing CDVWebViewEngineProtocol conforming plugins use it
    
    * chore: clean up newCordovaViewWithFrame in order to extract initialization with configuration
    
    * chore: find existing methods that can return nil, and mark them as such for clarity
---
 .../Plugins/CDVWebViewEngine/CDVWebViewEngine.m    | 23 ++++++--
 CordovaLib/Classes/Public/CDVViewController.h      | 35 +++++++++--
 CordovaLib/Classes/Public/CDVViewController.m      | 69 +++++++++++++++-------
 .../Classes/Public/CDVWebViewEngineProtocol.h      | 16 ++++-
 tests/CordovaLibTests/CDVWebViewEngineTest.m       |  2 +-
 5 files changed, 108 insertions(+), 37 deletions(-)

diff --git a/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewEngine.m b/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewEngine.m
index a07bf29..5be8a41 100644
--- a/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewEngine.m
+++ b/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewEngine.m
@@ -45,6 +45,7 @@
 @property (nonatomic, strong) CDVURLSchemeHandler * schemeHandler;
 @property (nonatomic, readwrite) NSString *CDV_ASSETS_URL;
 @property (nonatomic, readwrite) Boolean cdvIsFileScheme;
+@property (nullable, nonatomic, strong, readwrite) WKWebViewConfiguration *configuration;
 
 @end
 
@@ -55,24 +56,36 @@
 
 @synthesize engineWebView = _engineWebView;
 
-- (instancetype)initWithFrame:(CGRect)frame
+- (nullable instancetype)initWithFrame:(CGRect)frame configuration:(nullable WKWebViewConfiguration *)configuration
 {
     self = [super init];
     if (self) {
         if (NSClassFromString(@"WKWebView") == nil) {
             return nil;
         }
-
-        self.engineWebView = [[WKWebView alloc] initWithFrame:frame];
+        
+        self.configuration = configuration;
+        self.engineWebView = configuration ? [[WKWebView alloc] initWithFrame:frame configuration:configuration] : [[WKWebView alloc] initWithFrame:frame];
     }
 
     return self;
 }
 
+- (nullable instancetype)initWithFrame:(CGRect)frame
+{
+    return [self initWithFrame:frame configuration:nil];
+}
+
 - (WKWebViewConfiguration*) createConfigurationFromSettings:(NSDictionary*)settings
 {
-    WKWebViewConfiguration* configuration = [[WKWebViewConfiguration alloc] init];
-    configuration.processPool = [[CDVWebViewProcessPoolFactory sharedFactory] sharedProcessPool];
+    WKWebViewConfiguration* configuration;
+    if (_configuration) {
+        configuration = _configuration;
+    } else {
+        configuration = [[WKWebViewConfiguration alloc] init];
+        configuration.processPool = [[CDVWebViewProcessPoolFactory sharedFactory] sharedProcessPool];
+    }
+    
     if (settings == nil) {
         return configuration;
     }
diff --git a/CordovaLib/Classes/Public/CDVViewController.h b/CordovaLib/Classes/Public/CDVViewController.h
index 81c7128..8e595e3 100644
--- a/CordovaLib/Classes/Public/CDVViewController.h
+++ b/CordovaLib/Classes/Public/CDVViewController.h
@@ -26,6 +26,25 @@
 #import "CDVScreenOrientationDelegate.h"
 #import "CDVPlugin.h"
 #import "CDVWebViewEngineProtocol.h"
+@import WebKit;
+
+@protocol CDVWebViewEngineConfigurationDelegate <NSObject>
+
+@optional
+/// Provides a fully configured WKWebViewConfiguration which will be overriden with
+/// any related settings you add to config.xml (e.g., `PreferredContentMode`).
+/// Useful for more complex configuration, including websiteDataStore.
+///
+/// Example usage:
+///
+/// extension CDVViewController: CDVWebViewEngineConfigurationDelegate {
+///     public func configuration() -> WKWebViewConfiguration {
+///         // return your config here
+///     }
+/// }
+- (nonnull WKWebViewConfiguration*)configuration;
+
+@end
 
 @interface CDVViewController : UIViewController <CDVScreenOrientationDelegate>{
     @protected
@@ -36,10 +55,12 @@
     CDVCommandQueue* _commandQueue;
 }
 
+NS_ASSUME_NONNULL_BEGIN
+
 @property (nonatomic, readonly, weak) IBOutlet UIView* webView;
 @property (nonatomic, readonly, strong) UIView* launchView;
 
-@property (nonatomic, readonly, strong) NSMutableDictionary* pluginObjects;
+@property (nullable, nonatomic, readonly, strong) NSMutableDictionary* pluginObjects;
 @property (nonatomic, readonly, strong) NSDictionary* pluginsMap;
 @property (nonatomic, readonly, strong) NSMutableDictionary* settings;
 @property (nonatomic, readonly, strong) NSXMLParser* configParser;
@@ -53,21 +74,21 @@
 @property (nonatomic, readonly, strong) id <CDVCommandDelegate> commandDelegate;
 
 /**
-	Takes/Gives an array of UIInterfaceOrientation (int) objects
-	ex. UIInterfaceOrientationPortrait
+    Takes/Gives an array of UIInterfaceOrientation (int) objects
+    ex. UIInterfaceOrientationPortrait
 */
 @property (nonatomic, readwrite, strong) NSArray* supportedOrientations;
 
 - (UIView*)newCordovaViewWithFrame:(CGRect)bounds;
 
-- (NSString*)appURLScheme;
-- (NSURL*)errorURL;
+- (nullable NSString*)appURLScheme;
+- (nullable NSURL*)errorURL;
 
 - (UIColor*)colorFromColorString:(NSString*)colorString CDV_DEPRECATED(7.0.0, "Use BackgroundColor in xcassets");
 - (NSArray*)parseInterfaceOrientations:(NSArray*)orientations;
 - (BOOL)supportsOrientation:(UIInterfaceOrientation)orientation;
 
-- (id)getCommandInstance:(NSString*)pluginName;
+- (nullable id)getCommandInstance:(NSString*)pluginName;
 - (void)registerPlugin:(CDVPlugin*)plugin withClassName:(NSString*)className;
 - (void)registerPlugin:(CDVPlugin*)plugin withPluginName:(NSString*)pluginName;
 
@@ -75,4 +96,6 @@
 
 - (void)showLaunchScreen:(BOOL)visible;
 
+NS_ASSUME_NONNULL_END
+
 @end
diff --git a/CordovaLib/Classes/Public/CDVViewController.m b/CordovaLib/Classes/Public/CDVViewController.m
index 50dcf5e..1ebfd1e 100644
--- a/CordovaLib/Classes/Public/CDVViewController.m
+++ b/CordovaLib/Classes/Public/CDVViewController.m
@@ -27,7 +27,7 @@
 #import "CDVCommandDelegateImpl.h"
 #import <Foundation/NSCharacterSet.h>
 
-@interface CDVViewController () { }
+@interface CDVViewController () <CDVWebViewEngineConfigurationDelegate> { }
 
 @property (nonatomic, readwrite, strong) NSXMLParser* configParser;
 @property (nonatomic, readwrite, strong) NSMutableDictionary* settings;
@@ -238,7 +238,7 @@
     return appURL;
 }
 
-- (NSURL*)errorURL
+- (nullable NSURL*)errorURL
 {
     NSURL* errorUrl = nil;
 
@@ -485,36 +485,61 @@
     return [self.supportedOrientations containsObject:@(orientation)];
 }
 
-- (UIView*)newCordovaViewWithFrame:(CGRect)bounds
+/// Retrieves the view from a newwly initialized webViewEngine
+/// @param bounds The bounds with which the webViewEngine will be initialized
+- (nonnull UIView*)newCordovaViewWithFrame:(CGRect)bounds
 {
-    NSString* defaultWebViewEngineClass = [self.settings cordovaSettingForKey:@"CordovaDefaultWebViewEngine"];
-    NSString* webViewEngineClass = [self.settings cordovaSettingForKey:@"CordovaWebViewEngine"];
+    NSString* defaultWebViewEngineClassName = [self.settings cordovaSettingForKey:@"CordovaDefaultWebViewEngine"];
+    NSString* webViewEngineClassName = [self.settings cordovaSettingForKey:@"CordovaWebViewEngine"];
 
-    if (!defaultWebViewEngineClass) {
-        defaultWebViewEngineClass = @"CDVWebViewEngine";
+    if (!defaultWebViewEngineClassName) {
+        defaultWebViewEngineClassName = @"CDVWebViewEngine";
     }
-    if (!webViewEngineClass) {
-        webViewEngineClass = defaultWebViewEngineClass;
+    if (!webViewEngineClassName) {
+        webViewEngineClassName = defaultWebViewEngineClassName;
     }
 
-    // Find webViewEngine
-    if (NSClassFromString(webViewEngineClass)) {
-        self.webViewEngine = [[NSClassFromString(webViewEngineClass) alloc] initWithFrame:bounds];
-        // if a webView engine returns nil (not supported by the current iOS version) or doesn't conform to the protocol, or can't load the request, we use WKWebView
-        if (!self.webViewEngine || ![self.webViewEngine conformsToProtocol:@protocol(CDVWebViewEngineProtocol)] || ![self.webViewEngine canLoadRequest:[NSURLRequest requestWithURL:self.appUrl]]) {
-            self.webViewEngine = [[NSClassFromString(defaultWebViewEngineClass) alloc] initWithFrame:bounds];
+    // Determine if a provided custom web view engine is sufficient
+    id <CDVWebViewEngineProtocol> engine;
+    Class customWebViewEngineClass = NSClassFromString(webViewEngineClassName);
+    if (customWebViewEngineClass) {
+        id customWebViewEngine = [self initWebViewEngine:customWebViewEngineClass bounds:bounds];
+        BOOL customConformsToProtocol = [customWebViewEngine conformsToProtocol:@protocol(CDVWebViewEngineProtocol)];
+        BOOL customCanLoad = [customWebViewEngine canLoadRequest:[NSURLRequest requestWithURL:self.appUrl]];
+        if (customConformsToProtocol && customCanLoad) {
+            engine = customWebViewEngine;
         }
-    } else {
-        self.webViewEngine = [[NSClassFromString(defaultWebViewEngineClass) alloc] initWithFrame:bounds];
     }
-
-    if ([self.webViewEngine isKindOfClass:[CDVPlugin class]]) {
-        [self registerPlugin:(CDVPlugin*)self.webViewEngine withClassName:webViewEngineClass];
+    
+    // Otherwise use the default web view engine
+    if (!engine) {
+        Class defaultWebViewEngineClass = NSClassFromString(defaultWebViewEngineClassName);
+        id defaultWebViewEngine = [self initWebViewEngine:defaultWebViewEngineClass bounds:bounds];
+        NSAssert([defaultWebViewEngine conformsToProtocol:@protocol(CDVWebViewEngineProtocol)],
+                 @"we expected the default web view engine to conform to the CDVWebViewEngineProtocol");
+        engine = defaultWebViewEngine;
+    }
+    
+    if ([engine isKindOfClass:[CDVPlugin class]]) {
+        [self registerPlugin:(CDVPlugin*)engine withClassName:webViewEngineClassName];
     }
 
+    self.webViewEngine = engine;
     return self.webViewEngine.engineWebView;
 }
 
+/// Initialiizes the webViewEngine, with config, if supported and provided
+/// @param engineClass A class that must conform to the `CDVWebViewEngineProtocol`
+/// @param bounds with which the webview will be initialized
+- (id _Nullable) initWebViewEngine:(nonnull Class)engineClass bounds:(CGRect)bounds {
+    WKWebViewConfiguration *config = [self respondsToSelector:@selector(configuration)] ? [self configuration] : nil;
+    if (config && [engineClass respondsToSelector:@selector(initWithFrame:configuration:)]) {
+        return [[engineClass alloc] initWithFrame:bounds configuration:config];
+    } else {
+        return [[engineClass alloc] initWithFrame:bounds];
+    }
+}
+
 - (void)createLaunchView
 {
     CGRect webViewBounds = self.view.bounds;
@@ -608,7 +633,7 @@
 /**
  Returns an instance of a CordovaCommand object, based on its name.  If one exists already, it is returned.
  */
-- (id)getCommandInstance:(NSString*)pluginName
+- (nullable id)getCommandInstance:(NSString*)pluginName
 {
     // first, we try to find the pluginName in the pluginsMap
     // (acts as a allowList as well) if it does not exist, we return nil
@@ -642,7 +667,7 @@
 
 #pragma mark -
 
-- (NSString*)appURLScheme
+- (nullable NSString*)appURLScheme
 {
     NSString* URLScheme = nil;
 
diff --git a/CordovaLib/Classes/Public/CDVWebViewEngineProtocol.h b/CordovaLib/Classes/Public/CDVWebViewEngineProtocol.h
index e6126a4..8a562a7 100644
--- a/CordovaLib/Classes/Public/CDVWebViewEngineProtocol.h
+++ b/CordovaLib/Classes/Public/CDVWebViewEngineProtocol.h
@@ -18,6 +18,7 @@
  */
 
 #import <UIKit/UIKit.h>
+@import WebKit;
 
 #define kCDVWebViewEngineScriptMessageHandlers @"kCDVWebViewEngineScriptMessageHandlers"
 #define kCDVWebViewEngineWKNavigationDelegate @"kCDVWebViewEngineWKNavigationDelegate"
@@ -26,16 +27,25 @@
 
 @protocol CDVWebViewEngineProtocol <NSObject>
 
+NS_ASSUME_NONNULL_BEGIN
+
 @property (nonatomic, strong, readonly) UIView* engineWebView;
 
 - (id)loadRequest:(NSURLRequest*)request;
-- (id)loadHTMLString:(NSString*)string baseURL:(NSURL*)baseURL;
-- (void)evaluateJavaScript:(NSString*)javaScriptString completionHandler:(void (^)(id, NSError*))completionHandler;
+- (id)loadHTMLString:(NSString*)string baseURL:(nullable NSURL*)baseURL;
+- (void)evaluateJavaScript:(NSString*)javaScriptString completionHandler:(void (^_Nullable)(id, NSError*))completionHandler;
 
 - (NSURL*)URL;
 - (BOOL)canLoadRequest:(NSURLRequest*)request;
+- (nullable instancetype)initWithFrame:(CGRect)frame;
+
+/// Convenience Initializer
+/// @param frame The frame for the new web view.
+/// @param configuration The configuration for the new web view.
+- (nullable instancetype)initWithFrame:(CGRect)frame configuration:(nullable WKWebViewConfiguration *)configuration;
 
-- (instancetype)initWithFrame:(CGRect)frame;
 - (void)updateWithInfo:(NSDictionary*)info;
 
+NS_ASSUME_NONNULL_END
+
 @end
diff --git a/tests/CordovaLibTests/CDVWebViewEngineTest.m b/tests/CordovaLibTests/CDVWebViewEngineTest.m
index 0facc70..962d943 100644
--- a/tests/CordovaLibTests/CDVWebViewEngineTest.m
+++ b/tests/CordovaLibTests/CDVWebViewEngineTest.m
@@ -126,7 +126,7 @@
 
 - (void) testConfigurationFromSettings {
     // we need to re-set the plugin from the "setup" to take in the app settings we need
-    self.plugin = [[CDVWebViewEngine alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
+    self.plugin = [[CDVWebViewEngine alloc] initWithFrame:CGRectMake(0, 0, 100, 100) configuration:nil];
     self.viewController = [[CDVViewController alloc] init];
 
     // generate the app settings

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