Permalink
Browse files

Remove the `error` parameter from all response callbacks. This change…

… breaks API backwards compatibility!

Previously, responses were sent using either `response.respondWith(data)` or `response.respondWithError(error)`. Response handlers were then required to take two parameters:

`
function responseHandler(error, responseData) {
    if (error) { /* handle error */ }
	...
}
`

However, this approach causes confusion, as seen in GH issue #18. Instead, we do away with the notion of errors in responses and simply have response callback blocks with a single data parameter:

`responseCallback(data)`

and

`function responseHandler(responseData) { ... }`

To migrate from old ObjC code, simple replace all instances of `WVJBResponse* response` with `WVJBResponseCallback responseCallback`, and replace all instances of `response.respondWith(data)` with `responseCallback(data)`.

To migrate from old Javascript code, replace all instances of `response.respondWith(data)` with `response(data)`.
  • Loading branch information...
1 parent 318e72a commit 4ab41bb4d71050c5bc05ea9da9409aa159b14839 @marcuswestin committed Dec 9, 2012
View
@@ -10,7 +10,7 @@
<h1>WebViewJavascriptBridge Demo</h1>
<script>
window.onerror = function(err) {
- alert('window.onerror: ' + err)
+ log('window.onerror: ' + err)
}
document.addEventListener('WebViewJavascriptBridgeReady', onBridgeReady, false)
function onBridgeReady(event) {
@@ -20,24 +20,33 @@
var log = document.getElementById('log')
var el = document.createElement('div')
el.className = 'logLine'
- el.innerHTML = uniqueId++ + '. ' + message + (data ? ': ' + JSON.stringify(data) : '')
+ el.innerHTML = uniqueId++ + '. ' + message + (data ? ':<br/>' + JSON.stringify(data) : '')
if (log.children.length) { log.insertBefore(el, log.children[0]) }
else { log.appendChild(el) }
}
- bridge.init(function(message) {
+ bridge.init(function(message, responseCallback) {
log('JS got a message', message)
+ var data = { 'Javascript Responds':'Wee!' }
+ log('JS responding with', data)
+ responseCallback(data)
})
- bridge.registerHandler('testJavascriptHandler', function(data, response) {
- log('JS handler testJavascriptHandler was called', data)
- response.respondWith({ 'Javascript Says':'Right back atcha!' })
+ bridge.registerHandler('testJavascriptHandler', function(data, responseCallback) {
+ log('ObjC called testJavascriptHandler with', data)
+ var responseData = { 'Javascript Says':'Right back atcha!' }
+ log('JS responding with', responseData)
+ responseCallback(responseData)
})
var button = document.getElementById('buttons').appendChild(document.createElement('button'))
button.innerHTML = 'Send message to ObjC'
button.ontouchstart = function(e) {
e.preventDefault()
- bridge.send('Hello from JS button')
+ var data = 'Hello from JS button'
+ log('JS sending message', data)
+ bridge.send(data, function(responseData) {
+ log('JS got response', responseData)
+ })
}
document.body.appendChild(document.createElement('br'))
@@ -46,9 +55,9 @@
callbackButton.innerHTML = 'Fire testObjcCallback'
callbackButton.ontouchstart = function(e) {
e.preventDefault()
- log("Calling handler testObjcCallback")
+ log('JS calling handler "testObjcCallback"')
bridge.callHandler('testObjcCallback', {'foo': 'bar'}, function(response) {
- log('Got response from testObjcCallback', response)
+ log('JS got response', response)
})
}
}
@@ -12,20 +12,18 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
[WebViewJavascriptBridge enableLogging];
- _bridge = [WebViewJavascriptBridge bridgeForWebView:webView handler:^(id data, WVJBResponse *response) {
+ _bridge = [WebViewJavascriptBridge bridgeForWebView:webView handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@"ObjC received message from JS: %@", data);
- UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"ObjC got message from Javascript:" message:data delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
- [alert show];
+ responseCallback(@"Response for message from ObjC");
}];
- [_bridge registerHandler:@"testObjcCallback" handler:^(id data, WVJBResponse *response) {
+ [_bridge registerHandler:@"testObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@"testObjcCallback called: %@", data);
- [response respondWith:@"Response from testObjcCallback"];
+ responseCallback(@"Response from testObjcCallback");
}];
- [_bridge send:@"A string sent from ObjC before Webview has loaded." responseCallback:^(id error, id responseData) {
- if (error) { return NSLog(@"Uh oh - I got an error: %@", error); }
- NSLog(@"objc got response! %@ %@", error, responseData);
+ [_bridge send:@"A string sent from ObjC before Webview has loaded." responseCallback:^(id responseData) {
+ NSLog(@"objc got response! %@", responseData);
}];
[_bridge callHandler:@"testJavascriptHandler" data:[NSDictionary dictionaryWithObject:@"before ready" forKey:@"foo"]];
@@ -54,12 +52,15 @@ - (void)renderButtons:(UIWebView*)webView {
}
- (void)sendMessage:(id)sender {
- [_bridge send:@"A string sent from ObjC to JS"];
+ [_bridge send:@"A string sent from ObjC to JS" responseCallback:^(id response) {
+ NSLog(@"sendMessage got response: %@", response);
+ }];
}
- (void)callHandler:(id)sender {
- [_bridge callHandler:@"testJavascriptHandler" data:[NSDictionary dictionaryWithObject:@"Hi there, JS!" forKey:@"greetingFromObjC"] responseCallback:^(id error, id response) {
- NSLog(@"testJavascriptHandler responded: %@ %@", error, response);
+ NSDictionary* data = [NSDictionary dictionaryWithObject:@"Hi there, JS!" forKey:@"greetingFromObjC"];
+ [_bridge callHandler:@"testJavascriptHandler" data:data responseCallback:^(id response) {
+ NSLog(@"testJavascriptHandler responded: %@", response);
}];
}
View
@@ -36,34 +36,32 @@ To use a WebViewJavascriptBridge in your own project:
3) Instantiate a UIWebView and a WebViewJavascriptBridge:
UIWebView* webView = [[UIWebView alloc] initWithFrame:self.window.bounds];
- WebViewJavascriptBridge* bridge = [WebViewJavascriptBridge bridgeForWebView:webView handler:^(id data, WVJBResponse* response) {
+ WebViewJavascriptBridge* bridge = [WebViewJavascriptBridge bridgeForWebView:webView handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@"Received message from javascript: %@", data);
- [response respondWith:@"Right back atcha"];
- // or [response respondWithError:]
+ responseCallback(@"Right back atcha");
}];
4) Go ahead and send some messages from ObjC to javascript:
[bridge send:@"Well hello there"];
[bridge send:[NSDictionary dictionaryWithObject:@"Foo" forKey:@"Bar"]];
- [bridge send:@"Give me a response, will you?" responseCallback:^(id error, id responseData) {
- NSLog(@"objc got its response! %@ %@", error, responseData);
+ [bridge send:@"Give me a response, will you?" responseCallback:^(id responseData) {
+ NSLog(@"ObjC got its response! %@ %@", responseData);
}];
4) Finally, set up the javascript side:
document.addEventListener('WebViewJavascriptBridgeReady', function onBridgeReady(event) {
var bridge = event.bridge
- bridge.init(function(message, response) {
+ bridge.init(function(message, responseCallback) {
alert('Received message: ' + message)
- if (response) {
- response.respondWith("Right back atcha")
- // or use response.respondWithError("Booh!")
+ if (responseCallback) {
+ responseCallback("Right back atcha")
}
})
bridge.send('Hello from the javascript')
- bridge.send('Please respond to this', function responseCallback(error, responseData) {
- console.log("javascript got its response", error, responseData)
+ bridge.send('Please respond to this', function responseCallback(responseData) {
+ console.log("Javascript got its response", responseData)
})
}, false)
@@ -77,20 +75,20 @@ API Reference
Create a javascript bridge for the given UIWebView.
-The `WVJBResponse` will not be `nil` if the javascript expects a response.
+The `WVJBResponseCallback` will not be `nil` if the javascript expects a response.
Optionally, pass in `webViewDelegate:(UIWebViewDelegate*)webViewDelegate` if you need to respond to the [UIWebView's lifecycle events](http://developer.apple.com/library/ios/documentation/uikit/reference/UIWebViewDelegate_Protocol/Reference/Reference.html).
Example:
- [WebViewJavascriptBridge bridgeForWebView:webView handler:^(id data, WVJBResponse response) {
+ [WebViewJavascriptBridge bridgeForWebView:webView handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@"Received message from javascript: %@", data);
- if (response) {
- [response respondWith:@"Right back atcha"];
+ if (responseCallback) {
+ responseCallback(@"Right back atcha");
}
}]
- [WebViewJavascriptBridge bridgeForWebView:webView webViewDelegate:self handler:^(id data, WVJBResponse response) { /* ... */ }];
+ [WebViewJavascriptBridge bridgeForWebView:webView webViewDelegate:self handler:^(id data, WVJBResponseCallback responseCallback) { /* ... */ }];
##### `[bridge send:(id)data]`
##### `[bridge send:(id)data responseCallback:(WVJBResponseCallback)responseCallback]`
@@ -101,8 +99,7 @@ Example:
[bridge send:@"Hi"];
[bridge send:[NSDictionary dictionaryWithObject:@"Foo" forKey:@"Bar"]];
- [bridge send:@"I expect a response!" responseCallback:^(id error, id responseData) {
- if (error) { return NSLog(@"Uh oh, I got an error: %@", error); }
+ [bridge send:@"I expect a response!" responseCallback:^(id responseData) {
NSLog(@"Got response! %@", responseData);
}];
@@ -112,8 +109,8 @@ Register a handler called `handlerName`. The javascript can then call this handl
Example:
- [bridge registerHandler:@"getScreenHeight" handler:^(id data, WVJBResponse response) {
- [response respondWith:[NSNumber numberWithInt:[UIScreen mainScreen].bounds.size.height]];
+ [bridge registerHandler:@"getScreenHeight" handler:^(id data, WVJBResponseCallback responseCallback) {
+ responseCallback([NSNumber numberWithInt:[UIScreen mainScreen].bounds.size.height]);
}];
##### `[bridge callHandler:(NSString*)handlerName data:(id)data]`
@@ -124,8 +121,7 @@ Call the javascript handler called `handlerName`. Optionally expect a response b
Example:
[bridge callHandler:@"showAlert" data:@"Hi from ObjC to JS!"];
- [bridge callHandler:@"getCurrentPageUrl" data:nil responseCallback:^(id error, id responseData) {
- if (error) { return NSLog(@"Huston, we got a problem: %@", error); }
+ [bridge callHandler:@"getCurrentPageUrl" data:nil responseCallback:^(id responseData) {
NSLog(@"Current UIWebView page URL is: %@", responseData);
}];
@@ -153,37 +149,35 @@ The `response` object will be defined if if ObjC sent the message with a `WVJBRe
Example:
- bridge.init(function(data, response) {
+ bridge.init(function(data, responseCallback) {
alert("Got data " + JSON.stringify(data))
- if (response) {
- response.respondWith("Right back atcha!")
- // or, response.respondWithError("It went wrong!")
+ if (responseCallback) {
+ responseCallback("Right back atcha!")
}
})
##### `bridge.send("Hi there!")`
##### `bridge.send({ Foo:"Bar" })`
-##### `bridge.send(data, function responseCallback(error, responseData) { ... })`
+##### `bridge.send(data, function responseCallback(responseData) { ... })`
Send a message to ObjC. Optionally expect a response by giving a `responseCallback` function.
Example:
bridge.send("Hi there!")
- bridge.send("Hi there!", function(error, responseData) {
- if (error) { return alert("Uh oh, we got an error: "+error) }
- alert("I got a response! "+JSON.stringify(data))
+ bridge.send("Hi there!", function(responseData) {
+ alert("I got a response! "+JSON.stringify(responseData))
})
-##### `bridge.registerHandler("handlerName", function(error, responseData) { ... })`
+##### `bridge.registerHandler("handlerName", function(responseData) { ... })`
-Register a handler called `handlerName`. The ObjC can then call this handler with `[bridge callHandler:"handlerName" data:@"Foo"]` and `[bridge callHandler:"handlerName" data:@"Foo" responseCallback:^(id error, id responseData) { ... }]`
+Register a handler called `handlerName`. The ObjC can then call this handler with `[bridge callHandler:"handlerName" data:@"Foo"]` and `[bridge callHandler:"handlerName" data:@"Foo" responseCallback:^(id responseData) { ... }]`
Example:
bridge.registerHandler("showAlert", function(data) { alert(data) })
- bridge.registerHandler("getCurrentPageUrl", function(data, response) {
- response.respondWith(document.location.toString())
+ bridge.registerHandler("getCurrentPageUrl", function(data, responseCallback) {
+ responseCallback(document.location.toString())
})
@@ -1,8 +1,7 @@
#import <UIKit/UIKit.h>
-@class WVJBResponse;
-typedef void (^WVJBResponseCallback)(id error, id responseData);
-typedef void (^WVJBHandler)(id data, WVJBResponse* response);
+typedef void (^WVJBResponseCallback)(id responseData);
+typedef void (^WVJBHandler)(id data, WVJBResponseCallback responseCallback);
@interface WebViewJavascriptBridge : NSObject <UIWebViewDelegate>
+ (id)bridgeForWebView:(UIWebView*)webView handler:(WVJBHandler)handler;
@@ -16,9 +15,3 @@ typedef void (^WVJBHandler)(id data, WVJBResponse* response);
- (void)callHandler:(NSString*)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback;
- (void)reset;
@end
-
-@interface WVJBResponse : NSObject
-- (WVJBResponse*) initWithCallbackId:(NSString*)callbackId bridge:(WebViewJavascriptBridge*)bridge;
-- (void) respondWith:(id)responseData;
-- (void) respondWithError:(id)error;
-@end
@@ -63,19 +63,14 @@
if (message.responseId) {
var responseCallback = responseCallbacks[message.responseId]
- responseCallback(message.error, message.responseData)
+ responseCallback(message.responseData)
delete responseCallbacks[message.responseId]
} else {
- var response
+ var responseCallback
if (message.callbackId) {
var callbackResponseId = message.callbackId
- response = {
- respondWith: function(responseData) {
- _doSend({ responseId:callbackResponseId, responseData:responseData })
- },
- respondWithError: function(error) {
- _doSend({ responseId:callbackResponseId, error:error })
- }
+ responseCallback = function(responseData) {
+ _doSend({ responseId:callbackResponseId, responseData:responseData })
}
}
@@ -85,9 +80,11 @@
}
try {
- handler(message.data, response)
+ handler(message.data, responseCallback)
} catch(exception) {
- console.log("WebViewJavascriptBridge: WARNING: javascript handler threw.", message, exception)
+ if (typeof console != 'undefined') {
+ console.log("WebViewJavascriptBridge: WARNING: javascript handler threw.", message, exception)
+ }
}
}
})
Oops, something went wrong.

0 comments on commit 4ab41bb

Please sign in to comment.