77//
88
99#import " WebViewJavascriptBridge.h"
10+ #import " WebViewJavascriptBridgeBase.h"
1011
1112#if __has_feature(objc_arc_weak)
1213 #define WVJB_WEAK __weak
1920@implementation WebViewJavascriptBridge {
2021 WVJB_WEAK WVJB_WEBVIEW_TYPE* _webView;
2122 WVJB_WEAK id _webViewDelegate;
22- NSMutableArray * _startupMessageQueue;
23- NSMutableDictionary * _responseCallbacks;
24- NSMutableDictionary * _messageHandlers;
2523 long _uniqueId;
26- WVJBHandler _messageHandler;
27-
28- NSBundle *_resourceBundle;
29-
24+ WebViewJavascriptBridgeBase *_base;
3025#if defined WVJB_PLATFORM_IOS
3126 NSUInteger _numRequestsLoading;
3227#endif
@@ -36,8 +31,7 @@ @implementation WebViewJavascriptBridge {
3631/* API
3732 *****/
3833
39- static bool logging = false ;
40- + (void )enableLogging { logging = true ; }
34+ + (void )enableLogging { [WebViewJavascriptBridgeBase enableLogging ]; }
4135
4236+ (instancetype )bridgeForWebView : (WVJB_WEBVIEW_TYPE*)webView handler : (WVJBHandler)handler {
4337 return [self bridgeForWebView: webView webViewDelegate: nil handler: handler];
@@ -59,7 +53,7 @@ - (void)send:(id)data {
5953}
6054
6155- (void )send : (id )data responseCallback : (WVJBResponseCallback)responseCallback {
62- [self _sendData: data responseCallback: responseCallback handlerName: nil ];
56+ [_base _sendData: data responseCallback: responseCallback handlerName: nil ];
6357}
6458
6559- (void )callHandler : (NSString *)handlerName {
@@ -71,162 +65,28 @@ - (void)callHandler:(NSString *)handlerName data:(id)data {
7165}
7266
7367- (void )callHandler : (NSString *)handlerName data : (id )data responseCallback : (WVJBResponseCallback)responseCallback {
74- [self _sendData: data responseCallback: responseCallback handlerName: handlerName];
68+ [_base _sendData: data responseCallback: responseCallback handlerName: handlerName];
7569}
7670
7771- (void )registerHandler : (NSString *)handlerName handler : (WVJBHandler)handler {
78- _messageHandlers [handlerName] = [handler copy ];
72+ _base. messageHandlers [handlerName] = [handler copy ];
7973}
8074
8175/* Platform agnostic internals
8276 *****************************/
8377
84- - (id )init {
85- if (self = [super init ]) {
86- _startupMessageQueue = [NSMutableArray array ];
87- _responseCallbacks = [NSMutableDictionary dictionary ];
88- _uniqueId = 0 ;
89- }
90- return self;
91- }
92-
9378- (void )dealloc {
9479 [self _platformSpecificDealloc ];
95-
80+ _base = nil ;
9681 _webView = nil ;
9782 _webViewDelegate = nil ;
98- _startupMessageQueue = nil ;
99- _responseCallbacks = nil ;
100- _messageHandlers = nil ;
101- _messageHandler = nil ;
102- }
103-
104- - (void )_sendData : (id )data responseCallback : (WVJBResponseCallback)responseCallback handlerName : (NSString *)handlerName {
105- NSMutableDictionary * message = [NSMutableDictionary dictionary ];
106-
107- if (data) {
108- message[@" data" ] = data;
109- }
110-
111- if (responseCallback) {
112- NSString * callbackId = [NSString stringWithFormat: @" objc_cb_%ld " , ++_uniqueId];
113- _responseCallbacks[callbackId] = [responseCallback copy ];
114- message[@" callbackId" ] = callbackId;
115- }
116-
117- if (handlerName) {
118- message[@" handlerName" ] = handlerName;
119- }
120- [self _queueMessage: message];
121- }
122-
123- - (void )_queueMessage : (WVJBMessage*)message {
124- if (_startupMessageQueue) {
125- [_startupMessageQueue addObject: message];
126- } else {
127- [self _dispatchMessage: message];
128- }
129- }
130-
131- - (void )_dispatchMessage : (WVJBMessage*)message {
132- NSString *messageJSON = [self _serializeMessage: message];
133- [self _log: @" SEND" json: messageJSON];
134- messageJSON = [messageJSON stringByReplacingOccurrencesOfString: @" \\ " withString: @" \\\\ " ];
135- messageJSON = [messageJSON stringByReplacingOccurrencesOfString: @" \" " withString: @" \\\" " ];
136- messageJSON = [messageJSON stringByReplacingOccurrencesOfString: @" \' " withString: @" \\\' " ];
137- messageJSON = [messageJSON stringByReplacingOccurrencesOfString: @" \n " withString: @" \\ n" ];
138- messageJSON = [messageJSON stringByReplacingOccurrencesOfString: @" \r " withString: @" \\ r" ];
139- messageJSON = [messageJSON stringByReplacingOccurrencesOfString: @" \f " withString: @" \\ f" ];
140- messageJSON = [messageJSON stringByReplacingOccurrencesOfString: @" \u2028 " withString: @" \\ u2028" ];
141- messageJSON = [messageJSON stringByReplacingOccurrencesOfString: @" \u2029 " withString: @" \\ u2029" ];
142-
143- NSString * javascriptCommand = [NSString stringWithFormat: @" WebViewJavascriptBridge._handleMessageFromObjC('%@ ');" , messageJSON];
144- if ([[NSThread currentThread ] isMainThread ]) {
145- [_webView stringByEvaluatingJavaScriptFromString: javascriptCommand];
146- } else {
147- __strong WVJB_WEBVIEW_TYPE* strongWebView = _webView;
148- dispatch_sync (dispatch_get_main_queue (), ^{
149- [strongWebView stringByEvaluatingJavaScriptFromString: javascriptCommand];
150- });
151- }
152- }
153-
154- - (void )_flushMessageQueue {
155- NSString *messageQueueString = [_webView stringByEvaluatingJavaScriptFromString: @" WebViewJavascriptBridge._fetchQueue();" ];
156-
157- id messages = [self _deserializeMessageJSON: messageQueueString];
158- if (![messages isKindOfClass: [NSArray class ]]) {
159- NSLog (@" WebViewJavascriptBridge: WARNING: Invalid %@ received: %@ " , [messages class ], messages);
160- return ;
161- }
162- for (WVJBMessage* message in messages) {
163- if (![message isKindOfClass: [WVJBMessage class ]]) {
164- NSLog (@" WebViewJavascriptBridge: WARNING: Invalid %@ received: %@ " , [message class ], message);
165- continue ;
166- }
167- [self _log: @" RCVD" json: message];
168-
169- NSString * responseId = message[@" responseId" ];
170- if (responseId) {
171- WVJBResponseCallback responseCallback = _responseCallbacks[responseId];
172- responseCallback (message[@" responseData" ]);
173- [_responseCallbacks removeObjectForKey: responseId];
174- } else {
175- WVJBResponseCallback responseCallback = NULL ;
176- NSString * callbackId = message[@" callbackId" ];
177- if (callbackId) {
178- responseCallback = ^(id responseData) {
179- if (responseData == nil ) {
180- responseData = [NSNull null ];
181- }
182-
183- WVJBMessage* msg = @{ @" responseId" :callbackId, @" responseData" :responseData };
184- [self _queueMessage: msg];
185- };
186- } else {
187- responseCallback = ^(id ignoreResponseData) {
188- // Do nothing
189- };
190- }
191-
192- WVJBHandler handler;
193- if (message[@" handlerName" ]) {
194- handler = _messageHandlers[message[@" handlerName" ]];
195- } else {
196- handler = _messageHandler;
197- }
198-
199- if (!handler) {
200- [NSException raise: @" WVJBNoHandlerException" format: @" No handler for message from JS: %@ " , message];
201- }
202-
203- handler (message[@" data" ], responseCallback);
204- }
205- }
206- }
207-
208- - (NSString *)_serializeMessage : (id )message {
209- return [[NSString alloc ] initWithData: [NSJSONSerialization dataWithJSONObject: message options: 0 error: nil ] encoding: NSUTF8StringEncoding];
21083}
21184
212- - (NSArray *)_deserializeMessageJSON : (NSString *)messageJSON {
213- return [NSJSONSerialization JSONObjectWithData: [messageJSON dataUsingEncoding: NSUTF8StringEncoding] options: NSJSONReadingAllowFragments error: nil ];
214- }
215-
216- - (void )_log : (NSString *)action json : (id )json {
217- if (!logging) { return ; }
218- if (![json isKindOfClass: [NSString class ]]) {
219- json = [self _serializeMessage: json];
220- }
221- if ([json length ] > 500 ) {
222- NSLog (@" WVJB %@ : %@ [...]" , action, [json substringToIndex: 500 ]);
223- } else {
224- NSLog (@" WVJB %@ : %@ " , action, json);
225- }
85+ - (NSString *) _evaluateJavascript : (NSString *)javascriptCommand
86+ {
87+ return [_webView stringByEvaluatingJavaScriptFromString: javascriptCommand];
22688}
22789
228-
229-
23090/* Platform specific internals: OSX
23191 **********************************/
23292#if defined WVJB_PLATFORM_OSX
@@ -325,12 +185,9 @@ - (NSURLRequest *)webView:(WebView *)webView resource:(id)identifier willSendReq
325185#elif defined WVJB_PLATFORM_IOS
326186
327187- (void ) _platformSpecificSetup : (WVJB_WEBVIEW_TYPE*)webView webViewDelegate : (id <UIWebViewDelegate>)webViewDelegate handler : (WVJBHandler)messageHandler resourceBundle : (NSBundle *)bundle {
328- _messageHandler = messageHandler;
329188 _webView = webView;
330189 _webViewDelegate = webViewDelegate;
331- _messageHandlers = [NSMutableDictionary dictionary ];
332- _webView.delegate = self;
333- _resourceBundle = bundle;
190+ _base = [[WebViewJavascriptBridgeBase alloc ] initWithWebViewType: @" WebView" handler: (WVJBHandler)messageHandler resourceBundle: (NSBundle *)bundle];
334191}
335192
336193- (void ) _platformSpecificDealloc {
@@ -342,19 +199,10 @@ - (void)webViewDidFinishLoad:(UIWebView *)webView {
342199
343200 _numRequestsLoading--;
344201
345- if (_numRequestsLoading == 0 && ![[webView stringByEvaluatingJavaScriptFromString: @" typeof WebViewJavascriptBridge == 'object'" ] isEqualToString: @" true" ]) {
346- NSBundle *bundle = _resourceBundle ? _resourceBundle : [NSBundle mainBundle ];
347- NSString *filePath = [bundle pathForResource: @" WebViewJavascriptBridge.js" ofType: @" txt" ];
348- NSString *js = [NSString stringWithContentsOfFile: filePath encoding: NSUTF8StringEncoding error: nil ];
349- [webView stringByEvaluatingJavaScriptFromString: js];
350- }
351-
352- if (_startupMessageQueue) {
353- for (id queuedMessage in _startupMessageQueue) {
354- [self _dispatchMessage: queuedMessage];
355- }
356- _startupMessageQueue = nil ;
202+ if (_numRequestsLoading == 0 && ![[webView stringByEvaluatingJavaScriptFromString: [_base webViewJavascriptCheckCommand ]] isEqualToString: @" true" ]) {
203+ [_base injectJavascriptFile: YES ];
357204 }
205+ [_base dispatchStartUpMessageQueue ];
358206
359207 __strong WVJB_WEBVIEW_DELEGATE_TYPE* strongDelegate = _webViewDelegate;
360208 if (strongDelegate && [strongDelegate respondsToSelector: @selector (webViewDidFinishLoad: )]) {
@@ -377,11 +225,12 @@ - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)
377225 if (webView != _webView) { return YES ; }
378226 NSURL *url = [request URL ];
379227 __strong WVJB_WEBVIEW_DELEGATE_TYPE* strongDelegate = _webViewDelegate;
380- if ([[url scheme ] isEqualToString: kCustomProtocolScheme ]) {
381- if ([[url host ] isEqualToString: kQueueHasMessage ]) {
382- [self _flushMessageQueue ];
228+ if ([_base correctProcotocolScheme: url]) {
229+ if ([_base correctHost: url]) {
230+ NSString *messageQueueString = [self _evaluateJavascript: [_base webViewJavascriptFetchQueyCommand ]];
231+ [_base _flushMessageQueue: messageQueueString];
383232 } else {
384- NSLog ( @" WebViewJavascriptBridge: WARNING: Received unknown WebViewJavascriptBridge command %@ :// %@ " , kCustomProtocolScheme , [ url path ]) ;
233+ [_base logUnkownMessage: url] ;
385234 }
386235 return NO ;
387236 } else if (strongDelegate && [strongDelegate respondsToSelector: @selector (webView:shouldStartLoadWithRequest:navigationType: )]) {
0 commit comments