You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by sh...@apache.org on 2014/11/06 11:07:08 UTC
[2/2] ios commit: Separate the WebViews into plugins,
prep for plugin breakout (plus style mixups)
Separate the WebViews into plugins, prep for plugin breakout (plus style mixups)
Project: http://git-wip-us.apache.org/repos/asf/cordova-ios/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-ios/commit/ce6604db
Tree: http://git-wip-us.apache.org/repos/asf/cordova-ios/tree/ce6604db
Diff: http://git-wip-us.apache.org/repos/asf/cordova-ios/diff/ce6604db
Branch: refs/heads/wkwebview
Commit: ce6604dbf1f2e0ecc5f80a94da9da88eac287561
Parents: 5bb4245
Author: Shazron Abdullah <sh...@apache.org>
Authored: Thu Nov 6 02:07:05 2014 -0800
Committer: Shazron Abdullah <sh...@apache.org>
Committed: Thu Nov 6 02:07:05 2014 -0800
----------------------------------------------------------------------
CordovaLib/Classes/CDV.h | 32 +-
CordovaLib/Classes/CDVCommandDelegateImpl.m | 2 +-
CordovaLib/Classes/CDVCommandQueue.m | 4 +-
CordovaLib/Classes/CDVPlugin.m | 2 +-
CordovaLib/Classes/CDVUIWebViewDelegate.h | 42 ++
CordovaLib/Classes/CDVUIWebViewDelegate.m | 417 +++++++++++++++++++
CordovaLib/Classes/CDVUIWebViewEngine.h | 26 ++
CordovaLib/Classes/CDVUIWebViewEngine.m | 164 ++++++++
CordovaLib/Classes/CDVUIWebViewPreferences.h | 29 --
CordovaLib/Classes/CDVUIWebViewPreferences.m | 103 -----
CordovaLib/Classes/CDVViewController.h | 7 +-
CordovaLib/Classes/CDVViewController.m | 114 ++---
CordovaLib/Classes/CDVWKWebViewEngine.h | 28 ++
CordovaLib/Classes/CDVWKWebViewEngine.m | 139 +++++++
CordovaLib/Classes/CDVWKWebViewPreferences.h | 29 --
CordovaLib/Classes/CDVWKWebViewPreferences.m | 48 ---
CordovaLib/Classes/CDVWKWebViewUIDelegate.h | 29 ++
CordovaLib/Classes/CDVWKWebViewUIDelegate.m | 126 ++++++
CordovaLib/Classes/CDVWebViewDelegate.h | 42 --
CordovaLib/Classes/CDVWebViewDelegate.m | 417 -------------------
CordovaLib/Classes/CDVWebViewEngineProtocol.h | 41 ++
CordovaLib/Classes/CDVWebViewPreferences.h | 36 --
CordovaLib/Classes/CDVWebViewPreferences.m | 88 ----
CordovaLib/Classes/CDVWebViewProxy.h | 39 --
CordovaLib/Classes/CDVWebViewProxy.m | 87 ----
CordovaLib/Classes/CDVWebViewUIDelegate.h | 35 --
CordovaLib/Classes/CDVWebViewUIDelegate.m | 126 ------
.../Classes/NSDictionary+CordovaPreferences.h | 35 ++
.../Classes/NSDictionary+CordovaPreferences.m | 63 +++
CordovaLib/CordovaLib.xcodeproj/project.pbxproj | 106 ++---
.../project/__PROJECT_NAME__/config.xml | 2 +-
31 files changed, 1234 insertions(+), 1224 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/ce6604db/CordovaLib/Classes/CDV.h
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDV.h b/CordovaLib/Classes/CDV.h
index 771bdc5..2d14fc3 100644
--- a/CordovaLib/Classes/CDV.h
+++ b/CordovaLib/Classes/CDV.h
@@ -18,26 +18,32 @@
*/
#import "CDVAvailability.h"
-
-#import "CDVPlugin.h"
-#import "CDVViewController.h"
+#import "CDVAvailabilityDeprecated.h"
#import "CDVCommandDelegate.h"
-#import "CDVURLProtocol.h"
-#import "CDVInvokedUrlCommand.h"
-
+#import "CDVCommandDelegateImpl.h"
+#import "CDVCommandQueue.h"
+#import "CDVConfigParser.h"
#import "CDVDebug.h"
-#import "CDVPluginResult.h"
-#import "CDVWhitelist.h"
+#import "CDVInvokedUrlCommand.h"
+#import "CDVJSON.h"
#import "CDVLocalStorage.h"
+#import "CDVPlugin.h"
+#import "CDVPluginResult.h"
#import "CDVScreenOrientationDelegate.h"
+#import "CDVShared.h"
#import "CDVTimer.h"
-#import "CDVWebViewPreferences.h"
-#import "CDVWebViewProxy.h"
-
+#import "CDVUIWebViewDelegate.h"
+#import "CDVUIWebViewEngine.h"
+#import "CDVURLProtocol.h"
+#import "CDVUserAgentUtil.h"
+#import "CDVViewController.h"
+#import "CDVWKWebViewEngine.h"
+#import "CDVWKWebViewUIDelegate.h"
+#import "CDVWebViewEngineProtocol.h"
+#import "CDVWhitelist.h"
#import "NSArray+Comparisons.h"
#import "NSData+Base64.h"
+#import "NSDictionary+CordovaPreferences.h"
#import "NSDictionary+Extensions.h"
#import "NSMutableArray+QueueAdditions.h"
#import "UIDevice+Extensions.h"
-
-#import "CDVJSON.h"
http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/ce6604db/CordovaLib/Classes/CDVCommandDelegateImpl.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVCommandDelegateImpl.m b/CordovaLib/Classes/CDVCommandDelegateImpl.m
index 9a5f2aa..7f4254a 100644
--- a/CordovaLib/Classes/CDVCommandDelegateImpl.m
+++ b/CordovaLib/Classes/CDVCommandDelegateImpl.m
@@ -71,7 +71,7 @@
- (void)evalJsHelper2:(NSString*)js
{
CDV_EXEC_LOG(@"Exec: evalling: %@", [js substringToIndex:MIN([js length], 160)]);
- [_viewController.webViewProxy evaluateJavaScript:js completionHandler:^(id obj, NSError* error) {
+ [_viewController.webViewEngine evaluateJavaScript:js completionHandler:^(id obj, NSError* error) {
// TODO: obj can be something other than string
if ([obj isKindOfClass:[NSString class]]) {
NSString* commandsJSON = (NSString*)obj;
http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/ce6604db/CordovaLib/Classes/CDVCommandQueue.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVCommandQueue.m b/CordovaLib/Classes/CDVCommandQueue.m
index 21a6489..efaf640 100644
--- a/CordovaLib/Classes/CDVCommandQueue.m
+++ b/CordovaLib/Classes/CDVCommandQueue.m
@@ -112,8 +112,8 @@ static const double MAX_EXECUTION_TIME = .008; // Half of a 60fps frame.
__weak CDVCommandQueue* weakSelf = self;
NSString* js = @"cordova.require('cordova/exec').nativeFetchMessages()";
- [_viewController.webViewProxy evaluateJavaScript:js
- completionHandler:^(id obj, NSError* error) {
+ [_viewController.webViewEngine evaluateJavaScript:js
+ completionHandler:^(id obj, NSError* error) {
if ((error == nil) && [obj isKindOfClass:[NSString class]]) {
NSString* queuedCommandsJSON = (NSString*)obj;
CDV_EXEC_LOG(@"Exec: Flushed JS->native queue (hadCommands=%d).", [queuedCommandsJSON length] > 0);
http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/ce6604db/CordovaLib/Classes/CDVPlugin.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVPlugin.m b/CordovaLib/Classes/CDVPlugin.m
index bae6926..ac1ac4d 100644
--- a/CordovaLib/Classes/CDVPlugin.m
+++ b/CordovaLib/Classes/CDVPlugin.m
@@ -132,7 +132,7 @@ NSString* const CDVRemoteNotificationError = @"CDVRemoteNotificationError";
- (NSString*)writeJavascript:(NSString*)javascript
{
// TODO: although deprecated, should have some solution here instead of removing it
- [((CDVViewController*)self.viewController).webViewProxy evaluateJavaScript : javascript completionHandler : nil]; // bad cast, but ok for now
+ [((CDVViewController*)self.viewController).webViewEngine evaluateJavaScript : javascript completionHandler : nil]; // bad cast, but ok for now
return @"";
}
http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/ce6604db/CordovaLib/Classes/CDVUIWebViewDelegate.h
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVUIWebViewDelegate.h b/CordovaLib/Classes/CDVUIWebViewDelegate.h
new file mode 100644
index 0000000..05979ed
--- /dev/null
+++ b/CordovaLib/Classes/CDVUIWebViewDelegate.h
@@ -0,0 +1,42 @@
+/*
+ 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 <UIKit/UIKit.h>
+#import "CDVAvailability.h"
+
+/**
+ * Distinguishes top-level navigations from sub-frame navigations.
+ * shouldStartLoadWithRequest is called for every request, but didStartLoad
+ * and didFinishLoad is called only for top-level navigations.
+ * Relevant bug: CB-2389
+ */
+@interface CDVUIWebViewDelegate : NSObject <UIWebViewDelegate>{
+ __weak NSObject <UIWebViewDelegate>* _delegate;
+ NSInteger _loadCount;
+ NSInteger _state;
+ NSInteger _curLoadToken;
+ NSInteger _loadStartPollCount;
+}
+
+- (id)initWithDelegate:(NSObject <UIWebViewDelegate>*)delegate;
+- (BOOL)request:(NSURLRequest*)newRequest isFragmentIdentifierToRequest:(NSURLRequest*)originalRequest CDV_DEPRECATED(3.5, "Use request:isEqualToRequestAfterStrippingFragments: instead.");
+
+- (BOOL)request:(NSURLRequest*)newRequest isEqualToRequestAfterStrippingFragments:(NSURLRequest*)originalRequest;
+
+@end
http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/ce6604db/CordovaLib/Classes/CDVUIWebViewDelegate.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVUIWebViewDelegate.m b/CordovaLib/Classes/CDVUIWebViewDelegate.m
new file mode 100644
index 0000000..230a7fa
--- /dev/null
+++ b/CordovaLib/Classes/CDVUIWebViewDelegate.m
@@ -0,0 +1,417 @@
+/*
+ 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.
+ */
+
+//
+// Testing shows:
+//
+// In all cases, webView.request.URL is the previous page's URL (or empty) during the didStartLoad callback.
+// When loading a page with a redirect:
+// 1. shouldStartLoading (requestURL is target page)
+// 2. didStartLoading
+// 3. shouldStartLoading (requestURL is redirect target)
+// 4. didFinishLoad (request.URL is redirect target)
+//
+// Note the lack of a second didStartLoading **
+//
+// When loading a page with iframes:
+// 1. shouldStartLoading (requestURL is main page)
+// 2. didStartLoading
+// 3. shouldStartLoading (requestURL is one of the iframes)
+// 4. didStartLoading
+// 5. didFinishLoad
+// 6. didFinishLoad
+//
+// Note there is no way to distinguish which didFinishLoad maps to which didStartLoad **
+//
+// Loading a page by calling window.history.go(-1):
+// 1. didStartLoading
+// 2. didFinishLoad
+//
+// Note the lack of a shouldStartLoading call **
+// Actually - this is fixed on iOS6. iOS6 has a shouldStart. **
+//
+// Loading a page by calling location.reload()
+// 1. shouldStartLoading
+// 2. didStartLoading
+// 3. didFinishLoad
+//
+// Loading a page with an iframe that fails to load:
+// 1. shouldStart (main page)
+// 2. didStart
+// 3. shouldStart (iframe)
+// 4. didStart
+// 5. didFailWithError
+// 6. didFinish
+//
+// Loading a page with an iframe that fails to load due to an invalid URL:
+// 1. shouldStart (main page)
+// 2. didStart
+// 3. shouldStart (iframe)
+// 5. didFailWithError
+// 6. didFinish
+//
+// This case breaks our logic since there is a missing didStart. To prevent this,
+// we check URLs in shouldStart and return NO if they are invalid.
+//
+// Loading a page with an invalid URL
+// 1. shouldStart (main page)
+// 2. didFailWithError
+//
+// TODO: Record order when page is re-navigated before the first navigation finishes.
+//
+
+#import "CDVUIWebViewDelegate.h"
+#import "CDVAvailability.h"
+
+// #define VerboseLog NSLog
+#define VerboseLog(...) do {} while (0)
+
+typedef enum {
+ STATE_IDLE = 0,
+ STATE_WAITING_FOR_LOAD_START = 1,
+ STATE_WAITING_FOR_LOAD_FINISH = 2,
+ STATE_IOS5_POLLING_FOR_LOAD_START = 3,
+ STATE_IOS5_POLLING_FOR_LOAD_FINISH = 4,
+ STATE_CANCELLED = 5
+} State;
+
+static NSString *stripFragment(NSString* url)
+{
+ NSRange r = [url rangeOfString:@"#"];
+
+ if (r.location == NSNotFound) {
+ return url;
+ }
+ return [url substringToIndex:r.location];
+}
+
+@implementation CDVUIWebViewDelegate
+
+- (id)initWithDelegate:(NSObject <UIWebViewDelegate>*)delegate
+{
+ self = [super init];
+ if (self != nil) {
+ _delegate = delegate;
+ _loadCount = -1;
+ _state = STATE_IDLE;
+ }
+ return self;
+}
+
+- (BOOL)request:(NSURLRequest*)newRequest isFragmentIdentifierToRequest:(NSURLRequest*)originalRequest
+{
+ return [self request:newRequest isEqualToRequestAfterStrippingFragments:originalRequest];
+}
+
+- (BOOL)request:(NSURLRequest*)newRequest isEqualToRequestAfterStrippingFragments:(NSURLRequest*)originalRequest
+{
+ if (originalRequest.URL && newRequest.URL) {
+ NSString* originalRequestUrl = [originalRequest.URL absoluteString];
+ NSString* newRequestUrl = [newRequest.URL absoluteString];
+
+ NSString* baseOriginalRequestUrl = stripFragment(originalRequestUrl);
+ NSString* baseNewRequestUrl = stripFragment(newRequestUrl);
+ return [baseOriginalRequestUrl isEqualToString:baseNewRequestUrl];
+ }
+
+ return NO;
+}
+
+- (BOOL)isPageLoaded:(UIWebView*)webView
+{
+ NSString* readyState = [webView stringByEvaluatingJavaScriptFromString:@"document.readyState"];
+
+ return [readyState isEqualToString:@"loaded"] || [readyState isEqualToString:@"complete"];
+}
+
+- (BOOL)isJsLoadTokenSet:(UIWebView*)webView
+{
+ NSString* loadToken = [webView stringByEvaluatingJavaScriptFromString:@"window.__cordovaLoadToken"];
+
+ return [[NSString stringWithFormat:@"%ld", (long)_curLoadToken] isEqualToString:loadToken];
+}
+
+- (void)setLoadToken:(UIWebView*)webView
+{
+ _curLoadToken += 1;
+ [webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"window.__cordovaLoadToken=%ld", (long)_curLoadToken]];
+}
+
+- (NSString*)evalForCurrentURL:(UIWebView*)webView
+{
+ return [webView stringByEvaluatingJavaScriptFromString:@"location.href"];
+}
+
+- (void)pollForPageLoadStart:(UIWebView*)webView
+{
+ if (_state != STATE_IOS5_POLLING_FOR_LOAD_START) {
+ return;
+ }
+ if (![self isJsLoadTokenSet:webView]) {
+ VerboseLog(@"Polled for page load start. result = YES!");
+ _state = STATE_IOS5_POLLING_FOR_LOAD_FINISH;
+ [self setLoadToken:webView];
+ if ([_delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
+ [_delegate webViewDidStartLoad:webView];
+ }
+ [self pollForPageLoadFinish:webView];
+ } else {
+ VerboseLog(@"Polled for page load start. result = NO");
+ // Poll only for 1 second, and then fall back on checking only when delegate methods are called.
+ ++_loadStartPollCount;
+ if (_loadStartPollCount < (1000 * .05)) {
+ [self performSelector:@selector(pollForPageLoadStart:) withObject:webView afterDelay:.05];
+ }
+ }
+}
+
+- (void)pollForPageLoadFinish:(UIWebView*)webView
+{
+ if (_state != STATE_IOS5_POLLING_FOR_LOAD_FINISH) {
+ return;
+ }
+ if ([self isPageLoaded:webView]) {
+ VerboseLog(@"Polled for page load finish. result = YES!");
+ _state = STATE_IDLE;
+ if ([_delegate respondsToSelector:@selector(webViewDidFinishLoad:)]) {
+ [_delegate webViewDidFinishLoad:webView];
+ }
+ } else {
+ VerboseLog(@"Polled for page load finish. result = NO");
+ [self performSelector:@selector(pollForPageLoadFinish:) withObject:webView afterDelay:.05];
+ }
+}
+
+- (BOOL)shouldLoadRequest:(NSURLRequest*)request
+{
+ NSString* scheme = [[request URL] scheme];
+
+ if ([scheme isEqualToString:@"mailto"] || [scheme isEqualToString:@"tel"]) {
+ return YES;
+ }
+
+ return [NSURLConnection canHandleRequest:request];
+}
+
+- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
+{
+ BOOL shouldLoad = YES;
+
+ if ([_delegate respondsToSelector:@selector(webView:shouldStartLoadWithRequest:navigationType:)]) {
+ shouldLoad = [_delegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType];
+ }
+
+ VerboseLog(@"webView shouldLoad=%d (before) state=%d loadCount=%d URL=%@", shouldLoad, _state, _loadCount, request.URL);
+
+ if (shouldLoad) {
+ // When devtools refresh occurs, it blindly uses the same request object. If a history.replaceState() has occured, then
+ // mainDocumentURL != URL even though it's a top-level navigation.
+ BOOL isDevToolsRefresh = (request == webView.request);
+ BOOL isTopLevelNavigation = isDevToolsRefresh || [request.URL isEqual:[request mainDocumentURL]];
+ if (isTopLevelNavigation) {
+ // Ignore hash changes that don't navigate to a different page.
+ // webView.request does actually update when history.replaceState() gets called.
+ if ([self request:request isEqualToRequestAfterStrippingFragments:webView.request]) {
+ NSString* prevURL = [self evalForCurrentURL:webView];
+ if ([prevURL isEqualToString:[request.URL absoluteString]]) {
+ VerboseLog(@"Page reload detected.");
+ } else {
+ VerboseLog(@"Detected hash change shouldLoad");
+ return shouldLoad;
+ }
+ }
+
+ switch (_state) {
+ case STATE_WAITING_FOR_LOAD_FINISH:
+ // Redirect case.
+ // We expect loadCount == 1.
+ if (_loadCount != 1) {
+ NSLog(@"CDVWebViewDelegate: Detected redirect when loadCount=%ld", (long)_loadCount);
+ }
+ break;
+
+ case STATE_IDLE:
+ case STATE_IOS5_POLLING_FOR_LOAD_START:
+ case STATE_CANCELLED:
+ // Page navigation start.
+ _loadCount = 0;
+ _state = STATE_WAITING_FOR_LOAD_START;
+ break;
+
+ default:
+ {
+ _loadCount = 0;
+ _state = STATE_WAITING_FOR_LOAD_START;
+ NSString* description = [NSString stringWithFormat:@"CDVWebViewDelegate: Navigation started when state=%ld", (long)_state];
+ NSLog(@"%@", description);
+ if ([_delegate respondsToSelector:@selector(webView:didFailLoadWithError:)]) {
+ NSDictionary* errorDictionary = @{NSLocalizedDescriptionKey : description};
+ NSError* error = [[NSError alloc] initWithDomain:@"CDVUIWebViewDelegate" code:1 userInfo:errorDictionary];
+ [_delegate webView:webView didFailLoadWithError:error];
+ }
+ }
+ }
+ } else {
+ // Deny invalid URLs so that we don't get the case where we go straight from
+ // webViewShouldLoad -> webViewDidFailLoad (messes up _loadCount).
+ shouldLoad = shouldLoad && [self shouldLoadRequest:request];
+ }
+ VerboseLog(@"webView shouldLoad=%d (after) isTopLevelNavigation=%d state=%d loadCount=%d", shouldLoad, isTopLevelNavigation, _state, _loadCount);
+ }
+ return shouldLoad;
+}
+
+- (void)webViewDidStartLoad:(UIWebView*)webView
+{
+ VerboseLog(@"webView didStartLoad (before). state=%d loadCount=%d", _state, _loadCount);
+ BOOL fireCallback = NO;
+ switch (_state) {
+ case STATE_IDLE:
+ if (IsAtLeastiOSVersion(@"6.0")) {
+ break;
+ }
+ // If history.go(-1) is used pre-iOS6, the shouldStartLoadWithRequest function is not called.
+ // Without shouldLoad, we can't distinguish an iframe from a top-level navigation.
+ // We could try to distinguish using [UIWebView canGoForward], but that's too much complexity,
+ // and would work only on the first time it was used.
+
+ // Our work-around is to set a JS variable and poll until it disappears (from a navigation).
+ _state = STATE_IOS5_POLLING_FOR_LOAD_START;
+ _loadStartPollCount = 0;
+ [self setLoadToken:webView];
+ [self pollForPageLoadStart:webView];
+ break;
+
+ case STATE_CANCELLED:
+ fireCallback = YES;
+ _state = STATE_WAITING_FOR_LOAD_FINISH;
+ _loadCount += 1;
+ break;
+
+ case STATE_WAITING_FOR_LOAD_START:
+ if (_loadCount != 0) {
+ NSLog(@"CDVWebViewDelegate: Unexpected loadCount in didStart. count=%ld", (long)_loadCount);
+ }
+ fireCallback = YES;
+ _state = STATE_WAITING_FOR_LOAD_FINISH;
+ _loadCount = 1;
+ break;
+
+ case STATE_WAITING_FOR_LOAD_FINISH:
+ _loadCount += 1;
+ break;
+
+ case STATE_IOS5_POLLING_FOR_LOAD_START:
+ [self pollForPageLoadStart:webView];
+ break;
+
+ case STATE_IOS5_POLLING_FOR_LOAD_FINISH:
+ [self pollForPageLoadFinish:webView];
+ break;
+
+ default:
+ NSLog(@"CDVWebViewDelegate: Unexpected didStart with state=%ld loadCount=%ld", (long)_state, (long)_loadCount);
+ }
+ VerboseLog(@"webView didStartLoad (after). state=%d loadCount=%d fireCallback=%d", _state, _loadCount, fireCallback);
+ if (fireCallback && [_delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
+ [_delegate webViewDidStartLoad:webView];
+ }
+}
+
+- (void)webViewDidFinishLoad:(UIWebView*)webView
+{
+ VerboseLog(@"webView didFinishLoad (before). state=%d loadCount=%d", _state, _loadCount);
+ BOOL fireCallback = NO;
+ switch (_state) {
+ case STATE_IDLE:
+ break;
+
+ case STATE_WAITING_FOR_LOAD_START:
+ NSLog(@"CDVWebViewDelegate: Unexpected didFinish while waiting for load start.");
+ break;
+
+ case STATE_WAITING_FOR_LOAD_FINISH:
+ if (_loadCount == 1) {
+ fireCallback = YES;
+ _state = STATE_IDLE;
+ }
+ _loadCount -= 1;
+ break;
+
+ case STATE_IOS5_POLLING_FOR_LOAD_START:
+ [self pollForPageLoadStart:webView];
+ break;
+
+ case STATE_IOS5_POLLING_FOR_LOAD_FINISH:
+ [self pollForPageLoadFinish:webView];
+ break;
+ }
+ VerboseLog(@"webView didFinishLoad (after). state=%d loadCount=%d fireCallback=%d", _state, _loadCount, fireCallback);
+ if (fireCallback && [_delegate respondsToSelector:@selector(webViewDidFinishLoad:)]) {
+ [_delegate webViewDidFinishLoad:webView];
+ }
+}
+
+- (void)webView:(UIWebView*)webView didFailLoadWithError:(NSError*)error
+{
+ VerboseLog(@"webView didFailLoad (before). state=%d loadCount=%d", _state, _loadCount);
+ BOOL fireCallback = NO;
+
+ switch (_state) {
+ case STATE_IDLE:
+ break;
+
+ case STATE_WAITING_FOR_LOAD_START:
+ if ([error code] == NSURLErrorCancelled) {
+ _state = STATE_CANCELLED;
+ } else {
+ _state = STATE_IDLE;
+ }
+ fireCallback = YES;
+ break;
+
+ case STATE_WAITING_FOR_LOAD_FINISH:
+ if ([error code] != NSURLErrorCancelled) {
+ if (_loadCount == 1) {
+ _state = STATE_IDLE;
+ fireCallback = YES;
+ }
+ _loadCount = -1;
+ } else {
+ fireCallback = YES;
+ _state = STATE_CANCELLED;
+ _loadCount -= 1;
+ }
+ break;
+
+ case STATE_IOS5_POLLING_FOR_LOAD_START:
+ [self pollForPageLoadStart:webView];
+ break;
+
+ case STATE_IOS5_POLLING_FOR_LOAD_FINISH:
+ [self pollForPageLoadFinish:webView];
+ break;
+ }
+ VerboseLog(@"webView didFailLoad (after). state=%d loadCount=%d, fireCallback=%d", _state, _loadCount, fireCallback);
+ if (fireCallback && [_delegate respondsToSelector:@selector(webView:didFailLoadWithError:)]) {
+ [_delegate webView:webView didFailLoadWithError:error];
+ }
+}
+
+@end
http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/ce6604db/CordovaLib/Classes/CDVUIWebViewEngine.h
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVUIWebViewEngine.h b/CordovaLib/Classes/CDVUIWebViewEngine.h
new file mode 100644
index 0000000..ea1d8f5
--- /dev/null
+++ b/CordovaLib/Classes/CDVUIWebViewEngine.h
@@ -0,0 +1,26 @@
+/*
+ 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 <Foundation/Foundation.h>
+#import "CDVWebViewEngineProtocol.h"
+#import "CDVPlugin.h"
+
+@interface CDVUIWebViewEngine : CDVPlugin <CDVWebViewEngineProtocol>
+
+@end
http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/ce6604db/CordovaLib/Classes/CDVUIWebViewEngine.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVUIWebViewEngine.m b/CordovaLib/Classes/CDVUIWebViewEngine.m
new file mode 100644
index 0000000..e81778f
--- /dev/null
+++ b/CordovaLib/Classes/CDVUIWebViewEngine.m
@@ -0,0 +1,164 @@
+/*
+ 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 "CDVUIWebViewEngine.h"
+#import "CDVUIWebViewDelegate.h"
+#import "NSDictionary+CordovaPreferences.h"
+
+#import <objc/message.h>
+
+@interface CDVUIWebViewEngine ()
+
+@property (nonatomic, strong, readwrite) UIView* engineWebView;
+
+@end
+
+// see forwardingTargetForSelector: selector comment for the reason for this pragma
+#pragma clang diagnostic ignored "-Wprotocol"
+
+@implementation CDVUIWebViewEngine
+
+@synthesize engineWebView = _engineWebView;
+
+- (instancetype)initWithFrame:(CGRect)frame
+{
+ self = [super init];
+ if (self) {
+ self.engineWebView = [[UIWebView alloc] initWithFrame:frame];
+ NSLog(@"Using UIWebView");
+ }
+
+ return self;
+}
+
+- (void)evaluateJavaScript:(NSString*)javaScriptString completionHandler:(void (^)(id, NSError*))completionHandler
+{
+ NSString* ret = [(UIWebView*)_engineWebView stringByEvaluatingJavaScriptFromString : javaScriptString];
+
+ if (completionHandler) {
+ completionHandler(ret, nil);
+ }
+}
+
+- (void)loadFileURL:(NSURL*)url allowingReadAccessToURL:(NSURL*)readAccessURL
+{
+ __weak CDVUIWebViewEngine* weakSelf = self;
+
+ // UIKit operations have to be on the main thread. This method does not need to be synchronous
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [weakSelf loadRequest:[NSURLRequest requestWithURL:url]];
+ });
+}
+
+- (void)updateSettings:(NSDictionary*)settings
+{
+ UIWebView* uiWebView = (UIWebView*)_engineWebView;
+
+ uiWebView.scalesPageToFit = [settings cordovaBoolSettingForKey:@"EnableViewportScale" defaultValue:NO];
+ uiWebView.allowsInlineMediaPlayback = [settings cordovaBoolSettingForKey:@"AllowInlineMediaPlayback" defaultValue:NO];
+ uiWebView.mediaPlaybackRequiresUserAction = [settings cordovaBoolSettingForKey:@"MediaPlaybackRequiresUserAction" defaultValue:YES];
+ uiWebView.mediaPlaybackAllowsAirPlay = [settings cordovaBoolSettingForKey:@"MediaPlaybackAllowsAirPlay" defaultValue:YES];
+ uiWebView.keyboardDisplayRequiresUserAction = [settings cordovaBoolSettingForKey:@"KeyboardDisplayRequiresUserAction" defaultValue:YES];
+ uiWebView.suppressesIncrementalRendering = [settings cordovaBoolSettingForKey:@"SuppressesIncrementalRendering" defaultValue:NO];
+ uiWebView.gapBetweenPages = [settings cordovaFloatSettingForKey:@"GapBetweenPages" defaultValue:0.0];
+ uiWebView.pageLength = [settings cordovaFloatSettingForKey:@"PageLength" defaultValue:0.0];
+
+ id prefObj = nil;
+
+ // By default, DisallowOverscroll is false (thus bounce is allowed)
+ BOOL bounceAllowed = !([settings cordovaBoolSettingForKey:@"DisallowOverscroll" defaultValue:NO]);
+
+ // prevent webView from bouncing
+ if (!bounceAllowed) {
+ if ([self.webView respondsToSelector:@selector(scrollView)]) {
+ ((UIScrollView*)[uiWebView scrollView]).bounces = NO;
+ } else {
+ for (id subview in self.webView.subviews) {
+ if ([[subview class] isSubclassOfClass:[UIScrollView class]]) {
+ ((UIScrollView*)subview).bounces = NO;
+ }
+ }
+ }
+ }
+
+ NSString* decelerationSetting = [settings cordovaSettingForKey:@"UIWebViewDecelerationSpeed"];
+ if (![@"fast" isEqualToString : decelerationSetting]) {
+ [uiWebView.scrollView setDecelerationRate:UIScrollViewDecelerationRateNormal];
+ }
+
+ NSInteger paginationBreakingMode = 0; // default - UIWebPaginationBreakingModePage
+ prefObj = [settings cordovaSettingForKey:@"PaginationBreakingMode"];
+ if (prefObj != nil) {
+ NSArray* validValues = @[@"page", @"column"];
+ NSString* prefValue = [validValues objectAtIndex:0];
+
+ if ([prefObj isKindOfClass:[NSString class]]) {
+ prefValue = prefObj;
+ }
+
+ paginationBreakingMode = [validValues indexOfObject:[prefValue lowercaseString]];
+ if (paginationBreakingMode == NSNotFound) {
+ paginationBreakingMode = 0;
+ }
+ }
+ uiWebView.paginationBreakingMode = paginationBreakingMode;
+
+ NSInteger paginationMode = 0; // default - UIWebPaginationModeUnpaginated
+ prefObj = [settings cordovaSettingForKey:@"PaginationMode"];
+ if (prefObj != nil) {
+ NSArray* validValues = @[@"unpaginated", @"lefttoright", @"toptobottom", @"bottomtotop", @"righttoleft"];
+ NSString* prefValue = [validValues objectAtIndex:0];
+
+ if ([prefObj isKindOfClass:[NSString class]]) {
+ prefValue = prefObj;
+ }
+
+ paginationMode = [validValues indexOfObject:[prefValue lowercaseString]];
+ if (paginationMode == NSNotFound) {
+ paginationMode = 0;
+ }
+ }
+ uiWebView.paginationMode = paginationMode;
+}
+
+- (void)updateWithInfo:(NSDictionary*)info
+{
+ id <UIWebViewDelegate> uiWebViewDelegate = [info objectForKey:kCDVWebViewEngineUIWebViewDelegate];
+ NSDictionary* settings = [info objectForKey:kCDVWebViewEngineWebViewPreferences];
+
+ if (uiWebViewDelegate &&
+ [uiWebViewDelegate conformsToProtocol:@protocol(UIWebViewDelegate)]) {
+ ((UIWebView*)_engineWebView).delegate = uiWebViewDelegate;
+ }
+
+ if (settings && [settings isKindOfClass:[NSDictionary class]]) {
+ [self updateSettings:settings];
+ }
+}
+
+// This forwards the methods that are in the header that are not implemented here.
+// Both WKWebView and UIWebView implement the below:
+// loadHTMLString:baseURL:
+// loadRequest:
+- (id)forwardingTargetForSelector:(SEL)aSelector
+{
+ return _engineWebView;
+}
+
+@end
http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/ce6604db/CordovaLib/Classes/CDVUIWebViewPreferences.h
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVUIWebViewPreferences.h b/CordovaLib/Classes/CDVUIWebViewPreferences.h
deleted file mode 100644
index dd5caf9..0000000
--- a/CordovaLib/Classes/CDVUIWebViewPreferences.h
+++ /dev/null
@@ -1,29 +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 "CDVWebViewPreferences.h"
-#import <UIKit/UIKit.h>
-
-@interface CDVUIWebViewPreferences : CDVWebViewPreferences
-
-@property (nonatomic, weak) UIWebView* webView;
-
-- (instancetype)initWithWebView:(UIWebView*)webView settings:(NSDictionary*)settings;
-
-@end
http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/ce6604db/CordovaLib/Classes/CDVUIWebViewPreferences.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVUIWebViewPreferences.m b/CordovaLib/Classes/CDVUIWebViewPreferences.m
deleted file mode 100644
index 5eae9b1..0000000
--- a/CordovaLib/Classes/CDVUIWebViewPreferences.m
+++ /dev/null
@@ -1,103 +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 "CDVUIWebViewPreferences.h"
-
-@implementation CDVUIWebViewPreferences
-
-- (instancetype)initWithWebView:(UIWebView*)webView settings:(NSDictionary*)settings
-{
- self = [super initWithSettings:settings];
- if (self) {
- self.webView = webView;
- }
-
- return self;
-}
-
-- (void)update
-{
- self.webView.scalesPageToFit = [self boolSettingForKey:@"EnableViewportScale" defaultValue:NO];
- self.webView.allowsInlineMediaPlayback = [self boolSettingForKey:@"AllowInlineMediaPlayback" defaultValue:NO];
- self.webView.mediaPlaybackRequiresUserAction = [self boolSettingForKey:@"MediaPlaybackRequiresUserAction" defaultValue:YES];
- self.webView.mediaPlaybackAllowsAirPlay = [self boolSettingForKey:@"MediaPlaybackAllowsAirPlay" defaultValue:YES];
- self.webView.keyboardDisplayRequiresUserAction = [self boolSettingForKey:@"KeyboardDisplayRequiresUserAction" defaultValue:YES];
- self.webView.suppressesIncrementalRendering = [self boolSettingForKey:@"SuppressesIncrementalRendering" defaultValue:NO];
- self.webView.gapBetweenPages = [self floatSettingForKey:@"GapBetweenPages" defaultValue:0.0];
- self.webView.pageLength = [self floatSettingForKey:@"PageLength" defaultValue:0.0];
-
- id prefObj = nil;
-
- // By default, DisallowOverscroll is false (thus bounce is allowed)
- BOOL bounceAllowed = !([self boolSettingForKey:@"DisallowOverscroll" defaultValue:NO]);
-
- // prevent webView from bouncing
- if (!bounceAllowed) {
- if ([self.webView respondsToSelector:@selector(scrollView)]) {
- ((UIScrollView*)[self.webView scrollView]).bounces = NO;
- } else {
- for (id subview in self.webView.subviews) {
- if ([[subview class] isSubclassOfClass:[UIScrollView class]]) {
- ((UIScrollView*)subview).bounces = NO;
- }
- }
- }
- }
-
- NSString* decelerationSetting = [self settingForKey:@"UIWebViewDecelerationSpeed"];
- if (![@"fast" isEqualToString : decelerationSetting]) {
- [self.webView.scrollView setDecelerationRate:UIScrollViewDecelerationRateNormal];
- }
-
- NSInteger paginationBreakingMode = 0; // default - UIWebPaginationBreakingModePage
- prefObj = [self settingForKey:@"PaginationBreakingMode"];
- if (prefObj != nil) {
- NSArray* validValues = @[@"page", @"column"];
- NSString* prefValue = [validValues objectAtIndex:0];
-
- if ([prefObj isKindOfClass:[NSString class]]) {
- prefValue = prefObj;
- }
-
- paginationBreakingMode = [validValues indexOfObject:[prefValue lowercaseString]];
- if (paginationBreakingMode == NSNotFound) {
- paginationBreakingMode = 0;
- }
- }
- self.webView.paginationBreakingMode = paginationBreakingMode;
-
- NSInteger paginationMode = 0; // default - UIWebPaginationModeUnpaginated
- prefObj = [self settingForKey:@"PaginationMode"];
- if (prefObj != nil) {
- NSArray* validValues = @[@"unpaginated", @"lefttoright", @"toptobottom", @"bottomtotop", @"righttoleft"];
- NSString* prefValue = [validValues objectAtIndex:0];
-
- if ([prefObj isKindOfClass:[NSString class]]) {
- prefValue = prefObj;
- }
-
- paginationMode = [validValues indexOfObject:[prefValue lowercaseString]];
- if (paginationMode == NSNotFound) {
- paginationMode = 0;
- }
- }
- self.webView.paginationMode = paginationMode;
-}
-
-@end
http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/ce6604db/CordovaLib/Classes/CDVViewController.h
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVViewController.h b/CordovaLib/Classes/CDVViewController.h
index e5acc20..453ce30 100644
--- a/CordovaLib/Classes/CDVViewController.h
+++ b/CordovaLib/Classes/CDVViewController.h
@@ -26,7 +26,8 @@
#import "CDVWhitelist.h"
#import "CDVScreenOrientationDelegate.h"
#import "CDVPlugin.h"
-#import "CDVWebViewProxy.h"
+#import "CDVWebViewEngineProtocol.h"
+
#ifdef __IPHONE_8_0
#import <WebKit/WebKit.h>
#else
@@ -38,7 +39,7 @@
@interface CDVViewController : UIViewController <UIWebViewDelegate, CDVScreenOrientationDelegate, WKScriptMessageHandler>{
@protected
- CDVWebViewProxy* _webViewProxy;
+ id <CDVWebViewEngineProtocol> _webViewEngine;
@protected
id <CDVCommandDelegate> _commandDelegate;
@protected
@@ -58,7 +59,7 @@
@property (nonatomic, readwrite, copy) NSString* wwwFolderName;
@property (nonatomic, readwrite, copy) NSString* startPage;
@property (nonatomic, readonly, strong) CDVCommandQueue* commandQueue;
-@property (nonatomic, readonly, strong) CDVWebViewProxy* webViewProxy;
+@property (nonatomic, readonly, strong) id <CDVWebViewEngineProtocol> webViewEngine;
@property (nonatomic, readonly, strong) id <CDVCommandDelegate> commandDelegate;
/**
http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/ce6604db/CordovaLib/Classes/CDVViewController.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVViewController.m b/CordovaLib/Classes/CDVViewController.m
index be31591..10c68ec 100644
--- a/CordovaLib/Classes/CDVViewController.m
+++ b/CordovaLib/Classes/CDVViewController.m
@@ -17,21 +17,20 @@
under the License.
*/
-#import <objc/message.h>
#import "CDV.h"
#import "CDVCommandDelegateImpl.h"
#import "CDVConfigParser.h"
#import "CDVUserAgentUtil.h"
-#import "CDVWebViewDelegate.h"
-#import "CDVWebViewUIDelegate.h"
+#import "CDVUIWebViewDelegate.h"
+#import "NSDictionary+CordovaPreferences.h"
+
+#import <objc/message.h>
#import <AVFoundation/AVFoundation.h>
#define degreesToRadian(x) (M_PI * (x) / 180.0)
@interface CDVViewController () {
NSInteger _userAgentLockToken;
- CDVWebViewDelegate* _webViewDelegate;
- CDVWebViewUIDelegate* _webViewUIDelegate;
}
@property (nonatomic, readwrite, strong) NSXMLParser* configParser;
@@ -42,6 +41,7 @@
@property (nonatomic, readwrite, strong) NSDictionary* pluginsMap;
@property (nonatomic, readwrite, strong) NSArray* supportedOrientations;
@property (nonatomic, readwrite, assign) BOOL loadFromString;
+@property (nonatomic, readwrite, strong) id <CDVWebViewEngineProtocol> webViewEngine;
@property (readwrite, assign) BOOL initialized;
@@ -57,7 +57,7 @@
@synthesize wwwFolderName, startPage, initialized, openURL, baseUserAgent;
@synthesize commandDelegate = _commandDelegate;
@synthesize commandQueue = _commandQueue;
-@synthesize webViewProxy = _webViewProxy;
+@synthesize webViewEngine = _webViewEngine;
- (void)__init
{
@@ -177,13 +177,13 @@
NSURL* url = [NSURL fileURLWithPath:path];
- configParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
- if (configParser == nil) {
+ self.configParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
+ if (self.configParser == nil) {
NSLog(@"Failed to initialize XML parser.");
return;
}
- [configParser setDelegate:((id < NSXMLParserDelegate >)delegate)];
- [configParser parse];
+ [self.configParser setDelegate:((id < NSXMLParserDelegate >)delegate)];
+ [self.configParser parse];
// Get the plugin dictionary, whitelist and settings from the delegate.
self.pluginsMap = delegate.pluginsDict;
@@ -237,7 +237,7 @@
{
NSURL* errorURL = nil;
- id setting = [self settingForKey:@"ErrorUrl"];
+ id setting = [self.settings cordovaSettingForKey:@"ErrorUrl"];
if (setting) {
NSString* errorUrlString = (NSString*)setting;
@@ -264,11 +264,11 @@
NSString* backupWebStorageType = @"cloud"; // default value
- id backupWebStorage = [self settingForKey:@"BackupWebStorage"];
+ id backupWebStorage = [self.settings cordovaSettingForKey:@"BackupWebStorage"];
if ([backupWebStorage isKindOfClass:[NSString class]]) {
backupWebStorageType = backupWebStorage;
}
- [self setSetting:backupWebStorageType forKey:@"BackupWebStorage"];
+ [self.settings setCordovaSetting:backupWebStorageType forKey:@"BackupWebStorage"];
if (IsAtLeastiOSVersion(@"5.1")) {
[CDVLocalStorage __fixupDatabaseLocationsWithBackupType:backupWebStorageType];
@@ -280,12 +280,6 @@
[self createGapView];
}
- // Configure WebView
- _webViewDelegate = [[CDVWebViewDelegate alloc] initWithDelegate:self];
- if ([webView respondsToSelector:@selector(setDelegate:)]) {
- [webView setValue:_webViewDelegate forKey:@"delegate"];
- }
-
// register this viewcontroller with the NSURLProtocol, only after the User-Agent is set
[CDVURLProtocol registerViewController:self];
@@ -299,8 +293,9 @@
[self registerPlugin:[[CDVLocalStorage alloc] initWithWebView:self.webView] withClassName:NSStringFromClass([CDVLocalStorage class])];
}
- CDVWebViewPreferences* prefs = [[CDVWebViewPreferences alloc] initWithWebView:webView settings:self.settings];
- [prefs update];
+ // TODO:
+ // CDVWebViewPreferences* prefs = [[CDVWebViewPreferences alloc] initWithWebView:webView settings:self.settings];
+ // [prefs update];
if ([self.startupPluginNames count] > 0) {
[CDVTimer start:@"TotalPluginStartup"];
@@ -322,7 +317,7 @@
[CDVUserAgentUtil setUserAgent:self.userAgent lockToken:lockToken];
if (appURL) {
NSURLRequest* appReq = [NSURLRequest requestWithURL:appURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0];
- [_webViewProxy loadRequest:appReq];
+ [self.webViewEngine loadRequest:appReq];
} else {
NSString* loadErr = [NSString stringWithFormat:@"ERROR: Start Page at '%@/%@' was not found.", self.wwwFolderName, self.startPage];
NSLog(@"%@", loadErr);
@@ -331,25 +326,15 @@
if (errorUrl) {
errorUrl = [NSURL URLWithString:[NSString stringWithFormat:@"?error=%@", [loadErr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]] relativeToURL:errorUrl];
NSLog(@"%@", [errorUrl absoluteString]);
- [_webViewProxy loadRequest:[NSURLRequest requestWithURL:errorUrl]];
+ [self.webViewEngine loadRequest:[NSURLRequest requestWithURL:errorUrl]];
} else {
NSString* html = [NSString stringWithFormat:@"<html><body> %@ </body></html>", loadErr];
- [_webViewProxy loadHTMLString:html baseURL:nil];
+ [self.webViewEngine loadHTMLString:html baseURL:nil];
}
}
}];
}
-- (id)settingForKey:(NSString*)key
-{
- return [[self settings] objectForKey:[key lowercaseString]];
-}
-
-- (void)setSetting:(id)setting forKey:(NSString*)key
-{
- [[self settings] setObject:setting forKey:[key lowercaseString]];
-}
-
- (NSArray*)parseInterfaceOrientations:(NSArray*)orientations
{
NSMutableArray* result = [[NSMutableArray alloc] init];
@@ -407,7 +392,7 @@
, (long)[self mapIosOrientationToJsOrientation:interfaceOrientation]];
__weak CDVViewController* weakSelf = self;
- [_webViewProxy evaluateJavaScript:jsCall completionHandler:^(NSString* obj, NSError* error) {
+ [_webViewEngine evaluateJavaScript:jsCall completionHandler:^(NSString* obj, NSError* error) {
if ([obj length] > 0) {
completionHandler([obj boolValue]);
} else {
@@ -449,37 +434,28 @@
- (UIView*)newCordovaViewWithFrame:(CGRect)bounds
{
- UIView* cordovaView = nil;
- BOOL useWKWebView = NO; // default value
+ NSString* defaultWebViewEngineClass = @"CDVUIWebViewEngine";
+ NSString* webViewEngineClass = [self.settings cordovaSettingForKey:@"CordovaWebViewEngine"];
- if ([self settingForKey:@"UseWKWebView"]) {
- useWKWebView = [(NSNumber*)[self settingForKey:@"UseWKWebView"] boolValue];
+ if (!webViewEngineClass) {
+ webViewEngineClass = defaultWebViewEngineClass;
}
- if (NSClassFromString(@"WKWebView") && useWKWebView) {
-#ifdef __IPHONE_8_0
- WKUserContentController* userContentController = [[WKUserContentController alloc] init];
-
- // scriptMessageHandler is the object that conforms to the WKScriptMessageHandler protocol
- // see https://developer.apple.com/library/prerelease/ios/documentation/WebKit/Reference/WKScriptMessageHandler_Ref/index.html#//apple_ref/swift/intf/WKScriptMessageHandler
- if ([self conformsToProtocol:@protocol(WKScriptMessageHandler)]) {
- [userContentController addScriptMessageHandler:self name:@"cordova"];
- }
-
- WKWebViewConfiguration* configuration = [[WKWebViewConfiguration alloc] init];
- configuration.userContentController = userContentController;
-
- cordovaView = [[WKWebView alloc] initWithFrame:bounds configuration:configuration];
- NSLog(@"Using a WKWebView");
- _webViewUIDelegate = [[CDVWebViewUIDelegate alloc] initWithTitle:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"]];
- ((WKWebView*)cordovaView).UIDelegate = _webViewUIDelegate;
-#endif
+ // Find webViewEngine
+ if (NSClassFromString(webViewEngineClass)) {
+ self.webViewEngine = [[NSClassFromString(webViewEngineClass) alloc] initWithFrame:bounds];
} else {
- cordovaView = [[UIWebView alloc] initWithFrame:bounds];
- NSLog(@"Using a UIWebView");
+ self.webViewEngine = [[NSClassFromString(defaultWebViewEngineClass) alloc] initWithFrame:bounds];
}
- return cordovaView;
+ NSMutableDictionary* info = [NSMutableDictionary dictionaryWithCapacity:1];
+ [info setValue:@{@"cordova" : self} forKey:kCDVWebViewEngineScriptMessageHandlers];
+ [info setValue:self forKey:kCDVWebViewEngineUIWebViewDelegate];
+ [info setValue:self.settings forKey:kCDVWebViewEngineWebViewPreferences];
+
+ [self.webViewEngine updateWithInfo:info];
+
+ return self.webViewEngine.engineWebView;
}
- (NSString*)userAgent
@@ -504,9 +480,8 @@
webViewBounds.origin = self.view.bounds.origin;
self.webView = [self newCordovaViewWithFrame:webViewBounds];
- self.webView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
- _webViewProxy = [[CDVWebViewProxy alloc] initWithWebView:self.webView];
+ self.webView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
[self.view addSubview:self.webView];
[self.view sendSubviewToBack:self.webView];
}
@@ -541,9 +516,6 @@
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
- if ([webView respondsToSelector:@selector(setDelegate:)]) {
- [webView setValue:nil forKey:@"delegate"];
- }
self.webView = nil;
[CDVUserAgentUtil releaseLock:&_userAgentLockToken];
@@ -900,8 +872,8 @@
dispatch_block_t handleOpenUrl = ^(void) {
NSString* jsString = [NSString stringWithFormat:@"if (typeof handleOpenURL === 'function') { handleOpenURL(\"%@\");}", url];
- [_webViewProxy evaluateJavaScript:jsString
- completionHandler:^(id object, NSError* error) {
+ [_webViewEngine evaluateJavaScript:jsString
+ completionHandler:^(id object, NSError* error) {
if (error == nil) {
weakSelf.openURL = nil;
}
@@ -911,8 +883,8 @@
if (!pageLoaded) {
// query the webview for readystate
NSString* jsString = @"document.readystate";
- [_webViewProxy evaluateJavaScript:jsString
- completionHandler:^(id object, NSError* error) {
+ [_webViewEngine evaluateJavaScript:jsString
+ completionHandler:^(id object, NSError* error) {
if ((error == nil) && [object isKindOfClass:[NSString class]]) {
NSString* readyState = (NSString*)object;
BOOL ready = [readyState isEqualToString:@"loaded"] || [readyState isEqualToString:@"complete"];
@@ -967,10 +939,6 @@
[CDVURLProtocol unregisterViewController:self];
[[NSNotificationCenter defaultCenter] removeObserver:self];
- if ([webView respondsToSelector:@selector(setDelegate:)]) {
- [webView setValue:nil forKey:@"delegate"];
- }
-
self.webView = nil;
[CDVUserAgentUtil releaseLock:&_userAgentLockToken];
[_commandQueue dispose];
http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/ce6604db/CordovaLib/Classes/CDVWKWebViewEngine.h
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVWKWebViewEngine.h b/CordovaLib/Classes/CDVWKWebViewEngine.h
new file mode 100644
index 0000000..fde1d11
--- /dev/null
+++ b/CordovaLib/Classes/CDVWKWebViewEngine.h
@@ -0,0 +1,28 @@
+/*
+ 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 <Foundation/Foundation.h>
+#import "CDVWebViewEngineProtocol.h"
+#import "CDVPlugin.h"
+
+@interface CDVWKWebViewEngine : CDVPlugin <CDVWebViewEngineProtocol>
+
+@property (nonatomic, strong, readonly) id <WKUIDelegate> uiDelegate;
+
+@end
http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/ce6604db/CordovaLib/Classes/CDVWKWebViewEngine.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVWKWebViewEngine.m b/CordovaLib/Classes/CDVWKWebViewEngine.m
new file mode 100644
index 0000000..4907572
--- /dev/null
+++ b/CordovaLib/Classes/CDVWKWebViewEngine.m
@@ -0,0 +1,139 @@
+/*
+ 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 "CDVWKWebViewEngine.h"
+#import "CDVWKWebViewUIDelegate.h"
+#import "NSDictionary+CordovaPreferences.h"
+
+#import <objc/message.h>
+#import <WebKit/WebKit.h>
+
+@interface CDVWKWebViewEngine ()
+
+@property (nonatomic, strong, readwrite) UIView* engineWebView;
+@property (nonatomic, strong, readwrite) id <WKUIDelegate> uiDelegate;
+
+@end
+
+// see forwardingTargetForSelector: selector comment for the reason for this pragma
+#pragma clang diagnostic ignored "-Wprotocol"
+
+@implementation CDVWKWebViewEngine
+
+@synthesize engineWebView = _engineWebView;
+
+- (instancetype)initWithFrame:(CGRect)frame
+{
+ self = [super init];
+ if (self) {
+ self.uiDelegate = [[CDVWKWebViewUIDelegate alloc] initWithTitle:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"]];
+
+ WKUserContentController* userContentController = [[WKUserContentController alloc] init];
+
+ WKWebViewConfiguration* configuration = [[WKWebViewConfiguration alloc] init];
+ configuration.userContentController = userContentController;
+
+ WKWebView* wkWebView = [[WKWebView alloc] initWithFrame:frame configuration:configuration];
+
+ wkWebView.UIDelegate = self.uiDelegate;
+ self.engineWebView = wkWebView;
+
+ NSLog(@"Using WKWebView");
+ }
+
+ return self;
+}
+
+// We implement this here because certain versions of iOS 8 do not implement this
+// in WKWebView, so we need to test for this during runtime.
+// It is speculated that this selector will be available in iOS 8.2 for WKWebView
+- (void)loadFileURL:(NSURL*)url allowingReadAccessToURL:(NSURL*)readAccessURL
+{
+ SEL wk_sel = @selector(loadFileURL:allowingReadAccessToURL:);
+ __weak CDVWKWebViewEngine* weakSelf = self;
+
+ // UIKit operations have to be on the main thread. This method does not need to be synchronous
+ dispatch_async(dispatch_get_main_queue(), ^{
+ if ([_engineWebView respondsToSelector:wk_sel] && [[url scheme] isEqualToString:@"file"]) {
+ ((id (*)(id, SEL, id, id))objc_msgSend)(_engineWebView, wk_sel, url, readAccessURL);
+ } else {
+ [weakSelf loadRequest:[NSURLRequest requestWithURL:url]];
+ }
+ });
+}
+
+- (void)updateSettings:(NSDictionary*)settings
+{
+ WKWebView* wkWebView = (WKWebView*)_engineWebView;
+
+ wkWebView.configuration.preferences.minimumFontSize = [settings cordovaFloatSettingForKey:@"MinimumFontSize" defaultValue:0.0];
+ wkWebView.configuration.allowsInlineMediaPlayback = [settings cordovaBoolSettingForKey:@"AllowInlineMediaPlayback" defaultValue:NO];
+ wkWebView.configuration.mediaPlaybackRequiresUserAction = [settings cordovaBoolSettingForKey:@"MediaPlaybackRequiresUserAction" defaultValue:YES];
+ wkWebView.configuration.suppressesIncrementalRendering = [settings cordovaBoolSettingForKey:@"SuppressesIncrementalRendering" defaultValue:NO];
+ wkWebView.configuration.mediaPlaybackAllowsAirPlay = [settings cordovaBoolSettingForKey:@"MediaPlaybackAllowsAirPlay" defaultValue:YES];
+
+ /*
+ wkWebView.configuration.preferences.javaScriptEnabled = [settings cordovaBoolSettingForKey:@"JavaScriptEnabled" default:YES];
+ wkWebView.configuration.preferences.javaScriptCanOpenWindowsAutomatically = [settings cordovaBoolSettingForKey:@"JavaScriptCanOpenWindowsAutomatically" default:NO];
+ */
+}
+
+- (void)updateWithInfo:(NSDictionary*)info
+{
+ NSDictionary* scriptMessageHandlers = [info objectForKey:kCDVWebViewEngineScriptMessageHandlers];
+ NSDictionary* settings = [info objectForKey:kCDVWebViewEngineWebViewPreferences];
+ id navigationDelegate = [info objectForKey:kCDVWebViewEngineWKNavigationDelegate];
+ id uiDelegate = [info objectForKey:kCDVWebViewEngineWKUIDelegate];
+
+ WKWebView* wkWebView = (WKWebView*)_engineWebView;
+
+ if (scriptMessageHandlers && [scriptMessageHandlers isKindOfClass:[NSDictionary class]]) {
+ NSArray* allKeys = [scriptMessageHandlers allKeys];
+
+ for (NSString* key in allKeys) {
+ id object = [scriptMessageHandlers objectForKey:key];
+ if ([object conformsToProtocol:@protocol(WKScriptMessageHandler)]) {
+ [wkWebView.configuration.userContentController addScriptMessageHandler:object name:key];
+ }
+ }
+ }
+
+ if (navigationDelegate && [navigationDelegate conformsToProtocol:@protocol(WKNavigationDelegate)]) {
+ wkWebView.navigationDelegate = navigationDelegate;
+ }
+
+ if (uiDelegate && [uiDelegate conformsToProtocol:@protocol(WKUIDelegate)]) {
+ wkWebView.UIDelegate = uiDelegate;
+ }
+
+ if (settings && [settings isKindOfClass:[NSDictionary class]]) {
+ [self updateSettings:settings];
+ }
+}
+
+// This forwards the methods that are in the header that are not implemented here.
+// Both WKWebView and UIWebView implement the below:
+// loadHTMLString:baseURL:
+// loadRequest:
+- (id)forwardingTargetForSelector:(SEL)aSelector
+{
+ return _engineWebView;
+}
+
+@end
http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/ce6604db/CordovaLib/Classes/CDVWKWebViewPreferences.h
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVWKWebViewPreferences.h b/CordovaLib/Classes/CDVWKWebViewPreferences.h
deleted file mode 100644
index ffa357a..0000000
--- a/CordovaLib/Classes/CDVWKWebViewPreferences.h
+++ /dev/null
@@ -1,29 +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 "CDVWebViewPreferences.h"
-#import <WebKit/WebKit.h>
-
-@interface CDVWKWebViewPreferences : CDVWebViewPreferences
-
-@property (nonatomic, weak) WKWebView* webView;
-
-- (instancetype)initWithWebView:(WKWebView*)webView settings:(NSDictionary*)settings;
-
-@end
http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/ce6604db/CordovaLib/Classes/CDVWKWebViewPreferences.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVWKWebViewPreferences.m b/CordovaLib/Classes/CDVWKWebViewPreferences.m
deleted file mode 100644
index 6cf1a78..0000000
--- a/CordovaLib/Classes/CDVWKWebViewPreferences.m
+++ /dev/null
@@ -1,48 +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 "CDVWKWebViewPreferences.h"
-
-@implementation CDVWKWebViewPreferences
-
-- (instancetype)initWithWebView:(WKWebView*)webView settings:(NSDictionary*)settings
-{
- self = [super initWithSettings:settings];
- if (self) {
- self.webView = webView;
- }
-
- return self;
-}
-
-- (void)update
-{
- self.webView.configuration.preferences.minimumFontSize = [self floatSettingForKey:@"MinimumFontSize" defaultValue:0.0];
- self.webView.configuration.allowsInlineMediaPlayback = [self boolSettingForKey:@"AllowInlineMediaPlayback" defaultValue:NO];
- self.webView.configuration.mediaPlaybackRequiresUserAction = [self boolSettingForKey:@"MediaPlaybackRequiresUserAction" defaultValue:YES];
- self.webView.configuration.suppressesIncrementalRendering = [self boolSettingForKey:@"SuppressesIncrementalRendering" defaultValue:NO];
- self.webView.configuration.mediaPlaybackAllowsAirPlay = [self boolSettingForKey:@"MediaPlaybackAllowsAirPlay" defaultValue:YES];
-
- /*
- self.webView.configuration.preferences.javaScriptEnabled = [self boolSettingForKey:@"JavaScriptEnabled" default:YES];
- self.webView.configuration.preferences.javaScriptCanOpenWindowsAutomatically = [self boolSettingForKey:@"JavaScriptCanOpenWindowsAutomatically" default:NO];
- */
-}
-
-@end
http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/ce6604db/CordovaLib/Classes/CDVWKWebViewUIDelegate.h
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVWKWebViewUIDelegate.h b/CordovaLib/Classes/CDVWKWebViewUIDelegate.h
new file mode 100644
index 0000000..f8971a9
--- /dev/null
+++ b/CordovaLib/Classes/CDVWKWebViewUIDelegate.h
@@ -0,0 +1,29 @@
+/*
+ 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 <Foundation/Foundation.h>
+#import <WebKit/WebKit.h>
+
+@interface CDVWKWebViewUIDelegate : NSObject <WKUIDelegate>
+
+@property (nonatomic, copy) NSString* title;
+
+- (instancetype)initWithTitle:(NSString*)title;
+
+@end
http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/ce6604db/CordovaLib/Classes/CDVWKWebViewUIDelegate.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVWKWebViewUIDelegate.m b/CordovaLib/Classes/CDVWKWebViewUIDelegate.m
new file mode 100644
index 0000000..e3024b0
--- /dev/null
+++ b/CordovaLib/Classes/CDVWKWebViewUIDelegate.m
@@ -0,0 +1,126 @@
+/*
+ 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.
+ */
+
+#ifdef __IPHONE_8_0
+
+#import "CDVWKWebViewUIDelegate.h"
+
+ @implementation CDVWKWebViewUIDelegate
+
+ - (instancetype)initWithTitle:(NSString*)title
+ {
+ self = [super init];
+ if (self) {
+ self.title = title;
+ }
+
+ return self;
+ }
+
+ - (void) webView:(WKWebView*)webView runJavaScriptAlertPanelWithMessage:(NSString*)message
+ initiatedByFrame:(WKFrameInfo*)frame completionHandler:(void (^)())completionHandler
+ {
+ UIAlertController* alert = [UIAlertController alertControllerWithTitle:self.title
+ message:message
+ preferredStyle:UIAlertControllerStyleAlert];
+
+ UIAlertAction* ok = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", @"OK")
+ style:UIAlertActionStyleDefault
+ handler:^(UIAlertAction* action)
+ {
+ completionHandler();
+ [alert dismissViewControllerAnimated:YES completion:nil];
+ }];
+
+ [alert addAction:ok];
+
+ UIViewController* rootController = [UIApplication sharedApplication].delegate.window.rootViewController;
+
+ [rootController presentViewController:alert animated:YES completion:nil];
+ }
+
+ - (void) webView:(WKWebView*)webView runJavaScriptConfirmPanelWithMessage:(NSString*)message
+ initiatedByFrame:(WKFrameInfo*)frame completionHandler:(void (^)(BOOL result))completionHandler
+ {
+ UIAlertController* alert = [UIAlertController alertControllerWithTitle:self.title
+ message:message
+ preferredStyle:UIAlertControllerStyleAlert];
+
+ UIAlertAction* ok = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", @"OK")
+ style:UIAlertActionStyleDefault
+ handler:^(UIAlertAction* action)
+ {
+ completionHandler(YES);
+ [alert dismissViewControllerAnimated:YES completion:nil];
+ }];
+
+ [alert addAction:ok];
+
+ UIAlertAction* cancel = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", @"Cancel")
+ style:UIAlertActionStyleDefault
+ handler:^(UIAlertAction* action)
+ {
+ completionHandler(NO);
+ [alert dismissViewControllerAnimated:YES completion:nil];
+ }];
+ [alert addAction:cancel];
+
+ UIViewController* rootController = [UIApplication sharedApplication].delegate.window.rootViewController;
+
+ [rootController presentViewController:alert animated:YES completion:nil];
+ }
+
+ - (void) webView:(WKWebView*)webView runJavaScriptTextInputPanelWithPrompt:(NSString*)prompt
+ defaultText:(NSString*)defaultText initiatedByFrame:(WKFrameInfo*)frame
+ completionHandler:(void (^)(NSString* result))completionHandler
+ {
+ UIAlertController* alert = [UIAlertController alertControllerWithTitle:self.title
+ message:prompt
+ preferredStyle:UIAlertControllerStyleAlert];
+
+ UIAlertAction* ok = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", @"OK")
+ style:UIAlertActionStyleDefault
+ handler:^(UIAlertAction* action)
+ {
+ completionHandler(((UITextField*)alert.textFields[0]).text);
+ [alert dismissViewControllerAnimated:YES completion:nil];
+ }];
+
+ [alert addAction:ok];
+
+ UIAlertAction* cancel = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", @"Cancel")
+ style:UIAlertActionStyleDefault
+ handler:^(UIAlertAction* action)
+ {
+ completionHandler(nil);
+ [alert dismissViewControllerAnimated:YES completion:nil];
+ }];
+ [alert addAction:cancel];
+
+ [alert addTextFieldWithConfigurationHandler:^(UITextField* textField) {
+ textField.text = defaultText;
+ }];
+
+ UIViewController* rootController = [UIApplication sharedApplication].delegate.window.rootViewController;
+
+ [rootController presentViewController:alert animated:YES completion:nil];
+ }
+
+ @end
+#endif /* ifdef __IPHONE_8_0 */
http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/ce6604db/CordovaLib/Classes/CDVWebViewDelegate.h
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVWebViewDelegate.h b/CordovaLib/Classes/CDVWebViewDelegate.h
deleted file mode 100644
index 4b60bab..0000000
--- a/CordovaLib/Classes/CDVWebViewDelegate.h
+++ /dev/null
@@ -1,42 +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 <UIKit/UIKit.h>
-#import "CDVAvailability.h"
-
-/**
- * Distinguishes top-level navigations from sub-frame navigations.
- * shouldStartLoadWithRequest is called for every request, but didStartLoad
- * and didFinishLoad is called only for top-level navigations.
- * Relevant bug: CB-2389
- */
-@interface CDVWebViewDelegate : NSObject <UIWebViewDelegate>{
- __weak NSObject <UIWebViewDelegate>* _delegate;
- NSInteger _loadCount;
- NSInteger _state;
- NSInteger _curLoadToken;
- NSInteger _loadStartPollCount;
-}
-
-- (id)initWithDelegate:(NSObject <UIWebViewDelegate>*)delegate;
-- (BOOL)request:(NSURLRequest*)newRequest isFragmentIdentifierToRequest:(NSURLRequest*)originalRequest CDV_DEPRECATED(3.5, "Use request:isEqualToRequestAfterStrippingFragments: instead.");
-
-- (BOOL)request:(NSURLRequest*)newRequest isEqualToRequestAfterStrippingFragments:(NSURLRequest*)originalRequest;
-
-@end
http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/ce6604db/CordovaLib/Classes/CDVWebViewDelegate.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVWebViewDelegate.m b/CordovaLib/Classes/CDVWebViewDelegate.m
deleted file mode 100644
index 5a187f4..0000000
--- a/CordovaLib/Classes/CDVWebViewDelegate.m
+++ /dev/null
@@ -1,417 +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.
- */
-
-//
-// Testing shows:
-//
-// In all cases, webView.request.URL is the previous page's URL (or empty) during the didStartLoad callback.
-// When loading a page with a redirect:
-// 1. shouldStartLoading (requestURL is target page)
-// 2. didStartLoading
-// 3. shouldStartLoading (requestURL is redirect target)
-// 4. didFinishLoad (request.URL is redirect target)
-//
-// Note the lack of a second didStartLoading **
-//
-// When loading a page with iframes:
-// 1. shouldStartLoading (requestURL is main page)
-// 2. didStartLoading
-// 3. shouldStartLoading (requestURL is one of the iframes)
-// 4. didStartLoading
-// 5. didFinishLoad
-// 6. didFinishLoad
-//
-// Note there is no way to distinguish which didFinishLoad maps to which didStartLoad **
-//
-// Loading a page by calling window.history.go(-1):
-// 1. didStartLoading
-// 2. didFinishLoad
-//
-// Note the lack of a shouldStartLoading call **
-// Actually - this is fixed on iOS6. iOS6 has a shouldStart. **
-//
-// Loading a page by calling location.reload()
-// 1. shouldStartLoading
-// 2. didStartLoading
-// 3. didFinishLoad
-//
-// Loading a page with an iframe that fails to load:
-// 1. shouldStart (main page)
-// 2. didStart
-// 3. shouldStart (iframe)
-// 4. didStart
-// 5. didFailWithError
-// 6. didFinish
-//
-// Loading a page with an iframe that fails to load due to an invalid URL:
-// 1. shouldStart (main page)
-// 2. didStart
-// 3. shouldStart (iframe)
-// 5. didFailWithError
-// 6. didFinish
-//
-// This case breaks our logic since there is a missing didStart. To prevent this,
-// we check URLs in shouldStart and return NO if they are invalid.
-//
-// Loading a page with an invalid URL
-// 1. shouldStart (main page)
-// 2. didFailWithError
-//
-// TODO: Record order when page is re-navigated before the first navigation finishes.
-//
-
-#import "CDVWebViewDelegate.h"
-#import "CDVAvailability.h"
-
-// #define VerboseLog NSLog
-#define VerboseLog(...) do {} while (0)
-
-typedef enum {
- STATE_IDLE = 0,
- STATE_WAITING_FOR_LOAD_START = 1,
- STATE_WAITING_FOR_LOAD_FINISH = 2,
- STATE_IOS5_POLLING_FOR_LOAD_START = 3,
- STATE_IOS5_POLLING_FOR_LOAD_FINISH = 4,
- STATE_CANCELLED = 5
-} State;
-
-static NSString *stripFragment(NSString* url)
-{
- NSRange r = [url rangeOfString:@"#"];
-
- if (r.location == NSNotFound) {
- return url;
- }
- return [url substringToIndex:r.location];
-}
-
-@implementation CDVWebViewDelegate
-
-- (id)initWithDelegate:(NSObject <UIWebViewDelegate>*)delegate
-{
- self = [super init];
- if (self != nil) {
- _delegate = delegate;
- _loadCount = -1;
- _state = STATE_IDLE;
- }
- return self;
-}
-
-- (BOOL)request:(NSURLRequest*)newRequest isFragmentIdentifierToRequest:(NSURLRequest*)originalRequest
-{
- return [self request:newRequest isEqualToRequestAfterStrippingFragments:originalRequest];
-}
-
-- (BOOL)request:(NSURLRequest*)newRequest isEqualToRequestAfterStrippingFragments:(NSURLRequest*)originalRequest
-{
- if (originalRequest.URL && newRequest.URL) {
- NSString* originalRequestUrl = [originalRequest.URL absoluteString];
- NSString* newRequestUrl = [newRequest.URL absoluteString];
-
- NSString* baseOriginalRequestUrl = stripFragment(originalRequestUrl);
- NSString* baseNewRequestUrl = stripFragment(newRequestUrl);
- return [baseOriginalRequestUrl isEqualToString:baseNewRequestUrl];
- }
-
- return NO;
-}
-
-- (BOOL)isPageLoaded:(UIWebView*)webView
-{
- NSString* readyState = [webView stringByEvaluatingJavaScriptFromString:@"document.readyState"];
-
- return [readyState isEqualToString:@"loaded"] || [readyState isEqualToString:@"complete"];
-}
-
-- (BOOL)isJsLoadTokenSet:(UIWebView*)webView
-{
- NSString* loadToken = [webView stringByEvaluatingJavaScriptFromString:@"window.__cordovaLoadToken"];
-
- return [[NSString stringWithFormat:@"%ld", (long)_curLoadToken] isEqualToString:loadToken];
-}
-
-- (void)setLoadToken:(UIWebView*)webView
-{
- _curLoadToken += 1;
- [webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"window.__cordovaLoadToken=%ld", (long)_curLoadToken]];
-}
-
-- (NSString*)evalForCurrentURL:(UIWebView*)webView
-{
- return [webView stringByEvaluatingJavaScriptFromString:@"location.href"];
-}
-
-- (void)pollForPageLoadStart:(UIWebView*)webView
-{
- if (_state != STATE_IOS5_POLLING_FOR_LOAD_START) {
- return;
- }
- if (![self isJsLoadTokenSet:webView]) {
- VerboseLog(@"Polled for page load start. result = YES!");
- _state = STATE_IOS5_POLLING_FOR_LOAD_FINISH;
- [self setLoadToken:webView];
- if ([_delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
- [_delegate webViewDidStartLoad:webView];
- }
- [self pollForPageLoadFinish:webView];
- } else {
- VerboseLog(@"Polled for page load start. result = NO");
- // Poll only for 1 second, and then fall back on checking only when delegate methods are called.
- ++_loadStartPollCount;
- if (_loadStartPollCount < (1000 * .05)) {
- [self performSelector:@selector(pollForPageLoadStart:) withObject:webView afterDelay:.05];
- }
- }
-}
-
-- (void)pollForPageLoadFinish:(UIWebView*)webView
-{
- if (_state != STATE_IOS5_POLLING_FOR_LOAD_FINISH) {
- return;
- }
- if ([self isPageLoaded:webView]) {
- VerboseLog(@"Polled for page load finish. result = YES!");
- _state = STATE_IDLE;
- if ([_delegate respondsToSelector:@selector(webViewDidFinishLoad:)]) {
- [_delegate webViewDidFinishLoad:webView];
- }
- } else {
- VerboseLog(@"Polled for page load finish. result = NO");
- [self performSelector:@selector(pollForPageLoadFinish:) withObject:webView afterDelay:.05];
- }
-}
-
-- (BOOL)shouldLoadRequest:(NSURLRequest*)request
-{
- NSString* scheme = [[request URL] scheme];
-
- if ([scheme isEqualToString:@"mailto"] || [scheme isEqualToString:@"tel"]) {
- return YES;
- }
-
- return [NSURLConnection canHandleRequest:request];
-}
-
-- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
-{
- BOOL shouldLoad = YES;
-
- if ([_delegate respondsToSelector:@selector(webView:shouldStartLoadWithRequest:navigationType:)]) {
- shouldLoad = [_delegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType];
- }
-
- VerboseLog(@"webView shouldLoad=%d (before) state=%d loadCount=%d URL=%@", shouldLoad, _state, _loadCount, request.URL);
-
- if (shouldLoad) {
- // When devtools refresh occurs, it blindly uses the same request object. If a history.replaceState() has occured, then
- // mainDocumentURL != URL even though it's a top-level navigation.
- BOOL isDevToolsRefresh = (request == webView.request);
- BOOL isTopLevelNavigation = isDevToolsRefresh || [request.URL isEqual:[request mainDocumentURL]];
- if (isTopLevelNavigation) {
- // Ignore hash changes that don't navigate to a different page.
- // webView.request does actually update when history.replaceState() gets called.
- if ([self request:request isEqualToRequestAfterStrippingFragments:webView.request]) {
- NSString* prevURL = [self evalForCurrentURL:webView];
- if ([prevURL isEqualToString:[request.URL absoluteString]]) {
- VerboseLog(@"Page reload detected.");
- } else {
- VerboseLog(@"Detected hash change shouldLoad");
- return shouldLoad;
- }
- }
-
- switch (_state) {
- case STATE_WAITING_FOR_LOAD_FINISH:
- // Redirect case.
- // We expect loadCount == 1.
- if (_loadCount != 1) {
- NSLog(@"CDVWebViewDelegate: Detected redirect when loadCount=%ld", (long)_loadCount);
- }
- break;
-
- case STATE_IDLE:
- case STATE_IOS5_POLLING_FOR_LOAD_START:
- case STATE_CANCELLED:
- // Page navigation start.
- _loadCount = 0;
- _state = STATE_WAITING_FOR_LOAD_START;
- break;
-
- default:
- {
- _loadCount = 0;
- _state = STATE_WAITING_FOR_LOAD_START;
- NSString* description = [NSString stringWithFormat:@"CDVWebViewDelegate: Navigation started when state=%ld", (long)_state];
- NSLog(@"%@", description);
- if ([_delegate respondsToSelector:@selector(webView:didFailLoadWithError:)]) {
- NSDictionary* errorDictionary = @{NSLocalizedDescriptionKey : description};
- NSError* error = [[NSError alloc] initWithDomain:@"CDVWebViewDelegate" code:1 userInfo:errorDictionary];
- [_delegate webView:webView didFailLoadWithError:error];
- }
- }
- }
- } else {
- // Deny invalid URLs so that we don't get the case where we go straight from
- // webViewShouldLoad -> webViewDidFailLoad (messes up _loadCount).
- shouldLoad = shouldLoad && [self shouldLoadRequest:request];
- }
- VerboseLog(@"webView shouldLoad=%d (after) isTopLevelNavigation=%d state=%d loadCount=%d", shouldLoad, isTopLevelNavigation, _state, _loadCount);
- }
- return shouldLoad;
-}
-
-- (void)webViewDidStartLoad:(UIWebView*)webView
-{
- VerboseLog(@"webView didStartLoad (before). state=%d loadCount=%d", _state, _loadCount);
- BOOL fireCallback = NO;
- switch (_state) {
- case STATE_IDLE:
- if (IsAtLeastiOSVersion(@"6.0")) {
- break;
- }
- // If history.go(-1) is used pre-iOS6, the shouldStartLoadWithRequest function is not called.
- // Without shouldLoad, we can't distinguish an iframe from a top-level navigation.
- // We could try to distinguish using [UIWebView canGoForward], but that's too much complexity,
- // and would work only on the first time it was used.
-
- // Our work-around is to set a JS variable and poll until it disappears (from a navigation).
- _state = STATE_IOS5_POLLING_FOR_LOAD_START;
- _loadStartPollCount = 0;
- [self setLoadToken:webView];
- [self pollForPageLoadStart:webView];
- break;
-
- case STATE_CANCELLED:
- fireCallback = YES;
- _state = STATE_WAITING_FOR_LOAD_FINISH;
- _loadCount += 1;
- break;
-
- case STATE_WAITING_FOR_LOAD_START:
- if (_loadCount != 0) {
- NSLog(@"CDVWebViewDelegate: Unexpected loadCount in didStart. count=%ld", (long)_loadCount);
- }
- fireCallback = YES;
- _state = STATE_WAITING_FOR_LOAD_FINISH;
- _loadCount = 1;
- break;
-
- case STATE_WAITING_FOR_LOAD_FINISH:
- _loadCount += 1;
- break;
-
- case STATE_IOS5_POLLING_FOR_LOAD_START:
- [self pollForPageLoadStart:webView];
- break;
-
- case STATE_IOS5_POLLING_FOR_LOAD_FINISH:
- [self pollForPageLoadFinish:webView];
- break;
-
- default:
- NSLog(@"CDVWebViewDelegate: Unexpected didStart with state=%ld loadCount=%ld", (long)_state, (long)_loadCount);
- }
- VerboseLog(@"webView didStartLoad (after). state=%d loadCount=%d fireCallback=%d", _state, _loadCount, fireCallback);
- if (fireCallback && [_delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
- [_delegate webViewDidStartLoad:webView];
- }
-}
-
-- (void)webViewDidFinishLoad:(UIWebView*)webView
-{
- VerboseLog(@"webView didFinishLoad (before). state=%d loadCount=%d", _state, _loadCount);
- BOOL fireCallback = NO;
- switch (_state) {
- case STATE_IDLE:
- break;
-
- case STATE_WAITING_FOR_LOAD_START:
- NSLog(@"CDVWebViewDelegate: Unexpected didFinish while waiting for load start.");
- break;
-
- case STATE_WAITING_FOR_LOAD_FINISH:
- if (_loadCount == 1) {
- fireCallback = YES;
- _state = STATE_IDLE;
- }
- _loadCount -= 1;
- break;
-
- case STATE_IOS5_POLLING_FOR_LOAD_START:
- [self pollForPageLoadStart:webView];
- break;
-
- case STATE_IOS5_POLLING_FOR_LOAD_FINISH:
- [self pollForPageLoadFinish:webView];
- break;
- }
- VerboseLog(@"webView didFinishLoad (after). state=%d loadCount=%d fireCallback=%d", _state, _loadCount, fireCallback);
- if (fireCallback && [_delegate respondsToSelector:@selector(webViewDidFinishLoad:)]) {
- [_delegate webViewDidFinishLoad:webView];
- }
-}
-
-- (void)webView:(UIWebView*)webView didFailLoadWithError:(NSError*)error
-{
- VerboseLog(@"webView didFailLoad (before). state=%d loadCount=%d", _state, _loadCount);
- BOOL fireCallback = NO;
-
- switch (_state) {
- case STATE_IDLE:
- break;
-
- case STATE_WAITING_FOR_LOAD_START:
- if ([error code] == NSURLErrorCancelled) {
- _state = STATE_CANCELLED;
- } else {
- _state = STATE_IDLE;
- }
- fireCallback = YES;
- break;
-
- case STATE_WAITING_FOR_LOAD_FINISH:
- if ([error code] != NSURLErrorCancelled) {
- if (_loadCount == 1) {
- _state = STATE_IDLE;
- fireCallback = YES;
- }
- _loadCount = -1;
- } else {
- fireCallback = YES;
- _state = STATE_CANCELLED;
- _loadCount -= 1;
- }
- break;
-
- case STATE_IOS5_POLLING_FOR_LOAD_START:
- [self pollForPageLoadStart:webView];
- break;
-
- case STATE_IOS5_POLLING_FOR_LOAD_FINISH:
- [self pollForPageLoadFinish:webView];
- break;
- }
- VerboseLog(@"webView didFailLoad (after). state=%d loadCount=%d, fireCallback=%d", _state, _loadCount, fireCallback);
- if (fireCallback && [_delegate respondsToSelector:@selector(webView:didFailLoadWithError:)]) {
- [_delegate webView:webView didFailLoadWithError:error];
- }
-}
-
-@end
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org