Updated Branches: refs/heads/master 07ee5c792 -> fdf804341
Support JS->Native messages via an XHR & URL Protocol. This also deprecates the need to manually register CDVURLProtocol. It is now lazily registered by the CDVViewController. Project: http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/commit/fdf80434 Tree: http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/tree/fdf80434 Diff: http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/diff/fdf80434 Branch: refs/heads/master Commit: fdf8043414e39914ffc29b682779a10fe1c147e7 Parents: 5a7b1ce Author: Andrew Grieve <agri...@chromium.org> Authored: Fri Aug 17 12:59:09 2012 -0400 Committer: Andrew Grieve <agri...@chromium.org> Committed: Fri Aug 17 12:59:09 2012 -0400 ---------------------------------------------------------------------- CordovaLib/Classes/CDVURLProtocol.h | 13 +++- CordovaLib/Classes/CDVURLProtocol.m | 55 +++++++++++---- CordovaLib/Classes/CDVViewController.h | 2 +- CordovaLib/Classes/CDVViewController.m | 17 ++--- .../project/__TESTING__/Classes/AppDelegate.m | 3 - 5 files changed, 62 insertions(+), 28 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/fdf80434/CordovaLib/Classes/CDVURLProtocol.h ---------------------------------------------------------------------- diff --git a/CordovaLib/Classes/CDVURLProtocol.h b/CordovaLib/Classes/CDVURLProtocol.h index a8b2fd5..ff4b77a 100644 --- a/CordovaLib/Classes/CDVURLProtocol.h +++ b/CordovaLib/Classes/CDVURLProtocol.h @@ -19,18 +19,27 @@ #import <Foundation/Foundation.h> +@class CDVViewController; + @interface CDVURLProtocol : NSURLProtocol { } + (void) registerPGHttpURLProtocol #ifdef __clang__ - __attribute__ ((deprecated("Renamed - use registerUrlProtocol instead."))); + __attribute__ ((deprecated("No longer required."))); #else __attribute__ ((deprecated())); #endif -+ (void) registerURLProtocol; ++ (void) registerURLProtocol +#ifdef __clang__ + __attribute__ ((deprecated("No longer required."))); +#else + __attribute__ ((deprecated())); +#endif ++ (void)registerViewController:(CDVViewController*)viewController; ++ (void)unregisterViewController:(CDVViewController*)viewController; @end @interface CDVHTTPURLResponse : NSHTTPURLResponse { http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/fdf80434/CordovaLib/Classes/CDVURLProtocol.m ---------------------------------------------------------------------- diff --git a/CordovaLib/Classes/CDVURLProtocol.m b/CordovaLib/Classes/CDVURLProtocol.m index 94b242a..42dbef7 100644 --- a/CordovaLib/Classes/CDVURLProtocol.m +++ b/CordovaLib/Classes/CDVURLProtocol.m @@ -22,37 +22,66 @@ #import "CDVViewController.h" static CDVWhitelist* gWhitelist = nil; +// Contains a set of NSNumbers of addresses of controllers. It doesn't store +// the actual pointer to avoid retaining. +static NSMutableSet* gRegisteredControllers = nil; @implementation CDVURLProtocol + (void) registerPGHttpURLProtocol { - return [[self class] registerURLProtocol]; } -// Called before any use of the protocol, ensure it is only called once + (void) registerURLProtocol { - static BOOL registered = NO; - if (!registered) { +} + +// Called to register the URLProtocol, and to make it away of an instance of +// a ViewController. ++ (void)registerViewController:(CDVViewController*)viewController { + if (gRegisteredControllers == nil) { [NSURLProtocol registerClass:[CDVURLProtocol class]]; - registered = YES; + gRegisteredControllers = [[NSMutableSet alloc] initWithCapacity:8]; + // The whitelist doesn't change, so grab the first one and store it. + gWhitelist = viewController.whitelist; + } + @synchronized (gRegisteredControllers) { + [gRegisteredControllers addObject:[NSNumber numberWithLongLong:(long long)viewController]]; } } ++ (void)unregisterViewController:(CDVViewController*)viewController { + [gRegisteredControllers removeObject:viewController]; +} + + + (BOOL) canInitWithRequest:(NSURLRequest *)theRequest { NSURL* theUrl = [theRequest URL]; NSString* theScheme = [theUrl scheme]; - if (gWhitelist == nil) { - id<UIApplicationDelegate> delegate = [[UIApplication sharedApplication] delegate]; - - if ([delegate respondsToSelector:@selector(viewController)]) { - id vc = [delegate performSelector:@selector(viewController)]; - if ([vc isKindOfClass:[CDVViewController class]]) { - gWhitelist = ((CDVViewController*)vc).whitelist; + if ([[theUrl path] isEqualToString:@"/!gap_exec"]) { + NSString* viewControllerAddressStr = [theRequest valueForHTTPHeaderField:@"vc"]; + if (viewControllerAddressStr == nil) { + NSLog(@"!cordova request missing vc header"); + return NO; + } + long long viewControllerAddress = [viewControllerAddressStr longLongValue]; + // Ensure that the CDVViewController has not been dealloc'ed. + @synchronized (gRegisteredControllers) { + if (![gRegisteredControllers containsObject:[NSNumber numberWithLongLong:viewControllerAddress]]) { + return NO; + } + CDVViewController* viewController = (__bridge CDVViewController*)(void *)viewControllerAddress; + + NSString* queuedCommandsJSON = [theRequest valueForHTTPHeaderField:@"cmds"]; + if ([queuedCommandsJSON length] > 0) { + [viewController performSelectorOnMainThread:@selector(executeCommandsFromJson:) withObject:queuedCommandsJSON waitUntilDone:NO]; + } else { + [viewController performSelectorOnMainThread:@selector(flushCommandQueue) withObject:nil waitUntilDone:NO]; } } - } + return NO; + } + // we only care about http and https connections if ([gWhitelist schemeIsAllowed:theScheme]) http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/fdf80434/CordovaLib/Classes/CDVViewController.h ---------------------------------------------------------------------- diff --git a/CordovaLib/Classes/CDVViewController.h b/CordovaLib/Classes/CDVViewController.h index abf7e89..23d703b 100644 --- a/CordovaLib/Classes/CDVViewController.h +++ b/CordovaLib/Classes/CDVViewController.h @@ -55,7 +55,7 @@ - (void) createGapView; - (CDVCordovaView*) newCordovaViewWithFrame:(CGRect)bounds; -- (int) executeQueuedCommands; +- (int) executeCommandsFromJson:(NSString*)queuedCommandsJSON; - (void) flushCommandQueue; - (void) javascriptAlert:(NSString*)text; http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/fdf80434/CordovaLib/Classes/CDVViewController.m ---------------------------------------------------------------------- diff --git a/CordovaLib/Classes/CDVViewController.m b/CordovaLib/Classes/CDVViewController.m index 6add9af..f3b1d73 100644 --- a/CordovaLib/Classes/CDVViewController.m +++ b/CordovaLib/Classes/CDVViewController.m @@ -81,6 +81,7 @@ [self printMultitaskingInfo]; [self printDeprecationNotice]; self.initialized = YES; + [CDVURLProtocol registerViewController:self]; } return self; @@ -467,7 +468,7 @@ [self didRotateFromInterfaceOrientation:(UIInterfaceOrientation)[[UIDevice currentDevice] orientation]]; // Tell the webview that native is ready. - NSString* nativeReady = @"try{cordova.require('cordova/channel').onNativeReady.fire();}catch(e){window._nativeReady = true;}"; + NSString* nativeReady = [NSString stringWithFormat:@"cordova.iOSVCAddr='%lld';try{cordova.require('cordova/channel').onNativeReady.fire();}catch(e){window._nativeReady = true;}", (long long)self]; [theWebView stringByEvaluatingJavaScriptFromString:nativeReady]; } @@ -759,13 +760,8 @@ BOOL gSplashScreenShown = NO; * * Returns the number of executed commands. */ -- (int) executeQueuedCommands +- (int) executeCommandsFromJson:(NSString*)queuedCommandsJSON { - // Grab all the queued commands from the JS side. - NSString* queuedCommandsJSON = [self.webView stringByEvaluatingJavaScriptFromString: - @"cordova.require('cordova/plugin/ios/nativecomm')()"]; - - // Parse the returned JSON array. NSArray* queuedCommands = [queuedCommandsJSON cdvjk_mutableObjectFromJSONString]; @@ -801,7 +797,10 @@ BOOL gSplashScreenShown = NO; // commands are executed as well. int numExecutedCommands = 0; do { - numExecutedCommands = [self executeQueuedCommands]; + // Grab all the queued commands from the JS side. + NSString* queuedCommandsJSON = [self.webView stringByEvaluatingJavaScriptFromString: + @"cordova.require('cordova/plugin/ios/nativecomm')()"]; + numExecutedCommands = [self executeCommandsFromJson:queuedCommandsJSON]; } while (numExecutedCommands != 0); [self.webView stringByEvaluatingJavaScriptFromString: @@ -1007,12 +1006,12 @@ BOOL gSplashScreenShown = NO; - (void)dealloc { + [CDVURLProtocol unregisterViewController:self]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillTerminateNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillResignActiveNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillEnterForegroundNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil]; - } @end http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/fdf80434/bin/templates/project/__TESTING__/Classes/AppDelegate.m ---------------------------------------------------------------------- diff --git a/bin/templates/project/__TESTING__/Classes/AppDelegate.m b/bin/templates/project/__TESTING__/Classes/AppDelegate.m index 86e2815..b6b14e8 100644 --- a/bin/templates/project/__TESTING__/Classes/AppDelegate.m +++ b/bin/templates/project/__TESTING__/Classes/AppDelegate.m @@ -29,7 +29,6 @@ #import "MainViewController.h" #import <Cordova/CDVPlugin.h> -#import <Cordova/CDVURLProtocol.h> @implementation AppDelegate @@ -44,8 +43,6 @@ NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; [cookieStorage setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways]; - [CDVURLProtocol registerURLProtocol]; - self = [super init]; return self; }