From 3ba0b84cce4d9c910f3c3c75c32ff6b3c0c28fe1 Mon Sep 17 00:00:00 2001 From: jacob berkman Date: Mon, 29 Jul 2013 21:47:10 -0700 Subject: [PATCH 001/239] use [NSNull null] instead of nil when using shorthand -callHandler: Fixes NSInvalidArgumentException: "attempt to insert nil object from objects[0]" --- WebViewJavascriptBridge/WebViewJavascriptBridge.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index 58ef2e70..8f2c4ab0 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -56,7 +56,7 @@ - (void)send:(NSDictionary *)data responseCallback:(WVJBResponseCallback)respons } - (void)callHandler:(NSString *)handlerName { - [self callHandler:handlerName data:nil responseCallback:nil]; + [self callHandler:handlerName data:[NSNull null] responseCallback:nil]; } - (void)callHandler:(NSString *)handlerName data:(id)data { From 9297f5c3db30945c31e1f38adea6dad4446666bd Mon Sep 17 00:00:00 2001 From: jacob berkman Date: Tue, 30 Jul 2013 09:59:23 -0700 Subject: [PATCH 002/239] encode message queue as JSON If JS included the separator as part of its data, the Obj-C side would interpret it incorrectly: WebViewJavascriptBridge.send('Including __WVJB_MESSAGE_SEPERATOR__ in my message is broken.'); Before: WVJB receivd: {"data":"Including WVJB receivd: in my message is broken."} After: WVJB receivd: {"data":"Including __WVJB_MESSAGE_SEPERATOR__ in my message is broken."} --- .../WebViewJavascriptBridge.h | 1 - .../WebViewJavascriptBridge.js.txt | 5 ++-- .../WebViewJavascriptBridge.m | 27 ++++++++++++------- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.h b/WebViewJavascriptBridge/WebViewJavascriptBridge.h index 836d0c52..d2d0544b 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.h +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.h @@ -8,7 +8,6 @@ #import -#define kMessageSeparator @"__WVJB_MESSAGE_SEPERATOR__" #define kCustomProtocolScheme @"wvjbscheme" #define kQueueHasMessage @"__WVJB_QUEUE_MESSAGE__" diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.js.txt b/WebViewJavascriptBridge/WebViewJavascriptBridge.js.txt index 7936c0e8..86303713 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.js.txt +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.js.txt @@ -5,7 +5,6 @@ var receiveMessageQueue = [] var messageHandlers = {} - var MESSAGE_SEPARATOR = '__WVJB_MESSAGE_SEPERATOR__' var CUSTOM_PROTOCOL_SCHEME = 'wvjbscheme' var QUEUE_HAS_MESSAGE = '__WVJB_QUEUE_MESSAGE__' @@ -46,12 +45,12 @@ responseCallbacks[callbackId] = responseCallback message['callbackId'] = callbackId } - sendMessageQueue.push(JSON.stringify(message)) + sendMessageQueue.push(message) messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE } function _fetchQueue() { - var messageQueueString = sendMessageQueue.join(MESSAGE_SEPARATOR) + var messageQueueString = JSON.stringify(sendMessageQueue) sendMessageQueue = [] return messageQueueString } diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index 8f2c4ab0..1e4920a5 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -138,12 +138,18 @@ - (void)_dispatchMessage:(NSDictionary *)message { - (void)_flushMessageQueue { NSString *messageQueueString = [_webView stringByEvaluatingJavaScriptFromString:@"WebViewJavascriptBridge._fetchQueue();"]; - NSArray* messages = [messageQueueString componentsSeparatedByString:kMessageSeparator]; - for (NSString *messageJSON in messages) { - [self _log:@"receivd" json:messageJSON]; - - NSDictionary* message = [self _deserializeMessageJSON:messageJSON]; - + id messages = [self _deserializeMessageJSON:messageQueueString]; + if (![messages isKindOfClass:[NSArray class]]) { + NSLog(@"WebViewJavascriptBridge: WARNING: Invalid %@ received: %@", [messages class], messages); + return; + } + for (NSDictionary *message in messages) { + if (![message isKindOfClass:[NSDictionary class]]) { + NSLog(@"WebViewJavascriptBridge: WARNING: Invalid %@ received: %@", [message class], message); + continue; + } + [self _log:@"receivd" json:message]; + NSString* responseId = message[@"responseId"]; if (responseId) { WVJBResponseCallback responseCallback = _responseCallbacks[responseId]; @@ -202,10 +208,13 @@ - (NSDictionary *)_deserializeMessageJSON:(NSString *)messageJSON { #endif } -- (void)_log:(NSString *)action json:(NSString *)json { +- (void)_log:(NSString *)action json:(id)json { if (!logging) { return; } - if (json.length > 500) { - NSLog(@"WVJB %@: %@", action, [[json substringToIndex:500] stringByAppendingString:@" [...]"]); + if (![json isKindOfClass:[NSString class]]) { + json = [self _serializeMessage:json]; + } + if ([json length] > 500) { + NSLog(@"WVJB %@: %@ [...]", action, [json substringToIndex:500]); } else { NSLog(@"WVJB %@: %@", action, json); } From 4859217465ebea744698eeaf1eb97a148f4121ea Mon Sep 17 00:00:00 2001 From: Miles Matthias Date: Fri, 13 Sep 2013 21:29:17 -0600 Subject: [PATCH 003/239] Fixed a typo in bridge logging statement. --- WebViewJavascriptBridge/WebViewJavascriptBridge.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index 58ef2e70..28865695 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -140,7 +140,7 @@ - (void)_flushMessageQueue { NSArray* messages = [messageQueueString componentsSeparatedByString:kMessageSeparator]; for (NSString *messageJSON in messages) { - [self _log:@"receivd" json:messageJSON]; + [self _log:@"received" json:messageJSON]; NSDictionary* message = [self _deserializeMessageJSON:messageJSON]; From 2f129dac1a842c80afaf6eecb6923985180d3fd9 Mon Sep 17 00:00:00 2001 From: jacob berkman Date: Fri, 27 Sep 2013 13:41:53 -0700 Subject: [PATCH 004/239] handle nil data in _sendData rather than each callHandler --- WebViewJavascriptBridge/WebViewJavascriptBridge.m | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index 1e4920a5..a540b0ec 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -56,7 +56,7 @@ - (void)send:(NSDictionary *)data responseCallback:(WVJBResponseCallback)respons } - (void)callHandler:(NSString *)handlerName { - [self callHandler:handlerName data:[NSNull null] responseCallback:nil]; + [self callHandler:handlerName data:nil responseCallback:nil]; } - (void)callHandler:(NSString *)handlerName data:(id)data { @@ -92,6 +92,9 @@ - (void)dealloc { } - (void)_sendData:(NSDictionary *)data responseCallback:(WVJBResponseCallback)responseCallback handlerName:(NSString*)handlerName { + if (!data) { + data = (NSDictionary *)[NSNull null]; + } NSMutableDictionary* message = [NSMutableDictionary dictionaryWithObject:data forKey:@"data"]; if (responseCallback) { From e75690e7fbca2439fc2f7a0357cb816e6a6137f5 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Fri, 27 Sep 2013 14:46:09 -0700 Subject: [PATCH 005/239] Clean up contributors list by using the github generated lists --- README.md | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 6edd5797..a309e453 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,12 @@ To use a WebViewJavascriptBridge in your own project: }) }, false) +Contributors & Forks +-------------------- +Contributors: https://github.com/marcuswestin/WebViewJavascriptBridge/graphs/contributors + +Forks: https://github.com/marcuswestin/WebViewJavascriptBridge/network/members + API Reference ------------- @@ -185,18 +191,3 @@ iOS4 support (with JSONKit) *Note*: iOS4 support has not yet been tested in v2+. WebViewJavascriptBridge uses `NSJSONSerialization` by default. If you need iOS 4 support then you can use [JSONKit](https://github.com/johnezang/JSONKit/), and add `USE_JSONKIT` to the preprocessor macros for your project. - -Contributors ------------- -- [@marcuswestin](https://github.com/marcuswestin) Marcus Westin (Author) -- [@oakho](https://github.com/oakho) Antoine Lagadec (OS X version) -- [@psineur](https://github.com/psineur) Stepan Generalov -- [@sergiocampama](https://github.com/sergiocampama) Sergio Campamá -- [@stringbean](https://github.com/stringbean) Michael Stringer -- [@tanis2000](https://github.com/tanis2000) Valerio Santinelli -- [@drewburch](https://github.com/drewburch) Andrew Burch -- [@pj4533](https://github.com/pj4533) PJ Gray -- [@xzeror](https://github.com/xzeror) -- [@kelp404](https://github.com/kelp404) -- [@peyton](https://github.com/peyton) Peyton Randolph -- [@wangjinhua](https://github.com/wangjinhua) From 54300126b98bd604015e79ef1db4258cd6b67cf2 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Fri, 27 Sep 2013 14:46:15 -0700 Subject: [PATCH 006/239] v4.0.2 --- Changelog | 4 ++++ WebViewJavascriptBridge.podspec | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Changelog b/Changelog index 632f803f..656786a5 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,7 @@ +v4.0.2 ++ Fix NSInvalidArgumentException: "attempt to insert nil object" when using shorthand -callHandler: ++ Fix sending messages including __WVJB_MESSAGE_SEPERATOR__ string + v4.0.1 + Fix detection of arc_weak support diff --git a/WebViewJavascriptBridge.podspec b/WebViewJavascriptBridge.podspec index ff4ac0bd..0f931ba0 100644 --- a/WebViewJavascriptBridge.podspec +++ b/WebViewJavascriptBridge.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'WebViewJavascriptBridge' - s.version = '4.0.1' + s.version = '4.0.2' s.summary = 'An iOS/OSX bridge for sending messages between Obj-C and JavaScript in UIWebViews/WebViews.' s.homepage = 'http://github.com/marcuswestin/WebViewJavascriptBridge' s.license = { :type => 'MIT', :file => 'LICENSE' } From 92f90ab7fedda84621891d2abd777581b16c58d3 Mon Sep 17 00:00:00 2001 From: Miles Matthias Date: Thu, 24 Oct 2013 09:55:37 -0600 Subject: [PATCH 007/239] Added our Imbed repo to list of uses in the wild. See http://dojo4.com/blog/announcing-imbed-the-best-way-to-use-web-content-in-an-i-os-app --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a309e453..3a3bfdc6 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ WebViewJavascriptBridge is used by a range of companies and projects. This list - [Sush.io](http://www.sush.io) - Flutterby Labs - JD Media's [鼎盛中华](https://itunes.apple.com/us/app/ding-sheng-zhong-hua/id537273940?mt=8) +- Dojo4's [Imbed](https://github.com/dojo4/imbed) Setup & Examples (iOS & OSX) ---------------------------- From d66f93e9f4a1d87d44dd949bdf99c68f30cb45a9 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Thu, 24 Oct 2013 15:35:31 -0700 Subject: [PATCH 008/239] Make log prefix capital SEND/RCVD --- WebViewJavascriptBridge/WebViewJavascriptBridge.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index a540b0ec..e673d73a 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -119,7 +119,7 @@ - (void)_queueMessage:(NSDictionary *)message { - (void)_dispatchMessage:(NSDictionary *)message { NSString *messageJSON = [self _serializeMessage:message]; - [self _log:@"sending" json:messageJSON]; + [self _log:@"SEND" json:messageJSON]; messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"]; messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""]; messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\'" withString:@"\\\'"]; @@ -151,7 +151,7 @@ - (void)_flushMessageQueue { NSLog(@"WebViewJavascriptBridge: WARNING: Invalid %@ received: %@", [message class], message); continue; } - [self _log:@"receivd" json:message]; + [self _log:@"RCVD" json:message]; NSString* responseId = message[@"responseId"]; if (responseId) { From a91f2906950aa2612178c0b9a6730839da099eaf Mon Sep 17 00:00:00 2001 From: Bastian Bense Date: Fri, 25 Oct 2013 16:06:10 +0200 Subject: [PATCH 009/239] Fix exception if _sendData is called with data == nil --- WebViewJavascriptBridge/WebViewJavascriptBridge.m | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index e673d73a..6935e389 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -95,7 +95,11 @@ - (void)_sendData:(NSDictionary *)data responseCallback:(WVJBResponseCallback)re if (!data) { data = (NSDictionary *)[NSNull null]; } - NSMutableDictionary* message = [NSMutableDictionary dictionaryWithObject:data forKey:@"data"]; + NSMutableDictionary* message = [NSMutableDictionary dictionary]; + + if (data) { + message[@"data"] = data; + } if (responseCallback) { NSString* callbackId = [NSString stringWithFormat:@"objc_cb_%ld", ++_uniqueId]; From dc584db1e5c7958100c324881d96a57178945532 Mon Sep 17 00:00:00 2001 From: Miles Matthias Date: Fri, 25 Oct 2013 14:58:00 -0600 Subject: [PATCH 010/239] Replaced source code link to fancy project page for Imbed. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3a3bfdc6..f28c52b3 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ WebViewJavascriptBridge is used by a range of companies and projects. This list - [Sush.io](http://www.sush.io) - Flutterby Labs - JD Media's [鼎盛中华](https://itunes.apple.com/us/app/ding-sheng-zhong-hua/id537273940?mt=8) -- Dojo4's [Imbed](https://github.com/dojo4/imbed) +- Dojo4's [Imbed](http://dojo4.github.io/imbed/) Setup & Examples (iOS & OSX) ---------------------------- From c4cb6ab13c18a96db90906b7ea69b48eaa2ed5d0 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Fri, 25 Oct 2013 16:56:32 -0700 Subject: [PATCH 011/239] The declared interface for WVJB expected data to be an `id`. However, the implementation assumed `NSDictionary` in a bunch of places. Furthermore, messages received from JS by ObjC were previously always forced into an `NSDictionary` but javascript did not replace null data packets with `{}`. This patch introduces consistency in all of these cases, assuming data to be `id` everywhere, and never changing the value of data. Drop JSONKit. It's 2013! --- Changelog | 4 ++++ .../WebViewJavascriptBridge.m | 24 +++++-------------- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/Changelog b/Changelog index 656786a5..101de003 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,7 @@ +v4.1.0 ++ Allow for sending null/nil data packets ++ Drop support for JSONKit + v4.0.2 + Fix NSInvalidArgumentException: "attempt to insert nil object" when using shorthand -callHandler: + Fix sending messages including __WVJB_MESSAGE_SEPERATOR__ string diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index 6935e389..fcce490f 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -47,11 +47,11 @@ + (instancetype)bridgeForWebView:(WVJB_WEBVIEW_TYPE*)webView webViewDelegate:(WV return bridge; } -- (void)send:(NSDictionary *)data { +- (void)send:(id)data { [self send:data responseCallback:nil]; } -- (void)send:(NSDictionary *)data responseCallback:(WVJBResponseCallback)responseCallback { +- (void)send:(id)data responseCallback:(WVJBResponseCallback)responseCallback { [self _sendData:data responseCallback:responseCallback handlerName:nil]; } @@ -91,10 +91,7 @@ - (void)dealloc { _messageHandler = nil; } -- (void)_sendData:(NSDictionary *)data responseCallback:(WVJBResponseCallback)responseCallback handlerName:(NSString*)handlerName { - if (!data) { - data = (NSDictionary *)[NSNull null]; - } +- (void)_sendData:(id)data responseCallback:(WVJBResponseCallback)responseCallback handlerName:(NSString*)handlerName { NSMutableDictionary* message = [NSMutableDictionary dictionary]; if (data) { @@ -188,8 +185,7 @@ - (void)_flushMessageQueue { } @try { - NSDictionary* data = message[@"data"]; - if (!data || ((id)data) == [NSNull null]) { data = [NSDictionary dictionary]; } + id data = message[@"data"]; handler(data, responseCallback); } @catch (NSException *exception) { @@ -199,20 +195,12 @@ - (void)_flushMessageQueue { } } -- (NSString *)_serializeMessage:(NSDictionary *)message { -#if defined _JSONKIT_H_ - return [message JSONString]; -#else +- (NSString *)_serializeMessage:(id)message { return [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:message options:0 error:nil] encoding:NSUTF8StringEncoding]; -#endif } - (NSDictionary *)_deserializeMessageJSON:(NSString *)messageJSON { -#if defined _JSONKIT_H_ - return [messageJSON objectFromJSONString]; -#else - return [NSJSONSerialization JSONObjectWithData:[messageJSON dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil]; -#endif + return [NSJSONSerialization JSONObjectWithData:[messageJSON dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:nil]; } - (void)_log:(NSString *)action json:(id)json { From b68bc2680b00e7d10ef282275e2b2bf1e51b8bed Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Fri, 25 Oct 2013 17:05:25 -0700 Subject: [PATCH 012/239] Use dictionary literals in example app --- Example Apps/ExampleApp-OSX/AppDelegate.m | 4 ++-- Example Apps/ExampleApp-iOS/ExampleAppDelegate.m | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Example Apps/ExampleApp-OSX/AppDelegate.m b/Example Apps/ExampleApp-OSX/AppDelegate.m index d4b230c6..990f9779 100644 --- a/Example Apps/ExampleApp-OSX/AppDelegate.m +++ b/Example Apps/ExampleApp-OSX/AppDelegate.m @@ -38,7 +38,7 @@ - (void)_createBridge { NSLog(@"objc got response! %@", responseData); }]; - [_bridge callHandler:@"testJavascriptHandler" data:[NSDictionary dictionaryWithObject:@"before ready" forKey:@"foo"]]; + [_bridge callHandler:@"testJavascriptHandler" data:@{ @"foo":@"before ready" }]; } - (void)_createObjcButtons { @@ -64,7 +64,7 @@ - (void)_sendMessage { } - (void)_callHandler { - NSDictionary* data = [NSDictionary dictionaryWithObject:@"Hi there, JS!" forKey:@"greetingFromObjC"]; + is data = @{ @"greetingFromObjC": @"Hi there, JS!" }; [_bridge callHandler:@"testJavascriptHandler" data:data responseCallback:^(id response) { NSLog(@"testJavascriptHandler responded: %@", response); }]; diff --git a/Example Apps/ExampleApp-iOS/ExampleAppDelegate.m b/Example Apps/ExampleApp-iOS/ExampleAppDelegate.m index 11c6d310..944e4312 100644 --- a/Example Apps/ExampleApp-iOS/ExampleAppDelegate.m +++ b/Example Apps/ExampleApp-iOS/ExampleAppDelegate.m @@ -26,7 +26,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( NSLog(@"objc got response! %@", responseData); }]; - [_bridge callHandler:@"testJavascriptHandler" data:[NSDictionary dictionaryWithObject:@"before ready" forKey:@"foo"]]; + [_bridge callHandler:@"testJavascriptHandler" data:@{ @"foo":@"before ready" }]; [self renderButtons:webView]; [self loadExamplePage:webView]; @@ -58,7 +58,7 @@ - (void)sendMessage:(id)sender { } - (void)callHandler:(id)sender { - NSDictionary* data = [NSDictionary dictionaryWithObject:@"Hi there, JS!" forKey:@"greetingFromObjC"]; + id data = @{ @"greetingFromObjC": @"Hi there, JS!" }; [_bridge callHandler:@"testJavascriptHandler" data:data responseCallback:^(id response) { NSLog(@"testJavascriptHandler responded: %@", response); }]; From 5069f0849648f848648dfc2ec79b20a653943e54 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Fri, 25 Oct 2013 17:07:22 -0700 Subject: [PATCH 013/239] Clean up internal representation of messages with a WVJBMessage typedef --- Changelog | 1 + WebViewJavascriptBridge/WebViewJavascriptBridge.m | 13 +++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Changelog b/Changelog index 101de003..11ac8e4d 100644 --- a/Changelog +++ b/Changelog @@ -1,6 +1,7 @@ v4.1.0 + Allow for sending null/nil data packets + Drop support for JSONKit ++ Clean up internal represenation of messages v4.0.2 + Fix NSInvalidArgumentException: "attempt to insert nil object" when using shorthand -callHandler: diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index fcce490f..8ee60d17 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -14,6 +14,7 @@ #define WVJB_WEAK __unsafe_unretained #endif +typedef NSDictionary WVJBMessage; @implementation WebViewJavascriptBridge { WVJB_WEAK WVJB_WEBVIEW_TYPE* _webView; @@ -110,7 +111,7 @@ - (void)_sendData:(id)data responseCallback:(WVJBResponseCallback)responseCallba [self _queueMessage:message]; } -- (void)_queueMessage:(NSDictionary *)message { +- (void)_queueMessage:(WVJBMessage*)message { if (_startupMessageQueue) { [_startupMessageQueue addObject:message]; } else { @@ -118,7 +119,7 @@ - (void)_queueMessage:(NSDictionary *)message { } } -- (void)_dispatchMessage:(NSDictionary *)message { +- (void)_dispatchMessage:(WVJBMessage*)message { NSString *messageJSON = [self _serializeMessage:message]; [self _log:@"SEND" json:messageJSON]; messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"]; @@ -147,8 +148,8 @@ - (void)_flushMessageQueue { NSLog(@"WebViewJavascriptBridge: WARNING: Invalid %@ received: %@", [messages class], messages); return; } - for (NSDictionary *message in messages) { - if (![message isKindOfClass:[NSDictionary class]]) { + for (WVJBMessage* message in messages) { + if (![message isKindOfClass:[WVJBMessage class]]) { NSLog(@"WebViewJavascriptBridge: WARNING: Invalid %@ received: %@", [message class], message); continue; } @@ -164,7 +165,7 @@ - (void)_flushMessageQueue { NSString* callbackId = message[@"callbackId"]; if (callbackId) { responseCallback = ^(id responseData) { - NSDictionary* msg = @{ @"responseId":callbackId, @"responseData":responseData }; + WVJBMessage* msg = @{ @"responseId":callbackId, @"responseData":responseData }; [self _queueMessage:msg]; }; } else { @@ -199,7 +200,7 @@ - (NSString *)_serializeMessage:(id)message { return [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:message options:0 error:nil] encoding:NSUTF8StringEncoding]; } -- (NSDictionary *)_deserializeMessageJSON:(NSString *)messageJSON { +- (NSArray*)_deserializeMessageJSON:(NSString *)messageJSON { return [NSJSONSerialization JSONObjectWithData:[messageJSON dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:nil]; } From fb46cc066a35ce861f40a530309fa2a3d3bddbe0 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Fri, 25 Oct 2013 17:08:01 -0700 Subject: [PATCH 014/239] v4.1.0 --- WebViewJavascriptBridge.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WebViewJavascriptBridge.podspec b/WebViewJavascriptBridge.podspec index 0f931ba0..227d89be 100644 --- a/WebViewJavascriptBridge.podspec +++ b/WebViewJavascriptBridge.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'WebViewJavascriptBridge' - s.version = '4.0.2' + s.version = '4.1.0' s.summary = 'An iOS/OSX bridge for sending messages between Obj-C and JavaScript in UIWebViews/WebViews.' s.homepage = 'http://github.com/marcuswestin/WebViewJavascriptBridge' s.license = { :type => 'MIT', :file => 'LICENSE' } From 4d4fc9754a219358e894781a4ef243afe2c72146 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Fri, 25 Oct 2013 17:26:18 -0700 Subject: [PATCH 015/239] Update JS initialization snippet. Fix #56 (Thanks @refractalize!). Possibly fixes #52. --- Example Apps/ExampleApp-OSX/AppDelegate.m | 2 +- Example Apps/ExampleApp.html | 17 +++++++++++++---- README.md | 18 +++++++++++++++--- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/Example Apps/ExampleApp-OSX/AppDelegate.m b/Example Apps/ExampleApp-OSX/AppDelegate.m index 990f9779..4e77da67 100644 --- a/Example Apps/ExampleApp-OSX/AppDelegate.m +++ b/Example Apps/ExampleApp-OSX/AppDelegate.m @@ -64,7 +64,7 @@ - (void)_sendMessage { } - (void)_callHandler { - is data = @{ @"greetingFromObjC": @"Hi there, JS!" }; + id data = @{ @"greetingFromObjC": @"Hi there, JS!" }; [_bridge callHandler:@"testJavascriptHandler" data:data responseCallback:^(id response) { NSLog(@"testJavascriptHandler responded: %@", response); }]; diff --git a/Example Apps/ExampleApp.html b/Example Apps/ExampleApp.html index 30efb6c8..bf5b7bc7 100644 --- a/Example Apps/ExampleApp.html +++ b/Example Apps/ExampleApp.html @@ -12,9 +12,18 @@

WebViewJavascriptBridge Demo

window.onerror = function(err) { log('window.onerror: ' + err) } - document.addEventListener('WebViewJavascriptBridgeReady', onBridgeReady, false) - function onBridgeReady(event) { - var bridge = event.bridge + + function connectWebViewJavascriptBridge(callback) { + if (window.WebViewJavascriptBridge) { + callback(WebViewJavascriptBridge) + } else { + document.addEventListener('WebViewJavascriptBridgeReady', function() { + callback(WebViewJavascriptBridge) + }, false) + } + } + + connectWebViewJavascriptBridge(function(bridge) { var uniqueId = 1 function log(message, data) { var log = document.getElementById('log') @@ -60,7 +69,7 @@

WebViewJavascriptBridge Demo

log('JS got response', response) }) } - } + })
diff --git a/README.md b/README.md index f28c52b3..ef6eb762 100644 --- a/README.md +++ b/README.md @@ -50,8 +50,20 @@ To use a WebViewJavascriptBridge in your own project: 4) Finally, set up the javascript side: - document.addEventListener('WebViewJavascriptBridgeReady', function onBridgeReady(event) { - var bridge = event.bridge + function connectWebViewJavascriptBridge(callback) { + if (window.WebViewJavascriptBridge) { + callback(WebViewJavascriptBridge) + } else { + document.addEventListener('WebViewJavascriptBridgeReady', function() { + callback(WebViewJavascriptBridge) + }, false) + } + } + + connectWebViewJavascriptBridge(function(bridge) { + + /* Init your app here */ + bridge.init(function(message, responseCallback) { alert('Received message: ' + message) if (responseCallback) { @@ -62,7 +74,7 @@ To use a WebViewJavascriptBridge in your own project: bridge.send('Please respond to this', function responseCallback(responseData) { console.log("Javascript got its response", responseData) }) - }, false) + }) Contributors & Forks -------------------- From 3e8e51bc62cf9c26a903311b3b74d8919d971a81 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Fri, 25 Oct 2013 17:28:23 -0700 Subject: [PATCH 016/239] Changelog for upcoming v4.1.1 --- Changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Changelog b/Changelog index 11ac8e4d..45f82014 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,6 @@ +intended v4.1.1 ++ Better JS initialization script (thank @refractalize!) + v4.1.0 + Allow for sending null/nil data packets + Drop support for JSONKit From 197bab4152d8ae6e8adfdd65392655cd17bc73d0 Mon Sep 17 00:00:00 2001 From: Bastian Bense Date: Sat, 26 Oct 2013 11:14:17 +0200 Subject: [PATCH 017/239] Fix resource path in podspec --- WebViewJavascriptBridge.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WebViewJavascriptBridge.podspec b/WebViewJavascriptBridge.podspec index 227d89be..f4d86f8b 100644 --- a/WebViewJavascriptBridge.podspec +++ b/WebViewJavascriptBridge.podspec @@ -11,7 +11,7 @@ Pod::Spec.new do |s| s.osx.platform = :osx s.ios.source_files = 'WebViewJavascriptBridge/*.{h,m}' s.osx.source_files = 'WebViewJavascriptBridge/*.{h,m}' - s.resource = 'WebViewJavascriptBridgeAbstract/WebViewJavascriptBridge.js.txt' + s.resource = 'WebViewJavascriptBridge/WebViewJavascriptBridge.js.txt' s.ios.framework = 'UIKit' s.osx.framework = 'WebKit' end From 01eb1aa8cb5fab2b4f60ff462e8e55088d9661e8 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Tue, 26 Nov 2013 10:38:33 -0800 Subject: [PATCH 018/239] Migrate to latest XCode-recommended settings --- Example Apps/ExampleApp-iOS.xcodeproj/project.pbxproj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Example Apps/ExampleApp-iOS.xcodeproj/project.pbxproj b/Example Apps/ExampleApp-iOS.xcodeproj/project.pbxproj index b71010e5..7ae53eda 100644 --- a/Example Apps/ExampleApp-iOS.xcodeproj/project.pbxproj +++ b/Example Apps/ExampleApp-iOS.xcodeproj/project.pbxproj @@ -139,7 +139,7 @@ 2CEB3EB21602563600548120 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0450; + LastUpgradeCheck = 0500; ORGANIZATIONNAME = "Marcus Westin"; }; buildConfigurationList = 2CEB3EB51602563600548120 /* Build configuration list for PBXProject "ExampleApp-iOS" */; @@ -220,6 +220,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 6.0; + ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; }; name = Debug; From f5b48ee40e1bc92f1df49924e13c6b3b7b96c3fc Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Tue, 26 Nov 2013 10:39:16 -0800 Subject: [PATCH 019/239] Add example for webViewDidStartLoad:/webViewDidFinishLoad: to example app. References GH issue #61 --- Example Apps/ExampleApp-iOS/ExampleAppDelegate.h | 2 +- Example Apps/ExampleApp-iOS/ExampleAppDelegate.m | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Example Apps/ExampleApp-iOS/ExampleAppDelegate.h b/Example Apps/ExampleApp-iOS/ExampleAppDelegate.h index 5fc2d78b..d85c5e94 100644 --- a/Example Apps/ExampleApp-iOS/ExampleAppDelegate.h +++ b/Example Apps/ExampleApp-iOS/ExampleAppDelegate.h @@ -1,7 +1,7 @@ #import #import "WebViewJavascriptBridge.h" -@interface ExampleAppDelegate : UIResponder +@interface ExampleAppDelegate : UIResponder @property (strong, nonatomic) UIWindow *window; @property (strong, nonatomic) WebViewJavascriptBridge *javascriptBridge; diff --git a/Example Apps/ExampleApp-iOS/ExampleAppDelegate.m b/Example Apps/ExampleApp-iOS/ExampleAppDelegate.m index 944e4312..a41b51c2 100644 --- a/Example Apps/ExampleApp-iOS/ExampleAppDelegate.m +++ b/Example Apps/ExampleApp-iOS/ExampleAppDelegate.m @@ -5,6 +5,14 @@ @implementation ExampleAppDelegate @synthesize window = _window; @synthesize javascriptBridge = _bridge; +- (void)webViewDidStartLoad:(UIWebView *)webView { + NSLog(@"webViewDidStartLoad"); +} + +- (void)webViewDidFinishLoad:(UIWebView *)webView { + NSLog(@"webViewDidFinishLoad"); +} + - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; UIWebView* webView = [[UIWebView alloc] initWithFrame:self.window.bounds]; @@ -12,7 +20,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( [WebViewJavascriptBridge enableLogging]; - _bridge = [WebViewJavascriptBridge bridgeForWebView:webView handler:^(id data, WVJBResponseCallback responseCallback) { + _bridge = [WebViewJavascriptBridge bridgeForWebView:webView webViewDelegate:self handler:^(id data, WVJBResponseCallback responseCallback) { NSLog(@"ObjC received message from JS: %@", data); responseCallback(@"Response for message from ObjC"); }]; From cd1b1a71c157bfe59aa839408b5e613b78bfe92c Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Fri, 6 Dec 2013 13:26:23 -0800 Subject: [PATCH 020/239] Remove left/right landscape orientation support --- Example Apps/ExampleApp-iOS/ExampleApp-iOS-Info.plist | 2 -- 1 file changed, 2 deletions(-) diff --git a/Example Apps/ExampleApp-iOS/ExampleApp-iOS-Info.plist b/Example Apps/ExampleApp-iOS/ExampleApp-iOS-Info.plist index 2e36c495..81d25998 100644 --- a/Example Apps/ExampleApp-iOS/ExampleApp-iOS-Info.plist +++ b/Example Apps/ExampleApp-iOS/ExampleApp-iOS-Info.plist @@ -31,8 +31,6 @@ UISupportedInterfaceOrientations UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight From 4b95cde27472bc54b36556238561a050f4b94285 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Mon, 13 Jan 2014 15:33:05 -0800 Subject: [PATCH 021/239] Have the example iOS app use a UIViewController instead of adding the webview directly to the app window. Fixes #65 on GH --- .../ExampleApp-iOS.xcodeproj/project.pbxproj | 6 ++ .../ExampleApp-iOS/ExampleAppDelegate.h | 11 +-- .../ExampleApp-iOS/ExampleAppDelegate.m | 72 +-------------- .../ExampleApp-iOS/ExampleAppViewController.h | 13 +++ .../ExampleApp-iOS/ExampleAppViewController.m | 88 +++++++++++++++++++ 5 files changed, 111 insertions(+), 79 deletions(-) create mode 100644 Example Apps/ExampleApp-iOS/ExampleAppViewController.h create mode 100644 Example Apps/ExampleApp-iOS/ExampleAppViewController.m diff --git a/Example Apps/ExampleApp-iOS.xcodeproj/project.pbxproj b/Example Apps/ExampleApp-iOS.xcodeproj/project.pbxproj index 7ae53eda..4834adaf 100644 --- a/Example Apps/ExampleApp-iOS.xcodeproj/project.pbxproj +++ b/Example Apps/ExampleApp-iOS.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 2C1562B5176B9F8400B4AE50 /* WebViewJavascriptBridge.js.txt in Resources */ = {isa = PBXBuildFile; fileRef = 2C1562B4176B9F8400B4AE50 /* WebViewJavascriptBridge.js.txt */; }; 2C1562C0176BA63500B4AE50 /* WebViewJavascriptBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C1562A9176B9F6200B4AE50 /* WebViewJavascriptBridge.m */; }; + 2C45CA2C1884AD520002A4E2 /* ExampleAppViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C45CA2B1884AD520002A4E2 /* ExampleAppViewController.m */; }; 2CA045BF17117439006DEE8B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 2CA045B717117439006DEE8B /* InfoPlist.strings */; }; 2CA045C217117439006DEE8B /* ExampleAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CA045BD17117439006DEE8B /* ExampleAppDelegate.m */; }; 2CA045C317117439006DEE8B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CA045BE17117439006DEE8B /* main.m */; }; @@ -23,6 +24,8 @@ 2C1562A8176B9F6200B4AE50 /* WebViewJavascriptBridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridge.h; sourceTree = ""; }; 2C1562A9176B9F6200B4AE50 /* WebViewJavascriptBridge.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge.m; sourceTree = ""; }; 2C1562B4176B9F8400B4AE50 /* WebViewJavascriptBridge.js.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebViewJavascriptBridge.js.txt; sourceTree = ""; }; + 2C45CA2A1884AD520002A4E2 /* ExampleAppViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExampleAppViewController.h; sourceTree = ""; }; + 2C45CA2B1884AD520002A4E2 /* ExampleAppViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ExampleAppViewController.m; sourceTree = ""; }; 2CA045B817117439006DEE8B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 2CA045B917117439006DEE8B /* ExampleApp-iOS-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "ExampleApp-iOS-Info.plist"; sourceTree = ""; }; 2CA045BA17117439006DEE8B /* ExampleApp-iOS-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ExampleApp-iOS-Prefix.pch"; sourceTree = ""; }; @@ -68,6 +71,8 @@ 2CA0465B1711AC8D006DEE8B /* ExampleApp.html */, 2CA045BC17117439006DEE8B /* ExampleAppDelegate.h */, 2CA045BD17117439006DEE8B /* ExampleAppDelegate.m */, + 2C45CA2A1884AD520002A4E2 /* ExampleAppViewController.h */, + 2C45CA2B1884AD520002A4E2 /* ExampleAppViewController.m */, 2C1562A7176B9F5400B4AE50 /* WebViewJavascriptBridge */, 2CA046211711A94E006DEE8B /* Supporting Files */, ); @@ -179,6 +184,7 @@ buildActionMask = 2147483647; files = ( 2C1562C0176BA63500B4AE50 /* WebViewJavascriptBridge.m in Sources */, + 2C45CA2C1884AD520002A4E2 /* ExampleAppViewController.m in Sources */, 2CA045C217117439006DEE8B /* ExampleAppDelegate.m in Sources */, 2CA045C317117439006DEE8B /* main.m in Sources */, ); diff --git a/Example Apps/ExampleApp-iOS/ExampleAppDelegate.h b/Example Apps/ExampleApp-iOS/ExampleAppDelegate.h index d85c5e94..f59015d8 100644 --- a/Example Apps/ExampleApp-iOS/ExampleAppDelegate.h +++ b/Example Apps/ExampleApp-iOS/ExampleAppDelegate.h @@ -1,12 +1,5 @@ #import -#import "WebViewJavascriptBridge.h" - -@interface ExampleAppDelegate : UIResponder - -@property (strong, nonatomic) UIWindow *window; -@property (strong, nonatomic) WebViewJavascriptBridge *javascriptBridge; - -- (void)renderButtons:(UIWebView*)webView; -- (void)loadExamplePage:(UIWebView*)webView; +@interface ExampleAppDelegate : UIResponder +@property (nonatomic) UIWindow *window; @end diff --git a/Example Apps/ExampleApp-iOS/ExampleAppDelegate.m b/Example Apps/ExampleApp-iOS/ExampleAppDelegate.m index a41b51c2..72f35ded 100644 --- a/Example Apps/ExampleApp-iOS/ExampleAppDelegate.m +++ b/Example Apps/ExampleApp-iOS/ExampleAppDelegate.m @@ -1,81 +1,13 @@ #import "ExampleAppDelegate.h" +#import "ExampleAppViewController.h" @implementation ExampleAppDelegate -@synthesize window = _window; -@synthesize javascriptBridge = _bridge; - -- (void)webViewDidStartLoad:(UIWebView *)webView { - NSLog(@"webViewDidStartLoad"); -} - -- (void)webViewDidFinishLoad:(UIWebView *)webView { - NSLog(@"webViewDidFinishLoad"); -} - - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; - UIWebView* webView = [[UIWebView alloc] initWithFrame:self.window.bounds]; - [self.window addSubview:webView]; - - [WebViewJavascriptBridge enableLogging]; - - _bridge = [WebViewJavascriptBridge bridgeForWebView:webView webViewDelegate:self handler:^(id data, WVJBResponseCallback responseCallback) { - NSLog(@"ObjC received message from JS: %@", data); - responseCallback(@"Response for message from ObjC"); - }]; - - [_bridge registerHandler:@"testObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) { - NSLog(@"testObjcCallback called: %@", data); - responseCallback(@"Response from testObjcCallback"); - }]; - - [_bridge send:@"A string sent from ObjC before Webview has loaded." responseCallback:^(id responseData) { - NSLog(@"objc got response! %@", responseData); - }]; - - [_bridge callHandler:@"testJavascriptHandler" data:@{ @"foo":@"before ready" }]; - - [self renderButtons:webView]; - [self loadExamplePage:webView]; - - [_bridge send:@"A string sent from ObjC after Webview has loaded."]; - + self.window.rootViewController = [ExampleAppViewController new]; [self.window makeKeyAndVisible]; return YES; } -- (void)renderButtons:(UIWebView*)webView { - UIButton *messageButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; - [messageButton setTitle:@"Send message" forState:UIControlStateNormal]; - [messageButton addTarget:self action:@selector(sendMessage:) forControlEvents:UIControlEventTouchUpInside]; - [self.window insertSubview:messageButton aboveSubview:webView]; - messageButton.frame = CGRectMake(20, 414, 130, 45); - - UIButton *callbackButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; - [callbackButton setTitle:@"Call handler" forState:UIControlStateNormal]; - [callbackButton addTarget:self action:@selector(callHandler:) forControlEvents:UIControlEventTouchUpInside]; - [self.window insertSubview:callbackButton aboveSubview:webView]; - callbackButton.frame = CGRectMake(170, 414, 130, 45); -} - -- (void)sendMessage:(id)sender { - [_bridge send:@"A string sent from ObjC to JS" responseCallback:^(id response) { - NSLog(@"sendMessage got response: %@", response); - }]; -} - -- (void)callHandler:(id)sender { - id data = @{ @"greetingFromObjC": @"Hi there, JS!" }; - [_bridge callHandler:@"testJavascriptHandler" data:data responseCallback:^(id response) { - NSLog(@"testJavascriptHandler responded: %@", response); - }]; -} - -- (void)loadExamplePage:(UIWebView*)webView { - NSString* htmlPath = [[NSBundle mainBundle] pathForResource:@"ExampleApp" ofType:@"html"]; - NSString* appHtml = [NSString stringWithContentsOfFile:htmlPath encoding:NSUTF8StringEncoding error:nil]; - [webView loadHTMLString:appHtml baseURL:nil]; -} - @end diff --git a/Example Apps/ExampleApp-iOS/ExampleAppViewController.h b/Example Apps/ExampleApp-iOS/ExampleAppViewController.h new file mode 100644 index 00000000..d2e25c2d --- /dev/null +++ b/Example Apps/ExampleApp-iOS/ExampleAppViewController.h @@ -0,0 +1,13 @@ +// +// ExampleAppViewController.h +// ExampleApp-iOS +// +// Created by Marcus Westin on 1/13/14. +// Copyright (c) 2014 Marcus Westin. All rights reserved. +// + +#import + +@interface ExampleAppViewController : UINavigationController + +@end diff --git a/Example Apps/ExampleApp-iOS/ExampleAppViewController.m b/Example Apps/ExampleApp-iOS/ExampleAppViewController.m new file mode 100644 index 00000000..b9243d61 --- /dev/null +++ b/Example Apps/ExampleApp-iOS/ExampleAppViewController.m @@ -0,0 +1,88 @@ +// +// ExampleAppViewController.m +// ExampleApp-iOS +// +// Created by Marcus Westin on 1/13/14. +// Copyright (c) 2014 Marcus Westin. All rights reserved. +// + +#import "ExampleAppViewController.h" +#import "WebViewJavascriptBridge.h" + +@interface ExampleAppViewController () +@property WebViewJavascriptBridge* bridge; +@end + +@implementation ExampleAppViewController + +- (void)viewWillAppear:(BOOL)animated { + if (_bridge) { return; } + + UIWebView* webView = [[UIWebView alloc] initWithFrame:self.view.bounds]; + [self.view addSubview:webView]; + + [WebViewJavascriptBridge enableLogging]; + + _bridge = [WebViewJavascriptBridge bridgeForWebView:webView webViewDelegate:self handler:^(id data, WVJBResponseCallback responseCallback) { + NSLog(@"ObjC received message from JS: %@", data); + responseCallback(@"Response for message from ObjC"); + }]; + + [_bridge registerHandler:@"testObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) { + NSLog(@"testObjcCallback called: %@", data); + responseCallback(@"Response from testObjcCallback"); + }]; + + [_bridge send:@"A string sent from ObjC before Webview has loaded." responseCallback:^(id responseData) { + NSLog(@"objc got response! %@", responseData); + }]; + + [_bridge callHandler:@"testJavascriptHandler" data:@{ @"foo":@"before ready" }]; + + [self renderButtons:webView]; + [self loadExamplePage:webView]; + + [_bridge send:@"A string sent from ObjC after Webview has loaded."]; +} + +- (void)webViewDidStartLoad:(UIWebView *)webView { + NSLog(@"webViewDidStartLoad"); +} + +- (void)webViewDidFinishLoad:(UIWebView *)webView { + NSLog(@"webViewDidFinishLoad"); +} + +- (void)renderButtons:(UIWebView*)webView { + UIButton *messageButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; + [messageButton setTitle:@"Send message" forState:UIControlStateNormal]; + [messageButton addTarget:self action:@selector(sendMessage:) forControlEvents:UIControlEventTouchUpInside]; + [self.view insertSubview:messageButton aboveSubview:webView]; + messageButton.frame = CGRectMake(20, 414, 130, 45); + + 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(170, 414, 130, 45); +} + +- (void)sendMessage:(id)sender { + [_bridge send:@"A string sent from ObjC to JS" responseCallback:^(id response) { + NSLog(@"sendMessage got response: %@", response); + }]; +} + +- (void)callHandler:(id)sender { + id data = @{ @"greetingFromObjC": @"Hi there, JS!" }; + [_bridge callHandler:@"testJavascriptHandler" data:data responseCallback:^(id response) { + NSLog(@"testJavascriptHandler responded: %@", response); + }]; +} + +- (void)loadExamplePage:(UIWebView*)webView { + NSString* htmlPath = [[NSBundle mainBundle] pathForResource:@"ExampleApp" ofType:@"html"]; + NSString* appHtml = [NSString stringWithContentsOfFile:htmlPath encoding:NSUTF8StringEncoding error:nil]; + [webView loadHTMLString:appHtml baseURL:nil]; +} +@end From bae8975aeb3d769e65f6b662133538cc1defa805 Mon Sep 17 00:00:00 2001 From: Joao Antunes Date: Tue, 4 Feb 2014 19:04:38 +0000 Subject: [PATCH 022/239] Facebook Paper use of the bridge Updated the Readme with Facebook Paper app usage. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ef6eb762..9047233b 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ In the Wild ----------- WebViewJavascriptBridge is used by a range of companies and projects. This list is incomplete, but feel free to add your's and send a PR. +- [Facebook Paper](https://facebook.com/paper) - [Yardsale](https://www.getyardsale.com/) - [EverTrue](http://www.evertrue.com/) - [Game Insight](http://www.game-insight.com/) From 5183c4c848d2f9ce3d575081922ba7123edc2608 Mon Sep 17 00:00:00 2001 From: Kamil Burczyk Date: Sun, 9 Feb 2014 17:07:26 +0100 Subject: [PATCH 023/239] Added possibility to set custom bundle where core bridge.js script is located --- .../WebViewJavascriptBridge.h | 1 + .../WebViewJavascriptBridge.m | 22 ++++++++++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.h b/WebViewJavascriptBridge/WebViewJavascriptBridge.h index d2d0544b..baa341c8 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.h +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.h @@ -29,6 +29,7 @@ typedef void (^WVJBHandler)(id data, WVJBResponseCallback responseCallback); + (instancetype)bridgeForWebView:(WVJB_WEBVIEW_TYPE*)webView handler:(WVJBHandler)handler; + (instancetype)bridgeForWebView:(WVJB_WEBVIEW_TYPE*)webView webViewDelegate:(WVJB_WEBVIEW_DELEGATE_TYPE*)webViewDelegate handler:(WVJBHandler)handler; ++ (instancetype)bridgeForWebView:(WVJB_WEBVIEW_TYPE*)webView webViewDelegate:(WVJB_WEBVIEW_DELEGATE_TYPE*)webViewDelegate handler:(WVJBHandler)handler resourceBundle:(NSBundle*)bundle; + (void)enableLogging; - (void)send:(id)message; diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index 8ee60d17..2473c01e 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -25,6 +25,8 @@ @implementation WebViewJavascriptBridge { long _uniqueId; WVJBHandler _messageHandler; + NSBundle *_resourceBundle; + #if defined WVJB_PLATFORM_IOS NSUInteger _numRequestsLoading; #endif @@ -42,8 +44,13 @@ + (instancetype)bridgeForWebView:(WVJB_WEBVIEW_TYPE*)webView handler:(WVJBHandle } + (instancetype)bridgeForWebView:(WVJB_WEBVIEW_TYPE*)webView webViewDelegate:(WVJB_WEBVIEW_DELEGATE_TYPE*)webViewDelegate handler:(WVJBHandler)messageHandler { + return [self bridgeForWebView:webView webViewDelegate:webViewDelegate handler:messageHandler resourceBundle:nil]; +} + ++ (instancetype)bridgeForWebView:(WVJB_WEBVIEW_TYPE*)webView webViewDelegate:(WVJB_WEBVIEW_DELEGATE_TYPE*)webViewDelegate handler:(WVJBHandler)messageHandler resourceBundle:(NSBundle*)bundle +{ WebViewJavascriptBridge* bridge = [[WebViewJavascriptBridge alloc] init]; - [bridge _platformSpecificSetup:webView webViewDelegate:webViewDelegate handler:messageHandler]; + [bridge _platformSpecificSetup:webView webViewDelegate:webViewDelegate handler:messageHandler resourceBundle:bundle]; [bridge reset]; return bridge; } @@ -222,7 +229,7 @@ - (void)_log:(NSString *)action json:(id)json { **********************************/ #if defined WVJB_PLATFORM_OSX -- (void) _platformSpecificSetup:(WVJB_WEBVIEW_TYPE*)webView webViewDelegate:(WVJB_WEBVIEW_DELEGATE_TYPE*)webViewDelegate handler:(WVJBHandler)messageHandler { +- (void) _platformSpecificSetup:(WVJB_WEBVIEW_TYPE*)webView webViewDelegate:(WVJB_WEBVIEW_DELEGATE_TYPE*)webViewDelegate handler:(WVJBHandler)messageHandler resourceBundle:(NSBundle*)bundle{ _messageHandler = messageHandler; _webView = webView; _webViewDelegate = webViewDelegate; @@ -231,6 +238,8 @@ - (void) _platformSpecificSetup:(WVJB_WEBVIEW_TYPE*)webView webViewDelegate:(WVJ _webView.frameLoadDelegate = self; _webView.resourceLoadDelegate = self; _webView.policyDelegate = self; + + _resourceBundle = bundle; } - (void) _platformSpecificDealloc { @@ -244,7 +253,8 @@ - (void)webView:(WebView *)webView didFinishLoadForFrame:(WebFrame *)frame if (webView != _webView) { return; } if (![[webView stringByEvaluatingJavaScriptFromString:@"typeof WebViewJavascriptBridge == 'object'"] isEqualToString:@"true"]) { - NSString *filePath = [[NSBundle mainBundle] pathForResource:@"WebViewJavascriptBridge.js" ofType:@"txt"]; + NSBundle *bundle = _resourceBundle ? _resourceBundle : [NSBundle mainBundle]; + NSString *filePath = [bundle pathForResource:@"WebViewJavascriptBridge.js" ofType:@"txt"]; NSString *js = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; [webView stringByEvaluatingJavaScriptFromString:js]; } @@ -312,12 +322,13 @@ - (NSURLRequest *)webView:(WebView *)webView resource:(id)identifier willSendReq **********************************/ #elif defined WVJB_PLATFORM_IOS -- (void) _platformSpecificSetup:(WVJB_WEBVIEW_TYPE*)webView webViewDelegate:(id)webViewDelegate handler:(WVJBHandler)messageHandler { +- (void) _platformSpecificSetup:(WVJB_WEBVIEW_TYPE*)webView webViewDelegate:(id)webViewDelegate handler:(WVJBHandler)messageHandler resourceBundle:(NSBundle*)bundle{ _messageHandler = messageHandler; _webView = webView; _webViewDelegate = webViewDelegate; _messageHandlers = [NSMutableDictionary dictionary]; _webView.delegate = self; + _resourceBundle = bundle; } - (void) _platformSpecificDealloc { @@ -330,7 +341,8 @@ - (void)webViewDidFinishLoad:(UIWebView *)webView { _numRequestsLoading--; if (_numRequestsLoading == 0 && ![[webView stringByEvaluatingJavaScriptFromString:@"typeof WebViewJavascriptBridge == 'object'"] isEqualToString:@"true"]) { - NSString *filePath = [[NSBundle mainBundle] pathForResource:@"WebViewJavascriptBridge.js" ofType:@"txt"]; + NSBundle *bundle = _resourceBundle ? _resourceBundle : [NSBundle mainBundle]; + NSString *filePath = [bundle pathForResource:@"WebViewJavascriptBridge.js" ofType:@"txt"]; NSString *js = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; [webView stringByEvaluatingJavaScriptFromString:js]; } From f3e0c6acb031b9479f8f533015b7a06c81b51306 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Mon, 10 Feb 2014 09:41:13 -0800 Subject: [PATCH 024/239] Add Facebook Messenger to products/companies using WVJB. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9047233b..5af2b3ce 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ In the Wild ----------- WebViewJavascriptBridge is used by a range of companies and projects. This list is incomplete, but feel free to add your's and send a PR. +- [Facebook Messenger](https://www.facebook.com/mobile/messenger) - [Facebook Paper](https://facebook.com/paper) - [Yardsale](https://www.getyardsale.com/) - [EverTrue](http://www.evertrue.com/) From 16aa68e271e334c1aaf0424737953a6c83280d28 Mon Sep 17 00:00:00 2001 From: shuizhongyueming Date: Sat, 22 Feb 2014 00:09:26 +0800 Subject: [PATCH 025/239] add a method,make the user can decide whether the request from webview should be load except the WVJB request --- .../WebViewJavascriptBridge.h | 15 +++++++++++++ .../WebViewJavascriptBridge.m | 21 ++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.h b/WebViewJavascriptBridge/WebViewJavascriptBridge.h index baa341c8..dede2189 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.h +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.h @@ -22,13 +22,28 @@ #define WVJB_WEBVIEW_DELEGATE_TYPE NSObject #endif +@protocol WebViewJavascriptBridgeDelegate + +@optional + +// define a method,make the user decide every request from webview should be load except the WVJB request +-(BOOL) WVJB_webView:(UIWebView *)webView +shouldStartLoadWithRequest:(NSURLRequest *)request + navigationType:(UIWebViewNavigationType)navigationType; + + +@end + typedef void (^WVJBResponseCallback)(id responseData); typedef void (^WVJBHandler)(id data, WVJBResponseCallback responseCallback); @interface WebViewJavascriptBridge : WVJB_WEBVIEW_DELEGATE_TYPE +@property (nonatomic,weak) id delegate; + + (instancetype)bridgeForWebView:(WVJB_WEBVIEW_TYPE*)webView handler:(WVJBHandler)handler; + (instancetype)bridgeForWebView:(WVJB_WEBVIEW_TYPE*)webView webViewDelegate:(WVJB_WEBVIEW_DELEGATE_TYPE*)webViewDelegate handler:(WVJBHandler)handler; ++ (instancetype)bridgeForWebView:(WVJB_WEBVIEW_TYPE*)webView WVJBDelegate:(id)delegate handler:(WVJBHandler)handler; + (instancetype)bridgeForWebView:(WVJB_WEBVIEW_TYPE*)webView webViewDelegate:(WVJB_WEBVIEW_DELEGATE_TYPE*)webViewDelegate handler:(WVJBHandler)handler resourceBundle:(NSBundle*)bundle; + (void)enableLogging; diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index 2473c01e..919e119b 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -52,6 +52,15 @@ + (instancetype)bridgeForWebView:(WVJB_WEBVIEW_TYPE*)webView webViewDelegate:(WV WebViewJavascriptBridge* bridge = [[WebViewJavascriptBridge alloc] init]; [bridge _platformSpecificSetup:webView webViewDelegate:webViewDelegate handler:messageHandler resourceBundle:bundle]; [bridge reset]; + bridge.delegate = nil; + return bridge; +} + ++ (instancetype)bridgeForWebView:(WVJB_WEBVIEW_TYPE*)webView WVJBDelegate:(id)delegate handler:(WVJBHandler)handler { + WebViewJavascriptBridge* bridge = [[WebViewJavascriptBridge alloc] init]; + [bridge _platformSpecificSetup:webView webViewDelegate:nil handler:handler]; + [bridge reset]; + bridge.delegate = delegate; return bridge; } @@ -385,7 +394,17 @@ - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *) } else if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:shouldStartLoadWithRequest:navigationType:)]) { return [strongDelegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType]; } else { - return YES; + if(self.delegate){ + if([self.delegate respondsToSelector:@selector(WVJB_webView:shouldStartLoadWithRequest:navigationType:)]){ + return [self.delegate WVJB_webView:webView + shouldStartLoadWithRequest:request + navigationType:navigationType]; + }else{ + return YES; + } + }else{ + return YES; + } } } From 1dc02737d14c75d6d30f2aa792937a4199e04345 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BF=9C=E5=B0=98?= Date: Wed, 12 Mar 2014 10:53:59 +0800 Subject: [PATCH 026/239] prevent insert nil into dic --- WebViewJavascriptBridge/WebViewJavascriptBridge.m | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index 2473c01e..2d707e8a 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -172,6 +172,10 @@ - (void)_flushMessageQueue { NSString* callbackId = message[@"callbackId"]; if (callbackId) { responseCallback = ^(id responseData) { + if (responseData == nil) { + responseData = @{}; + } + WVJBMessage* msg = @{ @"responseId":callbackId, @"responseData":responseData }; [self _queueMessage:msg]; }; From 92d4715ff3f0725a37c91354d576f47771f07935 Mon Sep 17 00:00:00 2001 From: Johan Kanflo Date: Sat, 29 Mar 2014 09:49:00 +0100 Subject: [PATCH 027/239] #74 Not possible to load external javascript in ExampleApp.html --- Example Apps/ExampleApp-iOS/ExampleAppViewController.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Example Apps/ExampleApp-iOS/ExampleAppViewController.m b/Example Apps/ExampleApp-iOS/ExampleAppViewController.m index b9243d61..c81e136a 100644 --- a/Example Apps/ExampleApp-iOS/ExampleAppViewController.m +++ b/Example Apps/ExampleApp-iOS/ExampleAppViewController.m @@ -83,6 +83,7 @@ - (void)callHandler:(id)sender { - (void)loadExamplePage:(UIWebView*)webView { NSString* htmlPath = [[NSBundle mainBundle] pathForResource:@"ExampleApp" ofType:@"html"]; NSString* appHtml = [NSString stringWithContentsOfFile:htmlPath encoding:NSUTF8StringEncoding error:nil]; - [webView loadHTMLString:appHtml baseURL:nil]; + NSURL *baseURL = [NSURL fileURLWithPath:htmlPath]; + [webView loadHTMLString:appHtml baseURL:baseURL]; } @end From 4c34caa104e2213928dcbfe862ed2aba1119b89a Mon Sep 17 00:00:00 2001 From: Kamil Burczyk Date: Thu, 3 Apr 2014 14:26:17 +0200 Subject: [PATCH 028/239] Updated Readme with custom bundle example --- README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/README.md b/README.md index 5af2b3ce..5012ff33 100644 --- a/README.md +++ b/README.md @@ -144,6 +144,23 @@ Example: NSLog(@"Current UIWebView page URL is: %@", responseData); }]; +#### Custom bundle +`WebViewJavascriptBridge` requires `WebViewJavascriptBridge.js.txt` file that is injected into web view to create a bridge on JS side. Standard implementation uses `mainBundle` to search for this file. If you e.g. build a static library and you have that file placed somewhere else you can use this method to specify which bundle should be searched for `WebViewJavascriptBridge.js.txt` file: + +##### `[WebViewJavascriptBridge bridgeForWebView:(UIWebView/WebView*)webView webViewDelegate:(UIWebViewDelegate*)webViewDelegate handler:(WVJBHandler)handler resourceBundle:(NSBundle*)bundle` + +Example: + + +``` +[WebViewJavascriptBridge bridgeForWebView:_webView + webViewDelegate:self + handler:^(id data, WVJBResponseCallback responseCallback) { + NSLog(@"Received message from javascript: %@", data); + } + resourceBundle:[NSBundle bundleWithURL:[[NSBundle mainBundle] URLForResource:@"ResourcesBundle" withExtension:@"bundle"]] +]; +``` ### Javascript API From 1aa0ecfb83cb97ee5c1efbfa28b2948aa3801069 Mon Sep 17 00:00:00 2001 From: Nolan Waite Date: Wed, 16 Apr 2014 03:16:13 -0300 Subject: [PATCH 029/239] Escape U+2028 and U+2029 when writing JSON as a JavaScript string literal. U+2028 LINE SEPARATOR and U+2029 PARAGRAPH SEPARATOR are also not allowed in a JavaScript string literal. Trying to send a message with either would cause an "unexpected EOF" exception on the JavaScript side. --- WebViewJavascriptBridge/WebViewJavascriptBridge.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index 2473c01e..0f1e314a 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -135,6 +135,8 @@ - (void)_dispatchMessage:(WVJBMessage*)message { messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"]; messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\r" withString:@"\\r"]; messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\f" withString:@"\\f"]; + messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\u2028" withString:@"\\u2028"]; + messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\u2029" withString:@"\\u2029"]; NSString* javascriptCommand = [NSString stringWithFormat:@"WebViewJavascriptBridge._handleMessageFromObjC('%@');", messageJSON]; if ([[NSThread currentThread] isMainThread]) { From b8d5856a758f1b66e2f0e6dcb557ba8542a950be Mon Sep 17 00:00:00 2001 From: Nolan Waite Date: Tue, 15 Apr 2014 23:30:56 -0700 Subject: [PATCH 030/239] Fix little typo in comment --- WebViewJavascriptBridge/WebViewJavascriptBridge.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index 2473c01e..805cbc5c 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -318,7 +318,7 @@ - (NSURLRequest *)webView:(WebView *)webView resource:(id)identifier willSendReq -/* Platform specific internals: OSX +/* Platform specific internals: iOS **********************************/ #elif defined WVJB_PLATFORM_IOS From 18b51d212191d38dd237b47b7ad22d05b0060a25 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Thu, 22 May 2014 19:56:53 +0200 Subject: [PATCH 031/239] Upgrade to latest recommended xcode settings for example OSX project ("Automatically detect target architecture") --- Example Apps/ExampleApp-OSX.xcodeproj/project.pbxproj | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Example Apps/ExampleApp-OSX.xcodeproj/project.pbxproj b/Example Apps/ExampleApp-OSX.xcodeproj/project.pbxproj index 1a78a146..0e947166 100644 --- a/Example Apps/ExampleApp-OSX.xcodeproj/project.pbxproj +++ b/Example Apps/ExampleApp-OSX.xcodeproj/project.pbxproj @@ -152,7 +152,7 @@ 2C136A1917641106004C7401 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0460; + LastUpgradeCheck = 0510; ORGANIZATIONNAME = "Marcus Westin"; }; buildConfigurationList = 2C136A1C17641106004C7401 /* Build configuration list for PBXProject "ExampleApp-OSX" */; @@ -224,7 +224,6 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_64_BIT)"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_OBJC_ARC = YES; @@ -257,7 +256,6 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_64_BIT)"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_OBJC_ARC = YES; From 6da9284f76e59dcd72ca8dc0878c7f4fa5001484 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Thu, 22 May 2014 20:12:16 +0200 Subject: [PATCH 032/239] Revert "Merge pull request #70 from shuizhongyueming/master" This reverts commit 49579d689e23e7326260f5076764affe8f11c3e2, reversing changes made to 18b51d212191d38dd237b47b7ad22d05b0060a25. The added changes only worked for iOS projects, but broke OSX builds. --- .../WebViewJavascriptBridge.h | 15 ------------- .../WebViewJavascriptBridge.m | 21 +------------------ 2 files changed, 1 insertion(+), 35 deletions(-) diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.h b/WebViewJavascriptBridge/WebViewJavascriptBridge.h index dede2189..baa341c8 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.h +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.h @@ -22,28 +22,13 @@ #define WVJB_WEBVIEW_DELEGATE_TYPE NSObject #endif -@protocol WebViewJavascriptBridgeDelegate - -@optional - -// define a method,make the user decide every request from webview should be load except the WVJB request --(BOOL) WVJB_webView:(UIWebView *)webView -shouldStartLoadWithRequest:(NSURLRequest *)request - navigationType:(UIWebViewNavigationType)navigationType; - - -@end - typedef void (^WVJBResponseCallback)(id responseData); typedef void (^WVJBHandler)(id data, WVJBResponseCallback responseCallback); @interface WebViewJavascriptBridge : WVJB_WEBVIEW_DELEGATE_TYPE -@property (nonatomic,weak) id delegate; - + (instancetype)bridgeForWebView:(WVJB_WEBVIEW_TYPE*)webView handler:(WVJBHandler)handler; + (instancetype)bridgeForWebView:(WVJB_WEBVIEW_TYPE*)webView webViewDelegate:(WVJB_WEBVIEW_DELEGATE_TYPE*)webViewDelegate handler:(WVJBHandler)handler; -+ (instancetype)bridgeForWebView:(WVJB_WEBVIEW_TYPE*)webView WVJBDelegate:(id)delegate handler:(WVJBHandler)handler; + (instancetype)bridgeForWebView:(WVJB_WEBVIEW_TYPE*)webView webViewDelegate:(WVJB_WEBVIEW_DELEGATE_TYPE*)webViewDelegate handler:(WVJBHandler)handler resourceBundle:(NSBundle*)bundle; + (void)enableLogging; diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index 08a0fb66..4addea33 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -52,15 +52,6 @@ + (instancetype)bridgeForWebView:(WVJB_WEBVIEW_TYPE*)webView webViewDelegate:(WV WebViewJavascriptBridge* bridge = [[WebViewJavascriptBridge alloc] init]; [bridge _platformSpecificSetup:webView webViewDelegate:webViewDelegate handler:messageHandler resourceBundle:bundle]; [bridge reset]; - bridge.delegate = nil; - return bridge; -} - -+ (instancetype)bridgeForWebView:(WVJB_WEBVIEW_TYPE*)webView WVJBDelegate:(id)delegate handler:(WVJBHandler)handler { - WebViewJavascriptBridge* bridge = [[WebViewJavascriptBridge alloc] init]; - [bridge _platformSpecificSetup:webView webViewDelegate:nil handler:handler]; - [bridge reset]; - bridge.delegate = delegate; return bridge; } @@ -396,17 +387,7 @@ - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *) } else if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:shouldStartLoadWithRequest:navigationType:)]) { return [strongDelegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType]; } else { - if(self.delegate){ - if([self.delegate respondsToSelector:@selector(WVJB_webView:shouldStartLoadWithRequest:navigationType:)]){ - return [self.delegate WVJB_webView:webView - shouldStartLoadWithRequest:request - navigationType:navigationType]; - }else{ - return YES; - } - }else{ - return YES; - } + return YES; } } From 8a60345a424a857473acb044ca712e713fb14e25 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Fri, 23 May 2014 16:24:06 +0200 Subject: [PATCH 033/239] If a response callback gets called with a `nil` response value, then replace that value with `[NSNull null]` instead of `@{}`. This way the javascript will receive a `null` value instead of `{}`. See gh pr #73 --- WebViewJavascriptBridge/WebViewJavascriptBridge.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index 02ff7b2d..e6584568 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -175,7 +175,7 @@ - (void)_flushMessageQueue { if (callbackId) { responseCallback = ^(id responseData) { if (responseData == nil) { - responseData = @{}; + responseData = [NSNull null]; } WVJBMessage* msg = @{ @"responseId":callbackId, @"responseData":responseData }; From 328f341bbdf27fc9ec4f57d2f28512d950fc6651 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Fri, 23 May 2014 16:24:27 +0200 Subject: [PATCH 034/239] Always print the received response value, even if it is null --- Example Apps/ExampleApp.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Example Apps/ExampleApp.html b/Example Apps/ExampleApp.html index bf5b7bc7..d31f1fb1 100644 --- a/Example Apps/ExampleApp.html +++ b/Example Apps/ExampleApp.html @@ -29,7 +29,7 @@

WebViewJavascriptBridge Demo

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 + ':
' + JSON.stringify(data) if (log.children.length) { log.insertBefore(el, log.children[0]) } else { log.appendChild(el) } } From 0c2bf6248a2aa84c435a746b58eb2f02120d3308 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Fri, 23 May 2014 16:25:56 +0200 Subject: [PATCH 035/239] Changelog --- Changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog b/Changelog index 45f82014..ce17addf 100644 --- a/Changelog +++ b/Changelog @@ -1,5 +1,6 @@ intended v4.1.1 + Better JS initialization script (thank @refractalize!) ++ When passing nil to an objc response callback, replace it with [NSNull null] (becomes null in js) v4.1.0 + Allow for sending null/nil data packets From dba418a4d5ac40ffc52bba5637c7a23dfb8c64c4 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Fri, 23 May 2014 16:26:15 +0200 Subject: [PATCH 036/239] bump copyright date --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 1e732703..c44f4d9a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2011-2013 Marcus Westin, Antoine Lagadec +Copyright (c) 2011-2014 Marcus Westin, Antoine Lagadec Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation From da91f9b54c3ae41fd1597f2d2b95bec97ae6295a Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Fri, 23 May 2014 16:26:44 +0200 Subject: [PATCH 037/239] v4.1.1 --- Changelog | 2 +- WebViewJavascriptBridge.podspec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Changelog b/Changelog index ce17addf..f10fbc74 100644 --- a/Changelog +++ b/Changelog @@ -1,4 +1,4 @@ -intended v4.1.1 +v4.1.1 + Better JS initialization script (thank @refractalize!) + When passing nil to an objc response callback, replace it with [NSNull null] (becomes null in js) diff --git a/WebViewJavascriptBridge.podspec b/WebViewJavascriptBridge.podspec index f4d86f8b..0b5172b1 100644 --- a/WebViewJavascriptBridge.podspec +++ b/WebViewJavascriptBridge.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'WebViewJavascriptBridge' - s.version = '4.1.0' + s.version = '4.1.1' s.summary = 'An iOS/OSX bridge for sending messages between Obj-C and JavaScript in UIWebViews/WebViews.' s.homepage = 'http://github.com/marcuswestin/WebViewJavascriptBridge' s.license = { :type => 'MIT', :file => 'LICENSE' } From 48f88cf07d4eea63d15676b913d3d768041189c7 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Fri, 27 Jun 2014 23:51:03 -0400 Subject: [PATCH 038/239] Ensure that the iframe has a source set before appending it to the DOM. This fixes the problems described in github issue #86, where webViewDidStart/FinishLoad were called twice and isLoading was always true. --- WebViewJavascriptBridge/WebViewJavascriptBridge.js.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.js.txt b/WebViewJavascriptBridge/WebViewJavascriptBridge.js.txt index 86303713..12a8700e 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.js.txt +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.js.txt @@ -14,6 +14,7 @@ function _createQueueReadyIframe(doc) { messagingIframe = doc.createElement('iframe') messagingIframe.style.display = 'none' + messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE doc.documentElement.appendChild(messagingIframe) } From 083e876b25dee2c5d22215f21728f49289721252 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Mon, 30 Jun 2014 14:47:35 -0400 Subject: [PATCH 039/239] v4.1.2 --- Changelog | 3 +++ WebViewJavascriptBridge.podspec | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Changelog b/Changelog index f10fbc74..c7ddfdb4 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,6 @@ +v4.1.2 ++ Fix bug: webViewDidStart/FinishLoad were called twice and isLoading was always true (#86) + v4.1.1 + Better JS initialization script (thank @refractalize!) + When passing nil to an objc response callback, replace it with [NSNull null] (becomes null in js) diff --git a/WebViewJavascriptBridge.podspec b/WebViewJavascriptBridge.podspec index 0b5172b1..ac82c5a5 100644 --- a/WebViewJavascriptBridge.podspec +++ b/WebViewJavascriptBridge.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'WebViewJavascriptBridge' - s.version = '4.1.1' + s.version = '4.1.2' s.summary = 'An iOS/OSX bridge for sending messages between Obj-C and JavaScript in UIWebViews/WebViews.' s.homepage = 'http://github.com/marcuswestin/WebViewJavascriptBridge' s.license = { :type => 'MIT', :file => 'LICENSE' } From 4f05b6d88fab7aae34ea13ec09d28de975051e87 Mon Sep 17 00:00:00 2001 From: Pushpak Rangaiah Date: Wed, 9 Jul 2014 22:04:23 +0530 Subject: [PATCH 040/239] Added tag to PodFile git source path Required for PodFile to pass validation and to push updates. --- WebViewJavascriptBridge.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WebViewJavascriptBridge.podspec b/WebViewJavascriptBridge.podspec index ac82c5a5..74a55a8e 100644 --- a/WebViewJavascriptBridge.podspec +++ b/WebViewJavascriptBridge.podspec @@ -6,7 +6,7 @@ Pod::Spec.new do |s| s.license = { :type => 'MIT', :file => 'LICENSE' } s.author = { 'marcuswestin' => 'marcus.westin@gmail.com' } s.requires_arc = true - s.source = { :git => 'https://github.com/marcuswestin/WebViewJavascriptBridge.git' } + s.source = { :git => 'https://github.com/marcuswestin/WebViewJavascriptBridge.git', :tag => s.version.to_s } s.ios.platform = :ios, '5.0' s.osx.platform = :osx s.ios.source_files = 'WebViewJavascriptBridge/*.{h,m}' From 876a1a2e2162955c1da64f96a788b36fadcc8d53 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Thu, 10 Jul 2014 09:20:57 -0400 Subject: [PATCH 041/239] v4.1.3 --- Changelog | 3 +++ WebViewJavascriptBridge.podspec | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Changelog b/Changelog index c7ddfdb4..cf3b7731 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,6 @@ +v4.1.3 ++ Update podspec file with tag + v4.1.2 + Fix bug: webViewDidStart/FinishLoad were called twice and isLoading was always true (#86) diff --git a/WebViewJavascriptBridge.podspec b/WebViewJavascriptBridge.podspec index 74a55a8e..f3345073 100644 --- a/WebViewJavascriptBridge.podspec +++ b/WebViewJavascriptBridge.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'WebViewJavascriptBridge' - s.version = '4.1.2' + s.version = '4.1.3' s.summary = 'An iOS/OSX bridge for sending messages between Obj-C and JavaScript in UIWebViews/WebViews.' s.homepage = 'http://github.com/marcuswestin/WebViewJavascriptBridge' s.license = { :type => 'MIT', :file => 'LICENSE' } From ddb38a16f0db33ed6d678034d53f0fd2e685c314 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Tue, 15 Jul 2014 22:22:55 -0400 Subject: [PATCH 042/239] Update podspec to make `pod trunk push` work as expected --- WebViewJavascriptBridge.podspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WebViewJavascriptBridge.podspec b/WebViewJavascriptBridge.podspec index f3345073..de25a58a 100644 --- a/WebViewJavascriptBridge.podspec +++ b/WebViewJavascriptBridge.podspec @@ -2,11 +2,11 @@ Pod::Spec.new do |s| s.name = 'WebViewJavascriptBridge' s.version = '4.1.3' s.summary = 'An iOS/OSX bridge for sending messages between Obj-C and JavaScript in UIWebViews/WebViews.' - s.homepage = 'http://github.com/marcuswestin/WebViewJavascriptBridge' + s.homepage = 'https://github.com/marcuswestin/WebViewJavascriptBridge' s.license = { :type => 'MIT', :file => 'LICENSE' } s.author = { 'marcuswestin' => 'marcus.westin@gmail.com' } s.requires_arc = true - s.source = { :git => 'https://github.com/marcuswestin/WebViewJavascriptBridge.git', :tag => s.version.to_s } + s.source = { :git => 'https://github.com/marcuswestin/WebViewJavascriptBridge.git', :tag => 'v'+s.version.to_s } s.ios.platform = :ios, '5.0' s.osx.platform = :osx s.ios.source_files = 'WebViewJavascriptBridge/*.{h,m}' From 5b5a6e81fa97addd1f2c033590fb4856a6092f3a Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Tue, 15 Jul 2014 22:29:02 -0400 Subject: [PATCH 043/239] Annotate Changelog with release checklist --- Changelog | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Changelog b/Changelog index cf3b7731..6b7d8faf 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,18 @@ +WebViewJavascriptBridge Changelog +================================= + +Release Checklist +----------------- +- gitu-update +- Note Changelog +- Bump `WebViewJavascriptBridge.podspec` version "X.Y.Z" +- gitm-commit "vX.Y.Z" +- gitt-tag "vX.Y.Z" +- pod trunk push + +Version History +--------------- + v4.1.3 + Update podspec file with tag From 553c77b43461ea21445c85027cdd9e70320398d5 Mon Sep 17 00:00:00 2001 From: Victor Ilyukevich Date: Thu, 17 Jul 2014 01:05:36 +0300 Subject: [PATCH 044/239] Add CareZone to the list who use the library --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5012ff33..8420c7ec 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ WebViewJavascriptBridge is used by a range of companies and projects. This list - Flutterby Labs - JD Media's [鼎盛中华](https://itunes.apple.com/us/app/ding-sheng-zhong-hua/id537273940?mt=8) - Dojo4's [Imbed](http://dojo4.github.io/imbed/) +- [CareZone](https://carezone.com) Setup & Examples (iOS & OSX) ---------------------------- From 40eda37cff0c96d259e56e8faa7542ab523949c7 Mon Sep 17 00:00:00 2001 From: J Spencer Date: Tue, 22 Jul 2014 16:05:59 -0700 Subject: [PATCH 045/239] Removed extra format specifier --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8420c7ec..f36b17b0 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ To use a WebViewJavascriptBridge in your own project: [bridge send:@"Well hello there"]; [bridge send:[NSDictionary dictionaryWithObject:@"Foo" forKey:@"Bar"]]; [bridge send:@"Give me a response, will you?" responseCallback:^(id responseData) { - NSLog(@"ObjC got its response! %@ %@", responseData); + NSLog(@"ObjC got its response! %@", responseData); }]; 4) Finally, set up the javascript side: From 05891801d46ef5f3c049231c5e050f3fb79c2585 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Fri, 1 Aug 2014 12:15:34 -0400 Subject: [PATCH 046/239] Add button in example app to reload webview, to show that reloading the webview works. (See gh issue #94) --- .../ExampleApp-iOS/ExampleAppViewController.m | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/Example Apps/ExampleApp-iOS/ExampleAppViewController.m b/Example Apps/ExampleApp-iOS/ExampleAppViewController.m index c81e136a..3f1f7794 100644 --- a/Example Apps/ExampleApp-iOS/ExampleAppViewController.m +++ b/Example Apps/ExampleApp-iOS/ExampleAppViewController.m @@ -54,17 +54,29 @@ - (void)webViewDidFinishLoad:(UIWebView *)webView { } - (void)renderButtons:(UIWebView*)webView { + UIFont* font = [UIFont fontWithName:@"HelveticaNeue" size:12.0]; + UIButton *messageButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; [messageButton setTitle:@"Send message" forState:UIControlStateNormal]; [messageButton addTarget:self action:@selector(sendMessage:) forControlEvents:UIControlEventTouchUpInside]; [self.view insertSubview:messageButton aboveSubview:webView]; - messageButton.frame = CGRectMake(20, 414, 130, 45); - + messageButton.frame = CGRectMake(10, 414, 100, 35); + messageButton.titleLabel.font = font; + messageButton.backgroundColor = [UIColor colorWithWhite:1 alpha:0.75]; + 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(170, 414, 130, 45); + callbackButton.frame = CGRectMake(110, 414, 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(210, 414, 100, 35); + reloadButton.titleLabel.font = font; } - (void)sendMessage:(id)sender { From 10a214bcb9f1e844ceda9fd7797cdcc1db9dfbab Mon Sep 17 00:00:00 2001 From: Ruslan Skorb Date: Tue, 5 Aug 2014 19:23:06 +0300 Subject: [PATCH 047/239] [Fix] Import for iOS. Important for static libraries that do not import in the Precompiled Header (pch). --- WebViewJavascriptBridge/WebViewJavascriptBridge.h | 1 + 1 file changed, 1 insertion(+) diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.h b/WebViewJavascriptBridge/WebViewJavascriptBridge.h index baa341c8..6b0334b1 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.h +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.h @@ -17,6 +17,7 @@ #define WVJB_WEBVIEW_TYPE WebView #define WVJB_WEBVIEW_DELEGATE_TYPE NSObject #elif defined __IPHONE_OS_VERSION_MAX_ALLOWED + #import #define WVJB_PLATFORM_IOS #define WVJB_WEBVIEW_TYPE UIWebView #define WVJB_WEBVIEW_DELEGATE_TYPE NSObject From 68a37a2287e1590a8d7ab25181db8be4021da9a6 Mon Sep 17 00:00:00 2001 From: Ruslan Skorb Date: Tue, 5 Aug 2014 19:28:21 +0300 Subject: [PATCH 048/239] [Fix] App crash when no handler (_messageHandler) for message from JS. --- WebViewJavascriptBridge/WebViewJavascriptBridge.m | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index e6584568..6dac3016 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -196,6 +196,10 @@ - (void)_flushMessageQueue { } } else { handler = _messageHandler; + if (!handler) { + NSLog(@"WVJB Warning: No handler for message from JS: %@", message); + return responseCallback(@{}); + } } @try { From 9294201de4f4a6759a41e3975c18bc6d7f104562 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Wed, 27 Aug 2014 13:05:10 -0400 Subject: [PATCH 049/239] Simplify no-handler case: throw exception any time there is no handler for a message. Similarly, let runtime exceptions inside handlers bubble up and be caught by webkit instead of simply logging them in WVJB. References GH PR #97 --- .../WebViewJavascriptBridge.m | 20 +++++-------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index 6dac3016..388b0494 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -190,25 +190,15 @@ - (void)_flushMessageQueue { WVJBHandler handler; if (message[@"handlerName"]) { handler = _messageHandlers[message[@"handlerName"]]; - if (!handler) { - NSLog(@"WVJB Warning: No handler for %@", message[@"handlerName"]); - return responseCallback(@{}); - } } else { handler = _messageHandler; - if (!handler) { - NSLog(@"WVJB Warning: No handler for message from JS: %@", message); - return responseCallback(@{}); - } } - - @try { - id data = message[@"data"]; - handler(data, responseCallback); - } - @catch (NSException *exception) { - NSLog(@"WebViewJavascriptBridge: WARNING: objc handler threw. %@ %@", message, exception); + + if (!handler) { + [NSException raise:@"WVJBNoHandlerException" format:@"No handler for message from JS: %@", message]; } + + handler(message[@"data"], responseCallback); } } } From 646def3b11c19b943cc716894f1604d357c7ca09 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Wed, 27 Aug 2014 13:07:10 -0400 Subject: [PATCH 050/239] v4.1.4 --- Changelog | 4 ++++ WebViewJavascriptBridge.podspec | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Changelog b/Changelog index 6b7d8faf..b19f6cfe 100644 --- a/Changelog +++ b/Changelog @@ -13,6 +13,10 @@ Release Checklist Version History --------------- +v4.1.4 ++ Improve how WVJB handles the case when there is no ObjC handler for a message received from js. ++ If an objc handler throws and exception, let it bubble up to the webkit engine instead of catching it in WVJB. + v4.1.3 + Update podspec file with tag diff --git a/WebViewJavascriptBridge.podspec b/WebViewJavascriptBridge.podspec index de25a58a..fbb16a8b 100644 --- a/WebViewJavascriptBridge.podspec +++ b/WebViewJavascriptBridge.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'WebViewJavascriptBridge' - s.version = '4.1.3' + s.version = '4.1.4' s.summary = 'An iOS/OSX bridge for sending messages between Obj-C and JavaScript in UIWebViews/WebViews.' s.homepage = 'https://github.com/marcuswestin/WebViewJavascriptBridge' s.license = { :type => 'MIT', :file => 'LICENSE' } From dcecc1186719bd701a753360478c99835026fa2a Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Wed, 27 Aug 2014 13:10:56 -0400 Subject: [PATCH 051/239] Remove WebViewJavascriptBridge `-reset` method. It is unreliable and should not be used. See GH issue #99 --- Changelog | 3 +++ .../WebViewJavascriptBridge.h | 1 - .../WebViewJavascriptBridge.m | 16 +++++++++------- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Changelog b/Changelog index b19f6cfe..9553abaf 100644 --- a/Changelog +++ b/Changelog @@ -13,6 +13,9 @@ Release Checklist Version History --------------- +Intended v5.0.0 ++ Removed `WebViewJavascriptBridge -reset`. It should never have been exposed as a public API. + v4.1.4 + Improve how WVJB handles the case when there is no ObjC handler for a message received from js. + If an objc handler throws and exception, let it bubble up to the webkit engine instead of catching it in WVJB. diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.h b/WebViewJavascriptBridge/WebViewJavascriptBridge.h index 6b0334b1..9e90829f 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.h +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.h @@ -39,6 +39,5 @@ typedef void (^WVJBHandler)(id data, WVJBResponseCallback responseCallback); - (void)callHandler:(NSString*)handlerName; - (void)callHandler:(NSString*)handlerName data:(id)data; - (void)callHandler:(NSString*)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback; -- (void)reset; @end diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index 388b0494..04ab38ee 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -51,7 +51,6 @@ + (instancetype)bridgeForWebView:(WVJB_WEBVIEW_TYPE*)webView webViewDelegate:(WV { WebViewJavascriptBridge* bridge = [[WebViewJavascriptBridge alloc] init]; [bridge _platformSpecificSetup:webView webViewDelegate:webViewDelegate handler:messageHandler resourceBundle:bundle]; - [bridge reset]; return bridge; } @@ -79,15 +78,18 @@ - (void)registerHandler:(NSString *)handlerName handler:(WVJBHandler)handler { _messageHandlers[handlerName] = [handler copy]; } -- (void)reset { - _startupMessageQueue = [NSMutableArray array]; - _responseCallbacks = [NSMutableDictionary dictionary]; - _uniqueId = 0; -} - /* Platform agnostic internals *****************************/ +- (id)init { + if (self = [super init]) { + _startupMessageQueue = [NSMutableArray array]; + _responseCallbacks = [NSMutableDictionary dictionary]; + _uniqueId = 0; + } + return self; +} + - (void)dealloc { [self _platformSpecificDealloc]; From 5f10f81e9436b0e5f8ef399e56085b3f6f958bb7 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Wed, 27 Aug 2014 13:19:02 -0400 Subject: [PATCH 052/239] Use explicit `WVJB_WEBVIEW_DELEGATE_TYPE` instead of inferred `typeof(_webViewDelegate)`. Should hopefully fix GH issues #81 and #98 --- Changelog | 1 + WebViewJavascriptBridge/WebViewJavascriptBridge.m | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Changelog b/Changelog index 9553abaf..a7fb8544 100644 --- a/Changelog +++ b/Changelog @@ -15,6 +15,7 @@ Version History Intended v5.0.0 + Removed `WebViewJavascriptBridge -reset`. It should never have been exposed as a public API. ++ Fixed compilation in C99 mode v4.1.4 + Improve how WVJB handles the case when there is no ObjC handler for a message received from js. diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index 04ab38ee..dff06e62 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -356,7 +356,7 @@ - (void)webViewDidFinishLoad:(UIWebView *)webView { _startupMessageQueue = nil; } - __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; + __strong WVJB_WEBVIEW_DELEGATE_TYPE* strongDelegate = _webViewDelegate; if (strongDelegate && [strongDelegate respondsToSelector:@selector(webViewDidFinishLoad:)]) { [strongDelegate webViewDidFinishLoad:webView]; } @@ -367,7 +367,7 @@ - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { _numRequestsLoading--; - __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; + __strong WVJB_WEBVIEW_DELEGATE_TYPE* strongDelegate = _webViewDelegate; if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didFailLoadWithError:)]) { [strongDelegate webView:webView didFailLoadWithError:error]; } @@ -376,7 +376,7 @@ - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { if (webView != _webView) { return YES; } NSURL *url = [request URL]; - __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; + __strong WVJB_WEBVIEW_DELEGATE_TYPE* strongDelegate = _webViewDelegate; if ([[url scheme] isEqualToString:kCustomProtocolScheme]) { if ([[url host] isEqualToString:kQueueHasMessage]) { [self _flushMessageQueue]; @@ -396,7 +396,7 @@ - (void)webViewDidStartLoad:(UIWebView *)webView { _numRequestsLoading++; - __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; + __strong WVJB_WEBVIEW_DELEGATE_TYPE* strongDelegate = _webViewDelegate; if (strongDelegate && [strongDelegate respondsToSelector:@selector(webViewDidStartLoad:)]) { [strongDelegate webViewDidStartLoad:webView]; } From f39324d731045a664c90e20926e484b0397e9bbc Mon Sep 17 00:00:00 2001 From: lokimeyburg Date: Tue, 14 Oct 2014 13:51:10 -0700 Subject: [PATCH 053/239] Added the WKWebViewJavascriptBridge class --- .../ExampleApp-iOS.xcodeproj/project.pbxproj | 6 + .../WKWebViewJavascriptBridge.h | 39 +++ .../WKWebViewJavascriptBridge.m | 317 ++++++++++++++++++ 3 files changed, 362 insertions(+) create mode 100644 WebViewJavascriptBridge/WKWebViewJavascriptBridge.h create mode 100644 WebViewJavascriptBridge/WKWebViewJavascriptBridge.m diff --git a/Example Apps/ExampleApp-iOS.xcodeproj/project.pbxproj b/Example Apps/ExampleApp-iOS.xcodeproj/project.pbxproj index 4834adaf..43943042 100644 --- a/Example Apps/ExampleApp-iOS.xcodeproj/project.pbxproj +++ b/Example Apps/ExampleApp-iOS.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 0E8082DB19EDC32300479452 /* WKWebViewJavascriptBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 0E8082DA19EDC32300479452 /* WKWebViewJavascriptBridge.m */; }; 2C1562B5176B9F8400B4AE50 /* WebViewJavascriptBridge.js.txt in Resources */ = {isa = PBXBuildFile; fileRef = 2C1562B4176B9F8400B4AE50 /* WebViewJavascriptBridge.js.txt */; }; 2C1562C0176BA63500B4AE50 /* WebViewJavascriptBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C1562A9176B9F6200B4AE50 /* WebViewJavascriptBridge.m */; }; 2C45CA2C1884AD520002A4E2 /* ExampleAppViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C45CA2B1884AD520002A4E2 /* ExampleAppViewController.m */; }; @@ -21,6 +22,8 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 0E8082D919EDC32300479452 /* WKWebViewJavascriptBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKWebViewJavascriptBridge.h; sourceTree = ""; }; + 0E8082DA19EDC32300479452 /* WKWebViewJavascriptBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WKWebViewJavascriptBridge.m; sourceTree = ""; }; 2C1562A8176B9F6200B4AE50 /* WebViewJavascriptBridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridge.h; sourceTree = ""; }; 2C1562A9176B9F6200B4AE50 /* WebViewJavascriptBridge.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge.m; sourceTree = ""; }; 2C1562B4176B9F8400B4AE50 /* WebViewJavascriptBridge.js.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebViewJavascriptBridge.js.txt; sourceTree = ""; }; @@ -60,6 +63,8 @@ 2C1562B4176B9F8400B4AE50 /* WebViewJavascriptBridge.js.txt */, 2C1562A8176B9F6200B4AE50 /* WebViewJavascriptBridge.h */, 2C1562A9176B9F6200B4AE50 /* WebViewJavascriptBridge.m */, + 0E8082D919EDC32300479452 /* WKWebViewJavascriptBridge.h */, + 0E8082DA19EDC32300479452 /* WKWebViewJavascriptBridge.m */, ); name = WebViewJavascriptBridge; path = ../../WebViewJavascriptBridge; @@ -184,6 +189,7 @@ buildActionMask = 2147483647; files = ( 2C1562C0176BA63500B4AE50 /* WebViewJavascriptBridge.m in Sources */, + 0E8082DB19EDC32300479452 /* WKWebViewJavascriptBridge.m in Sources */, 2C45CA2C1884AD520002A4E2 /* ExampleAppViewController.m in Sources */, 2CA045C217117439006DEE8B /* ExampleAppDelegate.m in Sources */, 2CA045C317117439006DEE8B /* main.m in Sources */, diff --git a/WebViewJavascriptBridge/WKWebViewJavascriptBridge.h b/WebViewJavascriptBridge/WKWebViewJavascriptBridge.h new file mode 100644 index 00000000..0082a462 --- /dev/null +++ b/WebViewJavascriptBridge/WKWebViewJavascriptBridge.h @@ -0,0 +1,39 @@ +// +// WKWebViewJavascriptBridge.h +// +// Created by Loki Meyburg on 10/15/14. +// Copyright (c) 2014 Loki Meyburg. All rights reserved. +// + +#import + +#define kCustomProtocolScheme @"wvjbscheme" +#define kQueueHasMessage @"__WVJB_QUEUE_MESSAGE__" + + +#if defined(__IPHONE_8_0) + #import + #define WVJB_PLATFORM_IOS +// #define WVJB_WEBVIEW_TYPE WKWebView +// #define WVJB_WEBVIEW_DELEGATE_TYPE NSObject +#endif + +typedef void (^WVJBResponseCallback)(id responseData); +typedef void (^WVJBHandler)(id data, WVJBResponseCallback responseCallback); + +@interface WKWebViewJavascriptBridge : NSObject + ++ (instancetype)bridgeForWebView:(WKWebView*)webView handler:(WVJBHandler)handler; ++ (instancetype)bridgeForWebView:(WKWebView*)webView webViewDelegate:(NSObject*)webViewDelegate handler:(WVJBHandler)handler; ++ (instancetype)bridgeForWebView:(WKWebView*)webView webViewDelegate:(NSObject*)webViewDelegate handler:(WVJBHandler)handler resourceBundle:(NSBundle*)bundle; ++ (void)enableLogging; + +- (void)send:(id)message; +- (void)send:(id)message responseCallback:(WVJBResponseCallback)responseCallback; +- (void)registerHandler:(NSString*)handlerName handler:(WVJBHandler)handler; +- (void)callHandler:(NSString*)handlerName; +- (void)callHandler:(NSString*)handlerName data:(id)data; +- (void)callHandler:(NSString*)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback; +- (void)reset; + +@end \ No newline at end of file diff --git a/WebViewJavascriptBridge/WKWebViewJavascriptBridge.m b/WebViewJavascriptBridge/WKWebViewJavascriptBridge.m new file mode 100644 index 00000000..3b877912 --- /dev/null +++ b/WebViewJavascriptBridge/WKWebViewJavascriptBridge.m @@ -0,0 +1,317 @@ +// +// WKWebViewJavascriptBridge.m +// +// Created by Loki Meyburg on 10/15/14. +// Copyright (c) 2014 Loki Meyburg. All rights reserved. +// + +#import "WKWebViewJavascriptBridge.h" + +typedef NSDictionary WVJBMessage; + +@implementation WKWebViewJavascriptBridge { + WKWebView* _webView; + id _webViewDelegate; + NSMutableArray* _startupMessageQueue; + NSMutableDictionary* _responseCallbacks; + NSMutableDictionary* _messageHandlers; + long _uniqueId; + WVJBHandler _messageHandler; + NSBundle *_resourceBundle; + NSUInteger _numRequestsLoading; +} + +/* API + *****/ + +static bool logging = false; ++ (void)enableLogging { logging = true; } + ++ (instancetype)bridgeForWebView:(WKWebView*)webView handler:(WVJBHandler)handler { + return [self bridgeForWebView:webView webViewDelegate:nil handler:handler]; +} + ++ (instancetype)bridgeForWebView:(WKWebView*)webView webViewDelegate:(NSObject*)webViewDelegate handler:(WVJBHandler)messageHandler { + return [self bridgeForWebView:webView webViewDelegate:webViewDelegate handler:messageHandler resourceBundle:nil]; +} + ++ (instancetype)bridgeForWebView:(WKWebView*)webView webViewDelegate:(NSObject*)webViewDelegate handler:(WVJBHandler)messageHandler resourceBundle:(NSBundle*)bundle +{ + WKWebViewJavascriptBridge* bridge = [[WKWebViewJavascriptBridge alloc] init]; + [bridge _platformSpecificSetup:webView webViewDelegate:webViewDelegate handler:messageHandler resourceBundle:bundle]; + [bridge reset]; + return bridge; +} + +- (void)send:(id)data { + [self send:data responseCallback:nil]; +} + +- (void)send:(id)data responseCallback:(WVJBResponseCallback)responseCallback { + [self _sendData:data responseCallback:responseCallback handlerName:nil]; +} + +- (void)callHandler:(NSString *)handlerName { + [self callHandler:handlerName data:nil responseCallback:nil]; +} + +- (void)callHandler:(NSString *)handlerName data:(id)data { + [self callHandler:handlerName data:data responseCallback:nil]; +} + +- (void)callHandler:(NSString *)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback { + [self _sendData:data responseCallback:responseCallback handlerName:handlerName]; +} + +- (void)registerHandler:(NSString *)handlerName handler:(WVJBHandler)handler { + _messageHandlers[handlerName] = [handler copy]; +} + +- (void)reset { + _startupMessageQueue = [NSMutableArray array]; + _responseCallbacks = [NSMutableDictionary dictionary]; + _uniqueId = 0; +} + +/* Internals + ***********/ + +- (void)dealloc { + [self _platformSpecificDealloc]; + + _webView = nil; + _webViewDelegate = nil; + _startupMessageQueue = nil; + _responseCallbacks = nil; + _messageHandlers = nil; + _messageHandler = nil; +} + +- (void)_sendData:(id)data responseCallback:(WVJBResponseCallback)responseCallback handlerName:(NSString*)handlerName { + NSMutableDictionary* message = [NSMutableDictionary dictionary]; + + if (data) { + message[@"data"] = data; + } + + if (responseCallback) { + NSString* callbackId = [NSString stringWithFormat:@"objc_cb_%ld", ++_uniqueId]; + _responseCallbacks[callbackId] = [responseCallback copy]; + message[@"callbackId"] = callbackId; + } + + if (handlerName) { + message[@"handlerName"] = handlerName; + } + [self _queueMessage:message]; +} + +- (void)_queueMessage:(WVJBMessage*)message { + if (_startupMessageQueue) { + [_startupMessageQueue addObject:message]; + } else { + [self _dispatchMessage:message]; + } +} + +- (void)_dispatchMessage:(WVJBMessage*)message { + NSString *messageJSON = [self _serializeMessage:message]; + [self _log:@"SEND" json:messageJSON]; + messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"]; + messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""]; + messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\'" withString:@"\\\'"]; + messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"]; + messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\r" withString:@"\\r"]; + messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\f" withString:@"\\f"]; + messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\u2028" withString:@"\\u2028"]; + messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\u2029" withString:@"\\u2029"]; + + NSString* javascriptCommand = [NSString stringWithFormat:@"WebViewJavascriptBridge._handleMessageFromObjC('%@');", messageJSON]; + if ([[NSThread currentThread] isMainThread]) { + [_webView evaluateJavaScript:javascriptCommand completionHandler:nil]; + } else { + dispatch_sync(dispatch_get_main_queue(), ^{ + [_webView evaluateJavaScript:javascriptCommand completionHandler:nil]; + }); + } +} + +- (void)_flushMessageQueue:(NSString *)messageQueueString{ + id messages = [self _deserializeMessageJSON:messageQueueString]; + if (![messages isKindOfClass:[NSArray class]]) { + NSLog(@"WKWebViewJavascriptBridge: WARNING: Invalid %@ received: %@", [messages class], messages); + return; + } + for (WVJBMessage* message in messages) { + if (![message isKindOfClass:[WVJBMessage class]]) { + NSLog(@"WKWebViewJavascriptBridge: WARNING: Invalid %@ received: %@", [message class], message); + continue; + } + [self _log:@"RCVD" json:message]; + + NSString* responseId = message[@"responseId"]; + if (responseId) { + WVJBResponseCallback responseCallback = _responseCallbacks[responseId]; + responseCallback(message[@"responseData"]); + [_responseCallbacks removeObjectForKey:responseId]; + } else { + WVJBResponseCallback responseCallback = NULL; + NSString* callbackId = message[@"callbackId"]; + if (callbackId) { + responseCallback = ^(id responseData) { + if (responseData == nil) { + responseData = [NSNull null]; + } + + WVJBMessage* msg = @{ @"responseId":callbackId, @"responseData":responseData }; + [self _queueMessage:msg]; + }; + } else { + responseCallback = ^(id ignoreResponseData) { + // Do nothing + }; + } + + WVJBHandler handler; + if (message[@"handlerName"]) { + handler = _messageHandlers[message[@"handlerName"]]; + } else { + handler = _messageHandler; + } + + if (!handler) { + [NSException raise:@"WVJBNoHandlerException" format:@"No handler for message from JS: %@", message]; + } + + handler(message[@"data"], responseCallback); + } + } +} + +- (NSString *)_serializeMessage:(id)message { + return [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:message options:0 error:nil] encoding:NSUTF8StringEncoding]; +} + +- (NSArray*)_deserializeMessageJSON:(NSString *)messageJSON { + return [NSJSONSerialization JSONObjectWithData:[messageJSON dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:nil]; +} + +- (void)_log:(NSString *)action json:(id)json { + if (!logging) { return; } + if (![json isKindOfClass:[NSString class]]) { + json = [self _serializeMessage:json]; + } + if ([json length] > 500) { + NSLog(@"WVJB %@: %@ [...]", action, [json substringToIndex:500]); + } else { + NSLog(@"WVJB %@: %@", action, json); + } +} + + + + +/* WKWebView Specific Internals + ******************************/ + +- (void) _platformSpecificSetup:(WKWebView*)webView webViewDelegate:(id)webViewDelegate handler:(WVJBHandler)messageHandler resourceBundle:(NSBundle*)bundle{ + _messageHandler = messageHandler; + _webView = webView; + _webViewDelegate = webViewDelegate; + _messageHandlers = [NSMutableDictionary dictionary]; + _webView.navigationDelegate = self; + _resourceBundle = bundle; +} + +- (void) _platformSpecificDealloc { + _webView.navigationDelegate = nil; +} + + +- (void)WKFlushMessageQueue { + [_webView evaluateJavaScript:@"WebViewJavascriptBridge._fetchQueue();" completionHandler:^(NSString* result, NSError* error) { + [self _flushMessageQueue:result]; + }]; +} + +- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation +{ + if (webView != _webView) { return; } + + _numRequestsLoading--; + + if (_numRequestsLoading == 0) { + + [webView evaluateJavaScript:@"typeof WebViewJavascriptBridge == \'object\';" completionHandler:^(NSString *result, NSError *error) { + if(![result boolValue]){ + NSBundle *bundle = _resourceBundle ? _resourceBundle : [NSBundle mainBundle]; + NSString *filePath = [bundle pathForResource:@"WebViewJavascriptBridge.js" ofType:@"txt"]; + NSString *js = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; + [webView evaluateJavaScript:js completionHandler:nil]; + } + }]; + } + + if (_startupMessageQueue) { + for (id queuedMessage in _startupMessageQueue) { + [self _dispatchMessage:queuedMessage]; + } + _startupMessageQueue = nil; + } + + __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; + if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didFinishNavigation:)]) { + [strongDelegate webView:webView didFinishNavigation:navigation]; + } +} + + +- (void)webView:(WKWebView *)webView +decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction +decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { + if (webView != _webView) { return; } + NSURL *url = navigationAction.request.URL; + __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; + if ([[url scheme] isEqualToString:kCustomProtocolScheme]) { + if ([[url host] isEqualToString:kQueueHasMessage]) { + [self WKFlushMessageQueue]; + } else { + NSLog(@"WKWebViewJavascriptBridge: WARNING: Received unknown WKWebViewJavascriptBridge command %@://%@", kCustomProtocolScheme, [url path]); + } + [webView stopLoading]; + } + + if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:decidePolicyForNavigationAction:decisionHandler:)]) { + [_webViewDelegate webView:webView decidePolicyForNavigationAction:navigationAction decisionHandler:decisionHandler]; + } +} + +- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation { + if (webView != _webView) { return; } + + _numRequestsLoading++; + + __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; + if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didStartProvisionalNavigation:)]) { + [strongDelegate webView:webView didStartProvisionalNavigation:navigation]; + } +} + + +- (void)webView:(WKWebView *)webView +didFailNavigation:(WKNavigation *)navigation + withError:(NSError *)error { + + if (webView != _webView) { return; } + + _numRequestsLoading--; + + __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; + if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didFailNavigation:withError:)]) { + [strongDelegate webView:webView didFailNavigation:navigation withError:error]; + } +} + + + +@end From b535dc2662d06a64bfd2b93739773d155248b7f3 Mon Sep 17 00:00:00 2001 From: lokimeyburg Date: Tue, 14 Oct 2014 17:17:58 -0700 Subject: [PATCH 054/239] Updated the example app to use WKWebView --- .../ExampleApp-iOS.xcodeproj/project.pbxproj | 4 ++ .../ExampleApp-iOS/ExampleAppViewController.h | 17 +++++++- .../ExampleApp-iOS/ExampleAppViewController.m | 40 ++++++++++++++----- Example Apps/ExampleApp.html | 1 + .../WKWebViewJavascriptBridge.h | 9 +---- .../WKWebViewJavascriptBridge.m | 2 + 6 files changed, 53 insertions(+), 20 deletions(-) diff --git a/Example Apps/ExampleApp-iOS.xcodeproj/project.pbxproj b/Example Apps/ExampleApp-iOS.xcodeproj/project.pbxproj index 43943042..eaa1ace7 100644 --- a/Example Apps/ExampleApp-iOS.xcodeproj/project.pbxproj +++ b/Example Apps/ExampleApp-iOS.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 0E8082DB19EDC32300479452 /* WKWebViewJavascriptBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 0E8082DA19EDC32300479452 /* WKWebViewJavascriptBridge.m */; }; + 0E8082DD19EDD98700479452 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E8082DC19EDD98700479452 /* WebKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 2C1562B5176B9F8400B4AE50 /* WebViewJavascriptBridge.js.txt in Resources */ = {isa = PBXBuildFile; fileRef = 2C1562B4176B9F8400B4AE50 /* WebViewJavascriptBridge.js.txt */; }; 2C1562C0176BA63500B4AE50 /* WebViewJavascriptBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C1562A9176B9F6200B4AE50 /* WebViewJavascriptBridge.m */; }; 2C45CA2C1884AD520002A4E2 /* ExampleAppViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C45CA2B1884AD520002A4E2 /* ExampleAppViewController.m */; }; @@ -24,6 +25,7 @@ /* Begin PBXFileReference section */ 0E8082D919EDC32300479452 /* WKWebViewJavascriptBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKWebViewJavascriptBridge.h; sourceTree = ""; }; 0E8082DA19EDC32300479452 /* WKWebViewJavascriptBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WKWebViewJavascriptBridge.m; sourceTree = ""; }; + 0E8082DC19EDD98700479452 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; 2C1562A8176B9F6200B4AE50 /* WebViewJavascriptBridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridge.h; sourceTree = ""; }; 2C1562A9176B9F6200B4AE50 /* WebViewJavascriptBridge.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge.m; sourceTree = ""; }; 2C1562B4176B9F8400B4AE50 /* WebViewJavascriptBridge.js.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebViewJavascriptBridge.js.txt; sourceTree = ""; }; @@ -48,6 +50,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 0E8082DD19EDD98700479452 /* WebKit.framework in Frameworks */, 2CEB3EC01602563600548120 /* UIKit.framework in Frameworks */, 2CEB3EC21602563600548120 /* Foundation.framework in Frameworks */, 2CEB3EC41602563600548120 /* CoreGraphics.framework in Frameworks */, @@ -116,6 +119,7 @@ 2CEB3EBE1602563600548120 /* Frameworks */ = { isa = PBXGroup; children = ( + 0E8082DC19EDD98700479452 /* WebKit.framework */, 2CEB3EBF1602563600548120 /* UIKit.framework */, 2CEB3EC11602563600548120 /* Foundation.framework */, 2CEB3EC31602563600548120 /* CoreGraphics.framework */, diff --git a/Example Apps/ExampleApp-iOS/ExampleAppViewController.h b/Example Apps/ExampleApp-iOS/ExampleAppViewController.h index d2e25c2d..96028d55 100644 --- a/Example Apps/ExampleApp-iOS/ExampleAppViewController.h +++ b/Example Apps/ExampleApp-iOS/ExampleAppViewController.h @@ -8,6 +8,21 @@ #import -@interface ExampleAppViewController : UINavigationController + +#if defined(__IPHONE_8_0) + #import + #define EXAMPLE_WEBVIEW_TYPE WKWebView + #define EXAMPLE_WEBVIEW_DELEGATE_TYPE NSObject + #define EXAMPLE_WEBVIEW_DELEGATE_CONTROLLER UINavigationController + #define EXAMPLE_BRIDGE_TYPE WKWebViewJavascriptBridge +#else + #define EXAMPLE_WEBVIEW_TYPE UIWebView + #define EXAMPLE_WEBVIEW_DELEGATE_TYPE NSObject + #define EXAMPLE_WEBVIEW_DELEGATE_CONTROLLER UINavigationController + #define EXAMPLE_BRIDGE_TYPE WebViewJavascriptBridge +#endif + + +@interface ExampleAppViewController : EXAMPLE_WEBVIEW_DELEGATE_CONTROLLER @end diff --git a/Example Apps/ExampleApp-iOS/ExampleAppViewController.m b/Example Apps/ExampleApp-iOS/ExampleAppViewController.m index 3f1f7794..4865326a 100644 --- a/Example Apps/ExampleApp-iOS/ExampleAppViewController.m +++ b/Example Apps/ExampleApp-iOS/ExampleAppViewController.m @@ -7,10 +7,17 @@ // #import "ExampleAppViewController.h" + +#if defined(__IPHONE_8_0) +#import "WKWebViewJavascriptBridge.h" +# else #import "WebViewJavascriptBridge.h" +#endif @interface ExampleAppViewController () -@property WebViewJavascriptBridge* bridge; + +@property EXAMPLE_BRIDGE_TYPE* bridge; + @end @implementation ExampleAppViewController @@ -18,15 +25,26 @@ @implementation ExampleAppViewController - (void)viewWillAppear:(BOOL)animated { if (_bridge) { return; } - UIWebView* webView = [[UIWebView alloc] initWithFrame:self.view.bounds]; - [self.view addSubview:webView]; + #if defined(__IPHONE_8_0) + WKWebView* webView = [[WKWebView alloc] initWithFrame:self.view.bounds]; + webView.navigationDelegate = self; + [self.view addSubview:webView]; + [WKWebViewJavascriptBridge enableLogging]; + _bridge = [WKWebViewJavascriptBridge bridgeForWebView:webView webViewDelegate:self handler:^(id data, WVJBResponseCallback responseCallback) { + NSLog(@"ObjC received message from JS: %@", data); + responseCallback(@"Response for message from ObjC"); + }]; + #else + UIWebView* webView = [[UIWebView alloc] initWithFrame:self.view.bounds]; + [self.view addSubview:webView]; + [WebViewJavascriptBridge enableLogging]; + _bridge = [WebViewJavascriptBridge bridgeForWebView:webView webViewDelegate:self handler:^(id data, WVJBResponseCallback responseCallback) { + NSLog(@"ObjC received message from JS: %@", data); + responseCallback(@"Response for message from ObjC"); + }]; + #endif - [WebViewJavascriptBridge enableLogging]; - - _bridge = [WebViewJavascriptBridge bridgeForWebView:webView webViewDelegate:self handler:^(id data, WVJBResponseCallback responseCallback) { - NSLog(@"ObjC received message from JS: %@", data); - responseCallback(@"Response for message from ObjC"); - }]; + [_bridge registerHandler:@"testObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) { NSLog(@"testObjcCallback called: %@", data); @@ -53,7 +71,7 @@ - (void)webViewDidFinishLoad:(UIWebView *)webView { NSLog(@"webViewDidFinishLoad"); } -- (void)renderButtons:(UIWebView*)webView { +- (void)renderButtons:(EXAMPLE_WEBVIEW_TYPE*)webView { UIFont* font = [UIFont fontWithName:@"HelveticaNeue" size:12.0]; UIButton *messageButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; @@ -92,7 +110,7 @@ - (void)callHandler:(id)sender { }]; } -- (void)loadExamplePage:(UIWebView*)webView { +- (void)loadExamplePage:(EXAMPLE_WEBVIEW_TYPE*)webView { NSString* htmlPath = [[NSBundle mainBundle] pathForResource:@"ExampleApp" ofType:@"html"]; NSString* appHtml = [NSString stringWithContentsOfFile:htmlPath encoding:NSUTF8StringEncoding error:nil]; NSURL *baseURL = [NSURL fileURLWithPath:htmlPath]; diff --git a/Example Apps/ExampleApp.html b/Example Apps/ExampleApp.html index d31f1fb1..4278a8ad 100644 --- a/Example Apps/ExampleApp.html +++ b/Example Apps/ExampleApp.html @@ -1,5 +1,6 @@ +