Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add CDVWebViewEngineConfigurationDelegate #1050

Merged
merged 7 commits into from
Oct 1, 2021
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ @interface CDVWebViewEngine ()
@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

Expand All @@ -55,24 +56,36 @@ @implementation CDVWebViewEngine

@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;
}
Expand Down
25 changes: 24 additions & 1 deletion CordovaLib/Classes/Public/CDVViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -36,9 +55,11 @@
CDVCommandQueue* _commandQueue;
}

NS_ASSUME_NONNULL_BEGIN

@property (nonatomic, readonly, weak) IBOutlet UIView* webView;

@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;
Expand Down Expand Up @@ -74,4 +95,6 @@

- (void)showLaunchScreen:(BOOL)visible;

NS_ASSUME_NONNULL_END

@end
63 changes: 44 additions & 19 deletions CordovaLib/Classes/Public/CDVViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Licensed to the Apache Software Foundation (ASF) under one
#import "CDVCommandDelegateImpl.h"
#import <Foundation/NSCharacterSet.h>

@interface CDVViewController () { }
@interface CDVViewController () <CDVWebViewEngineConfigurationDelegate> { }

@property (nonatomic, readwrite, strong) NSXMLParser* configParser;
@property (nonatomic, readwrite, strong) NSMutableDictionary* settings;
Expand Down Expand Up @@ -485,36 +485,61 @@ - (BOOL)supportsOrientation:(UIInterfaceOrientation)orientation
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 {
if ([engineClass respondsToSelector:@selector(initWithFrame:configuration:)]) {
WKWebViewConfiguration *config = [self respondsToSelector:@selector(configuration)] ? [self configuration] : nil;
return [[engineClass alloc] initWithFrame:bounds configuration:config];
} else {
return [[engineClass alloc] initWithFrame:bounds];
}
}

- (void)createLaunchView
{
CGRect webViewBounds = self.view.bounds;
Expand Down
16 changes: 13 additions & 3 deletions CordovaLib/Classes/Public/CDVWebViewEngineProtocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/

#import <UIKit/UIKit.h>
@import WebKit;

#define kCDVWebViewEngineScriptMessageHandlers @"kCDVWebViewEngineScriptMessageHandlers"
#define kCDVWebViewEngineWKNavigationDelegate @"kCDVWebViewEngineWKNavigationDelegate"
Expand All @@ -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
2 changes: 1 addition & 1 deletion tests/CordovaLibTests/CDVWebViewEngineTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ - (void) testUpdateInfo {

- (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
Expand Down