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 optional compile-time decision for disabling UIWebView #715

Merged
merged 21 commits into from
Nov 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@
#import <Cordova/CDVPlugin.h>
#import <Cordova/CDVWhitelist.h>

#if WK_WEB_VIEW_ONLY
#define CDVWebViewNavigationType int
#else
#define CDVWebViewNavigationType UIWebViewNavigationType
#endif

typedef NS_ENUM(NSInteger, CDVIntentAndNavigationFilterValue) {
CDVIntentAndNavigationFilterValueIntentAllowed,
CDVIntentAndNavigationFilterValueNavigationAllowed,
Expand All @@ -29,6 +35,6 @@ typedef NS_ENUM(NSInteger, CDVIntentAndNavigationFilterValue) {
@interface CDVIntentAndNavigationFilter : CDVPlugin <NSXMLParserDelegate>

+ (CDVIntentAndNavigationFilterValue) filterUrl:(NSURL*)url intentsWhitelist:(CDVWhitelist*)intentsWhitelist navigationsWhitelist:(CDVWhitelist*)navigationsWhitelist;
+ (BOOL)shouldOverrideLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType filterValue:(CDVIntentAndNavigationFilterValue)filterValue;
+ (BOOL)shouldOpenURLRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType;
+ (BOOL)shouldOverrideLoadWithRequest:(NSURLRequest*)request navigationType:(CDVWebViewNavigationType)navigationType filterValue:(CDVIntentAndNavigationFilterValue)filterValue;
+ (BOOL)shouldOpenURLRequest:(NSURLRequest*)request navigationType:(CDVWebViewNavigationType)navigationType;
@end
Original file line number Diff line number Diff line change
Expand Up @@ -75,18 +75,18 @@ + (CDVIntentAndNavigationFilterValue) filterUrl:(NSURL*)url intentsWhitelist:(CD
{
// a URL can only allow-intent OR allow-navigation, if both are specified,
// only allow-navigation is allowed

BOOL allowNavigationsPass = [navigationsWhitelist URLIsAllowed:url logFailure:NO];
BOOL allowIntentPass = [intentsWhitelist URLIsAllowed:url logFailure:NO];

if (allowNavigationsPass && allowIntentPass) {
return CDVIntentAndNavigationFilterValueNavigationAllowed;
} else if (allowNavigationsPass) {
return CDVIntentAndNavigationFilterValueNavigationAllowed;
} else if (allowIntentPass) {
return CDVIntentAndNavigationFilterValueIntentAllowed;
}

return CDVIntentAndNavigationFilterValueNoneAllowed;
}

Expand All @@ -95,22 +95,30 @@ - (CDVIntentAndNavigationFilterValue) filterUrl:(NSURL*)url
return [[self class] filterUrl:url intentsWhitelist:self.allowIntentsWhitelist navigationsWhitelist:self.allowNavigationsWhitelist];
}

+ (BOOL)shouldOpenURLRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
#if WK_WEB_VIEW_ONLY
#define CDVWebViewNavigationTypeLinkClicked 0
#define CDVWebViewNavigationTypeOther 5
#else
#define CDVWebViewNavigationTypeLinkClicked UIWebViewNavigationTypeLinkClicked
#define CDVWebViewNavigationTypeOther UIWebViewNavigationTypeOther
#endif

+ (BOOL)shouldOpenURLRequest:(NSURLRequest*)request navigationType:(CDVWebViewNavigationType)navigationType
{
return (UIWebViewNavigationTypeLinkClicked == navigationType ||
(UIWebViewNavigationTypeOther == navigationType &&
return (CDVWebViewNavigationTypeLinkClicked == navigationType ||
(CDVWebViewNavigationTypeOther == navigationType &&
[[request.mainDocumentURL absoluteString] isEqualToString:[request.URL absoluteString]]
)
);
}

+ (BOOL)shouldOverrideLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType filterValue:(CDVIntentAndNavigationFilterValue)filterValue
+ (BOOL)shouldOverrideLoadWithRequest:(NSURLRequest*)request navigationType:(CDVWebViewNavigationType)navigationType filterValue:(CDVIntentAndNavigationFilterValue)filterValue
{
NSString* allowIntents_whitelistRejectionFormatString = @"ERROR External navigation rejected - <allow-intent> not set for url='%@'";
NSString* allowNavigations_whitelistRejectionFormatString = @"ERROR Internal navigation rejected - <allow-navigation> not set for url='%@'";

NSURL* url = [request URL];

switch (filterValue) {
case CDVIntentAndNavigationFilterValueNavigationAllowed:
return YES;
Expand All @@ -120,21 +128,21 @@ + (BOOL)shouldOverrideLoadWithRequest:(NSURLRequest*)request navigationType:(UIW
if ([[self class] shouldOpenURLRequest:request navigationType:navigationType]){
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
}

// consume the request (i.e. no error) if it wasn't handled above
return NO;
case CDVIntentAndNavigationFilterValueNoneAllowed:
// allow-navigation attempt failed for sure
NSLog(@"%@", [NSString stringWithFormat:allowNavigations_whitelistRejectionFormatString, [url absoluteString]]);
// anchor tag link means it was an allow-intent attempt that failed as well
if (UIWebViewNavigationTypeLinkClicked == navigationType) {
if (CDVWebViewNavigationTypeLinkClicked == navigationType) {
NSLog(@"%@", [NSString stringWithFormat:allowIntents_whitelistRejectionFormatString, [url absoluteString]]);
}
return NO;
}
}

- (BOOL)shouldOverrideLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
- (BOOL)shouldOverrideLoadWithRequest:(NSURLRequest*)request navigationType:(CDVWebViewNavigationType)navigationType
{
return [[self class] shouldOverrideLoadWithRequest:request navigationType:navigationType filterValue:[self filterUrl:request.URL]];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,19 @@ Licensed to the Apache Software Foundation (ASF) under one
@interface CDVLocalStorage ()

@property (nonatomic, readwrite, strong) NSMutableArray* backupInfo; // array of CDVBackupInfo objects
#if !WK_WEB_VIEW_ONLY
@property (nonatomic, readwrite, weak) id <UIWebViewDelegate> webviewDelegate;
#endif

@end

@implementation CDVLocalStorage

#if WK_WEB_VIEW_ONLY
@synthesize backupInfo;
#else
@synthesize backupInfo, webviewDelegate;
#endif

- (void)pluginInitialize
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
under the License.
*/

#if !WK_WEB_VIEW_ONLY

#import <UIKit/UIKit.h>
#import <Cordova/CDVAvailability.h>

Expand All @@ -39,3 +41,5 @@
- (BOOL)request:(NSURLRequest*)newRequest isEqualToRequestAfterStrippingFragments:(NSURLRequest*)originalRequest;

@end

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ Licensed to the Apache Software Foundation (ASF) under one
// TODO: Record order when page is re-navigated before the first navigation finishes.
//

#if !WK_WEB_VIEW_ONLY

#import "CDVUIWebViewDelegate.h"

// #define VerboseLog NSLog
Expand Down Expand Up @@ -256,7 +258,7 @@ - (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)re
NSLog(@"%@", description);
_loadCount = 0;
_state = STATE_WAITING_FOR_LOAD_START;

NSDictionary* errorDictionary = @{NSLocalizedDescriptionKey : description};
NSError* error = [[NSError alloc] initWithDomain:@"CDVUIWebViewDelegate" code:1 userInfo:errorDictionary];
[self webView:webView didFailLoadWithError:error];
Expand Down Expand Up @@ -402,3 +404,5 @@ - (void)webView:(UIWebView*)webView didFailLoadWithError:(NSError*)error
}

@end

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

@interface CDVUIWebViewEngine : CDVPlugin <CDVWebViewEngineProtocol>

#if !WK_WEB_VIEW_ONLY
@property (nonatomic, strong, readonly) id <UIWebViewDelegate> uiWebViewDelegate;
#endif

@end
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ Licensed to the Apache Software Foundation (ASF) under one
under the License.
*/

#if !WK_WEB_VIEW_ONLY

#import "CDVUIWebViewEngine.h"
#import "CDVUIWebViewDelegate.h"
#import "CDVUIWebViewNavigationDelegate.h"
Expand Down Expand Up @@ -200,3 +202,5 @@ - (UIView*)webView
}

@end

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
under the License.
*/

#if !WK_WEB_VIEW_ONLY

#import <UIKit/UIKit.h>
#import "CDVUIWebViewEngine.h"

Expand All @@ -27,3 +29,5 @@
- (instancetype)initWithEnginePlugin:(CDVPlugin*)enginePlugin;

@end

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ Licensed to the Apache Software Foundation (ASF) under one
under the License.
*/

#if !WK_WEB_VIEW_ONLY

#import "CDVUIWebViewNavigationDelegate.h"
#import <Cordova/CDVViewController.h>
#import <Cordova/CDVCommandDelegateImpl.h>
Expand Down Expand Up @@ -94,7 +96,7 @@ - (BOOL)defaultResourcePolicyForURL:(NSURL*)url
if ([url isFileURL]) {
return YES;
}

return NO;
}

Expand All @@ -120,7 +122,7 @@ - (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*
*/
BOOL anyPluginsResponded = NO;
BOOL shouldAllowRequest = NO;

for (NSString* pluginName in vc.pluginObjects) {
CDVPlugin* plugin = [vc.pluginObjects objectForKey:pluginName];
SEL selector = NSSelectorFromString(@"shouldOverrideLoadWithRequest:navigationType:");
Expand All @@ -132,7 +134,7 @@ - (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*
}
}
}

if (anyPluginsResponded) {
return shouldAllowRequest;
}
Expand All @@ -146,8 +148,10 @@ - (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*
} else {
[[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginHandleOpenURLNotification object:url]];
}

return NO;
}

@end

#endif
38 changes: 38 additions & 0 deletions CordovaLib/Classes/Public/CDVUserAgentUtil.m
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,40 @@ Licensed to the Apache Software Foundation (ASF) under one
static NSInteger gCurrentLockToken = 0;
static NSMutableArray* gPendingSetUserAgentBlocks = nil;

#if WK_WEB_VIEW_ONLY
#import <WebKit/WebKit.h>

@interface WKWebView(SynchronousEvaluateJavaScript)
- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;
@end

@implementation WKWebView(SynchronousEvaluateJavaScript)

- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script
{
__block NSString *resultString = nil;
__block BOOL finished = NO;

[self evaluateJavaScript:script completionHandler:^(id result, NSError *error) {
if (error == nil) {
if (result != nil) {
resultString = [NSString stringWithFormat:@"%@", result];
}
} else {
NSLog(@"evaluateJavaScript error : %@", error.localizedDescription);
}
finished = YES;
}];

while (!finished) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
}

return resultString;
}
@end
#endif

@implementation CDVUserAgentUtil

+ (NSString*)originalUserAgent
Expand All @@ -54,7 +88,11 @@ + (NSString*)originalUserAgent
BOOL cachedValueIsOld = ![systemAndLocale isEqualToString:cordovaUserAgentVersion];

if ((gOriginalUserAgent == nil) || cachedValueIsOld) {
#if WK_WEB_VIEW_ONLY
WKWebView* sampleWebView = [[WKWebView alloc] initWithFrame:CGRectZero];
#else
UIWebView* sampleWebView = [[UIWebView alloc] initWithFrame:CGRectZero];
#endif
gOriginalUserAgent = [sampleWebView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"];

[userDefaults setObject:gOriginalUserAgent forKey:kCdvUserAgentKey];
Expand Down
27 changes: 13 additions & 14 deletions CordovaLib/Classes/Public/CDVViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ Licensed to the Apache Software Foundation (ASF) under one
#import <objc/message.h>
#import "CDV.h"
#import "CDVPlugin+Private.h"
#import "CDVUIWebViewDelegate.h"
#import "CDVConfigParser.h"
#import "CDVUserAgentUtil.h"
#import <AVFoundation/AVFoundation.h>
Expand Down Expand Up @@ -343,9 +342,9 @@ - (void)viewDidLoad
}
}
}];

// /////////////////

NSString* bgColorString = [self.settings cordovaSettingForKey:@"BackgroundColor"];
UIColor* bgColor = [self colorFromColorString:bgColorString];
[self.webView setBackgroundColor:bgColor];
Expand Down Expand Up @@ -405,39 +404,39 @@ - (UIColor*)colorFromColorString:(NSString*)colorString
if (!colorString) {
return nil;
}

// Validate format
NSError* error = NULL;
NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:@"^(#[0-9A-F]{3}|(0x|#)([0-9A-F]{2})?[0-9A-F]{6})$" options:NSRegularExpressionCaseInsensitive error:&error];
NSUInteger countMatches = [regex numberOfMatchesInString:colorString options:0 range:NSMakeRange(0, [colorString length])];

if (!countMatches) {
return nil;
}

// #FAB to #FFAABB
if ([colorString hasPrefix:@"#"] && [colorString length] == 4) {
NSString* r = [colorString substringWithRange:NSMakeRange(1, 1)];
NSString* g = [colorString substringWithRange:NSMakeRange(2, 1)];
NSString* b = [colorString substringWithRange:NSMakeRange(3, 1)];
colorString = [NSString stringWithFormat:@"#%@%@%@%@%@%@", r, r, g, g, b, b];
}

// #RRGGBB to 0xRRGGBB
colorString = [colorString stringByReplacingOccurrencesOfString:@"#" withString:@"0x"];

// 0xRRGGBB to 0xAARRGGBB
if ([colorString hasPrefix:@"0x"] && [colorString length] == 8) {
colorString = [@"0xFF" stringByAppendingString:[colorString substringFromIndex:2]];
}

// 0xAARRGGBB to int
unsigned colorValue = 0;
NSScanner *scanner = [NSScanner scannerWithString:colorString];
if (![scanner scanHexInt:&colorValue]) {
return nil;
}

// int to UIColor
return [UIColor colorWithRed:((float)((colorValue & 0x00FF0000) >> 16))/255.0
green:((float)((colorValue & 0x0000FF00) >> 8))/255.0
Expand Down Expand Up @@ -480,9 +479,9 @@ - (BOOL)shouldAutorotate
}

// CB-12098
#if __IPHONE_OS_VERSION_MAX_ALLOWED < 90000
- (NSUInteger)supportedInterfaceOrientations
#else
#if __IPHONE_OS_VERSION_MAX_ALLOWED < 90000
- (NSUInteger)supportedInterfaceOrientations
#else
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
#endif
{
Expand Down Expand Up @@ -757,7 +756,7 @@ - (void)onAppWillEnterForeground:(NSNotification*)notification
[self checkAndReinitViewUrl];
// NSLog(@"%@",@"applicationWillEnterForeground");
[self.commandDelegate evalJs:@"cordova.fireDocumentEvent('resume');"];

if (!IsAtLeastiOSVersion(@"11.0")) {
/** Clipboard fix **/
UIPasteboard* pasteboard = [UIPasteboard generalPasteboard];
Expand Down
Loading