From 6c55e6172c80386cb0150e7cbc48317ed8c32e5b Mon Sep 17 00:00:00 2001 From: jcesarmobile Date: Thu, 5 Mar 2020 15:51:31 +0100 Subject: [PATCH] breaking(ios): remove UIWebView (#635) --- README.md | 11 +- plugin.xml | 13 - src/ios/CDVInAppBrowser.h | 36 - src/ios/CDVInAppBrowser.m | 172 ----- src/ios/CDVInAppBrowserOptions.h | 3 - src/ios/CDVInAppBrowserOptions.m | 3 - src/ios/CDVUIInAppBrowser.h | 95 --- src/ios/CDVUIInAppBrowser.m | 1131 ------------------------------ src/ios/CDVWKInAppBrowser.h | 6 +- src/ios/CDVWKInAppBrowser.m | 83 +-- tests/tests.js | 27 +- 11 files changed, 28 insertions(+), 1552 deletions(-) delete mode 100644 src/ios/CDVInAppBrowser.h delete mode 100644 src/ios/CDVInAppBrowser.m delete mode 100644 src/ios/CDVUIInAppBrowser.h delete mode 100644 src/ios/CDVUIInAppBrowser.m diff --git a/README.md b/README.md index 893eefa..aa5da3d 100644 --- a/README.md +++ b/README.md @@ -131,7 +131,6 @@ instance, or the system browser. iOS supports these additional options: - - __usewkwebview__: set to `yes` to use WKWebView engine for the InappBrowser. Omit or set to `no` (default) to use UIWebView. Note: Using `usewkwebview=yes` requires that a WKWebView engine plugin be installed in the Cordova project (e.g. [cordova-plugin-wkwebview-engine](https://github.com/apache/cordova-plugin-wkwebview-engine) or [cordova-plugin-ionic-webview](https://github.com/ionic-team/cordova-plugin-ionic-webview)). - __hidden__: set to `yes` to create the browser and load the page, but not show it. The loadstop event fires when loading is complete. Omit or set to `no` (default) to have the browser open and load normally. - __beforeload__: set to enable the `beforeload` event to modify which pages are actually loaded in the browser. Accepted values are `get` to intercept only GET requests, `post` to intercept on POST requests or `yes` to intercept both GET & POST requests. Note that POST requests are not currently supported and will be ignored (if you set `beforeload=post` it will raise an error). - __clearcache__: set to `yes` to have the browser's cookie cache cleared before the new window is opened @@ -139,18 +138,16 @@ instance, or the system browser. - __cleardata__: set to `yes` to have the browser's entire local storage cleared (cookies, HTML5 local storage, IndexedDB, etc.) before the new window is opened - __closebuttoncolor__: set as a valid hex color string, for example: `#00ff00`, to change from the default __Done__ button's color. Only applicable if toolbar is not disabled. - __closebuttoncaption__: set to a string to use as the __Done__ button's caption. Note that you need to localize this value yourself. - - __disallowoverscroll__: Set to `yes` or `no` (default is `no`). Turns on/off the UIWebViewBounce property. + - __disallowoverscroll__: Set to `yes` or `no` (default is `no`). Turns on/off the the bounce of the WKWebView's UIScrollView. - __hidenavigationbuttons__: set to `yes` or `no` to turn the toolbar navigation buttons on or off (defaults to `no`). Only applicable if toolbar is not disabled. - __navigationbuttoncolor__: set as a valid hex color string, for example: `#00ff00`, to change from the default color. Only applicable if navigation buttons are visible. - __toolbar__: set to `yes` or `no` to turn the toolbar on or off for the InAppBrowser (defaults to `yes`) - __toolbarcolor__: set as a valid hex color string, for example: `#00ff00`, to change from the default color of the toolbar. Only applicable if toolbar is not disabled. - __toolbartranslucent__: set to `yes` or `no` to make the toolbar translucent(semi-transparent) (defaults to `yes`). Only applicable if toolbar is not disabled. - __lefttoright__: Set to `yes` to swap positions of the navigation buttons and the close button. Specifically, close button goes to the right and navigation buttons to the left. - - __enableViewportScale__: Set to `yes` or `no` to prevent viewport scaling through a meta tag (defaults to `no`). Only applicable to UIWebView (`usewkwebview=no`) and WKWebView (`usewkwebview=yes`) on iOS 10+. - - __mediaPlaybackRequiresUserAction__: Set to `yes` to prevent HTML5 audio or video from autoplaying (defaults to `no`). Applicable to UIWebView (`usewkwebview=no`) and WKWebView (`usewkwebview=yes`). - - __allowInlineMediaPlayback__: Set to `yes` or `no` to allow in-line HTML5 media playback, displaying within the browser window rather than a device-specific playback interface. The HTML's `video` element must also include the `webkit-playsinline` attribute (defaults to `no`). Applicable to UIWebView (`usewkwebview=no`) and WKWebView (`usewkwebview=yes`). - - __keyboardDisplayRequiresUserAction__: Set to `yes` or `no` to open the keyboard when form elements receive focus via JavaScript's `focus()` call (defaults to `yes`). Only applicable to UIWebView (`usewkwebview=no`). - - __suppressesIncrementalRendering__: Set to `yes` or `no` to wait until all new view content is received before being rendered (defaults to `no`). Only applicable to UIWebView (`usewkwebview=no`). + - __enableViewportScale__: Set to `yes` or `no` to prevent viewport scaling through a meta tag (defaults to `no`). + - __mediaPlaybackRequiresUserAction__: Set to `yes` to prevent HTML5 audio or video from autoplaying (defaults to `no`). + - __allowInlineMediaPlayback__: Set to `yes` or `no` to allow in-line HTML5 media playback, displaying within the browser window rather than a device-specific playback interface. The HTML's `video` element must also include the `webkit-playsinline` attribute (defaults to `no`). - __presentationstyle__: Set to `pagesheet`, `formsheet` or `fullscreen` to set the [presentation style](http://developer.apple.com/library/ios/documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html#//apple_ref/occ/instp/UIViewController/modalPresentationStyle) (defaults to `fullscreen`). - __transitionstyle__: Set to `fliphorizontal`, `crossdissolve` or `coververtical` to set the [transition style](http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html#//apple_ref/occ/instp/UIViewController/modalTransitionStyle) (defaults to `coververtical`). - __toolbarposition__: Set to `top` or `bottom` (default is `bottom`). Causes the toolbar to be at the top or bottom of the window. diff --git a/plugin.xml b/plugin.xml index 92cd4bf..b3e3aac 100644 --- a/plugin.xml +++ b/plugin.xml @@ -75,27 +75,14 @@ - - - - - - - - - - - - - diff --git a/src/ios/CDVInAppBrowser.h b/src/ios/CDVInAppBrowser.h deleted file mode 100644 index 2ca6704..0000000 --- a/src/ios/CDVInAppBrowser.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - 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 -#import - -@interface CDVInAppBrowser : CDVPlugin {} - -@property (nonatomic, assign) BOOL wkwebviewavailable; -@property (nonatomic, assign) BOOL usewkwebview; - -- (void)open:(CDVInvokedUrlCommand*)command; -- (void)close:(CDVInvokedUrlCommand*)command; -- (void)injectScriptCode:(CDVInvokedUrlCommand*)command; -- (void)show:(CDVInvokedUrlCommand*)command; -- (void)hide:(CDVInvokedUrlCommand*)command; -- (void)loadAfterBeforeload:(CDVInvokedUrlCommand*)command; - -@end - diff --git a/src/ios/CDVInAppBrowser.m b/src/ios/CDVInAppBrowser.m deleted file mode 100644 index 6f30149..0000000 --- a/src/ios/CDVInAppBrowser.m +++ /dev/null @@ -1,172 +0,0 @@ -/* - 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 "CDVInAppBrowser.h" -#import "CDVInAppBrowserOptions.h" -#if !WK_WEB_VIEW_ONLY -#import "CDVUIInAppBrowser.h" -#endif -#import "CDVWKInAppBrowser.h" -#import - - -#pragma mark CDVInAppBrowser - -@implementation CDVInAppBrowser - -- (void)pluginInitialize -{ - // default values - self.usewkwebview = NO; - -#if __has_include("CDVWKWebViewEngine.h") - self.wkwebviewavailable = YES; -#else - self.wkwebviewavailable = NO; -#endif -} - -- (void)open:(CDVInvokedUrlCommand*)command -{ - NSString* options = [command argumentAtIndex:2 withDefault:@"" andClass:[NSString class]]; - CDVInAppBrowserOptions* browserOptions = [CDVInAppBrowserOptions parseOptions:options]; - if(browserOptions.usewkwebview && !self.wkwebviewavailable){ - [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:@{@"type":@"loaderror", @"message": @"usewkwebview option specified but but no plugin that supplies a WKWebView engine is present"}] callbackId:command.callbackId]; - return; - } - self.usewkwebview = browserOptions.usewkwebview; - #if WK_WEB_VIEW_ONLY - [[CDVWKInAppBrowser getInstance] open:command]; - #else - if(self.usewkwebview){ - [[CDVWKInAppBrowser getInstance] open:command]; - }else{ - [[CDVUIInAppBrowser getInstance] open:command]; - } - #endif -} - -- (void)close:(CDVInvokedUrlCommand*)command -{ - #if WK_WEB_VIEW_ONLY - [[CDVWKInAppBrowser getInstance] close:command]; - #else - if(self.usewkwebview){ - [[CDVWKInAppBrowser getInstance] close:command]; - }else{ - [[CDVUIInAppBrowser getInstance] close:command]; - } - #endif -} - - -- (void)show:(CDVInvokedUrlCommand*)command -{ - #if WK_WEB_VIEW_ONLY - [[CDVWKInAppBrowser getInstance] show:command]; - #else - if(self.usewkwebview){ - [[CDVWKInAppBrowser getInstance] show:command]; - }else{ - [[CDVUIInAppBrowser getInstance] show:command]; - } - #endif -} - -- (void)hide:(CDVInvokedUrlCommand*)command -{ - #if WK_WEB_VIEW_ONLY - [[CDVWKInAppBrowser getInstance] hide:command]; - #else - if(self.usewkwebview){ - [[CDVWKInAppBrowser getInstance] hide:command]; - }else{ - [[CDVUIInAppBrowser getInstance] hide:command]; - } - #endif -} - - -- (void)injectScriptCode:(CDVInvokedUrlCommand*)command -{ - #if WK_WEB_VIEW_ONLY - [[CDVWKInAppBrowser getInstance] injectScriptCode:command]; - #else - if(self.usewkwebview){ - [[CDVWKInAppBrowser getInstance] injectScriptCode:command]; - }else{ - [[CDVUIInAppBrowser getInstance] injectScriptCode:command]; - } - #endif -} - -- (void)injectScriptFile:(CDVInvokedUrlCommand*)command -{ - #if WK_WEB_VIEW_ONLY - [[CDVWKInAppBrowser getInstance] injectScriptFile:command]; - #else - if(self.usewkwebview){ - [[CDVWKInAppBrowser getInstance] injectScriptFile:command]; - }else{ - [[CDVUIInAppBrowser getInstance] injectScriptFile:command]; - } - #endif -} - -- (void)injectStyleCode:(CDVInvokedUrlCommand*)command -{ - #if WK_WEB_VIEW_ONLY - [[CDVWKInAppBrowser getInstance] injectStyleCode:command]; - #else - if(self.usewkwebview){ - [[CDVWKInAppBrowser getInstance] injectStyleCode:command]; - }else{ - [[CDVUIInAppBrowser getInstance] injectStyleCode:command]; - } - #endif -} - -- (void)injectStyleFile:(CDVInvokedUrlCommand*)command -{ - #if WK_WEB_VIEW_ONLY - [[CDVWKInAppBrowser getInstance] injectStyleFile:command]; - #else - if(self.usewkwebview){ - [[CDVWKInAppBrowser getInstance] injectStyleFile:command]; - }else{ - [[CDVUIInAppBrowser getInstance] injectStyleFile:command]; - } - #endif -} - -- (void)loadAfterBeforeload:(CDVInvokedUrlCommand*)command -{ - #if WK_WEB_VIEW_ONLY - [[CDVWKInAppBrowser getInstance] loadAfterBeforeload:command]; - #else - if(self.usewkwebview){ - [[CDVWKInAppBrowser getInstance] loadAfterBeforeload:command]; - }else{ - [[CDVUIInAppBrowser getInstance] loadAfterBeforeload:command]; - } - #endif -} - - -@end \ No newline at end of file diff --git a/src/ios/CDVInAppBrowserOptions.h b/src/ios/CDVInAppBrowserOptions.h index d9f46bf..c1c9fa5 100644 --- a/src/ios/CDVInAppBrowserOptions.h +++ b/src/ios/CDVInAppBrowserOptions.h @@ -20,7 +20,6 @@ @interface CDVInAppBrowserOptions : NSObject {} -@property (nonatomic, assign) BOOL usewkwebview; @property (nonatomic, assign) BOOL location; @property (nonatomic, assign) BOOL toolbar; @property (nonatomic, copy) NSString* closebuttoncaption; @@ -42,8 +41,6 @@ @property (nonatomic, assign) BOOL enableviewportscale; @property (nonatomic, assign) BOOL mediaplaybackrequiresuseraction; @property (nonatomic, assign) BOOL allowinlinemediaplayback; -@property (nonatomic, assign) BOOL keyboarddisplayrequiresuseraction; -@property (nonatomic, assign) BOOL suppressesincrementalrendering; @property (nonatomic, assign) BOOL hidden; @property (nonatomic, assign) BOOL disallowoverscroll; @property (nonatomic, copy) NSString* beforeload; diff --git a/src/ios/CDVInAppBrowserOptions.m b/src/ios/CDVInAppBrowserOptions.m index 4e62539..e20d1a8 100644 --- a/src/ios/CDVInAppBrowserOptions.m +++ b/src/ios/CDVInAppBrowserOptions.m @@ -25,7 +25,6 @@ { if (self = [super init]) { // default values - self.usewkwebview = NO; self.location = YES; self.toolbar = YES; self.closebuttoncaption = nil; @@ -38,8 +37,6 @@ self.enableviewportscale = NO; self.mediaplaybackrequiresuseraction = NO; self.allowinlinemediaplayback = NO; - self.keyboarddisplayrequiresuseraction = YES; - self.suppressesincrementalrendering = NO; self.hidden = NO; self.disallowoverscroll = NO; self.hidenavigationbuttons = NO; diff --git a/src/ios/CDVUIInAppBrowser.h b/src/ios/CDVUIInAppBrowser.h deleted file mode 100644 index d533b83..0000000 --- a/src/ios/CDVUIInAppBrowser.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - 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. - */ - -#if !WK_WEB_VIEW_ONLY - -#import -#import -#import -#import "CDVInAppBrowserOptions.h" -#import "CDVInAppBrowserNavigationController.h" - -#ifdef __CORDOVA_4_0_0 - #import -#else - #import -#endif - -@class CDVUIInAppBrowserViewController; - -@interface CDVUIInAppBrowser : CDVPlugin { - UIWindow * tmpWindow; - - @private - NSString* _beforeload; - BOOL _waitForBeforeload; -} - -@property (nonatomic, retain) CDVUIInAppBrowserViewController* inAppBrowserViewController; -@property (nonatomic, copy) NSString* callbackId; -@property (nonatomic, copy) NSRegularExpression *callbackIdPattern; - -+ (id) getInstance; -- (void)open:(CDVInvokedUrlCommand*)command; -- (void)close:(CDVInvokedUrlCommand*)command; -- (void)injectScriptCode:(CDVInvokedUrlCommand*)command; -- (void)show:(CDVInvokedUrlCommand*)command; -- (void)hide:(CDVInvokedUrlCommand*)command; -- (void)loadAfterBeforeload:(CDVInvokedUrlCommand*)command; - -@end - -@interface CDVUIInAppBrowserViewController : UIViewController { - @private - NSString* _userAgent; - NSString* _prevUserAgent; - NSInteger _userAgentLockToken; - CDVInAppBrowserOptions *_browserOptions; - -#ifdef __CORDOVA_4_0_0 - CDVUIWebViewDelegate* _webViewDelegate; -#else - CDVWebViewDelegate* _webViewDelegate; -#endif - -} - -@property (nonatomic, strong) IBOutlet UIWebView* webView; -@property (nonatomic, strong) IBOutlet UIBarButtonItem* closeButton; -@property (nonatomic, strong) IBOutlet UILabel* addressLabel; -@property (nonatomic, strong) IBOutlet UIBarButtonItem* backButton; -@property (nonatomic, strong) IBOutlet UIBarButtonItem* forwardButton; -@property (nonatomic, strong) IBOutlet UIActivityIndicatorView* spinner; -@property (nonatomic, strong) IBOutlet UIToolbar* toolbar; - -@property (nonatomic, weak) id orientationDelegate; -@property (nonatomic, weak) CDVUIInAppBrowser* navigationDelegate; -@property (nonatomic) NSURL* currentURL; - -- (void)close; -- (void)navigateTo:(NSURL*)url; -- (void)showLocationBar:(BOOL)show; -- (void)showToolBar:(BOOL)show : (NSString *) toolbarPosition; -- (void)setCloseButtonTitle:(NSString*)title : (NSString*) colorString : (int) buttonIndex; - -- (id)initWithUserAgent:(NSString*)userAgent prevUserAgent:(NSString*)prevUserAgent browserOptions: (CDVInAppBrowserOptions*) browserOptions; - -@end - -#endif \ No newline at end of file diff --git a/src/ios/CDVUIInAppBrowser.m b/src/ios/CDVUIInAppBrowser.m deleted file mode 100644 index 36c3b3e..0000000 --- a/src/ios/CDVUIInAppBrowser.m +++ /dev/null @@ -1,1131 +0,0 @@ -/* - 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. - */ - -#if !WK_WEB_VIEW_ONLY - -#import "CDVUIInAppBrowser.h" -#import -#import - -#define kInAppBrowserTargetSelf @"_self" -#define kInAppBrowserTargetSystem @"_system" -#define kInAppBrowserTargetBlank @"_blank" - -#define kInAppBrowserToolbarBarPositionBottom @"bottom" -#define kInAppBrowserToolbarBarPositionTop @"top" - -#define TOOLBAR_HEIGHT 44.0 -#define STATUSBAR_HEIGHT 20.0 -#define LOCATIONBAR_HEIGHT 21.0 -#define FOOTER_HEIGHT ((TOOLBAR_HEIGHT) + (LOCATIONBAR_HEIGHT)) - -#pragma mark CDVUIInAppBrowser - -@interface CDVUIInAppBrowser () { - NSInteger _previousStatusBarStyle; -} -@end - -@implementation CDVUIInAppBrowser - -static CDVUIInAppBrowser* instance = nil; - -+ (id) getInstance{ - return instance; -} - -- (void)pluginInitialize -{ - instance = self; - _previousStatusBarStyle = -1; - _callbackIdPattern = nil; - _beforeload = @""; - _waitForBeforeload = NO; -} - -- (id)settingForKey:(NSString*)key -{ - return [self.commandDelegate.settings objectForKey:[key lowercaseString]]; -} - -- (void)onReset -{ - [self close:nil]; -} - -- (void)close:(CDVInvokedUrlCommand*)command -{ - if (self.inAppBrowserViewController == nil) { - NSLog(@"IAB.close() called but it was already closed."); - return; - } - // Things are cleaned up in browserExit. - [self.inAppBrowserViewController close]; -} - -- (BOOL) isSystemUrl:(NSURL*)url -{ - if ([[url host] isEqualToString:@"itunes.apple.com"]) { - return YES; - } - - return NO; -} - -- (void)open:(CDVInvokedUrlCommand*)command -{ - CDVPluginResult* pluginResult; - - NSString* url = [command argumentAtIndex:0]; - NSString* target = [command argumentAtIndex:1 withDefault:kInAppBrowserTargetSelf]; - NSString* options = [command argumentAtIndex:2 withDefault:@"" andClass:[NSString class]]; - - self.callbackId = command.callbackId; - - if (url != nil) { -#ifdef __CORDOVA_4_0_0 - NSURL* baseUrl = [self.webViewEngine URL]; -#else - NSURL* baseUrl = [self.webView.request URL]; -#endif - NSURL* absoluteUrl = [[NSURL URLWithString:url relativeToURL:baseUrl] absoluteURL]; - - if ([self isSystemUrl:absoluteUrl]) { - target = kInAppBrowserTargetSystem; - } - - if ([target isEqualToString:kInAppBrowserTargetSelf]) { - [self openInCordovaWebView:absoluteUrl withOptions:options]; - } else if ([target isEqualToString:kInAppBrowserTargetSystem]) { - [self openInSystem:absoluteUrl]; - } else { // _blank or anything else - [self openInInAppBrowser:absoluteUrl withOptions:options]; - } - - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; - } else { - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"incorrect number of arguments"]; - } - - [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]]; - [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; -} - -- (void)openInInAppBrowser:(NSURL*)url withOptions:(NSString*)options -{ - CDVInAppBrowserOptions* browserOptions = [CDVInAppBrowserOptions parseOptions:options]; - - if (browserOptions.clearcache) { - NSHTTPCookie *cookie; - NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; - for (cookie in [storage cookies]) - { - if (![cookie.domain isEqual: @".^filecookies^"]) { - [storage deleteCookie:cookie]; - } - } - } - - if (browserOptions.clearsessioncache) { - NSHTTPCookie *cookie; - NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; - for (cookie in [storage cookies]) - { - if (![cookie.domain isEqual: @".^filecookies^"] && cookie.isSessionOnly) { - [storage deleteCookie:cookie]; - } - } - } - - if (self.inAppBrowserViewController == nil) { - NSString* userAgent = [CDVUserAgentUtil originalUserAgent]; - NSString* overrideUserAgent = [self settingForKey:@"OverrideUserAgent"]; - NSString* appendUserAgent = [self settingForKey:@"AppendUserAgent"]; - if(overrideUserAgent){ - userAgent = overrideUserAgent; - } - if(appendUserAgent){ - userAgent = [userAgent stringByAppendingString: appendUserAgent]; - } - self.inAppBrowserViewController = [[CDVUIInAppBrowserViewController alloc] initWithUserAgent:userAgent prevUserAgent:[self.commandDelegate userAgent] browserOptions: browserOptions]; - self.inAppBrowserViewController.navigationDelegate = self; - - if ([self.viewController conformsToProtocol:@protocol(CDVScreenOrientationDelegate)]) { - self.inAppBrowserViewController.orientationDelegate = (UIViewController *)self.viewController; - } - } - - [self.inAppBrowserViewController showLocationBar:browserOptions.location]; - [self.inAppBrowserViewController showToolBar:browserOptions.toolbar :browserOptions.toolbarposition]; - if (browserOptions.closebuttoncaption != nil || browserOptions.closebuttoncolor != nil) { - int closeButtonIndex = browserOptions.lefttoright ? (browserOptions.hidenavigationbuttons ? 1 : 4) : 0; - [self.inAppBrowserViewController setCloseButtonTitle:browserOptions.closebuttoncaption :browserOptions.closebuttoncolor :closeButtonIndex]; - } - // Set Presentation Style - UIModalPresentationStyle presentationStyle = UIModalPresentationFullScreen; // default - if (browserOptions.presentationstyle != nil) { - if ([[browserOptions.presentationstyle lowercaseString] isEqualToString:@"pagesheet"]) { - presentationStyle = UIModalPresentationPageSheet; - } else if ([[browserOptions.presentationstyle lowercaseString] isEqualToString:@"formsheet"]) { - presentationStyle = UIModalPresentationFormSheet; - } - } - self.inAppBrowserViewController.modalPresentationStyle = presentationStyle; - - // Set Transition Style - UIModalTransitionStyle transitionStyle = UIModalTransitionStyleCoverVertical; // default - if (browserOptions.transitionstyle != nil) { - if ([[browserOptions.transitionstyle lowercaseString] isEqualToString:@"fliphorizontal"]) { - transitionStyle = UIModalTransitionStyleFlipHorizontal; - } else if ([[browserOptions.transitionstyle lowercaseString] isEqualToString:@"crossdissolve"]) { - transitionStyle = UIModalTransitionStyleCrossDissolve; - } - } - self.inAppBrowserViewController.modalTransitionStyle = transitionStyle; - - // prevent webView from bouncing - if (browserOptions.disallowoverscroll) { - if ([self.inAppBrowserViewController.webView respondsToSelector:@selector(scrollView)]) { - ((UIScrollView*)[self.inAppBrowserViewController.webView scrollView]).bounces = NO; - } else { - for (id subview in self.inAppBrowserViewController.webView.subviews) { - if ([[subview class] isSubclassOfClass:[UIScrollView class]]) { - ((UIScrollView*)subview).bounces = NO; - } - } - } - } - - // UIWebView options - self.inAppBrowserViewController.webView.scalesPageToFit = browserOptions.enableviewportscale; - self.inAppBrowserViewController.webView.mediaPlaybackRequiresUserAction = browserOptions.mediaplaybackrequiresuseraction; - self.inAppBrowserViewController.webView.allowsInlineMediaPlayback = browserOptions.allowinlinemediaplayback; - if (IsAtLeastiOSVersion(@"6.0")) { - self.inAppBrowserViewController.webView.keyboardDisplayRequiresUserAction = browserOptions.keyboarddisplayrequiresuseraction; - self.inAppBrowserViewController.webView.suppressesIncrementalRendering = browserOptions.suppressesincrementalrendering; - } - - // use of beforeload event - if([browserOptions.beforeload isKindOfClass:[NSString class]]){ - _beforeload = browserOptions.beforeload; - }else{ - _beforeload = @"yes"; - } - _waitForBeforeload = ![_beforeload isEqualToString:@""]; - - [self.inAppBrowserViewController navigateTo:url]; - if (!browserOptions.hidden) { - [self show:nil]; - } -} - -- (void)show:(CDVInvokedUrlCommand*)command -{ - if (self.inAppBrowserViewController == nil) { - NSLog(@"Tried to show IAB after it was closed."); - return; - } - if (_previousStatusBarStyle != -1) { - NSLog(@"Tried to show IAB while already shown"); - return; - } - - _previousStatusBarStyle = [UIApplication sharedApplication].statusBarStyle; - - __block CDVInAppBrowserNavigationController* nav = [[CDVInAppBrowserNavigationController alloc] - initWithRootViewController:self.inAppBrowserViewController]; - nav.orientationDelegate = self.inAppBrowserViewController; - nav.navigationBarHidden = YES; - nav.modalPresentationStyle = self.inAppBrowserViewController.modalPresentationStyle; - - __weak CDVUIInAppBrowser* weakSelf = self; - - // Run later to avoid the "took a long time" log message. - dispatch_async(dispatch_get_main_queue(), ^{ - if (weakSelf.inAppBrowserViewController != nil) { - if (!tmpWindow) { - CGRect frame = [[UIScreen mainScreen] bounds]; - tmpWindow = [[UIWindow alloc] initWithFrame:frame]; - } - UIViewController *tmpController = [[UIViewController alloc] init]; - [tmpWindow setRootViewController:tmpController]; - - [tmpWindow makeKeyAndVisible]; - [tmpController presentViewController:nav animated:YES completion:nil]; - } - }); -} - -- (void)hide:(CDVInvokedUrlCommand*)command -{ - if (self.inAppBrowserViewController == nil) { - NSLog(@"Tried to hide IAB after it was closed."); - return; - - - } - if (_previousStatusBarStyle == -1) { - NSLog(@"Tried to hide IAB while already hidden"); - return; - } - - _previousStatusBarStyle = [UIApplication sharedApplication].statusBarStyle; - - // Run later to avoid the "took a long time" log message. - dispatch_async(dispatch_get_main_queue(), ^{ - if (self.inAppBrowserViewController != nil) { - _previousStatusBarStyle = -1; - [self.inAppBrowserViewController.presentingViewController dismissViewControllerAnimated:YES completion:^{ - [[[[UIApplication sharedApplication] delegate] window] makeKeyAndVisible]; - }]; - } - }); -} - -- (void)openInCordovaWebView:(NSURL*)url withOptions:(NSString*)options -{ - NSURLRequest* request = [NSURLRequest requestWithURL:url]; - -#ifdef __CORDOVA_4_0_0 - // the webview engine itself will filter for this according to policy - // in config.xml for cordova-ios-4.0 - [self.webViewEngine loadRequest:request]; -#else - if ([self.commandDelegate URLIsWhitelisted:url]) { - [self.webView loadRequest:request]; - } else { // this assumes the InAppBrowser can be excepted from the white-list - [self openInInAppBrowser:url withOptions:options]; - } -#endif -} - -- (void)openInSystem:(NSURL*)url -{ - if ([[UIApplication sharedApplication] openURL:url] == NO) { - [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginHandleOpenURLNotification object:url]]; - [[UIApplication sharedApplication] openURL:url]; - } -} - -- (void)loadAfterBeforeload:(CDVInvokedUrlCommand*)command -{ - NSString* urlStr = [command argumentAtIndex:0]; - - if ([_beforeload isEqualToString:@""]) { - NSLog(@"unexpected loadAfterBeforeload called without feature beforeload=yes"); - } - if (self.inAppBrowserViewController == nil) { - NSLog(@"Tried to invoke loadAfterBeforeload on IAB after it was closed."); - return; - } - if (urlStr == nil) { - NSLog(@"loadAfterBeforeload called with nil argument, ignoring."); - return; - } - - NSURL* url = [NSURL URLWithString:urlStr]; - _waitForBeforeload = NO; - [self.inAppBrowserViewController navigateTo:url]; -} - --(void)createIframeBridge -{ - // Create an iframe bridge in the new document to communicate with the CDVThemeableBrowserViewController - NSString* jsIframeBridge = @"var e = _cdvIframeBridge=d.getElementById('_cdvIframeBridge'); if(!_cdvIframeBridge) {e = _cdvIframeBridge = d.createElement('iframe'); e.id='_cdvIframeBridge'; e.style.display='none'; d.body.appendChild(e);}"; - // Add the postMessage API - NSString* jspostMessageApi = @"window.webkit={messageHandlers:{cordova_iab:{postMessage:function(message){_cdvIframeBridge.src='gap-iab://message/'+encodeURIComponent(message);}}}}"; - // Inject the JS to the webview - [self.inAppBrowserViewController.webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"(function(d){%@%@})(document)", jsIframeBridge, jspostMessageApi]]; -} - -// This is a helper method for the inject{Script|Style}{Code|File} API calls, which -// provides a consistent method for injecting JavaScript code into the document. -// -// If a wrapper string is supplied, then the source string will be JSON-encoded (adding -// quotes) and wrapped using string formatting. (The wrapper string should have a single -// '%@' marker). -// -// If no wrapper is supplied, then the source string is executed directly. - -- (void)injectDeferredObject:(NSString*)source withWrapper:(NSString*)jsWrapper -{ - [self createIframeBridge]; - if (jsWrapper != nil) { - NSData* jsonData = [NSJSONSerialization dataWithJSONObject:@[source] options:0 error:nil]; - NSString* sourceArrayString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; - if (sourceArrayString) { - NSString* sourceString = [sourceArrayString substringWithRange:NSMakeRange(1, [sourceArrayString length] - 2)]; - NSString* jsToInject = [NSString stringWithFormat:jsWrapper, sourceString]; - [self.inAppBrowserViewController.webView stringByEvaluatingJavaScriptFromString:jsToInject]; - } - } else { - [self.inAppBrowserViewController.webView stringByEvaluatingJavaScriptFromString:source]; - } -} - -- (void)injectScriptCode:(CDVInvokedUrlCommand*)command -{ - NSString* jsWrapper = nil; - - if ((command.callbackId != nil) && ![command.callbackId isEqualToString:@"INVALID"]) { - jsWrapper = [NSString stringWithFormat:@"_cdvIframeBridge.src='gap-iab://%@/'+encodeURIComponent(JSON.stringify([eval(%%@)]));", command.callbackId]; - } - [self injectDeferredObject:[command argumentAtIndex:0] withWrapper:jsWrapper]; -} - -- (void)injectScriptFile:(CDVInvokedUrlCommand*)command -{ - NSString* jsWrapper; - - if ((command.callbackId != nil) && ![command.callbackId isEqualToString:@"INVALID"]) { - jsWrapper = [NSString stringWithFormat:@"(function(d) { var c = d.createElement('script'); c.src = %%@; c.onload = function() { _cdvIframeBridge.src='gap-iab://%@'; }; d.body.appendChild(c); })(document)", command.callbackId]; - } else { - jsWrapper = @"(function(d) { var c = d.createElement('script'); c.src = %@; d.body.appendChild(c); })(document)"; - } - [self injectDeferredObject:[command argumentAtIndex:0] withWrapper:jsWrapper]; -} - -- (void)injectStyleCode:(CDVInvokedUrlCommand*)command -{ - NSString* jsWrapper; - - if ((command.callbackId != nil) && ![command.callbackId isEqualToString:@"INVALID"]) { - jsWrapper = [NSString stringWithFormat:@"(function(d) { var c = d.createElement('style'); c.innerHTML = %%@; c.onload = function() { _cdvIframeBridge.src='gap-iab://%@'; }; d.body.appendChild(c); })(document)", command.callbackId]; - } else { - jsWrapper = @"(function(d) { var c = d.createElement('style'); c.innerHTML = %@; d.body.appendChild(c); })(document)"; - } - [self injectDeferredObject:[command argumentAtIndex:0] withWrapper:jsWrapper]; -} - -- (void)injectStyleFile:(CDVInvokedUrlCommand*)command -{ - NSString* jsWrapper; - - if ((command.callbackId != nil) && ![command.callbackId isEqualToString:@"INVALID"]) { - jsWrapper = [NSString stringWithFormat:@"(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %%@; c.onload = function() { _cdvIframeBridge.src='gap-iab://%@'; }; d.body.appendChild(c); })(document)", command.callbackId]; - } else { - jsWrapper = @"(function(d) { var c = d.createElement('link'); c.rel='stylesheet', c.type='text/css'; c.href = %@; d.body.appendChild(c); })(document)"; - } - [self injectDeferredObject:[command argumentAtIndex:0] withWrapper:jsWrapper]; -} - -- (BOOL)isValidCallbackId:(NSString *)callbackId -{ - NSError *err = nil; - // Initialize on first use - if (self.callbackIdPattern == nil) { - self.callbackIdPattern = [NSRegularExpression regularExpressionWithPattern:@"^InAppBrowser[0-9]{1,10}$" options:0 error:&err]; - if (err != nil) { - // Couldn't initialize Regex; No is safer than Yes. - return NO; - } - } - if ([self.callbackIdPattern firstMatchInString:callbackId options:0 range:NSMakeRange(0, [callbackId length])]) { - return YES; - } - return NO; -} - -/** - * The iframe bridge provided for the InAppBrowser is capable of executing any oustanding callback belonging - * to the InAppBrowser plugin. Care has been taken that other callbacks cannot be triggered, and that no - * other code execution is possible. - * - * To trigger the bridge, the iframe (or any other resource) should attempt to load a url of the form: - * - * gap-iab:/// - * - * where is the string id of the callback to trigger (something like "InAppBrowser0123456789") - * - * If present, the path component of the special gap-iab:// url is expected to be a URL-escaped JSON-encoded - * value to pass to the callback. [NSURL path] should take care of the URL-unescaping, and a JSON_EXCEPTION - * is returned if the JSON is invalid. - */ -- (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType -{ - NSURL* url = request.URL; - BOOL isTopLevelNavigation = [request.URL isEqual:[request mainDocumentURL]]; - BOOL shouldStart = YES; - BOOL useBeforeLoad = NO; - NSString* httpMethod = request.HTTPMethod; - NSString* errorMessage = nil; - - if([_beforeload isEqualToString:@"post"]){ - //TODO handle POST requests by preserving POST data then remove this condition - errorMessage = @"beforeload doesn't yet support POST requests"; - } - else if(isTopLevelNavigation && ( - [_beforeload isEqualToString:@"yes"] - || ([_beforeload isEqualToString:@"get"] && [httpMethod isEqualToString:@"GET"]) - // TODO comment in when POST requests are handled - // || ([_beforeload isEqualToString:@"post"] && [httpMethod isEqualToString:@"POST"]) - )){ - useBeforeLoad = YES; - } - - // See if the url uses the 'gap-iab' protocol. If so, the host should be the id of a callback to execute, - // and the path, if present, should be a JSON-encoded value to pass to the callback. - if ([[url scheme] isEqualToString:@"gap-iab"]) { - NSString* scriptCallbackId = [url host]; - CDVPluginResult* pluginResult = nil; - - if ([self isValidCallbackId:scriptCallbackId]) { - NSString* scriptResult = [url path]; - NSError* __autoreleasing error = nil; - - // The message should be a JSON-encoded array of the result of the script which executed. - if ((scriptResult != nil) && ([scriptResult length] > 1)) { - scriptResult = [scriptResult substringFromIndex:1]; - NSData* decodedResult = [NSJSONSerialization JSONObjectWithData:[scriptResult dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error]; - if ((error == nil) && [decodedResult isKindOfClass:[NSArray class]]) { - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:(NSArray*)decodedResult]; - } else { - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_JSON_EXCEPTION]; - } - } else { - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:@[]]; - } - [self.commandDelegate sendPluginResult:pluginResult callbackId:scriptCallbackId]; - return NO; - }else if ([scriptCallbackId isEqualToString:@"message"] && (self.callbackId != nil)) { - // Send a message event - NSString* scriptResult = [url path]; - if ((scriptResult != nil) && ([scriptResult length] > 1)) { - scriptResult = [scriptResult substringFromIndex:1]; - NSError* __autoreleasing error = nil; - NSData* decodedResult = [NSJSONSerialization JSONObjectWithData:[scriptResult dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error]; - if (error == nil) { - NSMutableDictionary* dResult = [NSMutableDictionary new]; - [dResult setValue:@"message" forKey:@"type"]; - [dResult setObject:decodedResult forKey:@"data"]; - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dResult]; - [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]]; - [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId]; - } - } - } - } - - // When beforeload, on first URL change, initiate JS callback. Only after the beforeload event, continue. - if (_waitForBeforeload && useBeforeLoad) { - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK - messageAsDictionary:@{@"type":@"beforeload", @"url":[url absoluteString]}]; - [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]]; - - [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId]; - return NO; - } - - if(errorMessage != nil){ - NSLog(errorMessage); - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR - messageAsDictionary:@{@"type":@"loaderror", @"url":[url absoluteString], @"code": @"-1", @"message": errorMessage}]; - [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]]; - [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId]; - } - - //if is an app store link, let the system handle it, otherwise it fails to load it - if ([[ url scheme] isEqualToString:@"itms-appss"] || [[ url scheme] isEqualToString:@"itms-apps"]) { - [theWebView stopLoading]; - [self openInSystem:url]; - shouldStart = NO; - } - else if ((self.callbackId != nil) && isTopLevelNavigation) { - // Send a loadstart event for each top-level navigation (includes redirects). - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK - messageAsDictionary:@{@"type":@"loadstart", @"url":[url absoluteString]}]; - [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]]; - - [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId]; - } - - if (useBeforeLoad) { - _waitForBeforeload = YES; - } - - return shouldStart; -} - -- (void)webViewDidStartLoad:(UIWebView*)theWebView -{ -} - -- (void)webViewDidFinishLoad:(UIWebView*)theWebView -{ - if (self.callbackId != nil) { - // TODO: It would be more useful to return the URL the page is actually on (e.g. if it's been redirected). - NSString* url = [self.inAppBrowserViewController.currentURL absoluteString]; - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK - messageAsDictionary:@{@"type":@"loadstop", @"url":url}]; - [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]]; - - [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId]; - } -} - -- (void)webView:(UIWebView*)theWebView didFailLoadWithError:(NSError*)error -{ - if (self.callbackId != nil) { - NSString* url = [self.inAppBrowserViewController.currentURL absoluteString]; - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR - messageAsDictionary:@{@"type":@"loaderror", @"url":url, @"code": [NSNumber numberWithInteger:error.code], @"message": error.localizedDescription}]; - [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]]; - - [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId]; - } -} - -- (void)browserExit -{ - if (self.callbackId != nil) { - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK - messageAsDictionary:@{@"type":@"exit"}]; - [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId]; - self.callbackId = nil; - } - // Set navigationDelegate to nil to ensure no callbacks are received from it. - self.inAppBrowserViewController.navigationDelegate = nil; - // Don't recycle the ViewController since it may be consuming a lot of memory. - // Also - this is required for the PDF/User-Agent bug work-around. - self.inAppBrowserViewController = nil; - - if (IsAtLeastiOSVersion(@"7.0")) { - if (_previousStatusBarStyle != -1) { - [[UIApplication sharedApplication] setStatusBarStyle:_previousStatusBarStyle]; - } - } - - _previousStatusBarStyle = -1; // this value was reset before reapplying it. caused statusbar to stay black on ios7 -} - -@end - -#pragma mark CDVUIInAppBrowserViewController - -@implementation CDVUIInAppBrowserViewController - -@synthesize currentURL; - -- (id)initWithUserAgent:(NSString*)userAgent prevUserAgent:(NSString*)prevUserAgent browserOptions: (CDVInAppBrowserOptions*) browserOptions -{ - self = [super init]; - if (self != nil) { - _userAgent = userAgent; - _prevUserAgent = prevUserAgent; - _browserOptions = browserOptions; -#ifdef __CORDOVA_4_0_0 - _webViewDelegate = [[CDVUIWebViewDelegate alloc] initWithDelegate:self]; -#else - _webViewDelegate = [[CDVWebViewDelegate alloc] initWithDelegate:self]; -#endif - - [self createViews]; - } - - return self; -} - -// Prevent crashes on closing windows --(void)dealloc { - self.webView.delegate = nil; -} - -- (void)createViews -{ - // We create the views in code for primarily for ease of upgrades and not requiring an external .xib to be included - - CGRect webViewBounds = self.view.bounds; - BOOL toolbarIsAtBottom = ![_browserOptions.toolbarposition isEqualToString:kInAppBrowserToolbarBarPositionTop]; - webViewBounds.size.height -= _browserOptions.location ? FOOTER_HEIGHT : TOOLBAR_HEIGHT; - self.webView = [[UIWebView alloc] initWithFrame:webViewBounds]; - - self.webView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); - - [self.view addSubview:self.webView]; - [self.view sendSubviewToBack:self.webView]; - - self.webView.delegate = _webViewDelegate; - self.webView.backgroundColor = [UIColor whiteColor]; - - self.webView.clearsContextBeforeDrawing = YES; - self.webView.clipsToBounds = YES; - self.webView.contentMode = UIViewContentModeScaleToFill; - self.webView.multipleTouchEnabled = YES; - self.webView.opaque = YES; - self.webView.scalesPageToFit = NO; - self.webView.userInteractionEnabled = YES; - - self.spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; - self.spinner.alpha = 1.000; - self.spinner.autoresizesSubviews = YES; - self.spinner.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin); - self.spinner.clearsContextBeforeDrawing = NO; - self.spinner.clipsToBounds = NO; - self.spinner.contentMode = UIViewContentModeScaleToFill; - self.spinner.frame = CGRectMake(CGRectGetMidX(self.webView.frame), CGRectGetMidY(self.webView.frame), 20.0, 20.0); - self.spinner.hidden = NO; - self.spinner.hidesWhenStopped = YES; - self.spinner.multipleTouchEnabled = NO; - self.spinner.opaque = NO; - self.spinner.userInteractionEnabled = NO; - [self.spinner stopAnimating]; - - self.closeButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(close)]; - self.closeButton.enabled = YES; - - UIBarButtonItem* flexibleSpaceButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; - - UIBarButtonItem* fixedSpaceButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; - fixedSpaceButton.width = 20; - - float toolbarY = toolbarIsAtBottom ? self.view.bounds.size.height - TOOLBAR_HEIGHT : 0.0; - CGRect toolbarFrame = CGRectMake(0.0, toolbarY, self.view.bounds.size.width, TOOLBAR_HEIGHT); - - self.toolbar = [[UIToolbar alloc] initWithFrame:toolbarFrame]; - self.toolbar.alpha = 1.000; - self.toolbar.autoresizesSubviews = YES; - self.toolbar.autoresizingMask = toolbarIsAtBottom ? (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin) : UIViewAutoresizingFlexibleWidth; - self.toolbar.barStyle = UIBarStyleBlackOpaque; - self.toolbar.clearsContextBeforeDrawing = NO; - self.toolbar.clipsToBounds = NO; - self.toolbar.contentMode = UIViewContentModeScaleToFill; - self.toolbar.hidden = NO; - self.toolbar.multipleTouchEnabled = NO; - self.toolbar.opaque = NO; - self.toolbar.userInteractionEnabled = YES; - if (_browserOptions.toolbarcolor != nil) { // Set toolbar color if user sets it in options - self.toolbar.barTintColor = [self colorFromHexString:_browserOptions.toolbarcolor]; - } - if (!_browserOptions.toolbartranslucent) { // Set toolbar translucent to no if user sets it in options - self.toolbar.translucent = NO; - } - - CGFloat labelInset = 5.0; - float locationBarY = toolbarIsAtBottom ? self.view.bounds.size.height - FOOTER_HEIGHT : self.view.bounds.size.height - LOCATIONBAR_HEIGHT; - - self.addressLabel = [[UILabel alloc] initWithFrame:CGRectMake(labelInset, locationBarY, self.view.bounds.size.width - labelInset, LOCATIONBAR_HEIGHT)]; - self.addressLabel.adjustsFontSizeToFitWidth = NO; - self.addressLabel.alpha = 1.000; - self.addressLabel.autoresizesSubviews = YES; - self.addressLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin; - self.addressLabel.backgroundColor = [UIColor clearColor]; - self.addressLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters; - self.addressLabel.clearsContextBeforeDrawing = YES; - self.addressLabel.clipsToBounds = YES; - self.addressLabel.contentMode = UIViewContentModeScaleToFill; - self.addressLabel.enabled = YES; - self.addressLabel.hidden = NO; - self.addressLabel.lineBreakMode = NSLineBreakByTruncatingTail; - - if ([self.addressLabel respondsToSelector:NSSelectorFromString(@"setMinimumScaleFactor:")]) { - [self.addressLabel setValue:@(10.0/[UIFont labelFontSize]) forKey:@"minimumScaleFactor"]; - } else if ([self.addressLabel respondsToSelector:NSSelectorFromString(@"setMinimumFontSize:")]) { - [self.addressLabel setValue:@(10.0) forKey:@"minimumFontSize"]; - } - - self.addressLabel.multipleTouchEnabled = NO; - self.addressLabel.numberOfLines = 1; - self.addressLabel.opaque = NO; - self.addressLabel.shadowOffset = CGSizeMake(0.0, -1.0); - self.addressLabel.text = NSLocalizedString(@"Loading...", nil); - self.addressLabel.textAlignment = NSTextAlignmentLeft; - self.addressLabel.textColor = [UIColor colorWithWhite:1.000 alpha:1.000]; - self.addressLabel.userInteractionEnabled = NO; - - NSString* frontArrowString = NSLocalizedString(@"►", nil); // create arrow from Unicode char - self.forwardButton = [[UIBarButtonItem alloc] initWithTitle:frontArrowString style:UIBarButtonItemStylePlain target:self action:@selector(goForward:)]; - self.forwardButton.enabled = YES; - self.forwardButton.imageInsets = UIEdgeInsetsZero; - if (_browserOptions.navigationbuttoncolor != nil) { // Set button color if user sets it in options - self.forwardButton.tintColor = [self colorFromHexString:_browserOptions.navigationbuttoncolor]; - } - - NSString* backArrowString = NSLocalizedString(@"◄", nil); // create arrow from Unicode char - self.backButton = [[UIBarButtonItem alloc] initWithTitle:backArrowString style:UIBarButtonItemStylePlain target:self action:@selector(goBack:)]; - self.backButton.enabled = YES; - self.backButton.imageInsets = UIEdgeInsetsZero; - if (_browserOptions.navigationbuttoncolor != nil) { // Set button color if user sets it in options - self.backButton.tintColor = [self colorFromHexString:_browserOptions.navigationbuttoncolor]; - } - - // Filter out Navigation Buttons if user requests so - if (_browserOptions.hidenavigationbuttons) { - if (_browserOptions.lefttoright) { - [self.toolbar setItems:@[flexibleSpaceButton, self.closeButton]]; - } else { - [self.toolbar setItems:@[self.closeButton, flexibleSpaceButton]]; - } - } else if (_browserOptions.lefttoright) { - [self.toolbar setItems:@[self.backButton, fixedSpaceButton, self.forwardButton, flexibleSpaceButton, self.closeButton]]; - } else { - [self.toolbar setItems:@[self.closeButton, flexibleSpaceButton, self.backButton, fixedSpaceButton, self.forwardButton]]; - } - - self.view.backgroundColor = [UIColor grayColor]; - [self.view addSubview:self.toolbar]; - [self.view addSubview:self.addressLabel]; - [self.view addSubview:self.spinner]; -} - -- (void) setWebViewFrame : (CGRect) frame { - NSLog(@"Setting the WebView's frame to %@", NSStringFromCGRect(frame)); - [self.webView setFrame:frame]; -} - -- (void)setCloseButtonTitle:(NSString*)title : (NSString*) colorString : (int) buttonIndex -{ - // the advantage of using UIBarButtonSystemItemDone is the system will localize it for you automatically - // but, if you want to set this yourself, knock yourself out (we can't set the title for a system Done button, so we have to create a new one) - self.closeButton = nil; - // Initialize with title if title is set, otherwise the title will be 'Done' localized - self.closeButton = title != nil ? [[UIBarButtonItem alloc] initWithTitle:title style:UIBarButtonItemStyleBordered target:self action:@selector(close)] : [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(close)]; - self.closeButton.enabled = YES; - // If color on closebutton is requested then initialize with that that color, otherwise use initialize with default - self.closeButton.tintColor = colorString != nil ? [self colorFromHexString:colorString] : [UIColor colorWithRed:60.0 / 255.0 green:136.0 / 255.0 blue:230.0 / 255.0 alpha:1]; - - NSMutableArray* items = [self.toolbar.items mutableCopy]; - [items replaceObjectAtIndex:buttonIndex withObject:self.closeButton]; - [self.toolbar setItems:items]; -} - -- (void)showLocationBar:(BOOL)show -{ - CGRect locationbarFrame = self.addressLabel.frame; - - BOOL toolbarVisible = !self.toolbar.hidden; - - // prevent double show/hide - if (show == !(self.addressLabel.hidden)) { - return; - } - - if (show) { - self.addressLabel.hidden = NO; - - if (toolbarVisible) { - // toolBar at the bottom, leave as is - // put locationBar on top of the toolBar - - CGRect webViewBounds = self.view.bounds; - webViewBounds.size.height -= FOOTER_HEIGHT; - [self setWebViewFrame:webViewBounds]; - - locationbarFrame.origin.y = webViewBounds.size.height; - self.addressLabel.frame = locationbarFrame; - } else { - // no toolBar, so put locationBar at the bottom - - CGRect webViewBounds = self.view.bounds; - webViewBounds.size.height -= LOCATIONBAR_HEIGHT; - [self setWebViewFrame:webViewBounds]; - - locationbarFrame.origin.y = webViewBounds.size.height; - self.addressLabel.frame = locationbarFrame; - } - } else { - self.addressLabel.hidden = YES; - - if (toolbarVisible) { - // locationBar is on top of toolBar, hide locationBar - - // webView take up whole height less toolBar height - CGRect webViewBounds = self.view.bounds; - webViewBounds.size.height -= TOOLBAR_HEIGHT; - [self setWebViewFrame:webViewBounds]; - } else { - // no toolBar, expand webView to screen dimensions - [self setWebViewFrame:self.view.bounds]; - } - } -} - -- (void)showToolBar:(BOOL)show : (NSString *) toolbarPosition -{ - CGRect toolbarFrame = self.toolbar.frame; - CGRect locationbarFrame = self.addressLabel.frame; - - BOOL locationbarVisible = !self.addressLabel.hidden; - - // prevent double show/hide - if (show == !(self.toolbar.hidden)) { - return; - } - - if (show) { - self.toolbar.hidden = NO; - CGRect webViewBounds = self.view.bounds; - - if (locationbarVisible) { - // locationBar at the bottom, move locationBar up - // put toolBar at the bottom - webViewBounds.size.height -= FOOTER_HEIGHT; - locationbarFrame.origin.y = webViewBounds.size.height; - self.addressLabel.frame = locationbarFrame; - self.toolbar.frame = toolbarFrame; - } else { - // no locationBar, so put toolBar at the bottom - CGRect webViewBounds = self.view.bounds; - webViewBounds.size.height -= TOOLBAR_HEIGHT; - self.toolbar.frame = toolbarFrame; - } - - if ([toolbarPosition isEqualToString:kInAppBrowserToolbarBarPositionTop]) { - toolbarFrame.origin.y = 0; - webViewBounds.origin.y += toolbarFrame.size.height; - [self setWebViewFrame:webViewBounds]; - } else { - toolbarFrame.origin.y = (webViewBounds.size.height + LOCATIONBAR_HEIGHT); - } - [self setWebViewFrame:webViewBounds]; - - } else { - self.toolbar.hidden = YES; - - if (locationbarVisible) { - // locationBar is on top of toolBar, hide toolBar - // put locationBar at the bottom - - // webView take up whole height less locationBar height - CGRect webViewBounds = self.view.bounds; - webViewBounds.size.height -= LOCATIONBAR_HEIGHT; - [self setWebViewFrame:webViewBounds]; - - // move locationBar down - locationbarFrame.origin.y = webViewBounds.size.height; - self.addressLabel.frame = locationbarFrame; - } else { - // no locationBar, expand webView to screen dimensions - [self setWebViewFrame:self.view.bounds]; - } - } -} - -- (void)viewDidLoad -{ - [super viewDidLoad]; -} - -- (void)viewDidUnload -{ - [self.webView loadHTMLString:nil baseURL:nil]; - [CDVUserAgentUtil releaseLock:&_userAgentLockToken]; - [super viewDidUnload]; -} - -- (UIStatusBarStyle)preferredStatusBarStyle -{ - return UIStatusBarStyleDefault; -} - -- (BOOL)prefersStatusBarHidden { - return NO; -} - -- (void)close -{ - [CDVUserAgentUtil releaseLock:&_userAgentLockToken]; - self.currentURL = nil; - - if ((self.navigationDelegate != nil) && [self.navigationDelegate respondsToSelector:@selector(browserExit)]) { - [self.navigationDelegate browserExit]; - } - - __weak UIViewController* weakSelf = self; - - // Run later to avoid the "took a long time" log message. - dispatch_async(dispatch_get_main_queue(), ^{ - if ([weakSelf respondsToSelector:@selector(presentingViewController)]) { - [[weakSelf presentingViewController] dismissViewControllerAnimated:YES completion:^{ - [[[[UIApplication sharedApplication] delegate] window] makeKeyAndVisible]; - }]; - } else { - [[weakSelf parentViewController] dismissViewControllerAnimated:YES completion:^{ - [[[[UIApplication sharedApplication] delegate] window] makeKeyAndVisible]; - }]; - } - }); -} - -- (void)navigateTo:(NSURL*)url -{ - NSURLRequest* request = [NSURLRequest requestWithURL:url]; - - if (_userAgentLockToken != 0) { - [self.webView loadRequest:request]; - } else { - __weak CDVUIInAppBrowserViewController* weakSelf = self; - [CDVUserAgentUtil acquireLock:^(NSInteger lockToken) { - _userAgentLockToken = lockToken; - [CDVUserAgentUtil setUserAgent:_userAgent lockToken:lockToken]; - [weakSelf.webView loadRequest:request]; - }]; - } -} - -- (void)goBack:(id)sender -{ - [self.webView goBack]; -} - -- (void)goForward:(id)sender -{ - [self.webView goForward]; -} - -- (void)viewWillAppear:(BOOL)animated -{ - if (IsAtLeastiOSVersion(@"7.0")) { - [[UIApplication sharedApplication] setStatusBarStyle:[self preferredStatusBarStyle]]; - } - [self rePositionViews]; - - [super viewWillAppear:animated]; -} - -// -// On iOS 7 the status bar is part of the view's dimensions, therefore it's height has to be taken into account. -// The height of it could be hardcoded as 20 pixels, but that would assume that the upcoming releases of iOS won't -// change that value. -// -- (float) getStatusBarOffset { - CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame]; - float statusBarOffset = IsAtLeastiOSVersion(@"7.0") ? MIN(statusBarFrame.size.width, statusBarFrame.size.height) : 0.0; - return statusBarOffset; -} - -- (void) rePositionViews { - if ([_browserOptions.toolbarposition isEqualToString:kInAppBrowserToolbarBarPositionTop]) { - [self.webView setFrame:CGRectMake(self.webView.frame.origin.x, TOOLBAR_HEIGHT, self.webView.frame.size.width, self.webView.frame.size.height)]; - [self.toolbar setFrame:CGRectMake(self.toolbar.frame.origin.x, [self getStatusBarOffset], self.toolbar.frame.size.width, self.toolbar.frame.size.height)]; - } -} - -// Helper function to convert hex color string to UIColor -// Assumes input like "#00FF00" (#RRGGBB). -// Taken from https://stackoverflow.com/questions/1560081/how-can-i-create-a-uicolor-from-a-hex-string -- (UIColor *)colorFromHexString:(NSString *)hexString { - unsigned rgbValue = 0; - NSScanner *scanner = [NSScanner scannerWithString:hexString]; - [scanner setScanLocation:1]; // bypass '#' character - [scanner scanHexInt:&rgbValue]; - return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16)/255.0 green:((rgbValue & 0xFF00) >> 8)/255.0 blue:(rgbValue & 0xFF)/255.0 alpha:1.0]; -} - -#pragma mark UIWebViewDelegate - -- (void)webViewDidStartLoad:(UIWebView*)theWebView -{ - // loading url, start spinner, update back/forward - - self.addressLabel.text = NSLocalizedString(@"Loading...", nil); - self.backButton.enabled = theWebView.canGoBack; - self.forwardButton.enabled = theWebView.canGoForward; - - NSLog(_browserOptions.hidespinner ? @"Yes" : @"No"); - if(!_browserOptions.hidespinner) { - [self.spinner startAnimating]; - } - - return [self.navigationDelegate webViewDidStartLoad:theWebView]; -} - -- (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType -{ - BOOL isTopLevelNavigation = [request.URL isEqual:[request mainDocumentURL]]; - - if (isTopLevelNavigation) { - self.currentURL = request.URL; - } - return [self.navigationDelegate webView:theWebView shouldStartLoadWithRequest:request navigationType:navigationType]; -} - -- (void)webViewDidFinishLoad:(UIWebView*)theWebView -{ - // update url, stop spinner, update back/forward - - self.addressLabel.text = [self.currentURL absoluteString]; - self.backButton.enabled = theWebView.canGoBack; - self.forwardButton.enabled = theWebView.canGoForward; - - [self.spinner stopAnimating]; - - // Work around a bug where the first time a PDF is opened, all UIWebViews - // reload their User-Agent from NSUserDefaults. - // This work-around makes the following assumptions: - // 1. The app has only a single Cordova Webview. If not, then the app should - // take it upon themselves to load a PDF in the background as a part of - // their start-up flow. - // 2. That the PDF does not require any additional network requests. We change - // the user-agent here back to that of the CDVViewController, so requests - // from it must pass through its white-list. This *does* break PDFs that - // contain links to other remote PDF/websites. - // More info at https://issues.apache.org/jira/browse/CB-2225 - BOOL isPDF = [@"true" isEqualToString :[theWebView stringByEvaluatingJavaScriptFromString:@"document.body==null"]]; - if (isPDF) { - [CDVUserAgentUtil setUserAgent:_prevUserAgent lockToken:_userAgentLockToken]; - } - - [self.navigationDelegate webViewDidFinishLoad:theWebView]; -} - -- (void)webView:(UIWebView*)theWebView didFailLoadWithError:(NSError*)error -{ - // log fail message, stop spinner, update back/forward - NSLog(@"webView:didFailLoadWithError - %ld: %@", (long)error.code, [error localizedDescription]); - - self.backButton.enabled = theWebView.canGoBack; - self.forwardButton.enabled = theWebView.canGoForward; - [self.spinner stopAnimating]; - - self.addressLabel.text = NSLocalizedString(@"Load Error", nil); - - [self.navigationDelegate webView:theWebView didFailLoadWithError:error]; -} - -#pragma mark CDVScreenOrientationDelegate - -- (BOOL)shouldAutorotate -{ - if ((self.orientationDelegate != nil) && [self.orientationDelegate respondsToSelector:@selector(shouldAutorotate)]) { - return [self.orientationDelegate shouldAutorotate]; - } - return YES; -} - -- (NSUInteger)supportedInterfaceOrientations -{ - if ((self.orientationDelegate != nil) && [self.orientationDelegate respondsToSelector:@selector(supportedInterfaceOrientations)]) { - return [self.orientationDelegate supportedInterfaceOrientations]; - } - - return 1 << UIInterfaceOrientationPortrait; -} - -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation -{ - if ((self.orientationDelegate != nil) && [self.orientationDelegate respondsToSelector:@selector(shouldAutorotateToInterfaceOrientation:)]) { - return [self.orientationDelegate shouldAutorotateToInterfaceOrientation:interfaceOrientation]; - } - - return YES; -} - -@end - -#endif \ No newline at end of file diff --git a/src/ios/CDVWKInAppBrowser.h b/src/ios/CDVWKInAppBrowser.h index 7fddf9c..e339be1 100644 --- a/src/ios/CDVWKInAppBrowser.h +++ b/src/ios/CDVWKInAppBrowser.h @@ -51,10 +51,8 @@ @interface CDVWKInAppBrowserViewController : UIViewController { @private - NSString* _userAgent; - NSString* _prevUserAgent; - NSInteger _userAgentLockToken; CDVInAppBrowserOptions *_browserOptions; + NSDictionary *_settings; } @property (nonatomic, strong) IBOutlet WKWebView* webView; @@ -77,6 +75,6 @@ - (void)showToolBar:(BOOL)show : (NSString *) toolbarPosition; - (void)setCloseButtonTitle:(NSString*)title : (NSString*) colorString : (int) buttonIndex; -- (id)initWithUserAgent:(NSString*)userAgent prevUserAgent:(NSString*)prevUserAgent browserOptions: (CDVInAppBrowserOptions*) browserOptions; +- (id)initWithBrowserOptions: (CDVInAppBrowserOptions*) browserOptions andSettings:(NSDictionary*) settings; @end diff --git a/src/ios/CDVWKInAppBrowser.m b/src/ios/CDVWKInAppBrowser.m index f937714..9aa8c7e 100644 --- a/src/ios/CDVWKInAppBrowser.m +++ b/src/ios/CDVWKInAppBrowser.m @@ -24,7 +24,6 @@ #endif #import -#import #define kInAppBrowserTargetSelf @"_self" #define kInAppBrowserTargetSystem @"_system" @@ -64,11 +63,6 @@ static CDVWKInAppBrowser* instance = nil; _waitForBeforeload = NO; } -- (id)settingForKey:(NSString*)key -{ - return [self.commandDelegate.settings objectForKey:[key lowercaseString]]; -} - - (void)onReset { [self close:nil]; @@ -105,11 +99,7 @@ static CDVWKInAppBrowser* instance = nil; self.callbackId = command.callbackId; if (url != nil) { -#ifdef __CORDOVA_4_0_0 NSURL* baseUrl = [self.webViewEngine URL]; -#else - NSURL* baseUrl = [self.webView.request URL]; -#endif NSURL* absoluteUrl = [[NSURL URLWithString:url relativeToURL:baseUrl] absoluteURL]; if ([self isSystemUrl:absoluteUrl]) { @@ -209,16 +199,7 @@ static CDVWKInAppBrowser* instance = nil; } if (self.inAppBrowserViewController == nil) { - NSString* userAgent = [CDVUserAgentUtil originalUserAgent]; - NSString* overrideUserAgent = [self settingForKey:@"OverrideUserAgent"]; - NSString* appendUserAgent = [self settingForKey:@"AppendUserAgent"]; - if(overrideUserAgent){ - userAgent = overrideUserAgent; - } - if(appendUserAgent){ - userAgent = [userAgent stringByAppendingString: appendUserAgent]; - } - self.inAppBrowserViewController = [[CDVWKInAppBrowserViewController alloc] initWithUserAgent:userAgent prevUserAgent:[self.commandDelegate userAgent] browserOptions: browserOptions]; + self.inAppBrowserViewController = [[CDVWKInAppBrowserViewController alloc] initWithBrowserOptions: browserOptions andSettings:self.commandDelegate.settings]; self.inAppBrowserViewController.navigationDelegate = self; if ([self.viewController conformsToProtocol:@protocol(CDVScreenOrientationDelegate)]) { @@ -369,18 +350,9 @@ static CDVWKInAppBrowser* instance = nil; - (void)openInCordovaWebView:(NSURL*)url withOptions:(NSString*)options { NSURLRequest* request = [NSURLRequest requestWithURL:url]; - -#ifdef __CORDOVA_4_0_0 // the webview engine itself will filter for this according to policy // in config.xml for cordova-ios-4.0 [self.webViewEngine loadRequest:request]; -#else - if ([self.commandDelegate URLIsWhitelisted:url]) { - [self.webView loadRequest:request]; - } else { // this assumes the InAppBrowser can be excepted from the white-list - [self openInInAppBrowser:url withOptions:options]; - } -#endif } - (void)openInSystem:(NSURL*)url @@ -725,13 +697,12 @@ static CDVWKInAppBrowser* instance = nil; BOOL viewRenderedAtLeastOnce = FALSE; BOOL isExiting = FALSE; -- (id)initWithUserAgent:(NSString*)userAgent prevUserAgent:(NSString*)prevUserAgent browserOptions: (CDVInAppBrowserOptions*) browserOptions +- (id)initWithBrowserOptions: (CDVInAppBrowserOptions*) browserOptions andSettings:(NSDictionary *)settings { self = [super init]; if (self != nil) { - _userAgent = userAgent; - _prevUserAgent = prevUserAgent; _browserOptions = browserOptions; + _settings = settings; self.webViewUIDelegate = [[CDVWKInAppBrowserUIDelegate alloc] initWithTitle:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"]]; [self.webViewUIDelegate setViewController:self]; @@ -755,6 +726,15 @@ BOOL isExiting = FALSE; WKUserContentController* userContentController = [[WKUserContentController alloc] init]; WKWebViewConfiguration* configuration = [[WKWebViewConfiguration alloc] init]; + + NSString *userAgent = configuration.applicationNameForUserAgent; + if ( + [self settingForKey:@"OverrideUserAgent"] == nil && + [self settingForKey:@"AppendUserAgent"] != nil + ) { + userAgent = [NSString stringWithFormat:@"%@ %@", userAgent, [self settingForKey:@"AppendUserAgent"]]; + } + configuration.applicationNameForUserAgent = userAgent; configuration.userContentController = userContentController; #if __has_include("CDVWKProcessPoolFactory.h") configuration.processPool = [[CDVWKProcessPoolFactory sharedFactory] sharedProcessPool]; @@ -785,6 +765,9 @@ BOOL isExiting = FALSE; self.webView.navigationDelegate = self; self.webView.UIDelegate = self.webViewUIDelegate; self.webView.backgroundColor = [UIColor whiteColor]; + if ([self settingForKey:@"OverrideUserAgent"] != nil) { + self.webView.customUserAgent = [self settingForKey:@"OverrideUserAgent"]; + } self.webView.clearsContextBeforeDrawing = YES; self.webView.clipsToBounds = YES; @@ -915,6 +898,11 @@ BOOL isExiting = FALSE; [self.view addSubview:self.spinner]; } +- (id)settingForKey:(NSString*)key +{ + return [_settings objectForKey:[key lowercaseString]]; +} + - (void) setWebViewFrame : (CGRect) frame { NSLog(@"Setting the WebView's frame to %@", NSStringFromCGRect(frame)); [self.webView setFrame:frame]; @@ -1074,7 +1062,6 @@ BOOL isExiting = FALSE; - (void)close { - [CDVUserAgentUtil releaseLock:&_userAgentLockToken]; self.currentURL = nil; __weak UIViewController* weakSelf = self; @@ -1093,17 +1080,7 @@ BOOL isExiting = FALSE; - (void)navigateTo:(NSURL*)url { NSURLRequest* request = [NSURLRequest requestWithURL:url]; - - if (_userAgentLockToken != 0) { - [self.webView loadRequest:request]; - } else { - __weak CDVWKInAppBrowserViewController* weakSelf = self; - [CDVUserAgentUtil acquireLock:^(NSInteger lockToken) { - _userAgentLockToken = lockToken; - [CDVUserAgentUtil setUserAgent:_userAgent lockToken:lockToken]; - [weakSelf.webView loadRequest:request]; - }]; - } + [self.webView loadRequest:request]; } - (void)goBack:(id)sender @@ -1203,24 +1180,6 @@ BOOL isExiting = FALSE; [self.spinner stopAnimating]; - // Work around a bug where the first time a PDF is opened, all UIWebViews - // reload their User-Agent from NSUserDefaults. - // This work-around makes the following assumptions: - // 1. The app has only a single Cordova Webview. If not, then the app should - // take it upon themselves to load a PDF in the background as a part of - // their start-up flow. - // 2. That the PDF does not require any additional network requests. We change - // the user-agent here back to that of the CDVViewController, so requests - // from it must pass through its white-list. This *does* break PDFs that - // contain links to other remote PDF/websites. - // More info at https://issues.apache.org/jira/browse/CB-2225 - BOOL isPDF = NO; - //TODO webview class - //BOOL isPDF = [@"true" isEqualToString :[theWebView evaluateJavaScript:@"document.body==null"]]; - if (isPDF) { - [CDVUserAgentUtil setUserAgent:_prevUserAgent lockToken:_userAgentLockToken]; - } - [self.navigationDelegate didFinishNavigation:theWebView]; } diff --git a/tests/tests.js b/tests/tests.js index b4d2e68..85d5eba 100644 --- a/tests/tests.js +++ b/tests/tests.js @@ -182,24 +182,13 @@ exports.defineAutoTests = function () { }); }); }; - if (isIos) { - createTests('usewkwebview=no'); - createTests('usewkwebview=yes'); - } else { - createTests(); - } + createTests(); }; exports.defineManualTests = function (contentEl, createActionButton) { var platformOpts = ''; var platform_info = ''; - if (isIos) { - platformOpts = 'usewkwebview=no'; - platform_info = '

Webview

' + - '

Use this button to toggle the Webview implementation.

' + - '
'; - } function doOpen (url, target, params, numExpectedRedirects, useWindowOpen) { numExpectedRedirects = numExpectedRedirects || 0; @@ -543,20 +532,6 @@ exports.defineManualTests = function (contentEl, createActionButton) { var injectjs = isWindows ? basePath + 'inject.js' : 'inject.js'; var injectcss = isWindows ? basePath + 'inject.css' : 'inject.css'; var videohtml = basePath + 'video.html'; - if (isIos) { - createActionButton('Webview=UIWebView', function () { - var webviewOption = 'usewkwebview='; - var webviewToggle = document.getElementById('webviewToggle'); - var button = webviewToggle.getElementsByClassName('topcoat-button')[0]; - if (platformOpts === webviewOption + 'yes') { - platformOpts = webviewOption + 'no'; - button.textContent = 'Webview=UIWebView'; - } else { - platformOpts = webviewOption + 'yes'; - button.textContent = 'Webview=WKWebView'; - } - }, 'webviewToggle'); - } // Local createActionButton('target=Default', function () {