Skip to content

Commit bfa5076

Browse files
committed
Significantly simplify page load detection logic!
Do away with numRequestsLoading and replace it with additional logic in the "embed snippet" on the webpage side. The way things work now, the webpage includes a snippet code which: 1) checks if WVJB has already been loaded, in case we proceed immediately 2) or else stores the callback in `window.WVJBCallbacks`. 3) waits for the wvjb js code to be injected/loaded, at which point all load callbacks are called
1 parent 670fcdf commit bfa5076

9 files changed

Lines changed: 78 additions & 105 deletions

File tree

Example Apps/ExampleApp.html

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,19 @@ <h1>WebViewJavascriptBridge Demo</h1>
1313
window.onerror = function(err) {
1414
log('window.onerror: ' + err)
1515
}
16-
17-
function connectWebViewJavascriptBridge(callback) {
18-
if (window.WebViewJavascriptBridge) {
19-
callback(WebViewJavascriptBridge)
20-
} else {
21-
document.addEventListener('WebViewJavascriptBridgeReady', function() {
22-
callback(WebViewJavascriptBridge)
23-
}, false)
24-
}
25-
}
26-
27-
connectWebViewJavascriptBridge(function(bridge) {
16+
17+
function setupWebViewJavascriptBridge(callback) {
18+
if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
19+
if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
20+
window.WVJBCallbacks = [callback];
21+
var WVJBIframe = document.createElement('iframe');
22+
WVJBIframe.style.display = 'none';
23+
WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__';
24+
document.documentElement.appendChild(WVJBIframe);
25+
setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0)
26+
}
27+
28+
setupWebViewJavascriptBridge(function(bridge) {
2829
var uniqueId = 1
2930
function log(message, data) {
3031
var log = document.getElementById('log')

README.md

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -83,26 +83,27 @@ self.bridge = [WebViewJavascriptBridge bridgeForWebView:webView handler:^(id dat
8383
4) Finally, set up the javascript side:
8484

8585
```javascript
86-
function connectWebViewJavascriptBridge(callback) {
87-
if (window.WebViewJavascriptBridge) {
88-
callback(WebViewJavascriptBridge)
89-
} else {
90-
document.addEventListener('WebViewJavascriptBridgeReady', function() {
91-
callback(WebViewJavascriptBridge)
92-
}, false)
93-
}
86+
function setupWebViewJavascriptBridge(callback) {
87+
if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
88+
if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
89+
window.WVJBCallbacks = [callback];
90+
var WVJBIframe = document.createElement('iframe');
91+
WVJBIframe.style.display = 'none';
92+
WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__';
93+
document.documentElement.appendChild(WVJBIframe);
94+
setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0)
9495
}
9596

96-
connectWebViewJavascriptBridge(function(bridge) {
97-
98-
/* Init your app here */
99-
97+
setupWebViewJavascriptBridge(function(bridge) {
10098
bridge.init(function(message, responseCallback) {
10199
alert('Received message: ' + message)
102100
if (responseCallback) {
103101
responseCallback("Right back atcha")
104102
}
105103
})
104+
105+
/* Initialize your app here */
106+
106107
bridge.send('Hello from the javascript')
107108
bridge.send('Please respond to this', function responseCallback(responseData) {
108109
console.log("Javascript got its response", responseData)

Tests/WebViewJavascriptBridge.xcodeproj/project.pbxproj

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343
3D0FE47B1AE2886500BB4104 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
4444
3D99867D1AE2A3B2001DDA2C /* echo.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = echo.html; path = WebViewJavascriptBridgeTests/echo.html; sourceTree = SOURCE_ROOT; };
4545
3D9E5F2E1AE288E5009D1C36 /* BridgeTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BridgeTests.m; sourceTree = "<group>"; };
46-
3D9E5F301AE28A5E009D1C36 /* WebViewJavascriptBridge.js.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = WebViewJavascriptBridge.js.txt; path = ../WebViewJavascriptBridge/WebViewJavascriptBridge.js.txt; sourceTree = "<group>"; };
4746
3DCCF7D61AE28C2900CE7C51 /* WebViewJavascriptBridgeTestHost.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WebViewJavascriptBridgeTestHost.app; sourceTree = BUILT_PRODUCTS_DIR; };
4847
3DCCF7D91AE28C2900CE7C51 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
4948
3DCCF7DA1AE28C2900CE7C51 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
@@ -141,7 +140,6 @@
141140
3D99867D1AE2A3B2001DDA2C /* echo.html */,
142141
3DCCF7D91AE28C2900CE7C51 /* Info.plist */,
143142
3DCCF7DA1AE28C2900CE7C51 /* main.m */,
144-
3D9E5F301AE28A5E009D1C36 /* WebViewJavascriptBridge.js.txt */,
145143
);
146144
name = "Supporting Files";
147145
sourceTree = "<group>";

Tests/WebViewJavascriptBridgeTests/echo.html

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,25 @@
33
</head><body>
44
<p>WebViewJavascriptBridgeTests - echo.html</p>
55
<script>
6-
function connectWebViewJavascriptBridge(callback) {
7-
if (window.WebViewJavascriptBridge) {
8-
callback(WebViewJavascriptBridge)
9-
} else {
10-
document.addEventListener('WebViewJavascriptBridgeReady', function() {
11-
callback(WebViewJavascriptBridge)
12-
}, false)
13-
}
6+
function setupWebViewJavascriptBridge(callback) {
7+
if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
8+
if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
9+
window.WVJBCallbacks = [callback];
10+
var WVJBIframe = document.createElement('iframe');
11+
WVJBIframe.style.display = 'none';
12+
WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__';
13+
document.documentElement.appendChild(WVJBIframe);
14+
setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0)
1415
}
1516

16-
connectWebViewJavascriptBridge(function(bridge) {
17-
bridge.init(function(message, responseCallback) {
18-
if(responseCallback) {
19-
responseCallback(message);
17+
setupWebViewJavascriptBridge(function(bridge) {
18+
bridge.init(function(data, responseCallback) {
19+
if (responseCallback) {
20+
responseCallback(data);
2021
}
21-
})
22-
bridge.send('Hello world')
23-
24-
bridge.registerHandler('echoHandler', function(data, responseCallback) {
22+
});
23+
WebViewJavascriptBridge.send('Hello world')
24+
WebViewJavascriptBridge.registerHandler('echoHandler', function(data, responseCallback) {
2525
responseCallback(data)
2626
})
2727
})

WebViewJavascriptBridge/WKWebViewJavascriptBridge.m

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -97,14 +97,6 @@ - (void)WKFlushMessageQueue {
9797
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
9898
{
9999
if (webView != _webView) { return; }
100-
101-
_base.numRequestsLoading--;
102-
103-
if (_base.numRequestsLoading == 0) {
104-
[webView evaluateJavaScript:[_base webViewJavascriptCheckCommand] completionHandler:^(NSString *result, NSError *error) {
105-
[_base injectJavascriptFile:![result boolValue]];
106-
}];
107-
}
108100

109101
__strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate;
110102
if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didFinishNavigation:)]) {
@@ -121,7 +113,9 @@ - (void)webView:(WKWebView *)webView
121113
__strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate;
122114

123115
if ([_base isCorrectProcotocolScheme:url]) {
124-
if ([_base isCorrectHost:url]) {
116+
if ([_base isBridgeLoadedURL:url]) {
117+
[_base injectJavascriptFile];
118+
} else if ([_base isQueueMessageURL:url]) {
125119
[self WKFlushMessageQueue];
126120
} else {
127121
[_base logUnkownMessage:url];
@@ -139,8 +133,6 @@ - (void)webView:(WKWebView *)webView
139133
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
140134
if (webView != _webView) { return; }
141135

142-
_base.numRequestsLoading++;
143-
144136
__strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate;
145137
if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didStartProvisionalNavigation:)]) {
146138
[strongDelegate webView:webView didStartProvisionalNavigation:navigation];
@@ -153,8 +145,6 @@ - (void)webView:(WKWebView *)webView
153145
withError:(NSError *)error {
154146
if (webView != _webView) { return; }
155147

156-
_base.numRequestsLoading--;
157-
158148
__strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate;
159149
if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didFailNavigation:withError:)]) {
160150
[strongDelegate webView:webView didFailNavigation:navigation withError:error];

WebViewJavascriptBridge/WebViewJavascriptBridge.m

Lines changed: 6 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,6 @@ @implementation WebViewJavascriptBridge {
1919
WVJB_WEAK id _webViewDelegate;
2020
long _uniqueId;
2121
WebViewJavascriptBridgeBase *_base;
22-
#if defined WVJB_PLATFORM_IOS
23-
NSUInteger _numRequestsLoading;
24-
#endif
25-
2622
}
2723

2824
/* API
@@ -110,12 +106,6 @@ - (void)webView:(WebView *)webView didFinishLoadForFrame:(WebFrame *)frame
110106
{
111107
if (webView != _webView) { return; }
112108

113-
if (![[webView stringByEvaluatingJavaScriptFromString:[_base webViewJavascriptCheckCommand]] isEqualToString:@"true"]) {
114-
[_base injectJavascriptFile:YES];
115-
}
116-
117-
[_base dispatchStartUpMessageQueue];
118-
119109
if (_webViewDelegate && [_webViewDelegate respondsToSelector:@selector(webView:didFinishLoadForFrame:)]) {
120110
[_webViewDelegate webView:webView didFinishLoadForFrame:frame];
121111
}
@@ -135,7 +125,9 @@ - (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary
135125

136126
NSURL *url = [request URL];
137127
if ([_base isCorrectProcotocolScheme:url]) {
138-
if ([_base isCorrectHost:url]) {
128+
if ([_base isBridgeLoadedURL:url]) {
129+
[_base injectJavascriptFile];
130+
} else if ([_base isQueueMessageURL:url]) {
139131
NSString *messageQueueString = [self _evaluateJavascript:[_base webViewJavascriptFetchQueyCommand]];
140132
[_base flushMessageQueue:messageQueueString];
141133
} else {
@@ -188,14 +180,6 @@ - (void) _platformSpecificDealloc {
188180
- (void)webViewDidFinishLoad:(UIWebView *)webView {
189181
if (webView != _webView) { return; }
190182

191-
_numRequestsLoading--;
192-
193-
if (_numRequestsLoading == 0 && ![[webView stringByEvaluatingJavaScriptFromString:[_base webViewJavascriptCheckCommand]] isEqualToString:@"true"]) {
194-
[_base injectJavascriptFile:YES];
195-
}
196-
[_base dispatchStartUpMessageQueue];
197-
198-
199183
__strong WVJB_WEBVIEW_DELEGATE_TYPE* strongDelegate = _webViewDelegate;
200184
if (strongDelegate && [strongDelegate respondsToSelector:@selector(webViewDidFinishLoad:)]) {
201185
[strongDelegate webViewDidFinishLoad:webView];
@@ -205,8 +189,6 @@ - (void)webViewDidFinishLoad:(UIWebView *)webView {
205189
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
206190
if (webView != _webView) { return; }
207191

208-
_numRequestsLoading--;
209-
210192
__strong WVJB_WEBVIEW_DELEGATE_TYPE* strongDelegate = _webViewDelegate;
211193
if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didFailLoadWithError:)]) {
212194
[strongDelegate webView:webView didFailLoadWithError:error];
@@ -218,7 +200,9 @@ - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)
218200
NSURL *url = [request URL];
219201
__strong WVJB_WEBVIEW_DELEGATE_TYPE* strongDelegate = _webViewDelegate;
220202
if ([_base isCorrectProcotocolScheme:url]) {
221-
if ([_base isCorrectHost:url]) {
203+
if ([_base isBridgeLoadedURL:url]) {
204+
[_base injectJavascriptFile];
205+
} else if ([_base isQueueMessageURL:url]) {
222206
NSString *messageQueueString = [self _evaluateJavascript:[_base webViewJavascriptFetchQueyCommand]];
223207
[_base flushMessageQueue:messageQueueString];
224208
} else {
@@ -235,8 +219,6 @@ - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)
235219
- (void)webViewDidStartLoad:(UIWebView *)webView {
236220
if (webView != _webView) { return; }
237221

238-
_numRequestsLoading++;
239-
240222
__strong WVJB_WEBVIEW_DELEGATE_TYPE* strongDelegate = _webViewDelegate;
241223
if (strongDelegate && [strongDelegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
242224
[strongDelegate webViewDidStartLoad:webView];

WebViewJavascriptBridge/WebViewJavascriptBridgeBase.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#define kCustomProtocolScheme @"wvjbscheme"
1111
#define kQueueHasMessage @"__WVJB_QUEUE_MESSAGE__"
12+
#define kBridgeLoaded @"__BRIDGE_LOADED__"
1213

1314
typedef void (^WVJBResponseCallback)(id responseData);
1415
typedef void (^WVJBHandler)(id data, WVJBResponseCallback responseCallback);
@@ -26,19 +27,18 @@ typedef NSDictionary WVJBMessage;
2627
@property (strong, nonatomic) NSMutableDictionary* responseCallbacks;
2728
@property (strong, nonatomic) NSMutableDictionary* messageHandlers;
2829
@property (strong, nonatomic) WVJBHandler messageHandler;
29-
@property NSUInteger numRequestsLoading;
3030

3131
+ (void)enableLogging;
3232
+ (void)setLogMaxLength:(int)length;
3333
- (id)initWithHandler:(WVJBHandler)messageHandler;
3434
- (void)reset;
3535
- (void)sendData:(id)data responseCallback:(WVJBResponseCallback)responseCallback handlerName:(NSString*)handlerName;
3636
- (void)flushMessageQueue:(NSString *)messageQueueString;
37-
- (void)injectJavascriptFile:(BOOL)shouldInject;
37+
- (void)injectJavascriptFile;
3838
- (BOOL)isCorrectProcotocolScheme:(NSURL*)url;
39-
- (BOOL)isCorrectHost:(NSURL*)urll;
39+
- (BOOL)isQueueMessageURL:(NSURL*)urll;
40+
- (BOOL)isBridgeLoadedURL:(NSURL*)urll;
4041
- (void)logUnkownMessage:(NSURL*)url;
41-
- (void)dispatchStartUpMessageQueue;
4242
- (NSString *)webViewJavascriptCheckCommand;
4343
- (NSString *)webViewJavascriptFetchQueyCommand;
4444

WebViewJavascriptBridge/WebViewJavascriptBridgeBase.m

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -115,16 +115,13 @@ - (void)flushMessageQueue:(NSString *)messageQueueString{
115115
}
116116
}
117117

118-
- (void)injectJavascriptFile:(BOOL)shouldInject {
119-
if (shouldInject){
120-
NSString *js = WebViewJavascriptBridge_js();
121-
[self _evaluateJavascript:js];
122-
[self dispatchStartUpMessageQueue];
123-
}
124-
118+
- (void)injectJavascriptFile {
119+
NSString *js = WebViewJavascriptBridge_js();
120+
[self _evaluateJavascript:js];
121+
[self _dispatchStartUpMessageQueue];
125122
}
126123

127-
- (void)dispatchStartUpMessageQueue {
124+
- (void)_dispatchStartUpMessageQueue {
128125
if (self.startupMessageQueue) {
129126
for (id queuedMessage in self.startupMessageQueue) {
130127
[self _dispatchMessage:queuedMessage];
@@ -141,14 +138,18 @@ -(BOOL)isCorrectProcotocolScheme:(NSURL*)url {
141138
}
142139
}
143140

144-
-(BOOL)isCorrectHost:(NSURL*)url {
141+
-(BOOL)isQueueMessageURL:(NSURL*)url {
145142
if([[url host] isEqualToString:kQueueHasMessage]){
146143
return YES;
147144
} else {
148145
return NO;
149146
}
150147
}
151148

149+
-(BOOL)isBridgeLoadedURL:(NSURL*)url {
150+
return ([[url scheme] isEqualToString:kCustomProtocolScheme] && [[url host] isEqualToString:kBridgeLoaded]);
151+
}
152+
152153
-(void)logUnkownMessage:(NSURL*)url {
153154
NSLog(@"WebViewJavascriptBridge: WARNING: Received unknown WebViewJavascriptBridge command %@://%@", kCustomProtocolScheme, [url path]);
154155
}

WebViewJavascriptBridge/WebViewJavascriptBridge_JS.m

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,6 @@
3838

3939
var responseCallbacks = {};
4040
var uniqueId = 1;
41-
42-
function _createQueueReadyIframe(doc) {
43-
messagingIframe = doc.createElement('iframe');
44-
messagingIframe.style.display = 'none';
45-
messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE;
46-
doc.documentElement.appendChild(messagingIframe);
47-
}
4841

4942
function init(messageHandler) {
5043
if (WebViewJavascriptBridge._messageHandler) {
@@ -131,12 +124,19 @@ function _handleMessageFromObjC(messageJSON) {
131124
}
132125
}
133126

134-
var doc = document;
135-
_createQueueReadyIframe(doc);
136-
var readyEvent = doc.createEvent('Events');
137-
readyEvent.initEvent('WebViewJavascriptBridgeReady');
138-
readyEvent.bridge = WebViewJavascriptBridge;
139-
doc.dispatchEvent(readyEvent);
127+
messagingIframe = document.createElement('iframe');
128+
messagingIframe.style.display = 'none';
129+
messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE;
130+
document.documentElement.appendChild(messagingIframe);
131+
132+
setTimeout(_callWVJBCallbacks, 0);
133+
function _callWVJBCallbacks() {
134+
var callbacks = window.WVJBCallbacks;
135+
delete window.WVJBCallbacks;
136+
for (var i=0; i<callbacks.length; i++) {
137+
callbacks[i](WebViewJavascriptBridge);
138+
}
139+
}
140140
})();
141141
); // END preprocessorJSCode
142142

0 commit comments

Comments
 (0)