Permalink
Browse files

Restructure of WebViewJavascriptBridge, now the bridges delegate does…

…n't lose the delegation of the webview, it gets, well, bridged. Modified naming to be more conventional
  • Loading branch information...
1 parent 4dbb54e commit 83448f490243d5155a815e04d6ed1a02ccb404d5 @sergiocampama sergiocampama committed Dec 4, 2011
@@ -1,29 +1,33 @@
-#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
-@protocol WebViewJavascriptBridgeDelegate <NSObject>
+@class WebViewJavascriptBridge;
-- (void) handleMessage:(NSString*) message fromWebView: (UIWebView *)theWebView;
+@protocol WebViewJavascriptBridgeDelegate <UIWebViewDelegate>
+
+- (void)javascriptBridge:(WebViewJavascriptBridge *)bridge receivedMessage:(NSString *)message fromWebView:(UIWebView *)webView;
@end
-@interface WebViewJavascriptBridge : NSObject <UIWebViewDelegate> {
- id <WebViewJavascriptBridgeDelegate> _delegate;
- NSMutableArray *_startupMessageQueue;
-}
+@interface WebViewJavascriptBridge : NSObject <UIWebViewDelegate>
/** Delegate to receive messages from javascript. */
-@property (readwrite, assign) id <WebViewJavascriptBridgeDelegate> delegate;
+/** Defined as IBOutlet for Interface Builder assignment */
+@property (nonatomic, assign) IBOutlet id <WebViewJavascriptBridgeDelegate> delegate;
+
+/** Init with a predefined delegate */
+- (id)initWithDelegate:(id <WebViewJavascriptBridgeDelegate>)delegate;
-/** Creates & returns new autoreleased javascript Bridge with no delegate set. */
-+ (id) javascriptBridge;
+/** Convenience methods for obtaining a bridge */
++ (id)javascriptBridge;
++ (id)javascriptBridgeWithDelegate:(id <WebViewJavascriptBridgeDelegate>)delegate;
/** Sends message to given webView. You need to integrate javascript bridge into
* this view before by calling WebViewJavascriptBridge#webViewDidFinishLoad: with that view.
*
- * You can call this method before calling webViewDidFinishLoad: , than all messages
+ * You can call this method before calling webViewDidFinishLoad: , then all messages
* will be accumulated in _startupMessageQueue & sended to webView, provided by first
* webViewDidFinishLoad: call.
*/
-- (void) sendMessage:(NSString*) message toWebView:(UIWebView *) theWebView;
+- (void)sendMessage:(NSString *)message toWebView:(UIWebView *)webView;
@end
@@ -2,10 +2,10 @@
@interface WebViewJavascriptBridge ()
-@property (readwrite,retain) NSMutableArray* startupMessageQueue;
+@property (nonatomic,strong) NSMutableArray *startupMessageQueue;
-- (void) _flushMessageQueueFromWebView: (UIWebView *) theWebView;
-- (void) _doSendMessage:(NSString*)message toWebView:(UIWebView *) theWebView;
+- (void)_flushMessageQueueFromWebView:(UIWebView *)webView;
+- (void)_doSendMessage:(NSString*)message toWebView:(UIWebView *)webView;
@end
@@ -14,135 +14,176 @@ @implementation WebViewJavascriptBridge
@synthesize delegate = _delegate;
@synthesize startupMessageQueue = _startupMessageQueue;
-static NSString* MESSAGE_SEPERATOR = @"__wvjb_sep__";
-static NSString* CUSTOM_PROTOCOL_SCHEME = @"webviewjavascriptbridge";
-static NSString* QUEUE_HAS_MESSAGE = @"queuehasmessage";
+static NSString *MESSAGE_SEPARATOR = @"__wvjb_sep__";
+static NSString *CUSTOM_PROTOCOL_SCHEME = @"webviewjavascriptbridge";
+static NSString *QUEUE_HAS_MESSAGE = @"queuehasmessage";
-+ (id) javascriptBridge
+- (id)initWithDelegate:(id <WebViewJavascriptBridgeDelegate>)delegate
{
- return [[[self alloc] init] autorelease];
-}
-
-- (id) init
-{
- if ( (self = [super init]) )
+ if ((self = [super init]) )
{
- self.startupMessageQueue = [[NSMutableArray new] autorelease];
+ self.delegate = delegate;
+ self.startupMessageQueue = [[[NSMutableArray alloc] init] autorelease];
}
return self;
}
-- (void) dealloc
+- (id)init
{
- self.delegate = nil;
- self.startupMessageQueue = nil;
+ return [[[WebViewJavascriptBridge alloc] initWithDelegate:nil] autorelease];
+}
+
++ (id)javascriptBridgeWithDelegate:(id <WebViewJavascriptBridgeDelegate>)delegate
+{
+ return [[[self alloc] initWithDelegate:delegate] autorelease];
+}
+
++ (id)javascriptBridge
+{
+ return [[[self alloc] init] autorelease];
+}
+
+- (void)dealloc
+{
+ _delegate = nil;
+ [_startupMessageQueue release];
[super dealloc];
}
-- (void)sendMessage:(NSString *)message toWebView: (UIWebView *) theWebView {
+- (void)sendMessage:(NSString *)message toWebView:(UIWebView *)webView {
if (self.startupMessageQueue) { [self.startupMessageQueue addObject:message]; }
- else { [self _doSendMessage:message toWebView: theWebView]; }
+ else { [self _doSendMessage:message toWebView: webView]; }
}
-- (void)_doSendMessage:(NSString *)message toWebView: (UIWebView *) aWebView {
+- (void)_doSendMessage:(NSString *)message toWebView:(UIWebView *)webView {
message = [message stringByReplacingOccurrencesOfString:@"\\n" withString:@"\\\\n"];
message = [message stringByReplacingOccurrencesOfString:@"'" withString:@"\\'"];
message = [message stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""];
- [aWebView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"WebViewJavascriptBridge._handleMessageFromObjC('%@');", message]];
+ [webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"WebViewJavascriptBridge._handleMessageFromObjC('%@');", message]];
+}
+
+- (void)_flushMessageQueueFromWebView:(UIWebView *)webView {
+ NSString *messageQueueString = [webView stringByEvaluatingJavaScriptFromString:@"WebViewJavascriptBridge._fetchQueue();"];
+ NSArray* messages = [messageQueueString componentsSeparatedByString:MESSAGE_SEPARATOR];
+ for (id message in messages) {
+ [self.delegate javascriptBridge:self receivedMessage:message fromWebView:webView];
+ }
}
-- (void)webViewDidFinishLoad:(UIWebView *)theWebView {
- NSString* js;
- js = [NSString stringWithFormat:@";(function() {"
- "if (window.WebViewJavascriptBridge) { return; };"
- "var _readyMessageIframe,"
- " _sendMessageQueue = [],"
- " _receiveMessageQueue = [],"
- " _MESSAGE_SEPERATOR = '%@',"
- " _CUSTOM_PROTOCOL_SCHEME = '%@',"
- " _QUEUE_HAS_MESSAGE = '%@';"
- ""
- "function _createQueueReadyIframe(doc) {"
- " _readyMessageIframe = doc.createElement('iframe');"
- " _readyMessageIframe.style.display = 'none';"
- " doc.documentElement.appendChild(_readyMessageIframe);"
- "}"
- ""
- "function _sendMessage(message) {"
- " _sendMessageQueue.push(message);"
- " _readyMessageIframe.src = _CUSTOM_PROTOCOL_SCHEME + '://' + _QUEUE_HAS_MESSAGE;"
- "};"
- ""
- "function _fetchQueue() {"
- " var messageQueueString = _sendMessageQueue.join(_MESSAGE_SEPERATOR);"
- " _sendMessageQueue = [];"
- " return messageQueueString;"
- "};"
- ""
- "function _setMessageHandler(messageHandler) {"
- " if (WebViewJavascriptBridge._messageHandler) { return alert('WebViewJavascriptBridge.setMessageHandler called twice'); }"
- " WebViewJavascriptBridge._messageHandler = messageHandler;"
- " var receivedMessages = _receiveMessageQueue;"
- " _receiveMessageQueue = null;"
- " for (var i=0; i<receivedMessages.length; i++) {"
- " messageHandler(receivedMessages[i]);"
- " }"
- "};"
- ""
- "function _handleMessageFromObjC(message) {"
- " if (_receiveMessageQueue) { _receiveMessageQueue.push(message); }"
- " else { WebViewJavascriptBridge._messageHandler(message); }"
- "};"
- ""
- "window.WebViewJavascriptBridge = {"
- " setMessageHandler: _setMessageHandler,"
- " sendMessage: _sendMessage,"
- " _fetchQueue: _fetchQueue,"
- " _handleMessageFromObjC: _handleMessageFromObjC"
- "};"
- ""
- "setTimeout(function() {"
- " var doc = document;"
- " _createQueueReadyIframe(doc);"
- " var readyEvent = doc.createEvent('Events');"
- " readyEvent.initEvent('WebViewJavascriptBridgeReady');"
- " doc.dispatchEvent(readyEvent);"
- "}, 0);"
- "})();",
- MESSAGE_SEPERATOR,
- CUSTOM_PROTOCOL_SCHEME,
- QUEUE_HAS_MESSAGE];
+#pragma mark UIWebViewDelegate
+
+- (void)webViewDidFinishLoad:(UIWebView *)webView {
+ NSString *js = [NSString stringWithFormat:@";(function() {"
+ "if (window.WebViewJavascriptBridge) { return; };"
+ "var _readyMessageIframe,"
+ " _sendMessageQueue = [],"
+ " _receiveMessageQueue = [],"
+ " _MESSAGE_SEPERATOR = '%@',"
+ " _CUSTOM_PROTOCOL_SCHEME = '%@',"
+ " _QUEUE_HAS_MESSAGE = '%@';"
+ ""
+ "function _createQueueReadyIframe(doc) {"
+ " _readyMessageIframe = doc.createElement('iframe');"
+ " _readyMessageIframe.style.display = 'none';"
+ " doc.documentElement.appendChild(_readyMessageIframe);"
+ "}"
+ ""
+ "function _sendMessage(message) {"
+ " _sendMessageQueue.push(message);"
+ " _readyMessageIframe.src = _CUSTOM_PROTOCOL_SCHEME + '://' + _QUEUE_HAS_MESSAGE;"
+ "};"
+ ""
+ "function _fetchQueue() {"
+ " var messageQueueString = _sendMessageQueue.join(_MESSAGE_SEPERATOR);"
+ " _sendMessageQueue = [];"
+ " return messageQueueString;"
+ "};"
+ ""
+ "function _setMessageHandler(messageHandler) {"
+ " if (WebViewJavascriptBridge._messageHandler) { return alert('WebViewJavascriptBridge.setMessageHandler called twice'); }"
+ " WebViewJavascriptBridge._messageHandler = messageHandler;"
+ " var receivedMessages = _receiveMessageQueue;"
+ " _receiveMessageQueue = null;"
+ " for (var i=0; i<receivedMessages.length; i++) {"
+ " messageHandler(receivedMessages[i]);"
+ " }"
+ "};"
+ ""
+ "function _handleMessageFromObjC(message) {"
+ " if (_receiveMessageQueue) { _receiveMessageQueue.push(message); }"
+ " else { WebViewJavascriptBridge._messageHandler(message); }"
+ "};"
+ ""
+ "window.WebViewJavascriptBridge = {"
+ " setMessageHandler: _setMessageHandler,"
+ " sendMessage: _sendMessage,"
+ " _fetchQueue: _fetchQueue,"
+ " _handleMessageFromObjC: _handleMessageFromObjC"
+ "};"
+ ""
+ "setTimeout(function() {"
+ " var doc = document;"
+ " _createQueueReadyIframe(doc);"
+ " var readyEvent = doc.createEvent('Events');"
+ " readyEvent.initEvent('WebViewJavascriptBridgeReady');"
+ " doc.dispatchEvent(readyEvent);"
+ "}, 0);"
+ "})();",
+ MESSAGE_SEPARATOR,
+ CUSTOM_PROTOCOL_SCHEME,
+ QUEUE_HAS_MESSAGE];
- [theWebView stringByEvaluatingJavaScriptFromString:js];
+ [webView stringByEvaluatingJavaScriptFromString:js];
for (id message in self.startupMessageQueue) {
- [self _doSendMessage:message toWebView: theWebView];
+ [self _doSendMessage:message toWebView: webView];
}
+
self.startupMessageQueue = nil;
+
+ if(self.delegate != nil && [self.delegate respondsToSelector:@selector(webViewDidFinishLoad:)])
+ {
+ [self.delegate webViewDidFinishLoad:webView];
+ }
}
+- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
+{
+ if(self.delegate != nil && [self.delegate respondsToSelector:@selector(webView:didFailLoadWithError:)])
+ {
+ [self.delegate webView:webView didFailLoadWithError:error];
+ }
+}
-- (BOOL)webView:(UIWebView *)theWebView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
+- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSURL *url = [request URL];
- if (![[url scheme] isEqualToString:CUSTOM_PROTOCOL_SCHEME]) { return YES; }
-
+ if (![[url scheme] isEqualToString:CUSTOM_PROTOCOL_SCHEME])
+ {
+ if(self.delegate != nil && [self.delegate respondsToSelector:@selector(webView:shouldStartLoadWithRequest:navigationType:)])
+ {
+ [self.delegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType];
+ }
+ return YES;
+ }
+
if ([[url host] isEqualToString:QUEUE_HAS_MESSAGE]) {
- [self _flushMessageQueueFromWebView: theWebView];
- } else {
- NSLog(@"WARNING: Received unknown WebViewJavascriptBridge command %@://%@", CUSTOM_PROTOCOL_SCHEME, [url path]);
+ [self _flushMessageQueueFromWebView: webView];
+ }
+ else {
+ NSLog(@"WebViewJavascriptBridge: WARNING: Received unknown WebViewJavascriptBridge command %@://%@", CUSTOM_PROTOCOL_SCHEME, [url path]);
}
return NO;
}
-- (void) _flushMessageQueueFromWebView: (UIWebView *) theWebView {
- NSString* messageQueueString = [theWebView stringByEvaluatingJavaScriptFromString:@"WebViewJavascriptBridge._fetchQueue();"];
- NSArray* messages = [messageQueueString componentsSeparatedByString:MESSAGE_SEPERATOR];
- for (id message in messages) {
- [self.delegate handleMessage:message fromWebView: theWebView];
- }
+- (void)webViewDidStartLoad:(UIWebView *)webView
+{
+ if(self.delegate != nil && [self.delegate respondsToSelector:@selector(webViewDidStartLoad:)])
+ {
+ [self.delegate webViewDidStartLoad:webView];
+ }
}
@end
@@ -7,6 +7,6 @@
@property (strong, nonatomic) UIWebView *webView;
@property (strong, nonatomic) WebViewJavascriptBridge *javascriptBridge;
-- (void) loadExamplePage;
+- (void)loadExamplePage;
@end
Oops, something went wrong.

0 comments on commit 83448f4

Please sign in to comment.