Skip to content

Commit 6a11f45

Browse files
committed
Simplify API by focusing on explicitly named handlers instead of a default handler and plain send.
1 parent a0a2e85 commit 6a11f45

File tree

14 files changed

+71
-237
lines changed

14 files changed

+71
-237
lines changed

Changelog

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,17 @@ Release Checklist
1313
Version History
1414
---------------
1515

16-
Intended v5.0.0
16+
Next version
17+
+ Pretty-print json in log messages
18+
19+
Intended v5.0.1
1720
+ Removed `WebViewJavascriptBridge -reset`. It should never have been exposed as a public API.
1821
+ Fixed compilation in C99 mode
1922
+ Inline JS source code. WVJB no longer requires `WebViewJavascriptBridge.js.txt` to be included as a resource.
2023
+ Automated testing: see `make test`
2124
+ Added Makefile with common commands
22-
23-
Next version
24-
+ Pretty-print json in log messages
25+
+ Significantly simplified and improved wvjb load detection
26+
+ Simplify API by focusing on explicitly named handlers instead of a default handler and plain `send`.
2527

2628
v4.1.4
2729
+ Improve how WVJB handles the case when there is no ObjC handler for a message received from js.

Example Apps/ExampleApp-OSX/AppDelegate.m

Lines changed: 6 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -28,38 +28,24 @@ - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
2828

2929
- (void)_configureWebview {
3030
// Create Bridge
31-
_bridge = [WebViewJavascriptBridge bridgeForWebView:_webView handler:^(id data, WVJBResponseCallback responseCallback) {
32-
NSLog(@"ObjC received message from JS: %@", data);
33-
responseCallback(@"Response for message from ObjC");
34-
}];
31+
_bridge = [WebViewJavascriptBridge bridgeForWebView:_webView];
3532

3633
[_bridge registerHandler:@"testObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) {
3734
NSLog(@"testObjcCallback called: %@", data);
3835
responseCallback(@"Response from testObjcCallback");
3936
}];
4037

41-
[_bridge send:@"A string sent from ObjC before Webview has loaded." responseCallback:^(id responseData) {
42-
NSLog(@"objc got response! %@", responseData);
43-
}];
44-
4538
[_bridge callHandler:@"testJavascriptHandler" data:@{ @"foo":@"before ready" }];
4639

4740
// Create Buttons
48-
NSButton *messageButton = [[NSButton alloc] initWithFrame:NSMakeRect(5, 0, 120, 40)];
49-
[messageButton setTitle:@"Send message"];
50-
[messageButton setBezelStyle:NSRoundedBezelStyle];
51-
[messageButton setTarget:self];
52-
[messageButton setAction:@selector(_sendMessage)];
53-
[_webView addSubview:messageButton];
54-
55-
NSButton *callbackButton = [[NSButton alloc] initWithFrame:NSMakeRect(120, 0, 120, 40)];
41+
NSButton *callbackButton = [[NSButton alloc] initWithFrame:NSMakeRect(5, 0, 120, 40)];
5642
[callbackButton setTitle:@"Call handler"];
5743
[callbackButton setBezelStyle:NSRoundedBezelStyle];
5844
[callbackButton setTarget:self];
5945
[callbackButton setAction:@selector(_callHandler)];
6046
[_webView addSubview:callbackButton];
6147

62-
NSButton *webViewToggleButton = [[NSButton alloc] initWithFrame:NSMakeRect(235, 0, 180, 40)];
48+
NSButton *webViewToggleButton = [[NSButton alloc] initWithFrame:NSMakeRect(120, 0, 180, 40)];
6349
[webViewToggleButton setTitle:@"Switch to WKWebView"];
6450
[webViewToggleButton setBezelStyle:NSRoundedBezelStyle];
6551
[webViewToggleButton setTarget:self];
@@ -76,38 +62,24 @@ - (void)_configureWebview {
7662

7763
- (void)_configureWKWebview {
7864
// Create Bridge
79-
_WKBridge = [WKWebViewJavascriptBridge bridgeForWebView:_WKWebView handler:^(id data, WVJBResponseCallback responseCallback) {
80-
NSLog(@"ObjC received message from JS: %@", data);
81-
responseCallback(@"Response for message from ObjC");
82-
}];
65+
_WKBridge = [WKWebViewJavascriptBridge bridgeForWebView:_WKWebView];
8366

8467
[_WKBridge registerHandler:@"testObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) {
8568
NSLog(@"testObjcCallback called: %@", data);
8669
responseCallback(@"Response from testObjcCallback");
8770
}];
8871

89-
[_WKBridge send:@"A string sent from ObjC before Webview has loaded." responseCallback:^(id responseData) {
90-
NSLog(@"objc got response! %@", responseData);
91-
}];
92-
9372
[_WKBridge callHandler:@"testJavascriptHandler" data:@{ @"foo":@"before ready" }];
9473

9574
// Create Buttons
96-
NSButton *messageButton = [[NSButton alloc] initWithFrame:NSMakeRect(5, 0, 120, 40)];
97-
[messageButton setTitle:@"Send message"];
98-
[messageButton setBezelStyle:NSRoundedBezelStyle];
99-
[messageButton setTarget:self];
100-
[messageButton setAction:@selector(_WKSendMessage)];
101-
[_WKWebView addSubview:messageButton];
102-
103-
NSButton *callbackButton = [[NSButton alloc] initWithFrame:NSMakeRect(120, 0, 120, 40)];
75+
NSButton *callbackButton = [[NSButton alloc] initWithFrame:NSMakeRect(5, 0, 120, 40)];
10476
[callbackButton setTitle:@"Call handler"];
10577
[callbackButton setBezelStyle:NSRoundedBezelStyle];
10678
[callbackButton setTarget:self];
10779
[callbackButton setAction:@selector(_WKCallHandler)];
10880
[_WKWebView addSubview:callbackButton];
10981

110-
NSButton *webViewToggleButton = [[NSButton alloc] initWithFrame:NSMakeRect(235, 0, 180, 40)];
82+
NSButton *webViewToggleButton = [[NSButton alloc] initWithFrame:NSMakeRect(120, 0, 180, 40)];
11183
[webViewToggleButton setTitle:@"Switch to WebView"];
11284
[webViewToggleButton setBezelStyle:NSRoundedBezelStyle];
11385
[webViewToggleButton setTarget:self];
@@ -125,25 +97,13 @@ -(void)_toggleExample {
12597
_webView.hidden = !_webView.isHidden;
12698
}
12799

128-
- (void)_sendMessage {
129-
[_bridge send:@"A string sent from ObjC to JS" responseCallback:^(id response) {
130-
NSLog(@"sendMessage got response: %@", response);
131-
}];
132-
}
133-
134100
- (void)_callHandler {
135101
id data = @{ @"greetingFromObjC": @"Hi there, JS!" };
136102
[_bridge callHandler:@"testJavascriptHandler" data:data responseCallback:^(id response) {
137103
NSLog(@"testJavascriptHandler responded: %@", response);
138104
}];
139105
}
140106

141-
- (void)_WKSendMessage {
142-
[_WKBridge send:@"A string sent from ObjC to JS" responseCallback:^(id response) {
143-
NSLog(@"sendMessage got response: %@", response);
144-
}];
145-
}
146-
147107
- (void)_WKCallHandler {
148108
id data = @{ @"greetingFromObjC": @"Hi there, JS!" };
149109
[_WKBridge callHandler:@"testJavascriptHandler" data:data responseCallback:^(id response) {

Example Apps/ExampleApp-iOS/ExampleUIWebViewController.m

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -23,26 +23,17 @@ - (void)viewWillAppear:(BOOL)animated {
2323

2424
[WebViewJavascriptBridge enableLogging];
2525

26-
_bridge = [WebViewJavascriptBridge bridgeForWebView:webView webViewDelegate:self handler:^(id data, WVJBResponseCallback responseCallback) {
27-
NSLog(@"ObjC received message from JS: %@", data);
28-
responseCallback(@"Response for message from ObjC");
29-
}];
26+
_bridge = [WebViewJavascriptBridge bridgeForWebView:webView];
3027

3128
[_bridge registerHandler:@"testObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) {
3229
NSLog(@"testObjcCallback called: %@", data);
3330
responseCallback(@"Response from testObjcCallback");
3431
}];
3532

36-
[_bridge send:@"A string sent from ObjC before Webview has loaded." responseCallback:^(id responseData) {
37-
NSLog(@"objc got response! %@", responseData);
38-
}];
39-
4033
[_bridge callHandler:@"testJavascriptHandler" data:@{ @"foo":@"before ready" }];
4134

4235
[self renderButtons:webView];
4336
[self loadExamplePage:webView];
44-
45-
[_bridge send:@"A string sent from ObjC after Webview has loaded."];
4637
}
4738

4839
- (void)webViewDidStartLoad:(UIWebView *)webView {
@@ -56,35 +47,21 @@ - (void)webViewDidFinishLoad:(UIWebView *)webView {
5647
- (void)renderButtons:(UIWebView*)webView {
5748
UIFont* font = [UIFont fontWithName:@"HelveticaNeue" size:12.0];
5849

59-
UIButton *messageButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
60-
[messageButton setTitle:@"Send message" forState:UIControlStateNormal];
61-
[messageButton addTarget:self action:@selector(sendMessage:) forControlEvents:UIControlEventTouchUpInside];
62-
[self.view insertSubview:messageButton aboveSubview:webView];
63-
messageButton.frame = CGRectMake(10, 400, 100, 35);
64-
messageButton.titleLabel.font = font;
65-
messageButton.backgroundColor = [UIColor colorWithWhite:1 alpha:0.75];
66-
6750
UIButton *callbackButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
6851
[callbackButton setTitle:@"Call handler" forState:UIControlStateNormal];
6952
[callbackButton addTarget:self action:@selector(callHandler:) forControlEvents:UIControlEventTouchUpInside];
7053
[self.view insertSubview:callbackButton aboveSubview:webView];
71-
callbackButton.frame = CGRectMake(110, 400, 100, 35);
54+
callbackButton.frame = CGRectMake(10, 400, 100, 35);
7255
callbackButton.titleLabel.font = font;
7356

7457
UIButton* reloadButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
7558
[reloadButton setTitle:@"Reload webview" forState:UIControlStateNormal];
7659
[reloadButton addTarget:webView action:@selector(reload) forControlEvents:UIControlEventTouchUpInside];
7760
[self.view insertSubview:reloadButton aboveSubview:webView];
78-
reloadButton.frame = CGRectMake(210, 400, 100, 35);
61+
reloadButton.frame = CGRectMake(110, 400, 100, 35);
7962
reloadButton.titleLabel.font = font;
8063
}
8164

82-
- (void)sendMessage:(id)sender {
83-
[_bridge send:@"A string sent from ObjC to JS" responseCallback:^(id response) {
84-
NSLog(@"sendMessage got response: %@", response);
85-
}];
86-
}
87-
8865
- (void)callHandler:(id)sender {
8966
id data = @{ @"greetingFromObjC": @"Hi there, JS!" };
9067
[_bridge callHandler:@"testJavascriptHandler" data:data responseCallback:^(id response) {

Example Apps/ExampleApp-iOS/ExampleWKWebViewController.m

Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -24,28 +24,17 @@ - (void)viewWillAppear:(BOOL)animated {
2424
webView.navigationDelegate = self;
2525
[self.view addSubview:webView];
2626
[WKWebViewJavascriptBridge enableLogging];
27-
_bridge = [WKWebViewJavascriptBridge bridgeForWebView:webView webViewDelegate:self handler:^(id data, WVJBResponseCallback responseCallback) {
28-
NSLog(@"ObjC received message from JS: %@", data);
29-
responseCallback(@"Response for message from ObjC");
30-
}];
31-
32-
27+
_bridge = [WKWebViewJavascriptBridge bridgeForWebView:webView];
3328

3429
[_bridge registerHandler:@"testObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) {
3530
NSLog(@"testObjcCallback called: %@", data);
3631
responseCallback(@"Response from testObjcCallback");
3732
}];
3833

39-
[_bridge send:@"A string sent from ObjC before Webview has loaded." responseCallback:^(id responseData) {
40-
NSLog(@"objc got response! %@", responseData);
41-
}];
42-
4334
[_bridge callHandler:@"testJavascriptHandler" data:@{ @"foo":@"before ready" }];
4435

4536
[self renderButtons:webView];
4637
[self loadExamplePage:webView];
47-
48-
[_bridge send:@"A string sent from ObjC after Webview has loaded."];
4938
}
5039

5140
- (void)webViewDidStartLoad:(UIWebView *)webView {
@@ -59,35 +48,21 @@ - (void)webViewDidFinishLoad:(UIWebView *)webView {
5948
- (void)renderButtons:(WKWebView*)webView {
6049
UIFont* font = [UIFont fontWithName:@"HelveticaNeue" size:12.0];
6150

62-
UIButton *messageButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
63-
[messageButton setTitle:@"Send message" forState:UIControlStateNormal];
64-
[messageButton addTarget:self action:@selector(sendMessage:) forControlEvents:UIControlEventTouchUpInside];
65-
[self.view insertSubview:messageButton aboveSubview:webView];
66-
messageButton.frame = CGRectMake(10, 400, 100, 35);
67-
messageButton.titleLabel.font = font;
68-
messageButton.backgroundColor = [UIColor colorWithWhite:1 alpha:0.75];
69-
7051
UIButton *callbackButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
7152
[callbackButton setTitle:@"Call handler" forState:UIControlStateNormal];
7253
[callbackButton addTarget:self action:@selector(callHandler:) forControlEvents:UIControlEventTouchUpInside];
7354
[self.view insertSubview:callbackButton aboveSubview:webView];
74-
callbackButton.frame = CGRectMake(110, 400, 100, 35);
55+
callbackButton.frame = CGRectMake(10, 400, 100, 35);
7556
callbackButton.titleLabel.font = font;
7657

7758
UIButton* reloadButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
7859
[reloadButton setTitle:@"Reload webview" forState:UIControlStateNormal];
7960
[reloadButton addTarget:webView action:@selector(reload) forControlEvents:UIControlEventTouchUpInside];
8061
[self.view insertSubview:reloadButton aboveSubview:webView];
81-
reloadButton.frame = CGRectMake(210, 400, 100, 35);
62+
reloadButton.frame = CGRectMake(110, 400, 100, 35);
8263
reloadButton.titleLabel.font = font;
8364
}
8465

85-
- (void)sendMessage:(id)sender {
86-
[_bridge send:@"A string sent from ObjC to JS" responseCallback:^(id response) {
87-
NSLog(@"sendMessage got response: %@", response);
88-
}];
89-
}
90-
9166
- (void)callHandler:(id)sender {
9267
id data = @{ @"greetingFromObjC": @"Hi there, JS!" };
9368
[_bridge callHandler:@"testJavascriptHandler" data:data responseCallback:^(id response) {

Example Apps/ExampleApp.html

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,6 @@ <h1>WebViewJavascriptBridge Demo</h1>
3535
if (log.children.length) { log.insertBefore(el, log.children[0]) }
3636
else { log.appendChild(el) }
3737
}
38-
bridge.init(function(message, responseCallback) {
39-
log('JS got a message', message)
40-
var data = { 'Javascript Responds':'Wee!' }
41-
log('JS responding with', data)
42-
responseCallback(data)
43-
})
4438

4539
bridge.registerHandler('testJavascriptHandler', function(data, responseCallback) {
4640
log('ObjC called testJavascriptHandler with', data)
@@ -49,17 +43,6 @@ <h1>WebViewJavascriptBridge Demo</h1>
4943
responseCallback(responseData)
5044
})
5145

52-
var button = document.getElementById('buttons').appendChild(document.createElement('button'))
53-
button.innerHTML = 'Send message to ObjC'
54-
button.onclick = function(e) {
55-
e.preventDefault()
56-
var data = 'Hello from JS button'
57-
log('JS sending message', data)
58-
bridge.send(data, function(responseData) {
59-
log('JS got response', responseData)
60-
})
61-
}
62-
6346
document.body.appendChild(document.createElement('br'))
6447

6548
var callbackButton = document.getElementById('buttons').appendChild(document.createElement('button'))

Tests/WebViewJavascriptBridgeTests/BridgeTests.m

Lines changed: 22 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
#import "AppDelegate.h"
1313

1414
static NSString *const echoHandler = @"echoHandler";
15-
static const WVJBHandler nullHandler = ^(id data, WVJBResponseCallback callback) {};
1615

1716
@interface BridgeTests : XCTestCase
1817

@@ -46,46 +45,20 @@ static void loadEchoSample(UIWebView *webView)
4645
- (void)testInitialization
4746
{
4847
XCTestExpectation *startup = [self expectationWithDescription:@"Startup completed"];
49-
WebViewJavascriptBridge *bridge = [WebViewJavascriptBridge bridgeForWebView:_webView handler:^(id data, WVJBResponseCallback responseCallback) {
50-
XCTAssertEqualObjects(data, @"Hello world");
51-
[startup fulfill];
52-
}];
48+
WebViewJavascriptBridge *bridge = [WebViewJavascriptBridge bridgeForWebView:_webView];
49+
[bridge registerHandler:@"Greet" handler:^(id data, WVJBResponseCallback responseCallback) {
50+
XCTAssertEqualObjects(data, @"Hello world");
51+
[startup fulfill];
52+
}];
5353
XCTAssertNotNil(bridge);
5454

5555
loadEchoSample(_webView);
5656
[self waitForExpectationsWithTimeout:1 handler:NULL];
5757
}
5858

59-
- (void)testMessageAfterSetup {
60-
WebViewJavascriptBridge *bridge = [WebViewJavascriptBridge bridgeForWebView:_webView handler:nullHandler];
61-
loadEchoSample(_webView);
62-
XCTestExpectation *callbackInvoked = [self expectationWithDescription:@"Callback invoked"];
63-
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 150 * NSEC_PER_MSEC), dispatch_get_main_queue(), ^{
64-
[bridge send:@"testResponseHandler" responseCallback:^(id responseData) {
65-
XCTAssertEqualObjects(responseData, @"testResponseHandler");
66-
[callbackInvoked fulfill];
67-
}];
68-
});
69-
[self waitForExpectationsWithTimeout:1 handler:NULL];
70-
}
71-
72-
- (void)testResponseHandler
73-
{
74-
WebViewJavascriptBridge *bridge = [WebViewJavascriptBridge bridgeForWebView:_webView handler:nullHandler];
75-
76-
XCTestExpectation *callbackInvoked = [self expectationWithDescription:@"Callback invoked"];
77-
[bridge send:@"testResponseHandler" responseCallback:^(id responseData) {
78-
XCTAssertEqualObjects(responseData, @"testResponseHandler");
79-
[callbackInvoked fulfill];
80-
}];
81-
82-
loadEchoSample(_webView);
83-
[self waitForExpectationsWithTimeout:1 handler:NULL];
84-
}
85-
8659
- (void)testEchoHandler
8760
{
88-
WebViewJavascriptBridge *bridge = [WebViewJavascriptBridge bridgeForWebView:_webView handler:nullHandler];
61+
WebViewJavascriptBridge *bridge = [WebViewJavascriptBridge bridgeForWebView:_webView];
8962

9063
XCTestExpectation *callbackInvocked = [self expectationWithDescription:@"Callback invoked"];
9164
[bridge callHandler:echoHandler data:@"testEchoHandler" responseCallback:^(id responseData) {
@@ -97,9 +70,24 @@ - (void)testEchoHandler
9770
[self waitForExpectationsWithTimeout:1 handler:NULL];
9871
}
9972

73+
- (void)testEchoHandlerAfterSetup
74+
{
75+
WebViewJavascriptBridge *bridge = [WebViewJavascriptBridge bridgeForWebView:_webView];
76+
77+
XCTestExpectation *callbackInvocked = [self expectationWithDescription:@"Callback invoked"];
78+
loadEchoSample(_webView);
79+
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 150 * NSEC_PER_MSEC), dispatch_get_main_queue(), ^{
80+
[bridge callHandler:echoHandler data:@"testEchoHandler" responseCallback:^(id responseData) {
81+
XCTAssertEqualObjects(responseData, @"testEchoHandler");
82+
[callbackInvocked fulfill];
83+
}];
84+
});
85+
[self waitForExpectationsWithTimeout:1 handler:NULL];
86+
}
87+
10088
- (void)testObjectEncoding
10189
{
102-
WebViewJavascriptBridge *bridge = [WebViewJavascriptBridge bridgeForWebView:_webView handler:nullHandler];
90+
WebViewJavascriptBridge *bridge = [WebViewJavascriptBridge bridgeForWebView:_webView];
10391

10492
void (^echoObject)(id) = ^void(id object) {
10593
XCTestExpectation *callbackInvocked = [self expectationWithDescription:@"Callback invoked"];

Tests/WebViewJavascriptBridgeTests/echo.html

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,7 @@
1515
}
1616

1717
setupWebViewJavascriptBridge(function(bridge) {
18-
bridge.init(function(data, responseCallback) {
19-
if (responseCallback) {
20-
responseCallback(data);
21-
}
22-
});
23-
WebViewJavascriptBridge.send('Hello world')
18+
WebViewJavascriptBridge.callHandler('Greet', 'Hello world');
2419
WebViewJavascriptBridge.registerHandler('echoHandler', function(data, responseCallback) {
2520
responseCallback(data)
2621
})

0 commit comments

Comments
 (0)