diff --git a/Example Apps/ExampleApp-iOS/ExampleUIWebViewController.m b/Example Apps/ExampleApp-iOS/ExampleUIWebViewController.m index 720877d5..f988a014 100644 --- a/Example Apps/ExampleApp-iOS/ExampleUIWebViewController.m +++ b/Example Apps/ExampleApp-iOS/ExampleUIWebViewController.m @@ -46,21 +46,32 @@ - (void)webViewDidFinishLoad:(UIWebView *)webView { } - (void)renderButtons:(UIWebView*)webView { - UIFont* font = [UIFont fontWithName:@"HelveticaNeue" size:12.0]; + UIFont* font = [UIFont fontWithName:@"HelveticaNeue" size:11.0]; UIButton *callbackButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; [callbackButton setTitle:@"Call handler" forState:UIControlStateNormal]; [callbackButton addTarget:self action:@selector(callHandler:) forControlEvents:UIControlEventTouchUpInside]; [self.view insertSubview:callbackButton aboveSubview:webView]; - callbackButton.frame = CGRectMake(10, 400, 100, 35); + callbackButton.frame = CGRectMake(0, 400, 100, 35); callbackButton.titleLabel.font = font; UIButton* reloadButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; [reloadButton setTitle:@"Reload webview" forState:UIControlStateNormal]; [reloadButton addTarget:webView action:@selector(reload) forControlEvents:UIControlEventTouchUpInside]; [self.view insertSubview:reloadButton aboveSubview:webView]; - reloadButton.frame = CGRectMake(110, 400, 100, 35); + reloadButton.frame = CGRectMake(90, 400, 100, 35); reloadButton.titleLabel.font = font; + + UIButton* safetyTimeoutButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; + [safetyTimeoutButton setTitle:@"Disable safety timeout" forState:UIControlStateNormal]; + [safetyTimeoutButton addTarget:self action:@selector(disableSafetyTimeout) forControlEvents:UIControlEventTouchUpInside]; + [self.view insertSubview:safetyTimeoutButton aboveSubview:webView]; + safetyTimeoutButton.frame = CGRectMake(190, 400, 120, 35); + safetyTimeoutButton.titleLabel.font = font; +} + +- (void)disableSafetyTimeout { + [self.bridge disableJavscriptAlertBoxSafetyTimeout]; } - (void)callHandler:(id)sender { diff --git a/README.md b/README.md index d02caf97..512360f0 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ WebViewJavascriptBridge is used by a range of companies and projects. This is a - [鼎盛中华](https://itunes.apple.com/us/app/ding-sheng-zhong-hua/id537273940?mt=8) - [FRIL](https://fril.jp) - [留白·WHITE](http://liubaiapp.com) +- [BrowZine](http://thirdiron.com/browzine/) Installation (iOS & OSX) ------------------------ @@ -198,6 +199,13 @@ Example: Optionally, set a `UIWebViewDelegate` if you need to respond to the [web view's lifecycle events](http://developer.apple.com/library/ios/documentation/uikit/reference/UIWebViewDelegate_Protocol/Reference/Reference.html). +##### `[bridge disableJavscriptAlertBoxSafetyTimeout]` + +UNSAFE. Speed up bridge message passing by disabling the setTimeout safety check. It is only safe to disable this safety check if you do not call any of the javascript popup box functions (alert, confirm, and prompt). If you call any of these functions from the bridged javascript code, the app will hang. + +Example: + + [self.bridge disableJavscriptAlertBoxSafetyTimeout]; @@ -230,3 +238,14 @@ bridge.callHandler("getScreenHeight", null, function(response) { alert('Screen height:' + response) }) ``` + + +##### `bridge.disableJavscriptAlertBoxSafetyTimeout()` + +Calling `bridge.disableJavscriptAlertBoxSafetyTimeout()` has the same effect as calling `[bridge disableJavscriptAlertBoxSafetyTimeout];` in ObjC. + +Example: + +```javascript +bridge.disableJavscriptAlertBoxSafetyTimeout() +``` \ No newline at end of file diff --git a/Tests/WebViewJavascriptBridgeTests/BridgeTests.m b/Tests/WebViewJavascriptBridgeTests/BridgeTests.m index 3c59accd..1dac85aa 100644 --- a/Tests/WebViewJavascriptBridgeTests/BridgeTests.m +++ b/Tests/WebViewJavascriptBridgeTests/BridgeTests.m @@ -139,6 +139,26 @@ - (void)classSpecificTestJavascriptReceiveResponse:(Class)cls webView:(id)webVie }]; } +- (void)testJavascriptReceiveResponseWithoutSafetyTimeout { + [self classSpecificTestJavascriptReceiveResponseWithoutSafetyTimeout:[WebViewJavascriptBridge class] webView:_uiWebView]; + [self classSpecificTestJavascriptReceiveResponseWithoutSafetyTimeout:[WKWebViewJavascriptBridge class] webView:_wkWebView]; + [self waitForExpectationsWithTimeout:3 handler:NULL]; +} +- (void)classSpecificTestJavascriptReceiveResponseWithoutSafetyTimeout:(Class)cls webView:(id)webView { + WebViewJavascriptBridge *bridge = [self bridgeForCls:cls webView:webView]; + [bridge disableJavscriptAlertBoxSafetyTimeout]; + loadEchoSample(webView); + XCTestExpectation *callbackInvocked = [self expectationWithDescription:@"Callback invoked"]; + [bridge registerHandler:@"objcEchoToJs" handler:^(id data, WVJBResponseCallback responseCallback) { + responseCallback(data); + }]; + [bridge callHandler:@"jsRcvResponseTest" data:nil responseCallback:^(id responseData) { + XCTAssertEqualObjects(responseData, @"Response from JS"); + [callbackInvocked fulfill]; + }]; +} + + - (WebViewJavascriptBridge*)bridgeForCls:(Class)cls webView:(id)webView { if (cls == [WebViewJavascriptBridge class]) { return [WebViewJavascriptBridge bridgeForWebView:webView]; diff --git a/WebViewJavascriptBridge/WKWebViewJavascriptBridge.h b/WebViewJavascriptBridge/WKWebViewJavascriptBridge.h index 99859f00..5136f8d3 100644 --- a/WebViewJavascriptBridge/WKWebViewJavascriptBridge.h +++ b/WebViewJavascriptBridge/WKWebViewJavascriptBridge.h @@ -26,6 +26,7 @@ - (void)callHandler:(NSString*)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback; - (void)reset; - (void)setWebViewDelegate:(id)webViewDelegate; +- (void)disableJavscriptAlertBoxSafetyTimeout; @end diff --git a/WebViewJavascriptBridge/WKWebViewJavascriptBridge.m b/WebViewJavascriptBridge/WKWebViewJavascriptBridge.m index c91a154b..31dd8c55 100644 --- a/WebViewJavascriptBridge/WKWebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WKWebViewJavascriptBridge.m @@ -61,6 +61,10 @@ - (void)setWebViewDelegate:(id)webViewDelegate { _webViewDelegate = webViewDelegate; } +- (void)disableJavscriptAlertBoxSafetyTimeout { + [_base disableJavscriptAlertBoxSafetyTimeout]; +} + /* Internals ***********/ diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.h b/WebViewJavascriptBridge/WebViewJavascriptBridge.h index aff05531..0996944d 100755 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.h +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.h @@ -34,4 +34,6 @@ - (void)callHandler:(NSString*)handlerName data:(id)data; - (void)callHandler:(NSString*)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback; - (void)setWebViewDelegate:(WVJB_WEBVIEW_DELEGATE_TYPE*)webViewDelegate; +- (void)disableJavscriptAlertBoxSafetyTimeout; + @end diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index 20e88d4f..68a6964b 100755 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -61,6 +61,11 @@ - (void)registerHandler:(NSString *)handlerName handler:(WVJBHandler)handler { _base.messageHandlers[handlerName] = [handler copy]; } +- (void)disableJavscriptAlertBoxSafetyTimeout { + [_base disableJavscriptAlertBoxSafetyTimeout]; +} + + /* Platform agnostic internals *****************************/ diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridgeBase.h b/WebViewJavascriptBridge/WebViewJavascriptBridgeBase.h index b7df990e..3cf5a31c 100755 --- a/WebViewJavascriptBridge/WebViewJavascriptBridgeBase.h +++ b/WebViewJavascriptBridge/WebViewJavascriptBridgeBase.h @@ -40,5 +40,6 @@ typedef NSDictionary WVJBMessage; - (void)logUnkownMessage:(NSURL*)url; - (NSString *)webViewJavascriptCheckCommand; - (NSString *)webViewJavascriptFetchQueyCommand; +- (void)disableJavscriptAlertBoxSafetyTimeout; @end diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridgeBase.m b/WebViewJavascriptBridge/WebViewJavascriptBridgeBase.m index 0790c0b1..2711914e 100755 --- a/WebViewJavascriptBridge/WebViewJavascriptBridgeBase.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridgeBase.m @@ -153,6 +153,10 @@ -(NSString *)webViewJavascriptFetchQueyCommand { return @"WebViewJavascriptBridge._fetchQueue();"; } +- (void)disableJavscriptAlertBoxSafetyTimeout { + [self sendData:nil responseCallback:nil handlerName:@"_disableJavascriptAlertBoxSafetyTimeout"]; +} + // Private // ------------------------------------------- diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge_JS.m b/WebViewJavascriptBridge/WebViewJavascriptBridge_JS.m index 9df21c57..c99b7e6a 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge_JS.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge_JS.m @@ -28,6 +28,7 @@ window.WebViewJavascriptBridge = { registerHandler: registerHandler, callHandler: callHandler, + disableJavscriptAlertBoxSafetyTimeout: disableJavscriptAlertBoxSafetyTimeout, _fetchQueue: _fetchQueue, _handleMessageFromObjC: _handleMessageFromObjC }; @@ -41,6 +42,7 @@ var responseCallbacks = {}; var uniqueId = 1; + var dispatchMessagesWithTimeoutSafety = true; function registerHandler(handlerName, handler) { messageHandlers[handlerName] = handler; @@ -53,6 +55,9 @@ function callHandler(handlerName, data, responseCallback) { } _doSend({ handlerName:handlerName, data:data }, responseCallback); } + function disableJavscriptAlertBoxSafetyTimeout() { + dispatchMessagesWithTimeoutSafety = false; + } function _doSend(message, responseCallback) { if (responseCallback) { @@ -71,7 +76,13 @@ function _fetchQueue() { } function _dispatchMessageFromObjC(messageJSON) { - setTimeout(function _timeoutDispatchMessageFromObjC() { + if (dispatchMessagesWithTimeoutSafety) { + setTimeout(_doDispatchMessageFromObjC); + } else { + _doDispatchMessageFromObjC(); + } + + function _doDispatchMessageFromObjC() { var message = JSON.parse(messageJSON); var messageHandler; var responseCallback; @@ -98,7 +109,7 @@ function _dispatchMessageFromObjC(messageJSON) { handler(message.data, responseCallback); } } - }); + } } function _handleMessageFromObjC(messageJSON) { @@ -110,6 +121,8 @@ function _handleMessageFromObjC(messageJSON) { messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE; document.documentElement.appendChild(messagingIframe); + registerHandler("_disableJavascriptAlertBoxSafetyTimeout", disableJavscriptAlertBoxSafetyTimeout); + setTimeout(_callWVJBCallbacks, 0); function _callWVJBCallbacks() { var callbacks = window.WVJBCallbacks;