7
7
8
8
9
9
#import " WKWebViewJavascriptBridge.h"
10
+ #import " WebViewJavascriptBridgeBase.h"
10
11
11
12
#if defined(supportsWKWebKit)
12
13
13
- typedef NSDictionary WVJBMessage;
14
-
15
14
@implementation WKWebViewJavascriptBridge {
16
15
WKWebView * _webView;
17
16
id _webViewDelegate;
18
- NSMutableArray * _startupMessageQueue;
19
- NSMutableDictionary * _responseCallbacks;
20
- NSMutableDictionary * _messageHandlers;
21
17
long _uniqueId;
22
- WVJBHandler _messageHandler;
23
- NSBundle *_resourceBundle;
24
- NSUInteger _numRequestsLoading;
18
+ WebViewJavascriptBridgeBase *_base;
25
19
}
26
20
27
21
/* API
28
22
*****/
29
23
30
- static bool logging = false ;
31
- + (void )enableLogging { logging = true ; }
24
+ + (void )enableLogging { [WebViewJavascriptBridgeBase enableLogging ]; }
32
25
33
26
+ (instancetype )bridgeForWebView : (WKWebView *)webView handler : (WVJBHandler)handler {
34
27
return [self bridgeForWebView: webView webViewDelegate: nil handler: handler];
@@ -51,7 +44,7 @@ - (void)send:(id)data {
51
44
}
52
45
53
46
- (void )send : (id )data responseCallback : (WVJBResponseCallback)responseCallback {
54
- [self _sendData: data responseCallback: responseCallback handlerName: nil ];
47
+ [_base _sendData: data responseCallback: responseCallback handlerName: nil ];
55
48
}
56
49
57
50
- (void )callHandler : (NSString *)handlerName {
@@ -63,205 +56,57 @@ - (void)callHandler:(NSString *)handlerName data:(id)data {
63
56
}
64
57
65
58
- (void )callHandler : (NSString *)handlerName data : (id )data responseCallback : (WVJBResponseCallback)responseCallback {
66
- [self _sendData: data responseCallback: responseCallback handlerName: handlerName];
59
+ [_base _sendData: data responseCallback: responseCallback handlerName: handlerName];
67
60
}
68
61
69
62
- (void )registerHandler : (NSString *)handlerName handler : (WVJBHandler)handler {
70
- _messageHandlers [handlerName] = [handler copy ];
63
+ _base. messageHandlers [handlerName] = [handler copy ];
71
64
}
72
65
73
66
- (void )reset {
74
- _startupMessageQueue = [NSMutableArray array ];
75
- _responseCallbacks = [NSMutableDictionary dictionary ];
76
- _uniqueId = 0 ;
67
+ [_base reset ];
77
68
}
78
69
79
70
/* Internals
80
71
***********/
81
72
82
73
- (void )dealloc {
83
- [self _platformSpecificDealloc ];
84
-
74
+ _base = nil ;
85
75
_webView = nil ;
86
76
_webViewDelegate = nil ;
87
- _startupMessageQueue = nil ;
88
- _responseCallbacks = nil ;
89
- _messageHandlers = nil ;
90
- _messageHandler = nil ;
91
- }
92
-
93
- - (void )_sendData : (id )data responseCallback : (WVJBResponseCallback)responseCallback handlerName : (NSString *)handlerName {
94
- NSMutableDictionary * message = [NSMutableDictionary dictionary ];
95
-
96
- if (data) {
97
- message[@" data" ] = data;
98
- }
99
-
100
- if (responseCallback) {
101
- NSString * callbackId = [NSString stringWithFormat: @" objc_cb_%ld " , ++_uniqueId];
102
- _responseCallbacks[callbackId] = [responseCallback copy ];
103
- message[@" callbackId" ] = callbackId;
104
- }
105
-
106
- if (handlerName) {
107
- message[@" handlerName" ] = handlerName;
108
- }
109
- [self _queueMessage: message];
110
- }
111
-
112
- - (void )_queueMessage : (WVJBMessage*)message {
113
- if (_startupMessageQueue) {
114
- [_startupMessageQueue addObject: message];
115
- } else {
116
- [self _dispatchMessage: message];
117
- }
118
- }
119
-
120
- - (void )_dispatchMessage : (WVJBMessage*)message {
121
- NSString *messageJSON = [self _serializeMessage: message];
122
- [self _log: @" SEND" json: messageJSON];
123
- messageJSON = [messageJSON stringByReplacingOccurrencesOfString: @" \\ " withString: @" \\\\ " ];
124
- messageJSON = [messageJSON stringByReplacingOccurrencesOfString: @" \" " withString: @" \\\" " ];
125
- messageJSON = [messageJSON stringByReplacingOccurrencesOfString: @" \' " withString: @" \\\' " ];
126
- messageJSON = [messageJSON stringByReplacingOccurrencesOfString: @" \n " withString: @" \\ n" ];
127
- messageJSON = [messageJSON stringByReplacingOccurrencesOfString: @" \r " withString: @" \\ r" ];
128
- messageJSON = [messageJSON stringByReplacingOccurrencesOfString: @" \f " withString: @" \\ f" ];
129
- messageJSON = [messageJSON stringByReplacingOccurrencesOfString: @" \u2028 " withString: @" \\ u2028" ];
130
- messageJSON = [messageJSON stringByReplacingOccurrencesOfString: @" \u2029 " withString: @" \\ u2029" ];
131
-
132
- NSString * javascriptCommand = [NSString stringWithFormat: @" WebViewJavascriptBridge._handleMessageFromObjC('%@ ');" , messageJSON];
133
- if ([[NSThread currentThread ] isMainThread ]) {
134
- [_webView evaluateJavaScript: javascriptCommand completionHandler: nil ];
135
- } else {
136
- dispatch_sync (dispatch_get_main_queue (), ^{
137
- [_webView evaluateJavaScript: javascriptCommand completionHandler: nil ];
138
- });
139
- }
140
- }
141
-
142
- - (void )_flushMessageQueue : (NSString *)messageQueueString {
143
- id messages = [self _deserializeMessageJSON: messageQueueString];
144
- if (![messages isKindOfClass: [NSArray class ]]) {
145
- NSLog (@" WKWebViewJavascriptBridge: WARNING: Invalid %@ received: %@ " , [messages class ], messages);
146
- return ;
147
- }
148
- for (WVJBMessage* message in messages) {
149
- if (![message isKindOfClass: [WVJBMessage class ]]) {
150
- NSLog (@" WKWebViewJavascriptBridge: WARNING: Invalid %@ received: %@ " , [message class ], message);
151
- continue ;
152
- }
153
- [self _log: @" RCVD" json: message];
154
-
155
- NSString * responseId = message[@" responseId" ];
156
- if (responseId) {
157
- WVJBResponseCallback responseCallback = _responseCallbacks[responseId];
158
- responseCallback (message[@" responseData" ]);
159
- [_responseCallbacks removeObjectForKey: responseId];
160
- } else {
161
- WVJBResponseCallback responseCallback = NULL ;
162
- NSString * callbackId = message[@" callbackId" ];
163
- if (callbackId) {
164
- responseCallback = ^(id responseData) {
165
- if (responseData == nil ) {
166
- responseData = [NSNull null ];
167
- }
168
-
169
- WVJBMessage* msg = @{ @" responseId" :callbackId, @" responseData" :responseData };
170
- [self _queueMessage: msg];
171
- };
172
- } else {
173
- responseCallback = ^(id ignoreResponseData) {
174
- // Do nothing
175
- };
176
- }
177
-
178
- WVJBHandler handler;
179
- if (message[@" handlerName" ]) {
180
- handler = _messageHandlers[message[@" handlerName" ]];
181
- } else {
182
- handler = _messageHandler;
183
- }
184
-
185
- if (!handler) {
186
- [NSException raise: @" WVJBNoHandlerException" format: @" No handler for message from JS: %@ " , message];
187
- }
188
-
189
- handler (message[@" data" ], responseCallback);
190
- }
191
- }
192
- }
193
-
194
- - (NSString *)_serializeMessage : (id )message {
195
- return [[NSString alloc ] initWithData: [NSJSONSerialization dataWithJSONObject: message options: 0 error: nil ] encoding: NSUTF8StringEncoding];
196
- }
197
-
198
- - (NSArray *)_deserializeMessageJSON : (NSString *)messageJSON {
199
- return [NSJSONSerialization JSONObjectWithData: [messageJSON dataUsingEncoding: NSUTF8StringEncoding] options: NSJSONReadingAllowFragments error: nil ];
200
- }
201
-
202
- - (void )_log : (NSString *)action json : (id )json {
203
- if (!logging) { return ; }
204
- if (![json isKindOfClass: [NSString class ]]) {
205
- json = [self _serializeMessage: json];
206
- }
207
- if ([json length ] > 500 ) {
208
- NSLog (@" WVJB %@ : %@ [...]" , action, [json substringToIndex: 500 ]);
209
- } else {
210
- NSLog (@" WVJB %@ : %@ " , action, json);
211
- }
77
+ _webView.navigationDelegate = nil ;
212
78
}
213
79
214
80
215
-
216
-
217
81
/* WKWebView Specific Internals
218
82
******************************/
219
83
220
84
- (void ) _platformSpecificSetup : (WKWebView *)webView webViewDelegate : (id <WKNavigationDelegate >)webViewDelegate handler : (WVJBHandler)messageHandler resourceBundle : (NSBundle *)bundle {
221
- _messageHandler = messageHandler;
222
85
_webView = webView;
223
86
_webViewDelegate = webViewDelegate;
224
- _messageHandlers = [NSMutableDictionary dictionary ];
225
87
_webView.navigationDelegate = self;
226
- _resourceBundle = bundle;
227
- }
228
-
229
- - (void ) _platformSpecificDealloc {
230
- _webView.navigationDelegate = nil ;
88
+ _base = [[WebViewJavascriptBridgeBase alloc ] initWithWebViewType: @" WKWebView" handler: (WVJBHandler)messageHandler resourceBundle: (NSBundle *)bundle];
231
89
}
232
90
233
91
234
92
- (void )WKFlushMessageQueue {
235
- [_webView evaluateJavaScript: @" WebViewJavascriptBridge._fetchQueue(); " completionHandler: ^(NSString * result, NSError * error) {
236
- [self _flushMessageQueue: result];
93
+ [_webView evaluateJavaScript: [_base webViewJavascriptFetchQueyCommand ] completionHandler: ^(NSString * result, NSError * error) {
94
+ [_base _flushMessageQueue: result];
237
95
}];
238
96
}
239
97
240
98
- (void )webView : (WKWebView *)webView didFinishNavigation : (WKNavigation *)navigation
241
99
{
242
100
if (webView != _webView) { return ; }
101
+
102
+ _base.numRequestsLoading --;
243
103
244
- _numRequestsLoading--;
245
-
246
- if (_numRequestsLoading == 0 ) {
247
- [webView evaluateJavaScript: @" typeof WebViewJavascriptBridge == \' object\' ;" completionHandler: ^(NSString *result, NSError *error) {
248
- if (![result boolValue ]){
249
- NSBundle *bundle = _resourceBundle ? _resourceBundle : [NSBundle mainBundle ];
250
- NSString *filePath = [bundle pathForResource: @" WebViewJavascriptBridge.js" ofType: @" txt" ];
251
- NSString *js = [NSString stringWithContentsOfFile: filePath encoding: NSUTF8StringEncoding error: nil ];
252
- [webView evaluateJavaScript: js completionHandler: nil ];
253
-
254
- if (_startupMessageQueue) {
255
- for (id queuedMessage in _startupMessageQueue) {
256
- [self _dispatchMessage: queuedMessage];
257
- }
258
- _startupMessageQueue = nil ;
259
- }
260
- }
104
+ if (_base.numRequestsLoading == 0 ) {
105
+ [webView evaluateJavaScript: [_base webViewJavascriptCheckCommand ] completionHandler: ^(NSString *result, NSError *error) {
106
+ [_base injectJavascriptFile: [result boolValue ]];
261
107
}];
262
108
}
263
109
264
-
265
110
__strong typeof (_webViewDelegate) strongDelegate = _webViewDelegate;
266
111
if (strongDelegate && [strongDelegate respondsToSelector: @selector (webView:didFinishNavigation: )]) {
267
112
[strongDelegate webView: webView didFinishNavigation: navigation];
@@ -275,11 +120,12 @@ - (void)webView:(WKWebView *)webView
275
120
if (webView != _webView) { return ; }
276
121
NSURL *url = navigationAction.request .URL ;
277
122
__strong typeof (_webViewDelegate) strongDelegate = _webViewDelegate;
278
- if ([[url scheme ] isEqualToString: kCustomProtocolScheme ]) {
279
- if ([[url host ] isEqualToString: kQueueHasMessage ]) {
123
+
124
+ if ([_base correctProcotocolScheme: url]) {
125
+ if ([_base correctHost: url]) {
280
126
[self WKFlushMessageQueue ];
281
127
} else {
282
- NSLog ( @" WKWebViewJavascriptBridge: WARNING: Received unknown WKWebViewJavascriptBridge command %@ :// %@ " , kCustomProtocolScheme , [ url path ]) ;
128
+ [_base logUnkownMessage: url] ;
283
129
}
284
130
[webView stopLoading ];
285
131
}
@@ -294,7 +140,7 @@ - (void)webView:(WKWebView *)webView
294
140
- (void )webView : (WKWebView *)webView didStartProvisionalNavigation : (WKNavigation *)navigation {
295
141
if (webView != _webView) { return ; }
296
142
297
- _numRequestsLoading ++;
143
+ _base. numRequestsLoading ++;
298
144
299
145
__strong typeof (_webViewDelegate) strongDelegate = _webViewDelegate;
300
146
if (strongDelegate && [strongDelegate respondsToSelector: @selector (webView:didStartProvisionalNavigation: )]) {
@@ -306,10 +152,9 @@ - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation
306
152
- (void )webView : (WKWebView *)webView
307
153
didFailNavigation : (WKNavigation *)navigation
308
154
withError : (NSError *)error {
309
-
310
155
if (webView != _webView) { return ; }
311
156
312
- _numRequestsLoading --;
157
+ _base. numRequestsLoading --;
313
158
314
159
__strong typeof (_webViewDelegate) strongDelegate = _webViewDelegate;
315
160
if (strongDelegate && [strongDelegate respondsToSelector: @selector (webView:didFailNavigation:withError: )]) {
0 commit comments