You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ag...@apache.org on 2013/01/24 19:41:51 UTC
[3/3] ios commit: Fix CB-2271 - Multiple Cordova Views.
Updated Branches:
refs/heads/master 41955f942 -> be6e4d3cc
Fix CB-2271 - Multiple Cordova Views.
The problem was that multiple views loading at the same time would end
up with the same User-Agent. This change adds a locking mechanism around
User-Agent setting, so that multiple views will load in serial instead
at the same time.
Adds a unit test that failed before the fix, but now passes consistently
https://issues.apache.org/jira/browse/CB-2271
Project: http://git-wip-us.apache.org/repos/asf/cordova-ios/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-ios/commit/be6e4d3c
Tree: http://git-wip-us.apache.org/repos/asf/cordova-ios/tree/be6e4d3c
Diff: http://git-wip-us.apache.org/repos/asf/cordova-ios/diff/be6e4d3c
Branch: refs/heads/master
Commit: be6e4d3cce3b5d3d5682b62a63d0e402a059e7a8
Parents: b8f7515
Author: Andrew Grieve <ag...@chromium.org>
Authored: Thu Jan 24 10:55:55 2013 -0500
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Thu Jan 24 13:40:48 2013 -0500
----------------------------------------------------------------------
CordovaLib/Classes/CDVInAppBrowser.h | 3 +-
CordovaLib/Classes/CDVInAppBrowser.m | 57 +++++----
CordovaLib/Classes/CDVUserAgentUtil.h | 4 +-
CordovaLib/Classes/CDVUserAgentUtil.m | 64 ++++++++--
CordovaLib/Classes/CDVViewController.m | 35 ++++--
CordovaLibTests/CDVUserAgentTest.m | 93 +++++++++++++++
.../CordovaTests.xcodeproj/project.pbxproj | 4 +
7 files changed, 211 insertions(+), 49 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/be6e4d3c/CordovaLib/Classes/CDVInAppBrowser.h
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVInAppBrowser.h b/CordovaLib/Classes/CDVInAppBrowser.h
index a36a62a..9ff460a 100644
--- a/CordovaLib/Classes/CDVInAppBrowser.h
+++ b/CordovaLib/Classes/CDVInAppBrowser.h
@@ -31,7 +31,7 @@
@end
-@interface CDVInAppBrowser : CDVPlugin <CDVInAppBrowserNavigationDelegate>{}
+@interface CDVInAppBrowser : CDVPlugin <CDVInAppBrowserNavigationDelegate>
@property (nonatomic, retain) CDVInAppBrowserViewController* inAppBrowserViewController;
@property (nonatomic, copy) NSString* callbackId;
@@ -46,6 +46,7 @@
NSURL* _requestedURL;
NSString* _userAgent;
NSString* _prevUserAgent;
+ NSInteger _userAgentLockToken;
}
@property (nonatomic, strong) IBOutlet UIWebView* webView;
http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/be6e4d3c/CordovaLib/Classes/CDVInAppBrowser.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVInAppBrowser.m b/CordovaLib/Classes/CDVInAppBrowser.m
index fde68b8..45bf705 100644
--- a/CordovaLib/Classes/CDVInAppBrowser.m
+++ b/CordovaLib/Classes/CDVInAppBrowser.m
@@ -235,27 +235,23 @@
webViewBounds.size.height -= FOOTER_HEIGHT;
- if (!self.webView) {
- [CDVUserAgentUtil setUserAgent:_userAgent];
-
- self.webView = [[UIWebView alloc] initWithFrame:webViewBounds];
- self.webView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
-
- [self.view addSubview:self.webView];
- [self.view sendSubviewToBack:self.webView];
-
- self.webView.delegate = self;
- self.webView.backgroundColor = [UIColor whiteColor];
-
- self.webView.clearsContextBeforeDrawing = YES;
- self.webView.clipsToBounds = YES;
- self.webView.contentMode = UIViewContentModeScaleToFill;
- self.webView.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}");
- self.webView.multipleTouchEnabled = YES;
- self.webView.opaque = YES;
- self.webView.scalesPageToFit = NO;
- self.webView.userInteractionEnabled = YES;
- }
+ self.webView = [[UIWebView alloc] initWithFrame:webViewBounds];
+ self.webView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
+
+ [self.view addSubview:self.webView];
+ [self.view sendSubviewToBack:self.webView];
+
+ self.webView.delegate = self;
+ self.webView.backgroundColor = [UIColor whiteColor];
+
+ self.webView.clearsContextBeforeDrawing = YES;
+ self.webView.clipsToBounds = YES;
+ self.webView.contentMode = UIViewContentModeScaleToFill;
+ self.webView.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}");
+ self.webView.multipleTouchEnabled = YES;
+ self.webView.opaque = YES;
+ self.webView.scalesPageToFit = NO;
+ self.webView.userInteractionEnabled = YES;
self.spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
self.spinner.alpha = 1.000;
@@ -383,6 +379,11 @@
- (void)close
{
+ if (_userAgentLockToken != 0) {
+ [CDVUserAgentUtil releaseLock:_userAgentLockToken];
+ _userAgentLockToken = 0;
+ }
+
if ([self respondsToSelector:@selector(presentingViewController)]) {
[[self presentingViewController] dismissViewControllerAnimated:YES completion:nil];
} else {
@@ -397,9 +398,17 @@
- (void)navigateTo:(NSURL*)url
{
NSURLRequest* request = [NSURLRequest requestWithURL:url];
-
- [self.webView loadRequest:request];
_requestedURL = url;
+
+ if (_userAgentLockToken != 0) {
+ [self.webView loadRequest:request];
+ } else {
+ [CDVUserAgentUtil acquireLock:^(NSInteger lockToken) {
+ _userAgentLockToken = lockToken;
+ [CDVUserAgentUtil setUserAgent:_userAgent lockToken:lockToken];
+ [self.webView loadRequest:request];
+ }];
+ }
}
- (void)goBack:(id)sender
@@ -456,7 +465,7 @@
// 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];
+ [CDVUserAgentUtil setUserAgent:_prevUserAgent lockToken:_userAgentLockToken];
}
if ((self.navigationDelegate != nil) && [self.navigationDelegate respondsToSelector:@selector(browserLoadStop:)]) {
http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/be6e4d3c/CordovaLib/Classes/CDVUserAgentUtil.h
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVUserAgentUtil.h b/CordovaLib/Classes/CDVUserAgentUtil.h
index fdea596..662b674 100644
--- a/CordovaLib/Classes/CDVUserAgentUtil.h
+++ b/CordovaLib/Classes/CDVUserAgentUtil.h
@@ -21,5 +21,7 @@
@interface CDVUserAgentUtil : NSObject
+ (NSString*)originalUserAgent;
-+ (void)setUserAgent:(NSString*)newValue;
++ (void)acquireLock:(void (^)(NSInteger lockToken))block;
++ (void)releaseLock:(NSInteger)lockToken;
++ (void)setUserAgent:(NSString*)value lockToken:(NSInteger)lockToken;
@end
http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/be6e4d3c/CordovaLib/Classes/CDVUserAgentUtil.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVUserAgentUtil.m b/CordovaLib/Classes/CDVUserAgentUtil.m
index ac5c994..e2baef0 100644
--- a/CordovaLib/Classes/CDVUserAgentUtil.m
+++ b/CordovaLib/Classes/CDVUserAgentUtil.m
@@ -21,9 +21,16 @@
#import <UIKit/UIKit.h>
+// #define VerboseLog NSLog
+#define VerboseLog(...) do {} while (0)
+
+static NSString* const kCdvUserAgentKey = @"Cordova-User-Agent";
+static NSString* const kCdvUserAgentVersionKey = @"Cordova-User-Agent-Version";
+
static NSString* gOriginalUserAgent = nil;
-static NSString* kCdvUserAgentKey = @"Cordova-User-Agent";
-static NSString* kCdvUserAgentVersionKey = @"Cordova-User-Agent-Version";
+static NSInteger gNextLockToken = 0;
+static NSInteger gCurrentLockToken = 0;
+static NSMutableArray* gPendingSetUserAgentBlocks = nil;
@implementation CDVUserAgentUtil
@@ -55,22 +62,55 @@ static NSString* kCdvUserAgentVersionKey = @"Cordova-User-Agent-Version";
return gOriginalUserAgent;
}
-+ (void)setUserAgent:(NSString*)newValue
++ (void)onAppLocaleDidChange:(NSNotification*)notification
+{
+ // TODO: We should figure out how to update the user-agent of existing UIWebViews when this happens.
+ // Maybe use the PDF bug (noted in setUserAgent:).
+ gOriginalUserAgent = nil;
+}
+
++ (void)acquireLock:(void (^)(NSInteger lockToken))block
+{
+ if (gCurrentLockToken == 0) {
+ gCurrentLockToken = ++gNextLockToken;
+ VerboseLog(@"Gave lock %d", gCurrentLockToken);
+ block(gCurrentLockToken);
+ } else {
+ if (gPendingSetUserAgentBlocks == nil) {
+ gPendingSetUserAgentBlocks = [[NSMutableArray alloc] initWithCapacity:4];
+ }
+ VerboseLog(@"Waiting for lock");
+ [gPendingSetUserAgentBlocks addObject:block];
+ }
+}
+
++ (void)releaseLock:(NSInteger)lockToken
{
+ NSAssert(gCurrentLockToken == lockToken, @"Got token %d, expected %d", lockToken, gCurrentLockToken);
+
+ VerboseLog(@"Released lock %d", lockToken);
+ if ([gPendingSetUserAgentBlocks count] > 0) {
+ void (^block)() = [gPendingSetUserAgentBlocks objectAtIndex:0];
+ [gPendingSetUserAgentBlocks removeObjectAtIndex:0];
+ gCurrentLockToken = ++gNextLockToken;
+ NSLog (@"Gave lock %d", gCurrentLockToken);
+ block(gCurrentLockToken);
+ } else {
+ gCurrentLockToken = 0;
+ }
+}
+
++ (void)setUserAgent:(NSString*)value lockToken:(NSInteger)lockToken
+{
+ NSAssert(gCurrentLockToken == lockToken, @"Got token %d, expected %d", lockToken, gCurrentLockToken);
+ VerboseLog(@"User-Agent set to: %@", value);
+
// Setting the UserAgent must occur before a UIWebView is instantiated.
// It is read per instantiation, so it does not affect previously created views.
// Except! When a PDF is loaded, all currently active UIWebViews reload their
// User-Agent from the NSUserDefaults some time after the DidFinishLoad of the PDF bah!
- NSDictionary* dict = [[NSDictionary alloc] initWithObjectsAndKeys:newValue, @"UserAgent", nil];
-
+ NSDictionary* dict = [[NSDictionary alloc] initWithObjectsAndKeys:value, @"UserAgent", nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:dict];
}
-+ (void)onAppLocaleDidChange:(NSNotification*)notification
-{
- // TODO: We should figure out how to update the user-agent of existing UIWebViews when this happens.
- // Maybe use the PDF bug (noted in setUserAgent:).
- gOriginalUserAgent = nil;
-}
-
@end
http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/be6e4d3c/CordovaLib/Classes/CDVViewController.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVViewController.m b/CordovaLib/Classes/CDVViewController.m
index ef91f5f..36ae785 100644
--- a/CordovaLib/Classes/CDVViewController.m
+++ b/CordovaLib/Classes/CDVViewController.m
@@ -26,7 +26,9 @@
#define degreesToRadian(x) (M_PI * (x) / 180.0)
-@interface CDVViewController ()
+@interface CDVViewController () {
+ NSInteger _userAgentLockToken;
+}
@property (nonatomic, readwrite, strong) NSXMLParser* configParser;
@property (nonatomic, readwrite, strong) NSDictionary* settings;
@@ -303,14 +305,17 @@
}
// /////////////////
-
- if (!loadErr) {
- NSURLRequest* appReq = [NSURLRequest requestWithURL:appURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0];
- [self.webView loadRequest:appReq];
- } else {
- NSString* html = [NSString stringWithFormat:@"<html><body> %@ </body></html>", loadErr];
- [self.webView loadHTMLString:html baseURL:nil];
- }
+ [CDVUserAgentUtil acquireLock:^(NSInteger lockToken) {
+ _userAgentLockToken = lockToken;
+ [CDVUserAgentUtil setUserAgent:self.userAgent lockToken:lockToken];
+ if (!loadErr) {
+ NSURLRequest* appReq = [NSURLRequest requestWithURL:appURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0];
+ [self.webView loadRequest:appReq];
+ } else {
+ NSString* html = [NSString stringWithFormat:@"<html><body> %@ </body></html>", loadErr];
+ [self.webView loadHTMLString:html baseURL:nil];
+ }
+ }];
}
- (NSArray*)parseInterfaceOrientations:(NSArray*)orientations
@@ -430,8 +435,6 @@
webViewBounds.origin = self.view.bounds.origin;
if (!self.webView) {
- [CDVUserAgentUtil setUserAgent:self.userAgent];
-
self.webView = [self newCordovaViewWithFrame:webViewBounds];
self.webView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
@@ -496,6 +499,11 @@
*/
- (void)webViewDidFinishLoad:(UIWebView*)theWebView
{
+ if (_userAgentLockToken != 0) {
+ [CDVUserAgentUtil releaseLock:_userAgentLockToken];
+ _userAgentLockToken = 0;
+ }
+
/*
* Hide the Top Activity THROBBER in the Battery Bar
*/
@@ -521,6 +529,11 @@
- (void)webView:(UIWebView*)webView didFailLoadWithError:(NSError*)error
{
+ if (_userAgentLockToken != 0) {
+ [CDVUserAgentUtil releaseLock:_userAgentLockToken];
+ _userAgentLockToken = 0;
+ }
+
NSLog(@"Failed to load webpage with error: %@", [error localizedDescription]);
/*
http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/be6e4d3c/CordovaLibTests/CDVUserAgentTest.m
----------------------------------------------------------------------
diff --git a/CordovaLibTests/CDVUserAgentTest.m b/CordovaLibTests/CDVUserAgentTest.m
new file mode 100644
index 0000000..dcbf30a
--- /dev/null
+++ b/CordovaLibTests/CDVUserAgentTest.m
@@ -0,0 +1,93 @@
+/*
+ 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 <SenTestingKit/SenTestingKit.h>
+
+#import "CDVWebViewTest.h"
+#import "CDVViewController.h"
+#import "AppDelegate.h"
+
+@interface CDVUserAgentTestViewController : UIViewController
+@property (nonatomic) CDVViewController* vc1;
+@property (nonatomic) CDVViewController* vc2;
+@end
+
+@implementation CDVUserAgentTestViewController
+@synthesize vc1 = _vc1, vc2 = _vc2;
+
+- (void)loadView
+{
+ _vc1 = [[CDVViewController alloc] init];
+ _vc1.wwwFolderName = @"www";
+ _vc1.startPage = @"index.html";
+ [self addChildViewController:_vc1];
+
+ _vc2 = [[CDVViewController alloc] init];
+ _vc2.wwwFolderName = @"www";
+ _vc2.startPage = @"index.html";
+ [self addChildViewController:_vc2];
+
+ CGRect applicationFrame = [[UIScreen mainScreen] applicationFrame];
+ UIView* contentView = [[UIView alloc] initWithFrame:applicationFrame];
+
+ CGRect sub1, sub2;
+ CGRectDivide(applicationFrame, &sub1, &sub2, applicationFrame.size.height / 2, CGRectMinYEdge);
+ [_vc1.view setBounds:sub1];
+ [_vc2.view setBounds:sub2];
+
+ [contentView addSubview:_vc1.view];
+ [contentView addSubview:_vc2.view];
+
+ self.view = contentView;
+}
+
+@end
+
+@interface CDVUserAgentTest : CDVWebViewTest
+@end
+
+@implementation CDVUserAgentTest
+
+- (void)setUp
+{
+ [super setUp];
+}
+
+- (void)tearDown
+{
+ [super tearDown];
+}
+
+- (void)testMultipleViews
+{
+ CDVUserAgentTestViewController* rootVc = [[CDVUserAgentTestViewController alloc] init];
+
+ self.appDelegate.window.rootViewController = rootVc;
+
+ NSString* getUserAgentCode = @"navigator.userAgent";
+ [self waitForConditionName:@"getting user-agents" block:^{
+ return (BOOL)(rootVc.vc1.webView.request != nil && rootVc.vc2.webView.request != nil);
+ }];
+ NSString* ua1 = [rootVc.vc1.webView stringByEvaluatingJavaScriptFromString:getUserAgentCode];
+ NSString* ua2 = [rootVc.vc2.webView stringByEvaluatingJavaScriptFromString:getUserAgentCode];
+
+ STAssertFalse([ua1 isEqual:ua2], @"User-Agents should be different.");
+}
+
+@end
http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/be6e4d3c/CordovaLibTests/CordovaTests.xcodeproj/project.pbxproj
----------------------------------------------------------------------
diff --git a/CordovaLibTests/CordovaTests.xcodeproj/project.pbxproj b/CordovaLibTests/CordovaTests.xcodeproj/project.pbxproj
index 02490b5..f29ac11 100644
--- a/CordovaLibTests/CordovaTests.xcodeproj/project.pbxproj
+++ b/CordovaLibTests/CordovaTests.xcodeproj/project.pbxproj
@@ -43,6 +43,7 @@
68A32D7F141030F3006B237C /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 686357AC141002F100DF4CF2 /* Foundation.framework */; };
EB3B34E9161B5532003DBE7D /* libCordova.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EB3B34E6161B5454003DBE7D /* libCordova.a */; };
EB89634A15FE66EA00E12277 /* CDVInvokedUrlCommandTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EB89634915FE66EA00E12277 /* CDVInvokedUrlCommandTests.m */; };
+ EB96677216ADBCF500D86CDF /* CDVUserAgentTest.m in Sources */ = {isa = PBXBuildFile; fileRef = EB96677116ADBCF500D86CDF /* CDVUserAgentTest.m */; };
EBA3554615A731F100F4DE24 /* CDVFakeFileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = EBA3554515A731F100F4DE24 /* CDVFakeFileManager.m */; };
EBA3556F15ABD0C900F4DE24 /* CDVFileTransferTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EBA3556E15ABD0C900F4DE24 /* CDVFileTransferTests.m */; };
F8EB14D1165FFD3200616F39 /* config.xml in Resources */ = {isa = PBXBuildFile; fileRef = F8EB14D0165FFD3200616F39 /* config.xml */; };
@@ -105,6 +106,7 @@
68A32D7414103017006B237C /* AddressBook.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBook.framework; path = System/Library/Frameworks/AddressBook.framework; sourceTree = SDKROOT; };
EB37018115D18B2D00BEBC43 /* CordovaLib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = CordovaLib.xcodeproj; path = ../CordovaLib/CordovaLib.xcodeproj; sourceTree = "<group>"; };
EB89634915FE66EA00E12277 /* CDVInvokedUrlCommandTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVInvokedUrlCommandTests.m; sourceTree = "<group>"; };
+ EB96677116ADBCF500D86CDF /* CDVUserAgentTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVUserAgentTest.m; sourceTree = "<group>"; };
EBA3550F15A5F18900F4DE24 /* CDVWebViewTest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CDVWebViewTest.h; sourceTree = "<group>"; };
EBA3554415A731F100F4DE24 /* CDVFakeFileManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVFakeFileManager.h; sourceTree = "<group>"; };
EBA3554515A731F100F4DE24 /* CDVFakeFileManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVFakeFileManager.m; sourceTree = "<group>"; };
@@ -237,6 +239,7 @@
EB3B34F4161B585D003DBE7D /* CordovaLibTests */ = {
isa = PBXGroup;
children = (
+ EB96677116ADBCF500D86CDF /* CDVUserAgentTest.m */,
EBA3554415A731F100F4DE24 /* CDVFakeFileManager.h */,
EBA3554515A731F100F4DE24 /* CDVFakeFileManager.m */,
EBA3550F15A5F18900F4DE24 /* CDVWebViewTest.h */,
@@ -417,6 +420,7 @@
EBA3554615A731F100F4DE24 /* CDVFakeFileManager.m in Sources */,
EBA3556F15ABD0C900F4DE24 /* CDVFileTransferTests.m in Sources */,
EB89634A15FE66EA00E12277 /* CDVInvokedUrlCommandTests.m in Sources */,
+ EB96677216ADBCF500D86CDF /* CDVUserAgentTest.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};