22
33@interface WebViewJavascriptBridge ()
44
5- @property (readwrite , retain ) NSMutableArray * startupMessageQueue;
5+ @property (nonatomic , strong ) NSMutableArray * startupMessageQueue;
66
7- - (void ) _flushMessageQueueFromWebView : (UIWebView *) theWebView ;
8- - (void ) _doSendMessage : (NSString *)message toWebView : (UIWebView *) theWebView ;
7+ - (void )_flushMessageQueueFromWebView : (UIWebView *)webView ;
8+ - (void )_doSendMessage : (NSString *)message toWebView : (UIWebView *)webView ;
99
1010@end
1111
@@ -14,135 +14,176 @@ @implementation WebViewJavascriptBridge
1414@synthesize delegate = _delegate;
1515@synthesize startupMessageQueue = _startupMessageQueue;
1616
17- static NSString * MESSAGE_SEPERATOR = @" __wvjb_sep__" ;
18- static NSString * CUSTOM_PROTOCOL_SCHEME = @" webviewjavascriptbridge" ;
19- static NSString * QUEUE_HAS_MESSAGE = @" queuehasmessage" ;
17+ static NSString *MESSAGE_SEPARATOR = @" __wvjb_sep__" ;
18+ static NSString * CUSTOM_PROTOCOL_SCHEME = @" webviewjavascriptbridge" ;
19+ static NSString * QUEUE_HAS_MESSAGE = @" queuehasmessage" ;
2020
21- + (id ) javascriptBridge
21+ - (id )initWithDelegate : ( id <WebViewJavascriptBridgeDelegate>) delegate
2222{
23- return [[[self alloc ] init ] autorelease ];
24- }
25-
26- - (id ) init
27- {
28- if ( (self = [super init ]) )
23+ if ((self = [super init ]) )
2924 {
30- self.startupMessageQueue = [[NSMutableArray new ] autorelease ];
25+ self.delegate = delegate;
26+ self.startupMessageQueue = [[[NSMutableArray alloc ] init ] autorelease ];
3127 }
3228
3329 return self;
3430}
3531
36- - (void ) dealloc
32+ - (id ) init
3733{
38- self.delegate = nil ;
39- self.startupMessageQueue = nil ;
34+ return [[[WebViewJavascriptBridge alloc ] initWithDelegate: nil ] autorelease ];
35+ }
36+
37+ + (id )javascriptBridgeWithDelegate : (id <WebViewJavascriptBridgeDelegate>)delegate
38+ {
39+ return [[[self alloc ] initWithDelegate: delegate] autorelease ];
40+ }
41+
42+ + (id )javascriptBridge
43+ {
44+ return [[[self alloc ] init ] autorelease ];
45+ }
46+
47+ - (void )dealloc
48+ {
49+ _delegate = nil ;
50+ [_startupMessageQueue release ];
4051
4152 [super dealloc ];
4253}
4354
44- - (void )sendMessage : (NSString *)message toWebView : (UIWebView *) theWebView {
55+ - (void )sendMessage : (NSString *)message toWebView : (UIWebView *)webView {
4556 if (self.startupMessageQueue ) { [self .startupMessageQueue addObject: message]; }
46- else { [self _doSendMessage: message toWebView: theWebView ]; }
57+ else { [self _doSendMessage: message toWebView: webView ]; }
4758}
4859
49- - (void )_doSendMessage : (NSString *)message toWebView : (UIWebView *) aWebView {
60+ - (void )_doSendMessage : (NSString *)message toWebView : (UIWebView *)webView {
5061 message = [message stringByReplacingOccurrencesOfString: @" \\ n" withString: @" \\\\ n" ];
5162 message = [message stringByReplacingOccurrencesOfString: @" '" withString: @" \\ '" ];
5263 message = [message stringByReplacingOccurrencesOfString: @" \" " withString: @" \\\" " ];
53- [aWebView stringByEvaluatingJavaScriptFromString: [NSString stringWithFormat: @" WebViewJavascriptBridge._handleMessageFromObjC('%@ ');" , message]];
64+ [webView stringByEvaluatingJavaScriptFromString: [NSString stringWithFormat: @" WebViewJavascriptBridge._handleMessageFromObjC('%@ ');" , message]];
65+ }
66+
67+ - (void )_flushMessageQueueFromWebView : (UIWebView *)webView {
68+ NSString *messageQueueString = [webView stringByEvaluatingJavaScriptFromString: @" WebViewJavascriptBridge._fetchQueue();" ];
69+ NSArray * messages = [messageQueueString componentsSeparatedByString: MESSAGE_SEPARATOR];
70+ for (id message in messages) {
71+ [self .delegate javascriptBridge: self receivedMessage: message fromWebView: webView];
72+ }
5473}
5574
56- - (void )webViewDidFinishLoad : (UIWebView *)theWebView {
57- NSString * js;
58- js = [NSString stringWithFormat: @" ;(function() {"
59- " if (window.WebViewJavascriptBridge) { return; };"
60- " var _readyMessageIframe,"
61- " _sendMessageQueue = [],"
62- " _receiveMessageQueue = [],"
63- " _MESSAGE_SEPERATOR = '%@ ',"
64- " _CUSTOM_PROTOCOL_SCHEME = '%@ ',"
65- " _QUEUE_HAS_MESSAGE = '%@ ';"
66- " "
67- " function _createQueueReadyIframe(doc) {"
68- " _readyMessageIframe = doc.createElement('iframe');"
69- " _readyMessageIframe.style.display = 'none';"
70- " doc.documentElement.appendChild(_readyMessageIframe);"
71- " }"
72- " "
73- " function _sendMessage(message) {"
74- " _sendMessageQueue.push(message);"
75- " _readyMessageIframe.src = _CUSTOM_PROTOCOL_SCHEME + '://' + _QUEUE_HAS_MESSAGE;"
76- " };"
77- " "
78- " function _fetchQueue() {"
79- " var messageQueueString = _sendMessageQueue.join(_MESSAGE_SEPERATOR);"
80- " _sendMessageQueue = [];"
81- " return messageQueueString;"
82- " };"
83- " "
84- " function _setMessageHandler(messageHandler) {"
85- " if (WebViewJavascriptBridge._messageHandler) { return alert('WebViewJavascriptBridge.setMessageHandler called twice'); }"
86- " WebViewJavascriptBridge._messageHandler = messageHandler;"
87- " var receivedMessages = _receiveMessageQueue;"
88- " _receiveMessageQueue = null;"
89- " for (var i=0; i<receivedMessages.length; i++) {"
90- " messageHandler(receivedMessages[i]);"
91- " }"
92- " };"
93- " "
94- " function _handleMessageFromObjC(message) {"
95- " if (_receiveMessageQueue) { _receiveMessageQueue.push(message); }"
96- " else { WebViewJavascriptBridge._messageHandler(message); }"
97- " };"
98- " "
99- " window.WebViewJavascriptBridge = {"
100- " setMessageHandler: _setMessageHandler,"
101- " sendMessage: _sendMessage,"
102- " _fetchQueue: _fetchQueue,"
103- " _handleMessageFromObjC: _handleMessageFromObjC"
104- " };"
105- " "
106- " setTimeout(function() {"
107- " var doc = document;"
108- " _createQueueReadyIframe(doc);"
109- " var readyEvent = doc.createEvent('Events');"
110- " readyEvent.initEvent('WebViewJavascriptBridgeReady');"
111- " doc.dispatchEvent(readyEvent);"
112- " }, 0);"
113- " })();" ,
114- MESSAGE_SEPERATOR,
115- CUSTOM_PROTOCOL_SCHEME,
116- QUEUE_HAS_MESSAGE];
75+ #pragma mark UIWebViewDelegate
76+
77+ - (void )webViewDidFinishLoad : (UIWebView *)webView {
78+ NSString *js = [NSString stringWithFormat: @" ;(function() {"
79+ " if (window.WebViewJavascriptBridge) { return; };"
80+ " var _readyMessageIframe,"
81+ " _sendMessageQueue = [],"
82+ " _receiveMessageQueue = [],"
83+ " _MESSAGE_SEPERATOR = '%@ ',"
84+ " _CUSTOM_PROTOCOL_SCHEME = '%@ ',"
85+ " _QUEUE_HAS_MESSAGE = '%@ ';"
86+ " "
87+ " function _createQueueReadyIframe(doc) {"
88+ " _readyMessageIframe = doc.createElement('iframe');"
89+ " _readyMessageIframe.style.display = 'none';"
90+ " doc.documentElement.appendChild(_readyMessageIframe);"
91+ " }"
92+ " "
93+ " function _sendMessage(message) {"
94+ " _sendMessageQueue.push(message);"
95+ " _readyMessageIframe.src = _CUSTOM_PROTOCOL_SCHEME + '://' + _QUEUE_HAS_MESSAGE;"
96+ " };"
97+ " "
98+ " function _fetchQueue() {"
99+ " var messageQueueString = _sendMessageQueue.join(_MESSAGE_SEPERATOR);"
100+ " _sendMessageQueue = [];"
101+ " return messageQueueString;"
102+ " };"
103+ " "
104+ " function _setMessageHandler(messageHandler) {"
105+ " if (WebViewJavascriptBridge._messageHandler) { return alert('WebViewJavascriptBridge.setMessageHandler called twice'); }"
106+ " WebViewJavascriptBridge._messageHandler = messageHandler;"
107+ " var receivedMessages = _receiveMessageQueue;"
108+ " _receiveMessageQueue = null;"
109+ " for (var i=0; i<receivedMessages.length; i++) {"
110+ " messageHandler(receivedMessages[i]);"
111+ " }"
112+ " };"
113+ " "
114+ " function _handleMessageFromObjC(message) {"
115+ " if (_receiveMessageQueue) { _receiveMessageQueue.push(message); }"
116+ " else { WebViewJavascriptBridge._messageHandler(message); }"
117+ " };"
118+ " "
119+ " window.WebViewJavascriptBridge = {"
120+ " setMessageHandler: _setMessageHandler,"
121+ " sendMessage: _sendMessage,"
122+ " _fetchQueue: _fetchQueue,"
123+ " _handleMessageFromObjC: _handleMessageFromObjC"
124+ " };"
125+ " "
126+ " setTimeout(function() {"
127+ " var doc = document;"
128+ " _createQueueReadyIframe(doc);"
129+ " var readyEvent = doc.createEvent('Events');"
130+ " readyEvent.initEvent('WebViewJavascriptBridgeReady');"
131+ " doc.dispatchEvent(readyEvent);"
132+ " }, 0);"
133+ " })();" ,
134+ MESSAGE_SEPARATOR,
135+ CUSTOM_PROTOCOL_SCHEME,
136+ QUEUE_HAS_MESSAGE];
117137
118- [theWebView stringByEvaluatingJavaScriptFromString: js];
138+ [webView stringByEvaluatingJavaScriptFromString: js];
119139
120140 for (id message in self.startupMessageQueue ) {
121- [self _doSendMessage: message toWebView: theWebView ];
141+ [self _doSendMessage: message toWebView: webView ];
122142 }
143+
123144 self.startupMessageQueue = nil ;
145+
146+ if (self.delegate != nil && [self .delegate respondsToSelector: @selector (webViewDidFinishLoad: )])
147+ {
148+ [self .delegate webViewDidFinishLoad: webView];
149+ }
124150}
125151
152+ - (void )webView : (UIWebView *)webView didFailLoadWithError : (NSError *)error
153+ {
154+ if (self.delegate != nil && [self .delegate respondsToSelector: @selector (webView:didFailLoadWithError: )])
155+ {
156+ [self .delegate webView: webView didFailLoadWithError: error];
157+ }
158+ }
126159
127- - (BOOL )webView : (UIWebView *)theWebView shouldStartLoadWithRequest : (NSURLRequest *)request navigationType : (UIWebViewNavigationType)navigationType {
160+ - (BOOL )webView : (UIWebView *)webView shouldStartLoadWithRequest : (NSURLRequest *)request navigationType : (UIWebViewNavigationType)navigationType {
128161 NSURL *url = [request URL ];
129- if (![[url scheme ] isEqualToString: CUSTOM_PROTOCOL_SCHEME]) { return YES ; }
130-
162+ if (![[url scheme ] isEqualToString: CUSTOM_PROTOCOL_SCHEME])
163+ {
164+ if (self.delegate != nil && [self .delegate respondsToSelector: @selector (webView:shouldStartLoadWithRequest:navigationType: )])
165+ {
166+ [self .delegate webView: webView shouldStartLoadWithRequest: request navigationType: navigationType];
167+ }
168+ return YES ;
169+ }
170+
131171 if ([[url host ] isEqualToString: QUEUE_HAS_MESSAGE]) {
132- [self _flushMessageQueueFromWebView: theWebView];
133- } else {
134- NSLog (@" WARNING: Received unknown WebViewJavascriptBridge command %@ ://%@ " , CUSTOM_PROTOCOL_SCHEME, [url path ]);
172+ [self _flushMessageQueueFromWebView: webView];
173+ }
174+ else {
175+ NSLog (@" WebViewJavascriptBridge: WARNING: Received unknown WebViewJavascriptBridge command %@ ://%@ " , CUSTOM_PROTOCOL_SCHEME, [url path ]);
135176 }
136177
137178 return NO ;
138179}
139180
140- - (void ) _flushMessageQueueFromWebView : (UIWebView *) theWebView {
141- NSString * messageQueueString = [theWebView stringByEvaluatingJavaScriptFromString: @" WebViewJavascriptBridge._fetchQueue(); " ];
142- NSArray * messages = [messageQueueString componentsSeparatedByString: MESSAGE_SEPERATOR];
143- for ( id message in messages) {
144- [self .delegate handleMessage: message fromWebView: theWebView ];
145- }
181+ - (void )webViewDidStartLoad : (UIWebView *)webView
182+ {
183+ if (self. delegate != nil && [ self .delegate respondsToSelector: @selector ( webViewDidStartLoad: )])
184+ {
185+ [self .delegate webViewDidStartLoad: webView ];
186+ }
146187}
147188
148189@end
0 commit comments