From 62519d72339a18617498f94d2e568730addaaef9 Mon Sep 17 00:00:00 2001 From: Michael Stringer Date: Fri, 27 Jul 2012 13:11:44 +0100 Subject: [PATCH 001/353] Added basic JS -> ObjC callbacks. These can be registered from ObjC and then called from JS - passing in JSON parameters. --- .gitmodules | 3 + JSONKit | 1 + README.md | 18 +++++- .../project.pbxproj | 22 +++++++ WebViewJavascriptBridge/ExampleAppDelegate.m | 41 +++--------- .../WebViewJavascriptBridge.h | 4 ++ .../WebViewJavascriptBridge.m | 63 +++++++++++++++++-- 7 files changed, 112 insertions(+), 40 deletions(-) create mode 100644 .gitmodules create mode 160000 JSONKit diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..a0aa3c34 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "JSONKit"] + path = JSONKit + url = git://github.com/johnezang/JSONKit.git diff --git a/JSONKit b/JSONKit new file mode 160000 index 00000000..82157634 --- /dev/null +++ b/JSONKit @@ -0,0 +1 @@ +Subproject commit 82157634ca0ca5b6a4a67a194dd11f15d9b72835 diff --git a/README.md b/README.md index c69f3418..303e233f 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,23 @@ See ExampleAppDelegate.* for example code. To use it in your own project: }) WebViewJavascriptBridge.sendMessage('Hello from the javascript') }, false) - + +### Registering callbacks + +You can register Objc blocks and call them from Javascript. In Objc register a block with the JS bridge: + + [self.javascriptBridge registerJavascriptCallback:@"testCallback" withCallback:^(NSDictionary *params){ + NSLog(@"JS callback [testCallback] called with params: %@", params); + }]; + +Then call from Javascript using: + + WebViewJavascriptBridge.callCallback('testCallback', { 'foo': 'bar' }); + +This will result in the following being logged: + + JS callback [testCallback] called with params: { 'foo' = 'bar'; } + ARC --- If you're using ARC in your project, add `-fno-objc-arc` as a compiler flag to the `WebViewJavascriptBridge.m` file. diff --git a/WebViewJavascriptBridge.xcodeproj/project.pbxproj b/WebViewJavascriptBridge.xcodeproj/project.pbxproj index 8e6be248..ad9040eb 100644 --- a/WebViewJavascriptBridge.xcodeproj/project.pbxproj +++ b/WebViewJavascriptBridge.xcodeproj/project.pbxproj @@ -7,6 +7,9 @@ objects = { /* Begin PBXBuildFile section */ + 273AB9BC15C2AFDF00C804E7 /* CHANGELOG.md in Resources */ = {isa = PBXBuildFile; fileRef = 273AB9B815C2AFDF00C804E7 /* CHANGELOG.md */; }; + 273AB9BD15C2AFDF00C804E7 /* JSONKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 273AB9BA15C2AFDF00C804E7 /* JSONKit.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 273AB9BE15C2AFDF00C804E7 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 273AB9BB15C2AFDF00C804E7 /* README.md */; }; 2C1E9EA114099B4600C5C30E /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2C1E9EA014099B4600C5C30E /* UIKit.framework */; }; 2C1E9EA314099B4600C5C30E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2C1E9EA214099B4600C5C30E /* Foundation.framework */; }; 2C1E9EA914099B4600C5C30E /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 2C1E9EA714099B4600C5C30E /* InfoPlist.strings */; }; @@ -16,6 +19,10 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 273AB9B815C2AFDF00C804E7 /* CHANGELOG.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CHANGELOG.md; sourceTree = ""; }; + 273AB9B915C2AFDF00C804E7 /* JSONKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSONKit.h; sourceTree = ""; }; + 273AB9BA15C2AFDF00C804E7 /* JSONKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSONKit.m; sourceTree = ""; }; + 273AB9BB15C2AFDF00C804E7 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.md; sourceTree = ""; }; 2C1E9E9C14099B4600C5C30E /* WebViewJavascriptBridge.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WebViewJavascriptBridge.app; sourceTree = BUILT_PRODUCTS_DIR; }; 2C1E9EA014099B4600C5C30E /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 2C1E9EA214099B4600C5C30E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; @@ -42,6 +49,17 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 273AB9B715C2AFDF00C804E7 /* JSONKit */ = { + isa = PBXGroup; + children = ( + 273AB9B815C2AFDF00C804E7 /* CHANGELOG.md */, + 273AB9B915C2AFDF00C804E7 /* JSONKit.h */, + 273AB9BA15C2AFDF00C804E7 /* JSONKit.m */, + 273AB9BB15C2AFDF00C804E7 /* README.md */, + ); + path = JSONKit; + sourceTree = SOURCE_ROOT; + }; 2C1E9E9114099B4600C5C30E = { isa = PBXGroup; children = ( @@ -75,6 +93,7 @@ 2C66C03D14C787BA0050C940 /* WebViewJavascriptBridge.m */, 2C6D212F143017AF0069FA34 /* ExampleAppDelegate.h */, 2C6D2130143017AF0069FA34 /* ExampleAppDelegate.m */, + 273AB9B715C2AFDF00C804E7 /* JSONKit */, 2C1E9EA514099B4600C5C30E /* Supporting Files */, ); path = WebViewJavascriptBridge; @@ -143,6 +162,8 @@ buildActionMask = 2147483647; files = ( 2C1E9EA914099B4600C5C30E /* InfoPlist.strings in Resources */, + 273AB9BC15C2AFDF00C804E7 /* CHANGELOG.md in Resources */, + 273AB9BE15C2AFDF00C804E7 /* README.md in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -156,6 +177,7 @@ 2C1E9EAB14099B4600C5C30E /* main.m in Sources */, 2C6D2131143017AF0069FA34 /* ExampleAppDelegate.m in Sources */, 2C66C03E14C787BA0050C940 /* WebViewJavascriptBridge.m in Sources */, + 273AB9BD15C2AFDF00C804E7 /* JSONKit.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/WebViewJavascriptBridge/ExampleAppDelegate.m b/WebViewJavascriptBridge/ExampleAppDelegate.m index f7b78c1c..aca81ab5 100644 --- a/WebViewJavascriptBridge/ExampleAppDelegate.m +++ b/WebViewJavascriptBridge/ExampleAppDelegate.m @@ -20,6 +20,12 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( [button addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside]; [self.window insertSubview:button aboveSubview:self.webView]; button.frame = CGRectMake(95, 400, 130, 45); + + // register a callback + [self.javascriptBridge registerJavascriptCallback:@"testCallback" withCallback:^(NSDictionary *params){ + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Javascript Callback" message:[NSString stringWithFormat:@"params: %@", params] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; + [alert show]; + }]; [self.javascriptBridge sendMessage:@"Message from ObjC before Webview is complete!" toWebView:self.webView]; @@ -58,43 +64,10 @@ - (void)loadExamplePage { " var button = document.body.appendChild(document.createElement('button'));" " button.innerHTML = 'Click me to send a message to ObjC';" " button.onclick = button.ontouchstart = function() { WebViewJavascriptBridge.sendMessage('hello from JS button'); };" + " WebViewJavascriptBridge.callCallback('testCallback', {'arg1': 'foo', 'arg2': 'bar'});" " }" " " "" baseURL:nil]; } -- (void)applicationWillResignActive:(UIApplication *)application { - /* - Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. - Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. - */ -} - -- (void)applicationDidEnterBackground:(UIApplication *)application { - /* - Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. - If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. - */ -} - -- (void)applicationWillEnterForeground:(UIApplication *)application { - /* - Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. - */ -} - -- (void)applicationDidBecomeActive:(UIApplication *)application { - /* - Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. - */ -} - -- (void)applicationWillTerminate:(UIApplication *)application { - /* - Called when the application is about to terminate. - Save data if appropriate. - See also applicationDidEnterBackground:. - */ -} - @end diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.h b/WebViewJavascriptBridge/WebViewJavascriptBridge.h index 623780d3..74e76eaa 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.h +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.h @@ -22,4 +22,8 @@ /* Reset startup messaging queue */ - (void)resetQueue; +- (void)registerJavascriptCallback:(NSString *)name withCallback:(void (^)(NSDictionary *params))callback; + +- (void)unregisterJavascriptCallback:(NSString *)name; + @end diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index a678a4f0..a611bcbf 100755 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -1,8 +1,10 @@ #import "WebViewJavascriptBridge.h" +#import "JSONKit.h" @interface WebViewJavascriptBridge () @property (nonatomic,strong) NSMutableArray *startupMessageQueue; +@property (nonatomic,strong) NSMutableDictionary *javascriptCallbacks; - (void)_flushMessageQueueFromWebView:(UIWebView *)webView; - (void)_doSendMessage:(NSString*)message toWebView:(UIWebView *)webView; @@ -17,6 +19,9 @@ @implementation WebViewJavascriptBridge static NSString *MESSAGE_SEPARATOR = @"__wvjb_sep__"; static NSString *CUSTOM_PROTOCOL_SCHEME = @"webviewjavascriptbridge"; static NSString *QUEUE_HAS_MESSAGE = @"queuehasmessage"; +static NSString *CALLBACK_MESSAGE_PREFIX = @"__wvjb_cb__"; +static NSString *CALLBACK_FUNCTION_KEY = @"wvjb_function"; +static NSString *CALLBACK_ARGUMENTS_KEY = @"wvjb_arguments"; + (id)javascriptBridgeWithDelegate:(id )delegate { WebViewJavascriptBridge* bridge = [[[WebViewJavascriptBridge alloc] init] autorelease]; @@ -25,9 +30,18 @@ + (id)javascriptBridgeWithDelegate:(id )delegat return bridge; } +- (id)init { + if (self = [super init]) { + self.javascriptCallbacks = [NSMutableDictionary dictionary]; + } + + return self; +} + - (void)dealloc { _delegate = nil; [_startupMessageQueue release]; + [_javascriptCallbacks release]; [super dealloc]; } @@ -41,6 +55,14 @@ - (void)resetQueue { self.startupMessageQueue = [[[NSMutableArray alloc] init] autorelease]; } +- (void)registerJavascriptCallback:(NSString *)name withCallback:(void (^)(NSDictionary *params))callback { + [self.javascriptCallbacks setObject:callback forKey:name]; +} + +- (void)unregisterJavascriptCallback:(NSString *)name { + [self.javascriptCallbacks removeObjectForKey:name]; +} + - (void)_doSendMessage:(NSString *)message toWebView:(UIWebView *)webView { message = [message stringByReplacingOccurrencesOfString:@"\\n" withString:@"\\\\n"]; message = [message stringByReplacingOccurrencesOfString:@"'" withString:@"\\'"]; @@ -51,8 +73,26 @@ - (void)_doSendMessage:(NSString *)message toWebView:(UIWebView *)webView { - (void)_flushMessageQueueFromWebView:(UIWebView *)webView { NSString *messageQueueString = [webView stringByEvaluatingJavaScriptFromString:@"WebViewJavascriptBridge._fetchQueue();"]; NSArray* messages = [messageQueueString componentsSeparatedByString:MESSAGE_SEPARATOR]; - for (id message in messages) { - [self.delegate javascriptBridge:self receivedMessage:message fromWebView:webView]; + for (NSString *message in messages) { + if ([message hasPrefix:CALLBACK_MESSAGE_PREFIX]) { + // should be a JSON encoded callback + NSDictionary *decodedMessage = [[message stringByReplacingOccurrencesOfString:CALLBACK_MESSAGE_PREFIX withString:@""] objectFromJSONString]; + NSString *callbackName = [decodedMessage objectForKey:CALLBACK_FUNCTION_KEY]; + + void (^callback)(NSDictionary *params) = [self.javascriptCallbacks objectForKey:callbackName]; + + if (callback == NULL) { + // don't have a callback - pass to bridge + [self.delegate javascriptBridge:self receivedMessage:message fromWebView:webView]; + } else { + // call the callback + callback([decodedMessage objectForKey:CALLBACK_ARGUMENTS_KEY]); + } + } + else { + // normal message - pass to bridge + [self.delegate javascriptBridge:self receivedMessage:message fromWebView:webView]; + } } } @@ -66,8 +106,11 @@ - (void)webViewDidFinishLoad:(UIWebView *)webView { " _receiveMessageQueue = []," " _MESSAGE_SEPERATOR = '%@'," " _CUSTOM_PROTOCOL_SCHEME = '%@'," - " _QUEUE_HAS_MESSAGE = '%@';" - "" + " _QUEUE_HAS_MESSAGE = '%@'," + " _CALLBACK_MESSAGE_PREFIX = '%@'," + " _CALLBACK_FUNCTION_KEY = '%@'," + " _CALLBACK_ARGUMENTS_KEY = '%@';" + "" "function _createQueueReadyIframe(doc) {" " _readyMessageIframe = doc.createElement('iframe');" " _readyMessageIframe.style.display = 'none';" @@ -78,6 +121,12 @@ - (void)webViewDidFinishLoad:(UIWebView *)webView { " _sendMessageQueue.push(message);" " _readyMessageIframe.src = _CUSTOM_PROTOCOL_SCHEME + '://' + _QUEUE_HAS_MESSAGE;" "};" + "function _callCallback(name, params) {" + " var payload = {};" + " payload[_CALLBACK_FUNCTION_KEY] = name;" + " payload[_CALLBACK_ARGUMENTS_KEY] = params;" + " _sendMessage(_CALLBACK_MESSAGE_PREFIX + JSON.stringify(payload));" + "};" "" "function _fetchQueue() {" " var messageQueueString = _sendMessageQueue.join(_MESSAGE_SEPERATOR);" @@ -103,6 +152,7 @@ - (void)webViewDidFinishLoad:(UIWebView *)webView { "window.WebViewJavascriptBridge = {" " setMessageHandler: _setMessageHandler," " sendMessage: _sendMessage," + " callCallback: _callCallback," " _fetchQueue: _fetchQueue," " _handleMessageFromObjC: _handleMessageFromObjC" "};" @@ -116,7 +166,10 @@ - (void)webViewDidFinishLoad:(UIWebView *)webView { "})();", MESSAGE_SEPARATOR, CUSTOM_PROTOCOL_SCHEME, - QUEUE_HAS_MESSAGE]; + QUEUE_HAS_MESSAGE, + CALLBACK_MESSAGE_PREFIX, + CALLBACK_FUNCTION_KEY, + CALLBACK_ARGUMENTS_KEY]; if (![[webView stringByEvaluatingJavaScriptFromString:@"typeof WebViewJavascriptBridge == 'object'"] isEqualToString:@"true"]) { [webView stringByEvaluatingJavaScriptFromString:js]; From 6f1a55b3bae1b30b1306b34e04ead2bf27c45560 Mon Sep 17 00:00:00 2001 From: Michael Stringer Date: Sat, 28 Jul 2012 12:25:54 +0100 Subject: [PATCH 002/353] Added ObjC -> JS callbacks. These callbacks convert an NSDictionary into a JS object in a similar way to the JS -> ObjC callbacks. --- README.md | 31 +++++++++-- WebViewJavascriptBridge/ExampleAppDelegate.m | 36 +++++++++--- .../WebViewJavascriptBridge.h | 8 ++- .../WebViewJavascriptBridge.m | 55 ++++++++++++++++--- 4 files changed, 107 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 303e233f..d940d1b7 100644 --- a/README.md +++ b/README.md @@ -61,19 +61,40 @@ See ExampleAppDelegate.* for example code. To use it in your own project: ### Registering callbacks -You can register Objc blocks and call them from Javascript. In Objc register a block with the JS bridge: +#### JS to ObjC - [self.javascriptBridge registerJavascriptCallback:@"testCallback" withCallback:^(NSDictionary *params){ - NSLog(@"JS callback [testCallback] called with params: %@", params); +You can register Objective-C blocks and call them from Javascript. In Objective-C register a block with the bridge: + + [self.javascriptBridge registerObjcCallback:@"testObjcCallback" withCallback:^(NSDictionary *params){ + NSLog(@"ObjC callback [testObjcCallback] called with params: %@", params); }]; Then call from Javascript using: - WebViewJavascriptBridge.callCallback('testCallback', { 'foo': 'bar' }); + WebViewJavascriptBridge.callObjcCallback('testObjcCallback', { 'foo': 'bar' }); This will result in the following being logged: - JS callback [testCallback] called with params: { 'foo' = 'bar'; } + ObjC callback [testObjcCallback] called with params: { 'foo' = 'bar'; } + +#### ObjC to JS + +You can also register Javascript functions and call them from Objective-C. In Javascript register a function with the bridge: + + WebViewJavascriptBridge.registerJsCallback('testJsCallback', function(params) { + var el = document.body.appendChild(document.createElement('div')); + el.innerHTML = 'JS [testJsCallback] called with params: ' + JSON.stringify(params); + }); + +Then call from Objective-C using: + + [self.javascriptBridge callJavascriptCallback:@"testJsCallback" + withParams:[NSDictionary dictionaryWithObjectsAndKeys:@"bar", @"foo", nil] + toWebView:self.webView]; + +This will result in a div with the following getting added to the HTML: + + JS [testJsCallback] called with params: {"foo":"bar"} ARC --- diff --git a/WebViewJavascriptBridge/ExampleAppDelegate.m b/WebViewJavascriptBridge/ExampleAppDelegate.m index aca81ab5..1439f43e 100644 --- a/WebViewJavascriptBridge/ExampleAppDelegate.m +++ b/WebViewJavascriptBridge/ExampleAppDelegate.m @@ -15,15 +15,25 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( self.javascriptBridge = [WebViewJavascriptBridge javascriptBridgeWithDelegate:self]; self.webView.delegate = self.javascriptBridge; - UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect]; - [button setTitle:@"Send message" forState:UIControlStateNormal]; - [button addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside]; - [self.window insertSubview:button aboveSubview:self.webView]; - button.frame = CGRectMake(95, 400, 130, 45); + UIButton *messageButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; + [messageButton setTitle:@"Send message" forState:UIControlStateNormal]; + [messageButton addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self.window insertSubview:messageButton aboveSubview:self.webView]; + messageButton.frame = CGRectMake(20, 400, 130, 45); + + UIButton *callbackButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; + [callbackButton setTitle:@"Call callback" forState:UIControlStateNormal]; + [callbackButton addTarget:self action:@selector(callbackPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self.window insertSubview:callbackButton aboveSubview:self.webView]; + callbackButton.frame = CGRectMake(170, 400, 130, 45); // register a callback - [self.javascriptBridge registerJavascriptCallback:@"testCallback" withCallback:^(NSDictionary *params){ - UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Javascript Callback" message:[NSString stringWithFormat:@"params: %@", params] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; + [self.javascriptBridge registerObjcCallback:@"testObjcCallback" withCallback:^(NSDictionary *params){ + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Javascript called Objc callback" + message:[NSString stringWithFormat:@"params: %@", params] + delegate:nil + cancelButtonTitle:@"OK" + otherButtonTitles:nil]; [alert show]; }]; @@ -41,6 +51,12 @@ - (void)buttonPressed:(id)sender { [self.javascriptBridge sendMessage:@"Message from ObjC on normal situations!" toWebView:self.webView]; } +- (void)callbackPressed:(id)sender { + [self.javascriptBridge callJavascriptCallback:@"testJsCallback" + withParams:[NSDictionary dictionaryWithObjectsAndKeys:@"bar", @"foo", nil] + toWebView:self.webView]; +} + - (void)javascriptBridge:(WebViewJavascriptBridge *)bridge receivedMessage:(NSString *)message fromWebView:(UIWebView *)webView { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Message from Javascript" message:message delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alert show]; @@ -64,7 +80,11 @@ - (void)loadExamplePage { " var button = document.body.appendChild(document.createElement('button'));" " button.innerHTML = 'Click me to send a message to ObjC';" " button.onclick = button.ontouchstart = function() { WebViewJavascriptBridge.sendMessage('hello from JS button'); };" - " WebViewJavascriptBridge.callCallback('testCallback', {'arg1': 'foo', 'arg2': 'bar'});" + " WebViewJavascriptBridge.callObjcCallback('testObjcCallback', {'arg1': 'foo', 'arg2': 'bar'});" + " WebViewJavascriptBridge.registerJsCallback('testJsCallback', function(params) {" + " var el = document.body.appendChild(document.createElement('div'));" + " el.innerHTML = 'Callback called foo is [' + params.foo + ']';" + " });" " }" " " "" baseURL:nil]; diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.h b/WebViewJavascriptBridge/WebViewJavascriptBridge.h index 74e76eaa..90ec20df 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.h +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.h @@ -22,8 +22,12 @@ /* Reset startup messaging queue */ - (void)resetQueue; -- (void)registerJavascriptCallback:(NSString *)name withCallback:(void (^)(NSDictionary *params))callback; +- (void)callJavascriptCallback:(NSString *)name toWebView:(UIWebView *)webView; -- (void)unregisterJavascriptCallback:(NSString *)name; +- (void)callJavascriptCallback:(NSString *)name withParams:(NSDictionary *)params toWebView:(UIWebView *)webView; + +- (void)registerObjcCallback:(NSString *)name withCallback:(void (^)(NSDictionary *params))callback; + +- (void)unregisterObjcCallback:(NSString *)name; @end diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index a611bcbf..8734952f 100755 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -47,19 +47,38 @@ - (void)dealloc { } - (void)sendMessage:(NSString *)message toWebView:(UIWebView *)webView { - if (self.startupMessageQueue) { [self.startupMessageQueue addObject:message]; } - else { [self _doSendMessage:message toWebView: webView]; } + if (self.startupMessageQueue) { + [self.startupMessageQueue addObject:message]; + } else { + NSLog(@"msg: %@", message); + [self _doSendMessage:message toWebView: webView]; + } } - (void)resetQueue { self.startupMessageQueue = [[[NSMutableArray alloc] init] autorelease]; } -- (void)registerJavascriptCallback:(NSString *)name withCallback:(void (^)(NSDictionary *params))callback { +- (void)callJavascriptCallback:(NSString *)name toWebView:(UIWebView *)webView { + [self callJavascriptCallback:name withParams:[NSDictionary dictionary] toWebView:webView]; +} + +- (void)callJavascriptCallback:(NSString *)name withParams:(NSDictionary *)params toWebView:(UIWebView *)webView { + NSDictionary *callParams = [NSDictionary dictionaryWithObjectsAndKeys: + name, CALLBACK_FUNCTION_KEY, + params, CALLBACK_ARGUMENTS_KEY, + nil]; + NSString *encodedParams = [callParams JSONString]; + + [self sendMessage:[NSString stringWithFormat:@"%@%@", CALLBACK_MESSAGE_PREFIX, encodedParams] + toWebView:webView]; +} + +- (void)registerObjcCallback:(NSString *)name withCallback:(void (^)(NSDictionary *params))callback { [self.javascriptCallbacks setObject:callback forKey:name]; } -- (void)unregisterJavascriptCallback:(NSString *)name { +- (void)unregisterObjcCallback:(NSString *)name { [self.javascriptCallbacks removeObjectForKey:name]; } @@ -104,6 +123,7 @@ - (void)webViewDidFinishLoad:(UIWebView *)webView { "var _readyMessageIframe," " _sendMessageQueue = []," " _receiveMessageQueue = []," + " _jsCallbacks = []," " _MESSAGE_SEPERATOR = '%@'," " _CUSTOM_PROTOCOL_SCHEME = '%@'," " _QUEUE_HAS_MESSAGE = '%@'," @@ -121,7 +141,7 @@ - (void)webViewDidFinishLoad:(UIWebView *)webView { " _sendMessageQueue.push(message);" " _readyMessageIframe.src = _CUSTOM_PROTOCOL_SCHEME + '://' + _QUEUE_HAS_MESSAGE;" "};" - "function _callCallback(name, params) {" + "function _callObjcCallback(name, params) {" " var payload = {};" " payload[_CALLBACK_FUNCTION_KEY] = name;" " payload[_CALLBACK_ARGUMENTS_KEY] = params;" @@ -144,15 +164,34 @@ - (void)webViewDidFinishLoad:(UIWebView *)webView { " }" "};" "" + "function _registerJsCallback(name, callback) {" + " _jsCallbacks[name] = callback;" + "};" + "" "function _handleMessageFromObjC(message) {" - " if (_receiveMessageQueue) { _receiveMessageQueue.push(message); }" - " else { WebViewJavascriptBridge._messageHandler(message); }" + " if (_receiveMessageQueue) {" + " _receiveMessageQueue.push(message);" + " } else if (message.indexOf(_CALLBACK_MESSAGE_PREFIX) == 0) {" + " var payload = message.replace(_CALLBACK_MESSAGE_PREFIX, '');" + " var parsedPayload = JSON.parse(payload);" + " var callbackName = parsedPayload[_CALLBACK_FUNCTION_KEY];" + " var callback = _jsCallbacks[callbackName];" + "" + " if (callback) {" + " callback(parsedPayload[_CALLBACK_ARGUMENTS_KEY]);" + " } else {" + " WebViewJavascriptBridge._messageHandler(message);" + " }" + " } else {" + " WebViewJavascriptBridge._messageHandler(message);" + " }" "};" "" "window.WebViewJavascriptBridge = {" " setMessageHandler: _setMessageHandler," " sendMessage: _sendMessage," - " callCallback: _callCallback," + " callObjcCallback: _callObjcCallback," + " registerJsCallback: _registerJsCallback," " _fetchQueue: _fetchQueue," " _handleMessageFromObjC: _handleMessageFromObjC" "};" From 5f69cd0d9583f20f3738f95d7ab2a715a8c2fd33 Mon Sep 17 00:00:00 2001 From: Michael Stringer Date: Sat, 28 Jul 2012 23:06:15 +0100 Subject: [PATCH 003/353] Switched to NSJSONSerialization. JSONKit can be used by adding the USE_JSONKIT preprocessor macro. --- .gitmodules | 3 --- JSONKit | 1 - README.md | 2 ++ .../project.pbxproj | 22 ------------------- WebViewJavascriptBridge/ExampleAppDelegate.m | 15 +++++++++---- .../WebViewJavascriptBridge.m | 18 +++++++++++++-- 6 files changed, 29 insertions(+), 32 deletions(-) delete mode 100644 .gitmodules delete mode 160000 JSONKit diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index a0aa3c34..00000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "JSONKit"] - path = JSONKit - url = git://github.com/johnezang/JSONKit.git diff --git a/JSONKit b/JSONKit deleted file mode 160000 index 82157634..00000000 --- a/JSONKit +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 82157634ca0ca5b6a4a67a194dd11f15d9b72835 diff --git a/README.md b/README.md index d940d1b7..f427a4b9 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,8 @@ See ExampleAppDelegate.* for example code. To use it in your own project: ### Registering callbacks +The JS to ObjC and ObjC to JS callbacks use `NSJSONSerialization` to convert to/from JSON. If you need iOS 4 support then you can use [JSONKit](https://github.com/johnezang/JSONKit/) by adding `USE_JSONKIT` to the preprocessor macros for your project (you will need to include JSONKit in your project). + #### JS to ObjC You can register Objective-C blocks and call them from Javascript. In Objective-C register a block with the bridge: diff --git a/WebViewJavascriptBridge.xcodeproj/project.pbxproj b/WebViewJavascriptBridge.xcodeproj/project.pbxproj index ad9040eb..8e6be248 100644 --- a/WebViewJavascriptBridge.xcodeproj/project.pbxproj +++ b/WebViewJavascriptBridge.xcodeproj/project.pbxproj @@ -7,9 +7,6 @@ objects = { /* Begin PBXBuildFile section */ - 273AB9BC15C2AFDF00C804E7 /* CHANGELOG.md in Resources */ = {isa = PBXBuildFile; fileRef = 273AB9B815C2AFDF00C804E7 /* CHANGELOG.md */; }; - 273AB9BD15C2AFDF00C804E7 /* JSONKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 273AB9BA15C2AFDF00C804E7 /* JSONKit.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - 273AB9BE15C2AFDF00C804E7 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 273AB9BB15C2AFDF00C804E7 /* README.md */; }; 2C1E9EA114099B4600C5C30E /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2C1E9EA014099B4600C5C30E /* UIKit.framework */; }; 2C1E9EA314099B4600C5C30E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2C1E9EA214099B4600C5C30E /* Foundation.framework */; }; 2C1E9EA914099B4600C5C30E /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 2C1E9EA714099B4600C5C30E /* InfoPlist.strings */; }; @@ -19,10 +16,6 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 273AB9B815C2AFDF00C804E7 /* CHANGELOG.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CHANGELOG.md; sourceTree = ""; }; - 273AB9B915C2AFDF00C804E7 /* JSONKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSONKit.h; sourceTree = ""; }; - 273AB9BA15C2AFDF00C804E7 /* JSONKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSONKit.m; sourceTree = ""; }; - 273AB9BB15C2AFDF00C804E7 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.md; sourceTree = ""; }; 2C1E9E9C14099B4600C5C30E /* WebViewJavascriptBridge.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WebViewJavascriptBridge.app; sourceTree = BUILT_PRODUCTS_DIR; }; 2C1E9EA014099B4600C5C30E /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 2C1E9EA214099B4600C5C30E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; @@ -49,17 +42,6 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 273AB9B715C2AFDF00C804E7 /* JSONKit */ = { - isa = PBXGroup; - children = ( - 273AB9B815C2AFDF00C804E7 /* CHANGELOG.md */, - 273AB9B915C2AFDF00C804E7 /* JSONKit.h */, - 273AB9BA15C2AFDF00C804E7 /* JSONKit.m */, - 273AB9BB15C2AFDF00C804E7 /* README.md */, - ); - path = JSONKit; - sourceTree = SOURCE_ROOT; - }; 2C1E9E9114099B4600C5C30E = { isa = PBXGroup; children = ( @@ -93,7 +75,6 @@ 2C66C03D14C787BA0050C940 /* WebViewJavascriptBridge.m */, 2C6D212F143017AF0069FA34 /* ExampleAppDelegate.h */, 2C6D2130143017AF0069FA34 /* ExampleAppDelegate.m */, - 273AB9B715C2AFDF00C804E7 /* JSONKit */, 2C1E9EA514099B4600C5C30E /* Supporting Files */, ); path = WebViewJavascriptBridge; @@ -162,8 +143,6 @@ buildActionMask = 2147483647; files = ( 2C1E9EA914099B4600C5C30E /* InfoPlist.strings in Resources */, - 273AB9BC15C2AFDF00C804E7 /* CHANGELOG.md in Resources */, - 273AB9BE15C2AFDF00C804E7 /* README.md in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -177,7 +156,6 @@ 2C1E9EAB14099B4600C5C30E /* main.m in Sources */, 2C6D2131143017AF0069FA34 /* ExampleAppDelegate.m in Sources */, 2C66C03E14C787BA0050C940 /* WebViewJavascriptBridge.m in Sources */, - 273AB9BD15C2AFDF00C804E7 /* JSONKit.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/WebViewJavascriptBridge/ExampleAppDelegate.m b/WebViewJavascriptBridge/ExampleAppDelegate.m index 1439f43e..7540b4b7 100644 --- a/WebViewJavascriptBridge/ExampleAppDelegate.m +++ b/WebViewJavascriptBridge/ExampleAppDelegate.m @@ -29,8 +29,8 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( // register a callback [self.javascriptBridge registerObjcCallback:@"testObjcCallback" withCallback:^(NSDictionary *params){ - UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Javascript called Objc callback" - message:[NSString stringWithFormat:@"params: %@", params] + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"ObjC callback called" + message:[NSString stringWithFormat:@"Foo: %@", [params objectForKey:@"foo"]] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; @@ -77,13 +77,20 @@ - (void)loadExamplePage { " el.innerHTML = message;" " });" " WebViewJavascriptBridge.sendMessage('hello from the JS');" + "" " var button = document.body.appendChild(document.createElement('button'));" " button.innerHTML = 'Click me to send a message to ObjC';" " button.onclick = button.ontouchstart = function() { WebViewJavascriptBridge.sendMessage('hello from JS button'); };" - " WebViewJavascriptBridge.callObjcCallback('testObjcCallback', {'arg1': 'foo', 'arg2': 'bar'});" + "" + " document.body.appendChild(document.createElement('br'));" + "" + " var callbackButton = document.body.appendChild(document.createElement('button'));" + " callbackButton.innerHTML = 'Click me to call ObjC callback';" + " callbackButton.onclick = button.ontouchstart = function() { WebViewJavascriptBridge.callObjcCallback('testObjcCallback', {'foo': 'bar'}); };" + "" " WebViewJavascriptBridge.registerJsCallback('testJsCallback', function(params) {" " var el = document.body.appendChild(document.createElement('div'));" - " el.innerHTML = 'Callback called foo is [' + params.foo + ']';" + " el.innerHTML = 'JS Callback called foo is [' + params.foo + ']';" " });" " }" " " diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index 8734952f..97e4f20b 100755 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -1,5 +1,8 @@ #import "WebViewJavascriptBridge.h" + +#ifdef USE_JSONKIT #import "JSONKit.h" +#endif @interface WebViewJavascriptBridge () @@ -50,7 +53,6 @@ - (void)sendMessage:(NSString *)message toWebView:(UIWebView *)webView { if (self.startupMessageQueue) { [self.startupMessageQueue addObject:message]; } else { - NSLog(@"msg: %@", message); [self _doSendMessage:message toWebView: webView]; } } @@ -68,7 +70,12 @@ - (void)callJavascriptCallback:(NSString *)name withParams:(NSDictionary *)param name, CALLBACK_FUNCTION_KEY, params, CALLBACK_ARGUMENTS_KEY, nil]; +#ifdef USE_JSONKIT NSString *encodedParams = [callParams JSONString]; +#else + NSString *encodedParams = [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:callParams options:0 error:nil] + encoding:NSUTF8StringEncoding]; +#endif [self sendMessage:[NSString stringWithFormat:@"%@%@", CALLBACK_MESSAGE_PREFIX, encodedParams] toWebView:webView]; @@ -95,7 +102,14 @@ - (void)_flushMessageQueueFromWebView:(UIWebView *)webView { for (NSString *message in messages) { if ([message hasPrefix:CALLBACK_MESSAGE_PREFIX]) { // should be a JSON encoded callback - NSDictionary *decodedMessage = [[message stringByReplacingOccurrencesOfString:CALLBACK_MESSAGE_PREFIX withString:@""] objectFromJSONString]; + NSString *payload = [message stringByReplacingOccurrencesOfString:CALLBACK_MESSAGE_PREFIX withString:@""]; +#ifdef USE_JSONKIT + NSDictionary *decodedMessage = [payload objectFromJSONString]; +#else + NSDictionary *decodedMessage = [NSJSONSerialization JSONObjectWithData:[payload dataUsingEncoding:NSUTF8StringEncoding] + options:0 + error:nil]; +#endif NSString *callbackName = [decodedMessage objectForKey:CALLBACK_FUNCTION_KEY]; void (^callback)(NSDictionary *params) = [self.javascriptCallbacks objectForKey:callbackName]; From 2be22d8c64bd9040469ce05cb176104d5d871924 Mon Sep 17 00:00:00 2001 From: Michael Stringer Date: Sat, 28 Jul 2012 23:28:59 +0100 Subject: [PATCH 004/353] Handle JS callback calls made before page load. JS callback calls made before the page loads fully should now be processed correctly instead of being handled as normal messages. --- README.md | 2 ++ WebViewJavascriptBridge/ExampleAppDelegate.m | 13 ++++++++----- .../WebViewJavascriptBridge.m | 19 +++++++++++++------ 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index f427a4b9..278f5340 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,8 @@ This will result in a div with the following getting added to the HTML: JS [testJsCallback] called with params: {"foo":"bar"} +*Note:* You should register any callbacks before you call `WebViewJavascriptBridge.setMessageHandler` otherwise any callback calls received before the HTML is fully loaded will be delivered as normal messages. + ARC --- If you're using ARC in your project, add `-fno-objc-arc` as a compiler flag to the `WebViewJavascriptBridge.m` file. diff --git a/WebViewJavascriptBridge/ExampleAppDelegate.m b/WebViewJavascriptBridge/ExampleAppDelegate.m index 7540b4b7..5be5e529 100644 --- a/WebViewJavascriptBridge/ExampleAppDelegate.m +++ b/WebViewJavascriptBridge/ExampleAppDelegate.m @@ -38,6 +38,9 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( }]; [self.javascriptBridge sendMessage:@"Message from ObjC before Webview is complete!" toWebView:self.webView]; + [self.javascriptBridge callJavascriptCallback:@"testJsCallback" + withParams:[NSDictionary dictionaryWithObjectsAndKeys:@"before ready", @"foo", nil] + toWebView:self.webView]; [self loadExamplePage]; @@ -72,6 +75,11 @@ - (void)loadExamplePage { " " "" baseURL:nil]; diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index 97e4f20b..5eb64f9e 100755 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -174,7 +174,7 @@ - (void)webViewDidFinishLoad:(UIWebView *)webView { " var receivedMessages = _receiveMessageQueue;" " _receiveMessageQueue = null;" " for (var i=0; i Date: Mon, 30 Jul 2012 16:33:57 -0700 Subject: [PATCH 005/353] Add @stringbean to contributors --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 278f5340..62a17b1d 100644 --- a/README.md +++ b/README.md @@ -110,4 +110,4 @@ Contributors - [@marcuswestin](https://github.com/marcuswestin) Marcus Westin - [@psineur](https://github.com/psineur) Stepan Generalov - [@sergiocampama](https://github.com/sergiocampama) Sergio Campamá - +- [@stringbean](https://github.com/stringbean) Michael Stringer From a019e56c58b9d9db657d0805667ddf5d50a9a417 Mon Sep 17 00:00:00 2001 From: chrismcc Date: Sat, 11 Aug 2012 11:52:08 -0500 Subject: [PATCH 006/353] More README.md cleanup * Added a missing `self.` * Fixed paths to classes. * Spacing cleanup. --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 62a17b1d..0c3133e1 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Usage See ExampleAppDelegate.* for example code. To use it in your own project: -1) Copy `Classes/WebViewJavascriptBridge.h` and `Classes/WebViewJavascriptBridge.m` into your Xcode project +1) Copy `WebViewJavascriptBridge/WebViewJavascriptBridge.h` and `WebViewJavascriptBridge/WebViewJavascriptBridge.m` into your Xcode project 2) Instantiate a UIWebView, a WebViewJavascriptBridge, and set yourself as the bridge's delegate @@ -30,13 +30,13 @@ See ExampleAppDelegate.* for example code. To use it in your own project: { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; - self.webView = [[UIWebView alloc] initWithFrame:self.window.bounds]; - [self.window addSubview:webView]; + self.webView = [[UIWebView alloc] initWithFrame:self.window.bounds]; + [self.window addSubview:self.webView]; self.javascriptBridge = [WebViewJavascriptBridge javascriptBridgeWithDelegate:self]; self.webView.delegate = self.javascriptBridge; - [self.window makeKeyAndVisible]; - return YES; + [self.window makeKeyAndVisible]; + return YES; } - (void)javascriptBridge:(WebViewJavascriptBridge *)bridge receivedMessage:(NSString *)message fromWebView:(UIWebView *)webView From a81b813ea59cd5a242557c191de9ce9e1bbd3ef8 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Sat, 11 Aug 2012 14:14:29 -0700 Subject: [PATCH 007/353] Put the javascript content in a file instead of as a string in the source code --- README.md | 2 +- .../WebViewJavascriptBridge-template.js | 92 ++++++++++++++++++ .../WebViewJavascriptBridge.m | 94 +------------------ 3 files changed, 95 insertions(+), 93 deletions(-) create mode 100644 WebViewJavascriptBridge/WebViewJavascriptBridge-template.js diff --git a/README.md b/README.md index 0c3133e1..625fefdc 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Usage See ExampleAppDelegate.* for example code. To use it in your own project: -1) Copy `WebViewJavascriptBridge/WebViewJavascriptBridge.h` and `WebViewJavascriptBridge/WebViewJavascriptBridge.m` into your Xcode project +1) Copy `WebViewJavascriptBridge/WebViewJavascriptBridge.h`, `WebViewJavascriptBridge/WebViewJavascriptBridge.m` and `WebViewJavascriptBridge/WebViewJavascriptBridge-template.js` into your Xcode project 2) Instantiate a UIWebView, a WebViewJavascriptBridge, and set yourself as the bridge's delegate diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge-template.js b/WebViewJavascriptBridge/WebViewJavascriptBridge-template.js new file mode 100644 index 00000000..e01de3ce --- /dev/null +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge-template.js @@ -0,0 +1,92 @@ +;(function() { + if (window.WebViewJavascriptBridge) { return } + var _readyMessageIframe, + _sendMessageQueue = [], + _receiveMessageQueue = [], + _jsCallbacks = [], + _MESSAGE_SEPERATOR = '%@', + _CUSTOM_PROTOCOL_SCHEME = '%@', + _QUEUE_HAS_MESSAGE = '%@', + _CALLBACK_MESSAGE_PREFIX = '%@', + _CALLBACK_FUNCTION_KEY = '%@', + _CALLBACK_ARGUMENTS_KEY = '%@' + + function _createQueueReadyIframe(doc) { + _readyMessageIframe = doc.createElement('iframe') + _readyMessageIframe.style.display = 'none' + doc.documentElement.appendChild(_readyMessageIframe) + } + + function _sendMessage(message) { + _sendMessageQueue.push(message) + _readyMessageIframe.src = _CUSTOM_PROTOCOL_SCHEME + '://' + _QUEUE_HAS_MESSAGE + } + + function _callObjcCallback(name, params) { + var payload = {} + payload[_CALLBACK_FUNCTION_KEY] = name + payload[_CALLBACK_ARGUMENTS_KEY] = params + _sendMessage(_CALLBACK_MESSAGE_PREFIX + JSON.stringify(payload)) + } + + function _fetchQueue() { + var messageQueueString = _sendMessageQueue.join(_MESSAGE_SEPERATOR) + _sendMessageQueue = [] + return messageQueueString + } + + function _setMessageHandler(messageHandler) { + if (WebViewJavascriptBridge._messageHandler) { return alert('WebViewJavascriptBridge.setMessageHandler called twice') } + WebViewJavascriptBridge._messageHandler = messageHandler + var receivedMessages = _receiveMessageQueue + _receiveMessageQueue = null + for (var i=0; i Date: Sat, 11 Aug 2012 14:14:48 -0700 Subject: [PATCH 008/353] Make ARC compatible again --- WebViewJavascriptBridge/WebViewJavascriptBridge.m | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index d0776130..61a28970 100755 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -27,7 +27,7 @@ @implementation WebViewJavascriptBridge static NSString *CALLBACK_ARGUMENTS_KEY = @"wvjb_arguments"; + (id)javascriptBridgeWithDelegate:(id )delegate { - WebViewJavascriptBridge* bridge = [[[WebViewJavascriptBridge alloc] init] autorelease]; + WebViewJavascriptBridge* bridge = [[WebViewJavascriptBridge alloc] init]; bridge.delegate = delegate; [bridge resetQueue]; return bridge; @@ -43,10 +43,6 @@ - (id)init { - (void)dealloc { _delegate = nil; - [_startupMessageQueue release]; - [_javascriptCallbacks release]; - - [super dealloc]; } - (void)sendMessage:(NSString *)message toWebView:(UIWebView *)webView { @@ -58,7 +54,7 @@ - (void)sendMessage:(NSString *)message toWebView:(UIWebView *)webView { } - (void)resetQueue { - self.startupMessageQueue = [[[NSMutableArray alloc] init] autorelease]; + self.startupMessageQueue = [[NSMutableArray alloc] init]; } - (void)callJavascriptCallback:(NSString *)name toWebView:(UIWebView *)webView { From 7d857f461d1a162361935a9997b4cde6672c1bdb Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Sat, 11 Aug 2012 14:30:29 -0700 Subject: [PATCH 009/353] Ensure that the handling of a message on the javascript side always happens in a timeout - if you send a message back to objc in the same event loop as you received the message in, bad things happen. --- .../WebViewJavascriptBridge-template.js | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge-template.js b/WebViewJavascriptBridge/WebViewJavascriptBridge-template.js index e01de3ce..9971c850 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge-template.js +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge-template.js @@ -50,20 +50,22 @@ } function _dispatchMessageFromObjC(message) { - if (message.indexOf(_CALLBACK_MESSAGE_PREFIX) == 0) { - var payload = message.replace(_CALLBACK_MESSAGE_PREFIX, '') - var parsedPayload = JSON.parse(payload) - var callbackName = parsedPayload[_CALLBACK_FUNCTION_KEY] - var callback = _jsCallbacks[callbackName] + setTimeout(function _timeoutDispatchMessageFromObjC() { + if (message.indexOf(_CALLBACK_MESSAGE_PREFIX) == 0) { + var payload = message.replace(_CALLBACK_MESSAGE_PREFIX, '') + var parsedPayload = JSON.parse(payload) + var callbackName = parsedPayload[_CALLBACK_FUNCTION_KEY] + var callback = _jsCallbacks[callbackName] - if (callback) { - callback(parsedPayload[_CALLBACK_ARGUMENTS_KEY]) + if (callback) { + callback(parsedPayload[_CALLBACK_ARGUMENTS_KEY]) + } else { + WebViewJavascriptBridge._messageHandler(message) + } } else { WebViewJavascriptBridge._messageHandler(message) } - } else { - WebViewJavascriptBridge._messageHandler(message) - } + }) } function _handleMessageFromObjC(message) { From 287384df6c1c052a97a0ba4f3938b7a804e53b82 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Sat, 11 Aug 2012 15:24:36 -0700 Subject: [PATCH 010/353] copy the callback. See https://github.com/marcuswestin/WebViewJavascriptBridge/issues/3 and http://stackoverflow.com/questions/4664804/why-does-the-assignment-of-an-objc-block-have-to-be-copy-not-assign --- WebViewJavascriptBridge/WebViewJavascriptBridge.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index 61a28970..f332acff 100755 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -78,7 +78,7 @@ - (void)callJavascriptCallback:(NSString *)name withParams:(NSDictionary *)param } - (void)registerObjcCallback:(NSString *)name withCallback:(void (^)(NSDictionary *params))callback { - [self.javascriptCallbacks setObject:callback forKey:name]; + [self.javascriptCallbacks setObject:[callback copy] forKey:name]; } - (void)unregisterObjcCallback:(NSString *)name { From 5665a5f8d872dc01e3e3156d6e3d1bde45d36dd2 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Thu, 23 Aug 2012 10:07:17 -0700 Subject: [PATCH 011/353] Fix example app --- WebViewJavascriptBridge.xcodeproj/project.pbxproj | 4 ++++ ...avascriptBridge-template.js => WebViewJavascriptBridge.js} | 0 WebViewJavascriptBridge/WebViewJavascriptBridge.m | 3 ++- 3 files changed, 6 insertions(+), 1 deletion(-) rename WebViewJavascriptBridge/{WebViewJavascriptBridge-template.js => WebViewJavascriptBridge.js} (100%) diff --git a/WebViewJavascriptBridge.xcodeproj/project.pbxproj b/WebViewJavascriptBridge.xcodeproj/project.pbxproj index 8e6be248..26467d67 100644 --- a/WebViewJavascriptBridge.xcodeproj/project.pbxproj +++ b/WebViewJavascriptBridge.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ 2C1E9EAB14099B4600C5C30E /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C1E9EAA14099B4600C5C30E /* main.m */; }; 2C66C03E14C787BA0050C940 /* WebViewJavascriptBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C66C03D14C787BA0050C940 /* WebViewJavascriptBridge.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 2C6D2131143017AF0069FA34 /* ExampleAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C6D2130143017AF0069FA34 /* ExampleAppDelegate.m */; }; + 2C8D041515E699AA0016052D /* WebViewJavascriptBridge.js in Resources */ = {isa = PBXBuildFile; fileRef = 2C8D041415E699AA0016052D /* WebViewJavascriptBridge.js */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -27,6 +28,7 @@ 2C66C03D14C787BA0050C940 /* WebViewJavascriptBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge.m; sourceTree = ""; }; 2C6D212F143017AF0069FA34 /* ExampleAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExampleAppDelegate.h; sourceTree = ""; }; 2C6D2130143017AF0069FA34 /* ExampleAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ExampleAppDelegate.m; sourceTree = ""; }; + 2C8D041415E699AA0016052D /* WebViewJavascriptBridge.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = WebViewJavascriptBridge.js; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -73,6 +75,7 @@ children = ( 2C66C03C14C787BA0050C940 /* WebViewJavascriptBridge.h */, 2C66C03D14C787BA0050C940 /* WebViewJavascriptBridge.m */, + 2C8D041415E699AA0016052D /* WebViewJavascriptBridge.js */, 2C6D212F143017AF0069FA34 /* ExampleAppDelegate.h */, 2C6D2130143017AF0069FA34 /* ExampleAppDelegate.m */, 2C1E9EA514099B4600C5C30E /* Supporting Files */, @@ -143,6 +146,7 @@ buildActionMask = 2147483647; files = ( 2C1E9EA914099B4600C5C30E /* InfoPlist.strings in Resources */, + 2C8D041515E699AA0016052D /* WebViewJavascriptBridge.js in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge-template.js b/WebViewJavascriptBridge/WebViewJavascriptBridge.js similarity index 100% rename from WebViewJavascriptBridge/WebViewJavascriptBridge-template.js rename to WebViewJavascriptBridge/WebViewJavascriptBridge.js diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index f332acff..3f7ff102 100755 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -128,7 +128,8 @@ - (void)_flushMessageQueueFromWebView:(UIWebView *)webView { #pragma mark UIWebViewDelegate - (void)webViewDidFinishLoad:(UIWebView *)webView { - NSString* jsTemplate = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"WebViewJavascriptBridge-template" ofType:@"js"] encoding:NSUTF8StringEncoding error:nil]; + NSString *filePath = [[NSBundle mainBundle] pathForResource:@"WebViewJavascriptBridge" ofType:@"js"]; + NSString *jsTemplate = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; NSString *js = [NSString stringWithFormat:jsTemplate, MESSAGE_SEPARATOR, CUSTOM_PROTOCOL_SCHEME, From 9d0513b0979285f4d51edec4cf6d4184f9db23a0 Mon Sep 17 00:00:00 2001 From: gotomanners Date: Tue, 28 Aug 2012 15:34:33 +0100 Subject: [PATCH 012/353] Fixed typo issue with sendMessage button function being replaced by callbackButton function --- WebViewJavascriptBridge/ExampleAppDelegate.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WebViewJavascriptBridge/ExampleAppDelegate.m b/WebViewJavascriptBridge/ExampleAppDelegate.m index 5be5e529..5eadc141 100644 --- a/WebViewJavascriptBridge/ExampleAppDelegate.m +++ b/WebViewJavascriptBridge/ExampleAppDelegate.m @@ -94,7 +94,7 @@ - (void)loadExamplePage { "" " var callbackButton = document.body.appendChild(document.createElement('button'));" " callbackButton.innerHTML = 'Click me to call ObjC callback';" - " callbackButton.onclick = button.ontouchstart = function() { WebViewJavascriptBridge.callObjcCallback('testObjcCallback', {'foo': 'bar'}); };" + " callbackButton.onclick = callbackButton.ontouchstart = function() { WebViewJavascriptBridge.callObjcCallback('testObjcCallback', {'foo': 'bar'}); };" " }" " " "" baseURL:nil]; From c4479a5e693c70ad321f55c5b410a6d08f5e3871 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Wed, 12 Sep 2012 18:25:55 -0700 Subject: [PATCH 013/353] Always send messages as objects (rather than strings); Make message handler a block rather than a delegate; Implement request/response pattern; --- .../project.pbxproj | 4 + WebViewJavascriptBridge/ExampleApp.html | 44 ++++ WebViewJavascriptBridge/ExampleAppDelegate.h | 3 +- WebViewJavascriptBridge/ExampleAppDelegate.m | 107 +++----- .../WebViewJavascriptBridge.h | 32 +-- .../WebViewJavascriptBridge.js | 133 +++++----- .../WebViewJavascriptBridge.m | 235 +++++++++--------- 7 files changed, 289 insertions(+), 269 deletions(-) create mode 100644 WebViewJavascriptBridge/ExampleApp.html diff --git a/WebViewJavascriptBridge.xcodeproj/project.pbxproj b/WebViewJavascriptBridge.xcodeproj/project.pbxproj index 26467d67..9d6d0804 100644 --- a/WebViewJavascriptBridge.xcodeproj/project.pbxproj +++ b/WebViewJavascriptBridge.xcodeproj/project.pbxproj @@ -14,6 +14,7 @@ 2C66C03E14C787BA0050C940 /* WebViewJavascriptBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C66C03D14C787BA0050C940 /* WebViewJavascriptBridge.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 2C6D2131143017AF0069FA34 /* ExampleAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C6D2130143017AF0069FA34 /* ExampleAppDelegate.m */; }; 2C8D041515E699AA0016052D /* WebViewJavascriptBridge.js in Resources */ = {isa = PBXBuildFile; fileRef = 2C8D041415E699AA0016052D /* WebViewJavascriptBridge.js */; }; + 2CEB3E7D160155CF00548120 /* ExampleApp.html in Resources */ = {isa = PBXBuildFile; fileRef = 2CEB3E7C160155CF00548120 /* ExampleApp.html */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -29,6 +30,7 @@ 2C6D212F143017AF0069FA34 /* ExampleAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExampleAppDelegate.h; sourceTree = ""; }; 2C6D2130143017AF0069FA34 /* ExampleAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ExampleAppDelegate.m; sourceTree = ""; }; 2C8D041415E699AA0016052D /* WebViewJavascriptBridge.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = WebViewJavascriptBridge.js; sourceTree = ""; }; + 2CEB3E7C160155CF00548120 /* ExampleApp.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = ExampleApp.html; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -78,6 +80,7 @@ 2C8D041415E699AA0016052D /* WebViewJavascriptBridge.js */, 2C6D212F143017AF0069FA34 /* ExampleAppDelegate.h */, 2C6D2130143017AF0069FA34 /* ExampleAppDelegate.m */, + 2CEB3E7C160155CF00548120 /* ExampleApp.html */, 2C1E9EA514099B4600C5C30E /* Supporting Files */, ); path = WebViewJavascriptBridge; @@ -147,6 +150,7 @@ files = ( 2C1E9EA914099B4600C5C30E /* InfoPlist.strings in Resources */, 2C8D041515E699AA0016052D /* WebViewJavascriptBridge.js in Resources */, + 2CEB3E7D160155CF00548120 /* ExampleApp.html in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/WebViewJavascriptBridge/ExampleApp.html b/WebViewJavascriptBridge/ExampleApp.html new file mode 100644 index 00000000..7bbbde8b --- /dev/null +++ b/WebViewJavascriptBridge/ExampleApp.html @@ -0,0 +1,44 @@ + + + + +

Javascript Bridge Demo

+ +
+ diff --git a/WebViewJavascriptBridge/ExampleAppDelegate.h b/WebViewJavascriptBridge/ExampleAppDelegate.h index 64112b92..1354ba43 100644 --- a/WebViewJavascriptBridge/ExampleAppDelegate.h +++ b/WebViewJavascriptBridge/ExampleAppDelegate.h @@ -1,12 +1,13 @@ #import #import "WebViewJavascriptBridge.h" -@interface ExampleAppDelegate : UIResponder +@interface ExampleAppDelegate : UIResponder @property (strong, nonatomic) UIWindow *window; @property (strong, nonatomic) UIWebView *webView; @property (strong, nonatomic) WebViewJavascriptBridge *javascriptBridge; +- (void)renderButtons; - (void)loadExamplePage; @end diff --git a/WebViewJavascriptBridge/ExampleAppDelegate.m b/WebViewJavascriptBridge/ExampleAppDelegate.m index 5eadc141..4fc62452 100644 --- a/WebViewJavascriptBridge/ExampleAppDelegate.m +++ b/WebViewJavascriptBridge/ExampleAppDelegate.m @@ -12,92 +12,59 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( self.webView = [[UIWebView alloc] initWithFrame:self.window.bounds]; [self.window addSubview:self.webView]; - self.javascriptBridge = [WebViewJavascriptBridge javascriptBridgeWithDelegate:self]; - self.webView.delegate = self.javascriptBridge; - - UIButton *messageButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; - [messageButton setTitle:@"Send message" forState:UIControlStateNormal]; - [messageButton addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside]; - [self.window insertSubview:messageButton aboveSubview:self.webView]; - messageButton.frame = CGRectMake(20, 400, 130, 45); + self.javascriptBridge = [WebViewJavascriptBridge javascriptBridgeForWebView:self.webView handler:^(id data, WVJBCallback callback) { + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Message from Javascript" message:data delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; + [alert show]; + }]; - UIButton *callbackButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; - [callbackButton setTitle:@"Call callback" forState:UIControlStateNormal]; - [callbackButton addTarget:self action:@selector(callbackPressed:) forControlEvents:UIControlEventTouchUpInside]; - [self.window insertSubview:callbackButton aboveSubview:self.webView]; - callbackButton.frame = CGRectMake(170, 400, 130, 45); + + [self renderButtons]; // register a callback - [self.javascriptBridge registerObjcCallback:@"testObjcCallback" withCallback:^(NSDictionary *params){ - UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"ObjC callback called" - message:[NSString stringWithFormat:@"Foo: %@", [params objectForKey:@"foo"]] - delegate:nil - cancelButtonTitle:@"OK" - otherButtonTitles:nil]; - [alert show]; + [self.javascriptBridge registerHandler:@"testObjcCallback" callback:^(id data, WVJBCallback callback) { + NSLog(@"testObjcCallback called: %@", data); + callback(@"Response from testObjcCallback"); }]; - - [self.javascriptBridge sendMessage:@"Message from ObjC before Webview is complete!" toWebView:self.webView]; - [self.javascriptBridge callJavascriptCallback:@"testJsCallback" - withParams:[NSDictionary dictionaryWithObjectsAndKeys:@"before ready", @"foo", nil] - toWebView:self.webView]; - - [self loadExamplePage]; - - [self.javascriptBridge sendMessage:@"Message 2 from ObjC before Webview is complete!" toWebView:self.webView]; + [self.javascriptBridge send:@"A string sent from ObjC before Webview has loaded."]; + [self.javascriptBridge callHandler:@"testJavascriptHandler" data:[NSDictionary dictionaryWithObject:@"before ready" forKey:@"foo"]]; + + [self loadExamplePage]; + + [self.javascriptBridge send:@"A string sent from ObjC after Webview has loaded."]; + [self.window makeKeyAndVisible]; return YES; } -- (void)buttonPressed:(id)sender { - [self.javascriptBridge sendMessage:@"Message from ObjC on normal situations!" toWebView:self.webView]; +- (void)renderButtons { + UIButton *messageButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; + [messageButton setTitle:@"Send message" forState:UIControlStateNormal]; + [messageButton addTarget:self action:@selector(sendMessage:) forControlEvents:UIControlEventTouchUpInside]; + [self.window insertSubview:messageButton aboveSubview:self.webView]; + messageButton.frame = CGRectMake(20, 400, 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:self.webView]; + callbackButton.frame = CGRectMake(170, 400, 130, 45); } -- (void)callbackPressed:(id)sender { - [self.javascriptBridge callJavascriptCallback:@"testJsCallback" - withParams:[NSDictionary dictionaryWithObjectsAndKeys:@"bar", @"foo", nil] - toWebView:self.webView]; +- (void)sendMessage:(id)sender { + [self.javascriptBridge send:@"A string sent from ObjC to JS"]; } -- (void)javascriptBridge:(WebViewJavascriptBridge *)bridge receivedMessage:(NSString *)message fromWebView:(UIWebView *)webView { - UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Message from Javascript" message:message delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; - [alert show]; +- (void)callHandler:(id)sender { + [self.javascriptBridge callHandler:@"testJavascriptHandler" data:[NSDictionary dictionaryWithObject:@"Hi there, JS!" forKey:@"greetingFromObjC"] responseCallback:^(id data) { + NSLog(@"testJavascriptHandler responded: %@", data); + }]; } - (void)loadExamplePage { - [self.webView loadHTMLString:@"" - "" - "" - " " - "" - "

Javascript Bridge Demo

" - " " - "" baseURL:nil]; + NSString* htmlPath = [[NSBundle mainBundle] pathForResource:@"ExampleApp" ofType:@"html"]; + NSString* appHtml = [NSString stringWithContentsOfFile:htmlPath encoding:NSUTF8StringEncoding error:nil]; + [self.webView loadHTMLString:appHtml baseURL:nil]; } @end diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.h b/WebViewJavascriptBridge/WebViewJavascriptBridge.h index 90ec20df..66270330 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.h +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.h @@ -1,33 +1,21 @@ #import -@class WebViewJavascriptBridge; - -@protocol WebViewJavascriptBridgeDelegate - -- (void)javascriptBridge:(WebViewJavascriptBridge *)bridge receivedMessage:(NSString *)message fromWebView:(UIWebView *)webView; +typedef void (^WVJBCallback)(id data); +typedef void (^WVJBHandler)(id data, WVJBCallback callback); -@end +@class WebViewJavascriptBridge; @interface WebViewJavascriptBridge : NSObject -@property (nonatomic, assign) IBOutlet id delegate; - -/* Create a javascript bridge with the given delegate for handling messages */ -+ (id)javascriptBridgeWithDelegate:(id )delegate; - -/* Send a message to the web view. Make sure that this javascript bridge is the delegate - * of the webview before calling this method (see ExampleAppDelegate.m) */ -- (void)sendMessage:(NSString *)message toWebView:(UIWebView *)webView; - -/* Reset startup messaging queue */ -- (void)resetQueue; - -- (void)callJavascriptCallback:(NSString *)name toWebView:(UIWebView *)webView; ++ (id)javascriptBridgeForWebView:(UIWebView*)webView handler:(WVJBHandler)handler; ++ (id)javascriptBridgeForWebView:(UIWebView*)webView handler:(WVJBHandler)handler webViewDelegate:(id )webViewDelegate; -- (void)callJavascriptCallback:(NSString *)name withParams:(NSDictionary *)params toWebView:(UIWebView *)webView; +- (void)send:(id)message; +- (void)send:(id)message responseCallback:(WVJBCallback)responseCallback; -- (void)registerObjcCallback:(NSString *)name withCallback:(void (^)(NSDictionary *params))callback; +- (void)registerHandler:(NSString*)handlerName callback:(WVJBHandler)handler; -- (void)unregisterObjcCallback:(NSString *)name; +- (void)callHandler:(NSString*)handlerName data:(id)data; +- (void)callHandler:(NSString*)handlerName data:(id)data responseCallback:(WVJBCallback)responseCallback; @end diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.js b/WebViewJavascriptBridge/WebViewJavascriptBridge.js index 9971c850..f518a3e0 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.js +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.js @@ -1,89 +1,104 @@ ;(function() { if (window.WebViewJavascriptBridge) { return } - var _readyMessageIframe, - _sendMessageQueue = [], - _receiveMessageQueue = [], - _jsCallbacks = [], - _MESSAGE_SEPERATOR = '%@', - _CUSTOM_PROTOCOL_SCHEME = '%@', - _QUEUE_HAS_MESSAGE = '%@', - _CALLBACK_MESSAGE_PREFIX = '%@', - _CALLBACK_FUNCTION_KEY = '%@', - _CALLBACK_ARGUMENTS_KEY = '%@' - + var messagingIframe + var sendMessageQueue = [] + var receiveMessageQueue = [] + var messageHandlers = {} + + var MESSAGE_SEPARATOR = '__WVJB_MESSAGE_SEPERATOR__' + var CUSTOM_PROTOCOL_SCHEME = 'wvjbscheme' + var QUEUE_HAS_MESSAGE = '__WVJB_QUEUE_MESSAGE__' + + var responseCallbacks = {} + var uniqueId = 1 + function _createQueueReadyIframe(doc) { - _readyMessageIframe = doc.createElement('iframe') - _readyMessageIframe.style.display = 'none' - doc.documentElement.appendChild(_readyMessageIframe) + messagingIframe = doc.createElement('iframe') + messagingIframe.style.display = 'none' + doc.documentElement.appendChild(messagingIframe) } - function _sendMessage(message) { - _sendMessageQueue.push(message) - _readyMessageIframe.src = _CUSTOM_PROTOCOL_SCHEME + '://' + _QUEUE_HAS_MESSAGE + function init(messageHandler) { + if (WebViewJavascriptBridge._messageHandler) { throw new Error('WebViewJavascriptBridge.init called twice') } + WebViewJavascriptBridge._messageHandler = messageHandler + var receivedMessages = receiveMessageQueue + receiveMessageQueue = null + for (var i=0; i webViewDelegate; +@property (nonatomic, copy) WVJBHandler messageHandler; -- (void)_flushMessageQueueFromWebView:(UIWebView *)webView; -- (void)_doSendMessage:(NSString*)message toWebView:(UIWebView *)webView; +- (void)_flushMessageQueue; +- (void)_queueData:(NSDictionary*)data responseCallback:(WVJBCallback)responseCallback handlerName:(NSString*)handlerName; +- (void)_dispatchMessage:(NSDictionary*)message; @end @implementation WebViewJavascriptBridge -@synthesize delegate = _delegate; -@synthesize startupMessageQueue = _startupMessageQueue; +static NSString *MESSAGE_SEPARATOR = @"__WVJB_MESSAGE_SEPERATOR__"; +static NSString *CUSTOM_PROTOCOL_SCHEME = @"wvjbscheme"; +static NSString *QUEUE_HAS_MESSAGE = @"__WVJB_QUEUE_MESSAGE__"; -static NSString *MESSAGE_SEPARATOR = @"__wvjb_sep__"; -static NSString *CUSTOM_PROTOCOL_SCHEME = @"webviewjavascriptbridge"; -static NSString *QUEUE_HAS_MESSAGE = @"queuehasmessage"; -static NSString *CALLBACK_MESSAGE_PREFIX = @"__wvjb_cb__"; -static NSString *CALLBACK_FUNCTION_KEY = @"wvjb_function"; -static NSString *CALLBACK_ARGUMENTS_KEY = @"wvjb_arguments"; - -+ (id)javascriptBridgeWithDelegate:(id )delegate { - WebViewJavascriptBridge* bridge = [[WebViewJavascriptBridge alloc] init]; - bridge.delegate = delegate; - [bridge resetQueue]; - return bridge; ++ (id)javascriptBridgeForWebView:(UIWebView *)webView handler:(WVJBHandler)handler { + return [self javascriptBridgeForWebView:webView handler:handler webViewDelegate:nil]; } - -- (id)init { - if (self = [super init]) { - self.javascriptCallbacks = [NSMutableDictionary dictionary]; - } - return self; ++ (id)javascriptBridgeForWebView:(UIWebView *)webView handler:(WVJBHandler)messageHandler webViewDelegate:(id)webViewDelegate { + WebViewJavascriptBridge* bridge = [[WebViewJavascriptBridge alloc] init]; + bridge.messageHandler = messageHandler; + bridge.startupMessageQueue = [NSMutableArray array]; + bridge.responseCallbacks = [NSMutableDictionary dictionary]; + bridge.messageHandlers = [NSMutableDictionary dictionary]; + bridge.uniqueId = 0; + bridge.webView = webView; + bridge.webViewDelegate = webViewDelegate; + webView.delegate = bridge; + return bridge; } -- (void)dealloc { - _delegate = nil; +- (void)send:(NSDictionary *)data { + [self send:data responseCallback:nil]; } -- (void)sendMessage:(NSString *)message toWebView:(UIWebView *)webView { - if (self.startupMessageQueue) { - [self.startupMessageQueue addObject:message]; - } else { - [self _doSendMessage:message toWebView: webView]; - } +- (void)send:(NSDictionary *)data responseCallback:(WVJBCallback)responseCallback { + [self _queueData:data responseCallback:responseCallback handlerName:nil]; } -- (void)resetQueue { - self.startupMessageQueue = [[NSMutableArray alloc] init]; +- (void)callHandler:(NSString *)handlerName data:(id)data { + [self callHandler:handlerName data:data responseCallback:nil]; } -- (void)callJavascriptCallback:(NSString *)name toWebView:(UIWebView *)webView { - [self callJavascriptCallback:name withParams:[NSDictionary dictionary] toWebView:webView]; +- (void)callHandler:(NSString *)handlerName data:(id)data responseCallback:(WVJBCallback)responseCallback { + [self _queueData:data responseCallback:responseCallback handlerName:handlerName]; } -- (void)callJavascriptCallback:(NSString *)name withParams:(NSDictionary *)params toWebView:(UIWebView *)webView { - NSDictionary *callParams = [NSDictionary dictionaryWithObjectsAndKeys: - name, CALLBACK_FUNCTION_KEY, - params, CALLBACK_ARGUMENTS_KEY, - nil]; -#ifdef USE_JSONKIT - NSString *encodedParams = [callParams JSONString]; -#else - NSString *encodedParams = [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:callParams options:0 error:nil] - encoding:NSUTF8StringEncoding]; -#endif - - [self sendMessage:[NSString stringWithFormat:@"%@%@", CALLBACK_MESSAGE_PREFIX, encodedParams] - toWebView:webView]; +- (void)registerHandler:(NSString *)handlerName callback:(WVJBHandler)handler { + [self.messageHandlers setObject:handler forKey:handlerName]; } -- (void)registerObjcCallback:(NSString *)name withCallback:(void (^)(NSDictionary *params))callback { - [self.javascriptCallbacks setObject:[callback copy] forKey:name]; -} +- (void)_queueData:(NSDictionary *)data responseCallback:(WVJBCallback)responseCallback handlerName:(NSString*)handlerName { + NSMutableDictionary* message = [NSMutableDictionary dictionaryWithObject:data forKey:@"data"]; + + if (responseCallback) { + NSString* callbackId = [NSString stringWithFormat:@"objc_cb_%d", ++_uniqueId]; + [self.responseCallbacks setObject:responseCallback forKey:callbackId]; + [message setObject:callbackId forKey:@"callbackId"]; + } -- (void)unregisterObjcCallback:(NSString *)name { - [self.javascriptCallbacks removeObjectForKey:name]; + if (handlerName) { + [message setObject:handlerName forKey:@"handlerName"]; + } + + if (self.startupMessageQueue) { + [self.startupMessageQueue addObject:message]; + } else { + [self _dispatchMessage:message]; + } } -- (void)_doSendMessage:(NSString *)message toWebView:(UIWebView *)webView { - message = [message stringByReplacingOccurrencesOfString:@"\\n" withString:@"\\\\n"]; - message = [message stringByReplacingOccurrencesOfString:@"'" withString:@"\\'"]; - message = [message stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""]; - [webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"WebViewJavascriptBridge._handleMessageFromObjC('%@');", message]]; +- (void)_dispatchMessage:(NSDictionary *)message { +#ifdef USE_JSONKIT + NSString *messageJSON = [message JSONString]; +#else + NSString *messageJSON = [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:message options:0 error:nil] encoding:NSUTF8StringEncoding]; +#endif + messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\\n" withString:@"\\\\n"]; + messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"'" withString:@"\\'"]; + messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""]; + [_webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"WebViewJavascriptBridge._handleMessageFromObjC('%@');", messageJSON]]; } -- (void)_flushMessageQueueFromWebView:(UIWebView *)webView { - NSString *messageQueueString = [webView stringByEvaluatingJavaScriptFromString:@"WebViewJavascriptBridge._fetchQueue();"]; +- (void)_flushMessageQueue { + NSString *messageQueueString = [_webView stringByEvaluatingJavaScriptFromString:@"WebViewJavascriptBridge._fetchQueue();"]; NSArray* messages = [messageQueueString componentsSeparatedByString:MESSAGE_SEPARATOR]; - for (NSString *message in messages) { - if ([message hasPrefix:CALLBACK_MESSAGE_PREFIX]) { - // should be a JSON encoded callback - NSString *payload = [message stringByReplacingOccurrencesOfString:CALLBACK_MESSAGE_PREFIX withString:@""]; + for (NSString *messageJSON in messages) { + // normal message - pass to bridge #ifdef USE_JSONKIT - NSDictionary *decodedMessage = [payload objectFromJSONString]; + NSDictionary *message = [payload objectFromJSONString]; #else - NSDictionary *decodedMessage = [NSJSONSerialization JSONObjectWithData:[payload dataUsingEncoding:NSUTF8StringEncoding] - options:0 - error:nil]; + NSDictionary *message = [NSJSONSerialization JSONObjectWithData:[messageJSON dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil]; #endif - NSString *callbackName = [decodedMessage objectForKey:CALLBACK_FUNCTION_KEY]; - - void (^callback)(NSDictionary *params) = [self.javascriptCallbacks objectForKey:callbackName]; - - if (callback == NULL) { - // don't have a callback - pass to bridge - [self.delegate javascriptBridge:self receivedMessage:message fromWebView:webView]; - } else { - // call the callback - callback([decodedMessage objectForKey:CALLBACK_ARGUMENTS_KEY]); - } + WVJBCallback responseCallback = NULL; + if ([message objectForKey:@"callbackId"]) { + __block NSString* responseId = [message objectForKey:@"callbackId"]; + responseCallback = ^(NSDictionary* data) { + NSDictionary* response = [NSDictionary dictionaryWithObjectsAndKeys: responseId, @"responseId", data, @"data", nil]; + [self send:response]; + }; + } + + WVJBHandler handler = self.messageHandler; + if ([message objectForKey:@"handlerName"]) { + handler = [self.messageHandlers objectForKey:[message objectForKey:@"handlerName"]]; + } else if ([message objectForKey:@"responseId"]) { + handler = [self.responseCallbacks objectForKey:[message objectForKey:@"responseId"]]; + } + + @try { + handler([message objectForKey:@"data"], responseCallback); } - else { - // normal message - pass to bridge - [self.delegate javascriptBridge:self receivedMessage:message fromWebView:webView]; + @catch (NSException *exception) { + NSLog(@"WebViewJavascriptBridge: WARNING: handler threw. %@ %@", message, exception); } } } @@ -128,58 +133,54 @@ - (void)_flushMessageQueueFromWebView:(UIWebView *)webView { #pragma mark UIWebViewDelegate - (void)webViewDidFinishLoad:(UIWebView *)webView { - NSString *filePath = [[NSBundle mainBundle] pathForResource:@"WebViewJavascriptBridge" ofType:@"js"]; - NSString *jsTemplate = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; - NSString *js = [NSString stringWithFormat:jsTemplate, - MESSAGE_SEPARATOR, - CUSTOM_PROTOCOL_SCHEME, - QUEUE_HAS_MESSAGE, - CALLBACK_MESSAGE_PREFIX, - CALLBACK_FUNCTION_KEY, - CALLBACK_ARGUMENTS_KEY]; - - if (![[webView stringByEvaluatingJavaScriptFromString:@"typeof WebViewJavascriptBridge == 'object'"] isEqualToString:@"true"]) { - [webView stringByEvaluatingJavaScriptFromString:js]; + if (webView != _webView) { return; } + + if (![[_webView stringByEvaluatingJavaScriptFromString:@"typeof WebViewJavascriptBridge == 'object'"] isEqualToString:@"true"]) { + NSString *filePath = [[NSBundle mainBundle] pathForResource:@"WebViewJavascriptBridge" ofType:@"js"]; + NSString *js = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; + [_webView stringByEvaluatingJavaScriptFromString:js]; } - for (id message in self.startupMessageQueue) { - [self _doSendMessage:message toWebView: webView]; + if (self.startupMessageQueue) { + for (id queuedMessage in self.startupMessageQueue) { + [self _dispatchMessage:queuedMessage]; + } + self.startupMessageQueue = nil; } - - self.startupMessageQueue = nil; - - if(self.delegate != nil && [self.delegate respondsToSelector:@selector(webViewDidFinishLoad:)]) { - [self.delegate webViewDidFinishLoad:webView]; + + if (self.webViewDelegate) { + [self.webViewDelegate webViewDidFinishLoad:webView]; } } - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { - if(self.delegate != nil && [self.delegate respondsToSelector:@selector(webView:didFailLoadWithError:)]) { - [self.delegate webView:webView didFailLoadWithError:error]; + if (webView != _webView) { return; } + if (self.webViewDelegate) { + [self.webViewDelegate webView:_webView didFailLoadWithError:error]; } } - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { + if (webView != _webView) { return YES; } NSURL *url = [request URL]; - if (![[url scheme] isEqualToString:CUSTOM_PROTOCOL_SCHEME]) { - if (self.delegate != nil && [self.delegate respondsToSelector:@selector(webView:shouldStartLoadWithRequest:navigationType:)]) { - return [self.delegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType]; + if ([[url scheme] isEqualToString:CUSTOM_PROTOCOL_SCHEME]) { + if ([[url host] isEqualToString:QUEUE_HAS_MESSAGE]) { + [self _flushMessageQueue]; + } else { + NSLog(@"WebViewJavascriptBridge: WARNING: Received unknown WebViewJavascriptBridge command %@://%@", CUSTOM_PROTOCOL_SCHEME, [url path]); } - return YES; - } - - if ([[url host] isEqualToString:QUEUE_HAS_MESSAGE]) { - [self _flushMessageQueueFromWebView: webView]; + return NO; + } else if (self.webViewDelegate) { + return [self.webViewDelegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType]; } else { - NSLog(@"WebViewJavascriptBridge: WARNING: Received unknown WebViewJavascriptBridge command %@://%@", CUSTOM_PROTOCOL_SCHEME, [url path]); + return YES; } - - return NO; } - (void)webViewDidStartLoad:(UIWebView *)webView { - if(self.delegate != nil && [self.delegate respondsToSelector:@selector(webViewDidStartLoad:)]) { - [self.delegate webViewDidStartLoad:webView]; + if (webView != _webView) { return; } + if (self.webViewDelegate) { + [self.webViewDelegate webViewDidStartLoad:webView]; } } From b56bd0b4c06bc2270c1e13e66ad9b1f4833d9341 Mon Sep 17 00:00:00 2001 From: Valerio Santinelli Date: Thu, 13 Sep 2012 12:08:18 +0200 Subject: [PATCH 014/353] Fixed some missing escaping of parameters when sent as JSON --- WebViewJavascriptBridge/WebViewJavascriptBridge.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index e1bafd0f..8b349e1d 100755 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -89,7 +89,9 @@ - (void)_dispatchMessage:(NSDictionary *)message { #else NSString *messageJSON = [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:message options:0 error:nil] encoding:NSUTF8StringEncoding]; #endif + messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\\\\" withString:@"\\\\\\\\"]; messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\\n" withString:@"\\\\n"]; + messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\\r" withString:@"\\\\r"]; messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"'" withString:@"\\'"]; messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""]; [_webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"WebViewJavascriptBridge._handleMessageFromObjC('%@');", messageJSON]]; From 2c8789be9a660e191ef589d8b39cd9c8eff8ef98 Mon Sep 17 00:00:00 2001 From: Valerio Santinelli Date: Thu, 13 Sep 2012 12:23:05 +0200 Subject: [PATCH 015/353] Fixed a typo when using JSONKIT --- WebViewJavascriptBridge/WebViewJavascriptBridge.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index 8b349e1d..e9cdca2f 100755 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -103,7 +103,7 @@ - (void)_flushMessageQueue { for (NSString *messageJSON in messages) { // normal message - pass to bridge #ifdef USE_JSONKIT - NSDictionary *message = [payload objectFromJSONString]; + NSDictionary *message = [messageJSON objectFromJSONString]; #else NSDictionary *message = [NSJSONSerialization JSONObjectWithData:[messageJSON dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil]; #endif From 6a76196aea4c5b364678578ca0c658b6f2ee93a8 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Thu, 13 Sep 2012 10:37:09 -0700 Subject: [PATCH 016/353] escape according to http://stackoverflow.com/questions/5569794/escape-nsstring-for-javascript-input --- WebViewJavascriptBridge/WebViewJavascriptBridge.m | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index e9cdca2f..f3d7b620 100755 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -89,11 +89,12 @@ - (void)_dispatchMessage:(NSDictionary *)message { #else NSString *messageJSON = [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:message options:0 error:nil] encoding:NSUTF8StringEncoding]; #endif - messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\\\\" withString:@"\\\\\\\\"]; - messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\\n" withString:@"\\\\n"]; - messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\\r" withString:@"\\\\r"]; - messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"'" withString:@"\\'"]; + 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"]; [_webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"WebViewJavascriptBridge._handleMessageFromObjC('%@');", messageJSON]]; } From cc2bb082ce9a272407aea04c81fa1ade44f03801 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Thu, 13 Sep 2012 10:38:14 -0700 Subject: [PATCH 017/353] Add @tanis2000 to contributors --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 625fefdc..4709a25f 100644 --- a/README.md +++ b/README.md @@ -111,3 +111,5 @@ Contributors - [@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 + From 56e4be03f67708ff6c9c84baeb811a2731534582 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Thu, 13 Sep 2012 11:19:58 -0700 Subject: [PATCH 018/353] Make it simpler to setup the bridge - just copy in a single directory as oppposed to three files --- ExampleApp.xcodeproj/project.pbxproj | 289 ++++++++++++++++++ .../ExampleApp-Info.plist | 13 +- .../ExampleApp-Prefix.pch | 2 +- .../ExampleApp.html | 0 .../ExampleAppDelegate.h | 5 +- .../ExampleAppDelegate.m | 31 +- .../en.lproj/InfoPlist.strings | 0 .../main.m | 8 + README.md | 43 ++- .../project.pbxproj | 277 ----------------- .../WebViewJavascriptBridge.h | 1 + ...idge.js => WebViewJavascriptBridge.js.txt} | 0 .../WebViewJavascriptBridge.m | 6 +- 13 files changed, 343 insertions(+), 332 deletions(-) create mode 100644 ExampleApp.xcodeproj/project.pbxproj rename WebViewJavascriptBridge/WebViewJavascriptBridge-Info.plist => ExampleApp/ExampleApp-Info.plist (73%) rename WebViewJavascriptBridge/WebViewJavascriptBridge-Prefix.pch => ExampleApp/ExampleApp-Prefix.pch (65%) rename {WebViewJavascriptBridge => ExampleApp}/ExampleApp.html (100%) rename {WebViewJavascriptBridge => ExampleApp}/ExampleAppDelegate.h (72%) rename {WebViewJavascriptBridge => ExampleApp}/ExampleAppDelegate.m (81%) rename {WebViewJavascriptBridge => ExampleApp}/en.lproj/InfoPlist.strings (100%) rename {WebViewJavascriptBridge => ExampleApp}/main.m (61%) delete mode 100644 WebViewJavascriptBridge.xcodeproj/project.pbxproj rename WebViewJavascriptBridge/{WebViewJavascriptBridge.js => WebViewJavascriptBridge.js.txt} (100%) diff --git a/ExampleApp.xcodeproj/project.pbxproj b/ExampleApp.xcodeproj/project.pbxproj new file mode 100644 index 00000000..678d6cd1 --- /dev/null +++ b/ExampleApp.xcodeproj/project.pbxproj @@ -0,0 +1,289 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 2CEB3EC01602563600548120 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2CEB3EBF1602563600548120 /* UIKit.framework */; }; + 2CEB3EC21602563600548120 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2CEB3EC11602563600548120 /* Foundation.framework */; }; + 2CEB3EC41602563600548120 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2CEB3EC31602563600548120 /* CoreGraphics.framework */; }; + 2CEB3ECA1602563600548120 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 2CEB3EC81602563600548120 /* InfoPlist.strings */; }; + 2CEB3ECC1602563600548120 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CEB3ECB1602563600548120 /* main.m */; }; + 2CEB3ED01602563600548120 /* ExampleAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CEB3ECF1602563600548120 /* ExampleAppDelegate.m */; }; + 2CEB3F5216025A4E00548120 /* WebViewJavascriptBridge.js.txt in Resources */ = {isa = PBXBuildFile; fileRef = 2CEB3F5016025A4E00548120 /* WebViewJavascriptBridge.js.txt */; }; + 2CEB3F5316025A4E00548120 /* WebViewJavascriptBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CEB3F5116025A4E00548120 /* WebViewJavascriptBridge.m */; }; + 2CEB3F5516025A9000548120 /* ExampleApp.html in Resources */ = {isa = PBXBuildFile; fileRef = 2CEB3F5416025A9000548120 /* ExampleApp.html */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 2CEB3EBB1602563600548120 /* ExampleApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ExampleApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 2CEB3EBF1602563600548120 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + 2CEB3EC11602563600548120 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 2CEB3EC31602563600548120 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + 2CEB3EC71602563600548120 /* ExampleApp-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ExampleApp-Info.plist"; sourceTree = ""; }; + 2CEB3EC91602563600548120 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 2CEB3ECB1602563600548120 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 2CEB3ECD1602563600548120 /* ExampleApp-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ExampleApp-Prefix.pch"; sourceTree = ""; }; + 2CEB3ECE1602563600548120 /* ExampleAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ExampleAppDelegate.h; sourceTree = ""; }; + 2CEB3ECF1602563600548120 /* ExampleAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ExampleAppDelegate.m; sourceTree = ""; }; + 2CEB3F4F16025A4E00548120 /* WebViewJavascriptBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridge.h; sourceTree = ""; }; + 2CEB3F5016025A4E00548120 /* WebViewJavascriptBridge.js.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebViewJavascriptBridge.js.txt; sourceTree = ""; }; + 2CEB3F5116025A4E00548120 /* WebViewJavascriptBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge.m; sourceTree = ""; }; + 2CEB3F5416025A9000548120 /* ExampleApp.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = ExampleApp.html; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 2CEB3EB81602563600548120 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 2CEB3EC01602563600548120 /* UIKit.framework in Frameworks */, + 2CEB3EC21602563600548120 /* Foundation.framework in Frameworks */, + 2CEB3EC41602563600548120 /* CoreGraphics.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 2CEB3EB01602563600548120 = { + isa = PBXGroup; + children = ( + 2CEB3EC51602563600548120 /* ExampleApp */, + 2CEB3EBE1602563600548120 /* Frameworks */, + 2CEB3EBC1602563600548120 /* Products */, + ); + sourceTree = ""; + }; + 2CEB3EBC1602563600548120 /* Products */ = { + isa = PBXGroup; + children = ( + 2CEB3EBB1602563600548120 /* ExampleApp.app */, + ); + name = Products; + sourceTree = ""; + }; + 2CEB3EBE1602563600548120 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 2CEB3EBF1602563600548120 /* UIKit.framework */, + 2CEB3EC11602563600548120 /* Foundation.framework */, + 2CEB3EC31602563600548120 /* CoreGraphics.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 2CEB3EC51602563600548120 /* ExampleApp */ = { + isa = PBXGroup; + children = ( + 2CEB3ECE1602563600548120 /* ExampleAppDelegate.h */, + 2CEB3ECF1602563600548120 /* ExampleAppDelegate.m */, + 2CEB3F5416025A9000548120 /* ExampleApp.html */, + 2CEB3F4E16025A4E00548120 /* WebViewJavascriptBridge */, + 2CEB3EC61602563600548120 /* Supporting Files */, + ); + path = ExampleApp; + sourceTree = ""; + }; + 2CEB3EC61602563600548120 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 2CEB3EC71602563600548120 /* ExampleApp-Info.plist */, + 2CEB3EC81602563600548120 /* InfoPlist.strings */, + 2CEB3ECB1602563600548120 /* main.m */, + 2CEB3ECD1602563600548120 /* ExampleApp-Prefix.pch */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 2CEB3F4E16025A4E00548120 /* WebViewJavascriptBridge */ = { + isa = PBXGroup; + children = ( + 2CEB3F4F16025A4E00548120 /* WebViewJavascriptBridge.h */, + 2CEB3F5016025A4E00548120 /* WebViewJavascriptBridge.js.txt */, + 2CEB3F5116025A4E00548120 /* WebViewJavascriptBridge.m */, + ); + path = WebViewJavascriptBridge; + sourceTree = SOURCE_ROOT; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 2CEB3EBA1602563600548120 /* ExampleApp */ = { + isa = PBXNativeTarget; + buildConfigurationList = 2CEB3ED31602563600548120 /* Build configuration list for PBXNativeTarget "ExampleApp" */; + buildPhases = ( + 2CEB3EB71602563600548120 /* Sources */, + 2CEB3EB81602563600548120 /* Frameworks */, + 2CEB3EB91602563600548120 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ExampleApp; + productName = ExampleApp; + productReference = 2CEB3EBB1602563600548120 /* ExampleApp.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 2CEB3EB21602563600548120 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0450; + ORGANIZATIONNAME = "Marcus Westin"; + }; + buildConfigurationList = 2CEB3EB51602563600548120 /* Build configuration list for PBXProject "ExampleApp" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 2CEB3EB01602563600548120; + productRefGroup = 2CEB3EBC1602563600548120 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 2CEB3EBA1602563600548120 /* ExampleApp */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 2CEB3EB91602563600548120 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2CEB3ECA1602563600548120 /* InfoPlist.strings in Resources */, + 2CEB3F5216025A4E00548120 /* WebViewJavascriptBridge.js.txt in Resources */, + 2CEB3F5516025A9000548120 /* ExampleApp.html in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 2CEB3EB71602563600548120 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2CEB3ECC1602563600548120 /* main.m in Sources */, + 2CEB3ED01602563600548120 /* ExampleAppDelegate.m in Sources */, + 2CEB3F5316025A4E00548120 /* WebViewJavascriptBridge.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 2CEB3EC81602563600548120 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 2CEB3EC91602563600548120 /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 2CEB3ED11602563600548120 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 2CEB3ED21602563600548120 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; + OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 2CEB3ED41602563600548120 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "ExampleApp/ExampleApp-Prefix.pch"; + INFOPLIST_FILE = "ExampleApp/ExampleApp-Info.plist"; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + 2CEB3ED51602563600548120 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "ExampleApp/ExampleApp-Prefix.pch"; + INFOPLIST_FILE = "ExampleApp/ExampleApp-Info.plist"; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 2CEB3EB51602563600548120 /* Build configuration list for PBXProject "ExampleApp" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2CEB3ED11602563600548120 /* Debug */, + 2CEB3ED21602563600548120 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 2CEB3ED31602563600548120 /* Build configuration list for PBXNativeTarget "ExampleApp" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2CEB3ED41602563600548120 /* Debug */, + 2CEB3ED51602563600548120 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 2CEB3EB21602563600548120 /* Project object */; +} diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge-Info.plist b/ExampleApp/ExampleApp-Info.plist similarity index 73% rename from WebViewJavascriptBridge/WebViewJavascriptBridge-Info.plist rename to ExampleApp/ExampleApp-Info.plist index 310fa6ea..2e36c495 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge-Info.plist +++ b/ExampleApp/ExampleApp-Info.plist @@ -8,10 +8,8 @@ ${PRODUCT_NAME} CFBundleExecutable ${EXECUTABLE_NAME} - CFBundleIconFiles - CFBundleIdentifier - com.marcuswestin.${PRODUCT_NAME:rfc1034identifier} + com.example.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion 6.0 CFBundleName @@ -26,16 +24,13 @@ 1.0 LSRequiresIPhoneOS - UISupportedInterfaceOrientations + UIRequiredDeviceCapabilities - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight + armv7 - UISupportedInterfaceOrientations~ipad + UISupportedInterfaceOrientations UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge-Prefix.pch b/ExampleApp/ExampleApp-Prefix.pch similarity index 65% rename from WebViewJavascriptBridge/WebViewJavascriptBridge-Prefix.pch rename to ExampleApp/ExampleApp-Prefix.pch index 4916c385..29f2d2ac 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge-Prefix.pch +++ b/ExampleApp/ExampleApp-Prefix.pch @@ -1,5 +1,5 @@ // -// Prefix header for all source files of the 'WebViewJavascriptBridge' target in the 'WebViewJavascriptBridge' project +// Prefix header for all source files of the 'ExampleApp' target in the 'ExampleApp' project // #import diff --git a/WebViewJavascriptBridge/ExampleApp.html b/ExampleApp/ExampleApp.html similarity index 100% rename from WebViewJavascriptBridge/ExampleApp.html rename to ExampleApp/ExampleApp.html diff --git a/WebViewJavascriptBridge/ExampleAppDelegate.h b/ExampleApp/ExampleAppDelegate.h similarity index 72% rename from WebViewJavascriptBridge/ExampleAppDelegate.h rename to ExampleApp/ExampleAppDelegate.h index 1354ba43..5fc2d78b 100644 --- a/WebViewJavascriptBridge/ExampleAppDelegate.h +++ b/ExampleApp/ExampleAppDelegate.h @@ -4,10 +4,9 @@ @interface ExampleAppDelegate : UIResponder @property (strong, nonatomic) UIWindow *window; -@property (strong, nonatomic) UIWebView *webView; @property (strong, nonatomic) WebViewJavascriptBridge *javascriptBridge; -- (void)renderButtons; -- (void)loadExamplePage; +- (void)renderButtons:(UIWebView*)webView; +- (void)loadExamplePage:(UIWebView*)webView; @end diff --git a/WebViewJavascriptBridge/ExampleAppDelegate.m b/ExampleApp/ExampleAppDelegate.m similarity index 81% rename from WebViewJavascriptBridge/ExampleAppDelegate.m rename to ExampleApp/ExampleAppDelegate.m index 4fc62452..5ef8c202 100644 --- a/WebViewJavascriptBridge/ExampleAppDelegate.m +++ b/ExampleApp/ExampleAppDelegate.m @@ -3,51 +3,46 @@ @implementation ExampleAppDelegate @synthesize window = _window; -@synthesize webView = _webView; @synthesize javascriptBridge = _javascriptBridge; - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; - - self.webView = [[UIWebView alloc] initWithFrame:self.window.bounds]; - [self.window addSubview:self.webView]; - - self.javascriptBridge = [WebViewJavascriptBridge javascriptBridgeForWebView:self.webView handler:^(id data, WVJBCallback callback) { + UIWebView* webView = [[UIWebView alloc] initWithFrame:self.window.bounds]; + [self.window addSubview:webView]; + + self.javascriptBridge = [WebViewJavascriptBridge javascriptBridgeForWebView:webView handler:^(id data, WVJBCallback callback) { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Message from Javascript" message:data delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alert show]; }]; - - [self renderButtons]; - - // register a callback [self.javascriptBridge registerHandler:@"testObjcCallback" callback:^(id data, WVJBCallback callback) { NSLog(@"testObjcCallback called: %@", data); callback(@"Response from testObjcCallback"); }]; - + [self.javascriptBridge send:@"A string sent from ObjC before Webview has loaded."]; [self.javascriptBridge callHandler:@"testJavascriptHandler" data:[NSDictionary dictionaryWithObject:@"before ready" forKey:@"foo"]]; - [self loadExamplePage]; - + [self renderButtons:webView]; + [self loadExamplePage:webView]; + [self.javascriptBridge send:@"A string sent from ObjC after Webview has loaded."]; [self.window makeKeyAndVisible]; return YES; } -- (void)renderButtons { +- (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:self.webView]; + [self.window insertSubview:messageButton aboveSubview:webView]; messageButton.frame = CGRectMake(20, 400, 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:self.webView]; + [self.window insertSubview:callbackButton aboveSubview:webView]; callbackButton.frame = CGRectMake(170, 400, 130, 45); } @@ -61,10 +56,10 @@ - (void)callHandler:(id)sender { }]; } -- (void)loadExamplePage { +- (void)loadExamplePage:(UIWebView*)webView { NSString* htmlPath = [[NSBundle mainBundle] pathForResource:@"ExampleApp" ofType:@"html"]; NSString* appHtml = [NSString stringWithContentsOfFile:htmlPath encoding:NSUTF8StringEncoding error:nil]; - [self.webView loadHTMLString:appHtml baseURL:nil]; + [webView loadHTMLString:appHtml baseURL:nil]; } @end diff --git a/WebViewJavascriptBridge/en.lproj/InfoPlist.strings b/ExampleApp/en.lproj/InfoPlist.strings similarity index 100% rename from WebViewJavascriptBridge/en.lproj/InfoPlist.strings rename to ExampleApp/en.lproj/InfoPlist.strings diff --git a/WebViewJavascriptBridge/main.m b/ExampleApp/main.m similarity index 61% rename from WebViewJavascriptBridge/main.m rename to ExampleApp/main.m index 5887dbf1..a724dc9c 100644 --- a/WebViewJavascriptBridge/main.m +++ b/ExampleApp/main.m @@ -1,3 +1,11 @@ +// +// main.m +// ExampleApp +// +// Created by Marcus Westin on 9/13/12. +// Copyright (c) 2012 Marcus Westin. All rights reserved. +// + #import #import "ExampleAppDelegate.h" diff --git a/README.md b/README.md index 4709a25f..92b45aac 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,21 @@ WebViewJavascriptBridge ======================= -An iOS bridge for sending messages to and from javascript in a UIWebView +An iOS bridge for sending messages to and from javascript in a UIWebView. Getting started --------------- -Just open the Xcode project (requires Xcode > 4.2) and hit run to see the example application work. +Just open the Xcode project and hit run to see the example application. -Usage +Setup ----- See ExampleAppDelegate.* for example code. To use it in your own project: -1) Copy `WebViewJavascriptBridge/WebViewJavascriptBridge.h`, `WebViewJavascriptBridge/WebViewJavascriptBridge.m` and `WebViewJavascriptBridge/WebViewJavascriptBridge-template.js` into your Xcode project +1) Copy `WebViewJavascriptBridge` folder into your project. -2) Instantiate a UIWebView, a WebViewJavascriptBridge, and set yourself as the bridge's delegate +2) Instantiate a UIWebView and a WebViewJavascriptBridge: #import #import "WebViewJavascriptBridge.h" @@ -26,39 +26,36 @@ See ExampleAppDelegate.* for example code. To use it in your own project: @implementation ExampleAppDelegate - - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions - { - self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; - - self.webView = [[UIWebView alloc] initWithFrame:self.window.bounds]; - [self.window addSubview:self.webView]; - self.javascriptBridge = [WebViewJavascriptBridge javascriptBridgeWithDelegate:self]; - self.webView.delegate = self.javascriptBridge; - - [self.window makeKeyAndVisible]; - return YES; - } + - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; - - (void)javascriptBridge:(WebViewJavascriptBridge *)bridge receivedMessage:(NSString *)message fromWebView:(UIWebView *)webView - { - NSLog(@"MyJavascriptBridgeDelegate received message: %@", message); + UIWebView* webView = [[UIWebView alloc] initWithFrame:self.window.bounds]; + WebViewJavascriptBridge* javascriptBridge = [WebViewJavascriptBridge javascriptBridgeForWebView:webView handler:^(id data, WVJBCallback callback) { + NSLog(@"Received message from javascript: %@", data); + }]; + + [self.window addSubview:self.webView]; + [self.window makeKeyAndVisible]; + return YES; } @end 3) Go ahead and send some messages from Objc to javascript - [self.javascriptBridge sendMessage:@"Well hello there" toWebView:self.webView]; + [javascriptBridge sendMessage:@"Well hello there" toWebView:self.webView]; 4) Finally, set up the javascript side of things document.addEventListener('WebViewJavascriptBridgeReady', function onBridgeReady() { - WebViewJavascriptBridge.setMessageHandler(function(message) { + WebViewJavascriptBridge.init(function(message) { alert('Received message: ' + message) }) - WebViewJavascriptBridge.sendMessage('Hello from the javascript') + WebViewJavascriptBridge.send('Hello from the javascript') }, false) +5) Additional APIs: Responses + ### Registering callbacks The JS to ObjC and ObjC to JS callbacks use `NSJSONSerialization` to convert to/from JSON. If you need iOS 4 support then you can use [JSONKit](https://github.com/johnezang/JSONKit/) by adding `USE_JSONKIT` to the preprocessor macros for your project (you will need to include JSONKit in your project). diff --git a/WebViewJavascriptBridge.xcodeproj/project.pbxproj b/WebViewJavascriptBridge.xcodeproj/project.pbxproj deleted file mode 100644 index 9d6d0804..00000000 --- a/WebViewJavascriptBridge.xcodeproj/project.pbxproj +++ /dev/null @@ -1,277 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 2C1E9EA114099B4600C5C30E /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2C1E9EA014099B4600C5C30E /* UIKit.framework */; }; - 2C1E9EA314099B4600C5C30E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2C1E9EA214099B4600C5C30E /* Foundation.framework */; }; - 2C1E9EA914099B4600C5C30E /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 2C1E9EA714099B4600C5C30E /* InfoPlist.strings */; }; - 2C1E9EAB14099B4600C5C30E /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C1E9EAA14099B4600C5C30E /* main.m */; }; - 2C66C03E14C787BA0050C940 /* WebViewJavascriptBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C66C03D14C787BA0050C940 /* WebViewJavascriptBridge.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - 2C6D2131143017AF0069FA34 /* ExampleAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C6D2130143017AF0069FA34 /* ExampleAppDelegate.m */; }; - 2C8D041515E699AA0016052D /* WebViewJavascriptBridge.js in Resources */ = {isa = PBXBuildFile; fileRef = 2C8D041415E699AA0016052D /* WebViewJavascriptBridge.js */; }; - 2CEB3E7D160155CF00548120 /* ExampleApp.html in Resources */ = {isa = PBXBuildFile; fileRef = 2CEB3E7C160155CF00548120 /* ExampleApp.html */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - 2C1E9E9C14099B4600C5C30E /* WebViewJavascriptBridge.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WebViewJavascriptBridge.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 2C1E9EA014099B4600C5C30E /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; - 2C1E9EA214099B4600C5C30E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - 2C1E9EA614099B4600C5C30E /* WebViewJavascriptBridge-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "WebViewJavascriptBridge-Info.plist"; sourceTree = ""; }; - 2C1E9EA814099B4600C5C30E /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; - 2C1E9EAA14099B4600C5C30E /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - 2C1E9EAC14099B4600C5C30E /* WebViewJavascriptBridge-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "WebViewJavascriptBridge-Prefix.pch"; sourceTree = ""; }; - 2C66C03C14C787BA0050C940 /* WebViewJavascriptBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridge.h; sourceTree = ""; }; - 2C66C03D14C787BA0050C940 /* WebViewJavascriptBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge.m; sourceTree = ""; }; - 2C6D212F143017AF0069FA34 /* ExampleAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExampleAppDelegate.h; sourceTree = ""; }; - 2C6D2130143017AF0069FA34 /* ExampleAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ExampleAppDelegate.m; sourceTree = ""; }; - 2C8D041415E699AA0016052D /* WebViewJavascriptBridge.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = WebViewJavascriptBridge.js; sourceTree = ""; }; - 2CEB3E7C160155CF00548120 /* ExampleApp.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = ExampleApp.html; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 2C1E9E9914099B4600C5C30E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 2C1E9EA114099B4600C5C30E /* UIKit.framework in Frameworks */, - 2C1E9EA314099B4600C5C30E /* Foundation.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 2C1E9E9114099B4600C5C30E = { - isa = PBXGroup; - children = ( - 2C1E9EA414099B4600C5C30E /* WebViewJavascriptBridge */, - 2C1E9E9F14099B4600C5C30E /* Frameworks */, - 2C1E9E9D14099B4600C5C30E /* Products */, - ); - sourceTree = ""; - }; - 2C1E9E9D14099B4600C5C30E /* Products */ = { - isa = PBXGroup; - children = ( - 2C1E9E9C14099B4600C5C30E /* WebViewJavascriptBridge.app */, - ); - name = Products; - sourceTree = ""; - }; - 2C1E9E9F14099B4600C5C30E /* Frameworks */ = { - isa = PBXGroup; - children = ( - 2C1E9EA014099B4600C5C30E /* UIKit.framework */, - 2C1E9EA214099B4600C5C30E /* Foundation.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 2C1E9EA414099B4600C5C30E /* WebViewJavascriptBridge */ = { - isa = PBXGroup; - children = ( - 2C66C03C14C787BA0050C940 /* WebViewJavascriptBridge.h */, - 2C66C03D14C787BA0050C940 /* WebViewJavascriptBridge.m */, - 2C8D041415E699AA0016052D /* WebViewJavascriptBridge.js */, - 2C6D212F143017AF0069FA34 /* ExampleAppDelegate.h */, - 2C6D2130143017AF0069FA34 /* ExampleAppDelegate.m */, - 2CEB3E7C160155CF00548120 /* ExampleApp.html */, - 2C1E9EA514099B4600C5C30E /* Supporting Files */, - ); - path = WebViewJavascriptBridge; - sourceTree = ""; - }; - 2C1E9EA514099B4600C5C30E /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 2C1E9EA614099B4600C5C30E /* WebViewJavascriptBridge-Info.plist */, - 2C1E9EA714099B4600C5C30E /* InfoPlist.strings */, - 2C1E9EAA14099B4600C5C30E /* main.m */, - 2C1E9EAC14099B4600C5C30E /* WebViewJavascriptBridge-Prefix.pch */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 2C1E9E9B14099B4600C5C30E /* WebViewJavascriptBridge */ = { - isa = PBXNativeTarget; - buildConfigurationList = 2C1E9EB214099B4600C5C30E /* Build configuration list for PBXNativeTarget "WebViewJavascriptBridge" */; - buildPhases = ( - 2C1E9E9814099B4600C5C30E /* Sources */, - 2C1E9E9914099B4600C5C30E /* Frameworks */, - 2C1E9E9A14099B4600C5C30E /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = WebViewJavascriptBridge; - productName = WebViewJavascriptBridge; - productReference = 2C1E9E9C14099B4600C5C30E /* WebViewJavascriptBridge.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 2C1E9E9314099B4600C5C30E /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0420; - ORGANIZATIONNAME = Clover; - }; - buildConfigurationList = 2C1E9E9614099B4600C5C30E /* Build configuration list for PBXProject "WebViewJavascriptBridge" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - ); - mainGroup = 2C1E9E9114099B4600C5C30E; - productRefGroup = 2C1E9E9D14099B4600C5C30E /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 2C1E9E9B14099B4600C5C30E /* WebViewJavascriptBridge */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 2C1E9E9A14099B4600C5C30E /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 2C1E9EA914099B4600C5C30E /* InfoPlist.strings in Resources */, - 2C8D041515E699AA0016052D /* WebViewJavascriptBridge.js in Resources */, - 2CEB3E7D160155CF00548120 /* ExampleApp.html in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 2C1E9E9814099B4600C5C30E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 2C1E9EAB14099B4600C5C30E /* main.m in Sources */, - 2C6D2131143017AF0069FA34 /* ExampleAppDelegate.m in Sources */, - 2C66C03E14C787BA0050C940 /* WebViewJavascriptBridge.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 2C1E9EA714099B4600C5C30E /* InfoPlist.strings */ = { - isa = PBXVariantGroup; - children = ( - 2C1E9EA814099B4600C5C30E /* en */, - ); - name = InfoPlist.strings; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 2C1E9EB014099B4600C5C30E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; - CLANG_ENABLE_OBJC_ARC = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 5.0; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 2C1E9EB114099B4600C5C30E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; - CLANG_ENABLE_OBJC_ARC = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 5.0; - OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 2C1E9EB314099B4600C5C30E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "WebViewJavascriptBridge/WebViewJavascriptBridge-Prefix.pch"; - INFOPLIST_FILE = "WebViewJavascriptBridge/WebViewJavascriptBridge-Info.plist"; - PRODUCT_NAME = "$(TARGET_NAME)"; - WRAPPER_EXTENSION = app; - }; - name = Debug; - }; - 2C1E9EB414099B4600C5C30E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "WebViewJavascriptBridge/WebViewJavascriptBridge-Prefix.pch"; - INFOPLIST_FILE = "WebViewJavascriptBridge/WebViewJavascriptBridge-Info.plist"; - PRODUCT_NAME = "$(TARGET_NAME)"; - WRAPPER_EXTENSION = app; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 2C1E9E9614099B4600C5C30E /* Build configuration list for PBXProject "WebViewJavascriptBridge" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 2C1E9EB014099B4600C5C30E /* Debug */, - 2C1E9EB114099B4600C5C30E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 2C1E9EB214099B4600C5C30E /* Build configuration list for PBXNativeTarget "WebViewJavascriptBridge" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 2C1E9EB314099B4600C5C30E /* Debug */, - 2C1E9EB414099B4600C5C30E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 2C1E9E9314099B4600C5C30E /* Project object */; -} diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.h b/WebViewJavascriptBridge/WebViewJavascriptBridge.h index 66270330..1b4073c1 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.h +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.h @@ -15,6 +15,7 @@ typedef void (^WVJBHandler)(id data, WVJBCallback callback); - (void)registerHandler:(NSString*)handlerName callback:(WVJBHandler)handler; +- (void)callHandler:(NSString*)handlerName; - (void)callHandler:(NSString*)handlerName data:(id)data; - (void)callHandler:(NSString*)handlerName data:(id)data responseCallback:(WVJBCallback)responseCallback; diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.js b/WebViewJavascriptBridge/WebViewJavascriptBridge.js.txt similarity index 100% rename from WebViewJavascriptBridge/WebViewJavascriptBridge.js rename to WebViewJavascriptBridge/WebViewJavascriptBridge.js.txt diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index f3d7b620..99c2a697 100755 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -51,6 +51,10 @@ - (void)send:(NSDictionary *)data responseCallback:(WVJBCallback)responseCallbac [self _queueData: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]; } @@ -139,7 +143,7 @@ - (void)webViewDidFinishLoad:(UIWebView *)webView { if (webView != _webView) { return; } if (![[_webView stringByEvaluatingJavaScriptFromString:@"typeof WebViewJavascriptBridge == 'object'"] isEqualToString:@"true"]) { - NSString *filePath = [[NSBundle mainBundle] pathForResource:@"WebViewJavascriptBridge" ofType:@"js"]; + NSString *filePath = [[NSBundle mainBundle] pathForResource:@"WebViewJavascriptBridge.js" ofType:@"txt"]; NSString *js = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; [_webView stringByEvaluatingJavaScriptFromString:js]; } From 1f74d234c6785cc27cfef9dc4f109f44538f2eb7 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Thu, 13 Sep 2012 11:53:20 -0700 Subject: [PATCH 019/353] clean up api and documentation --- ExampleApp/ExampleAppDelegate.m | 6 +- README.md | 135 +++++++++--------- .../WebViewJavascriptBridge.h | 10 +- .../WebViewJavascriptBridge.m | 12 +- 4 files changed, 82 insertions(+), 81 deletions(-) diff --git a/ExampleApp/ExampleAppDelegate.m b/ExampleApp/ExampleAppDelegate.m index 5ef8c202..d797dcc0 100644 --- a/ExampleApp/ExampleAppDelegate.m +++ b/ExampleApp/ExampleAppDelegate.m @@ -10,14 +10,14 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( UIWebView* webView = [[UIWebView alloc] initWithFrame:self.window.bounds]; [self.window addSubview:webView]; - self.javascriptBridge = [WebViewJavascriptBridge javascriptBridgeForWebView:webView handler:^(id data, WVJBCallback callback) { + self.javascriptBridge = [WebViewJavascriptBridge javascriptBridgeForWebView:webView handler:^(id data, WVJBResponseCallback responseCallback) { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Message from Javascript" message:data delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alert show]; }]; - [self.javascriptBridge registerHandler:@"testObjcCallback" callback:^(id data, WVJBCallback callback) { + [self.javascriptBridge registerHandler:@"testObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) { NSLog(@"testObjcCallback called: %@", data); - callback(@"Response from testObjcCallback"); + responseCallback(@"Response from testObjcCallback"); }]; [self.javascriptBridge send:@"A string sent from ObjC before Webview has loaded."]; diff --git a/README.md b/README.md index 92b45aac..49f2e2bf 100644 --- a/README.md +++ b/README.md @@ -8,98 +8,100 @@ Getting started Just open the Xcode project and hit run to see the example application. -Setup ------ +Setup your project +------------------ -See ExampleAppDelegate.* for example code. To use it in your own project: +See ExampleApp/* for example code. To use it in your own project: -1) Copy `WebViewJavascriptBridge` folder into your project. +1) Drag the `WebViewJavascriptBridge` folder into your project. -2) Instantiate a UIWebView and a WebViewJavascriptBridge: +In the dialog that appears: +- Uncheck "Copy items into destination group's folder (if needed)" +- Select "Create groups for any folders" - #import - #import "WebViewJavascriptBridge.h" +2) Import the header file: - @interface ExampleAppDelegate : UIResponder - - @end - - @implementation ExampleAppDelegate - - - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + #import "WebViewJavascriptBridge.h" - UIWebView* webView = [[UIWebView alloc] initWithFrame:self.window.bounds]; - WebViewJavascriptBridge* javascriptBridge = [WebViewJavascriptBridge javascriptBridgeForWebView:webView handler:^(id data, WVJBCallback callback) { - NSLog(@"Received message from javascript: %@", data); - }]; - - [self.window addSubview:self.webView]; - [self.window makeKeyAndVisible]; - return YES; - } +3) Instantiate a UIWebView and a WebViewJavascriptBridge: - @end + UIWebView* webView = [[UIWebView alloc] initWithFrame:self.window.bounds]; + WebViewJavascriptBridge* javascriptBridge = [WebViewJavascriptBridge javascriptBridgeForWebView:webView handler:^(id data, WVJBCallback callback) { + NSLog(@"Received message from javascript: %@", data); + }]; -3) Go ahead and send some messages from Objc to javascript +4) Go ahead and send some messages from Objc to javascript: - [javascriptBridge sendMessage:@"Well hello there" toWebView:self.webView]; + [javascriptBridge send:@"Well hello there"]; + [javascriptBridge send:[NSDictionary dictionaryWithObject:@"Foo" forKey:@"Bar"]]; + [javascriptBridge send:@"Give me a response, will you?" responseCallback:^(id data) { + NSLog(@"I got a response! %@", data); + }]; -4) Finally, set up the javascript side of things +4) Finally, set up the javascript side of things: document.addEventListener('WebViewJavascriptBridgeReady', function onBridgeReady() { - WebViewJavascriptBridge.init(function(message) { - alert('Received message: ' + message) + WebViewJavascriptBridge.init(function(message, responseCallback) { + alert('Received message: ' + message) + if (responseCallback) { + responseCallback("Right back atcha") + } }) WebViewJavascriptBridge.send('Hello from the javascript') }, false) -5) Additional APIs: Responses - -### Registering callbacks - -The JS to ObjC and ObjC to JS callbacks use `NSJSONSerialization` to convert to/from JSON. If you need iOS 4 support then you can use [JSONKit](https://github.com/johnezang/JSONKit/) by adding `USE_JSONKIT` to the preprocessor macros for your project (you will need to include JSONKit in your project). - -#### JS to ObjC - -You can register Objective-C blocks and call them from Javascript. In Objective-C register a block with the bridge: +5) Optional API: Registered handlers - [self.javascriptBridge registerObjcCallback:@"testObjcCallback" withCallback:^(NSDictionary *params){ - NSLog(@"ObjC callback [testObjcCallback] called with params: %@", params); - }]; +This lets you register named handlers for e.g. command handling. You should register handlers -Then call from Javascript using: +*Note:* You need to 1) register ObjC handlers before loading the UIWebView, and 2) register javascript handlers before calling `WebViewJavascriptBridge.init`. - WebViewJavascriptBridge.callObjcCallback('testObjcCallback', { 'foo': 'bar' }); - -This will result in the following being logged: - - ObjC callback [testObjcCallback] called with params: { 'foo' = 'bar'; } - -#### ObjC to JS - -You can also register Javascript functions and call them from Objective-C. In Javascript register a function with the bridge: +In ObjC: + + // Register handler + [javascriptBridge registerHandler:@"greetPerson" responseCallback:^(id data, WVJBCallback callback) { + callback([NSString stringWithFormat:@"Hello, %@", [data objectForKey:@"name"]]); + }]; + // Call javascript handlers + [javascriptBridge callHandler:@"showAlert" data:@"FooBar"]; + [javascriptBridge callHandler:@"getUrl" data:nil callback:^(id data) { + NSLog(@"UIWebView url is %@", data); + }]; + +In javascript: + + // Register handlers + WebViewJavascriptBridge.registerHandler('showAlert', function(data) { + alert(data) + }) + WebViewJavascriptBridge.registerHandler('getUrl', function(data, responseCallback) { + responseCallback(document.location.toString()) + }) + // Call ObjC handler + WebViewJavascriptBridge.callHandler('greetPerson', { name:'Marcus' }, function responseCallback(data) { + alert("ObjC created greeting: "+ data) + }) - WebViewJavascriptBridge.registerJsCallback('testJsCallback', function(params) { - var el = document.body.appendChild(document.createElement('div')); - el.innerHTML = 'JS [testJsCallback] called with params: ' + JSON.stringify(params); - }); +### iOS4 support (with JSONKit) -Then call from Objective-C using: + 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. - [self.javascriptBridge callJavascriptCallback:@"testJsCallback" - withParams:[NSDictionary dictionaryWithObjectsAndKeys:@"bar", @"foo", nil] - toWebView:self.webView]; +### ObjC API Reference -This will result in a div with the following getting added to the HTML: +- `[WebViewJavascriptBridge javascriptBridgeForWebView:(UIWebView*) handler:(WVJBHandler)]` - JS [testJsCallback] called with params: {"foo":"bar"} +Create a javascript bridge for the given webview. -*Note:* You should register any callbacks before you call `WebViewJavascriptBridge.setMessageHandler` otherwise any callback calls received before the HTML is fully loaded will be delivered as normal messages. +Example: + + [WebViewJavascriptBridge javascriptBridgeForWebView:webView handler:^(id data, WVJBCallback responseCallback) { + NSLog(@"Received message from javascript: %@", data); + if (responseCallback) { + responseCallback(@"Right back atcha") + } + }] -ARC ---- -If you're using ARC in your project, add `-fno-objc-arc` as a compiler flag to the `WebViewJavascriptBridge.m` file. +... More to come soon ... Contributors ------------ @@ -109,4 +111,3 @@ Contributors - [@sergiocampama](https://github.com/sergiocampama) Sergio Campamá - [@stringbean](https://github.com/stringbean) Michael Stringer - [@tanis2000](https://github.com/tanis2000) Valerio Santinelli - diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.h b/WebViewJavascriptBridge/WebViewJavascriptBridge.h index 1b4073c1..7ac1ac70 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.h +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.h @@ -1,7 +1,7 @@ #import -typedef void (^WVJBCallback)(id data); -typedef void (^WVJBHandler)(id data, WVJBCallback callback); +typedef void (^WVJBResponseCallback)(id data); +typedef void (^WVJBHandler)(id data, WVJBResponseCallback responseCallback); @class WebViewJavascriptBridge; @@ -11,12 +11,12 @@ typedef void (^WVJBHandler)(id data, WVJBCallback callback); + (id)javascriptBridgeForWebView:(UIWebView*)webView handler:(WVJBHandler)handler webViewDelegate:(id )webViewDelegate; - (void)send:(id)message; -- (void)send:(id)message responseCallback:(WVJBCallback)responseCallback; +- (void)send:(id)message responseCallback:(WVJBResponseCallback)responseCallback; -- (void)registerHandler:(NSString*)handlerName callback:(WVJBHandler)handler; +- (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:(WVJBCallback)responseCallback; +- (void)callHandler:(NSString*)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback; @end diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index 99c2a697..301b876e 100755 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -15,7 +15,7 @@ @interface WebViewJavascriptBridge () @property (nonatomic, copy) WVJBHandler messageHandler; - (void)_flushMessageQueue; -- (void)_queueData:(NSDictionary*)data responseCallback:(WVJBCallback)responseCallback handlerName:(NSString*)handlerName; +- (void)_queueData:(NSDictionary*)data responseCallback:(WVJBResponseCallback)responseCallback handlerName:(NSString*)handlerName; - (void)_dispatchMessage:(NSDictionary*)message; @end @@ -47,7 +47,7 @@ - (void)send:(NSDictionary *)data { [self send:data responseCallback:nil]; } -- (void)send:(NSDictionary *)data responseCallback:(WVJBCallback)responseCallback { +- (void)send:(NSDictionary *)data responseCallback:(WVJBResponseCallback)responseCallback { [self _queueData:data responseCallback:responseCallback handlerName:nil]; } @@ -59,15 +59,15 @@ - (void)callHandler:(NSString *)handlerName data:(id)data { [self callHandler:handlerName data:data responseCallback:nil]; } -- (void)callHandler:(NSString *)handlerName data:(id)data responseCallback:(WVJBCallback)responseCallback { +- (void)callHandler:(NSString *)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback { [self _queueData:data responseCallback:responseCallback handlerName:handlerName]; } -- (void)registerHandler:(NSString *)handlerName callback:(WVJBHandler)handler { +- (void)registerHandler:(NSString *)handlerName handler:(WVJBHandler)handler { [self.messageHandlers setObject:handler forKey:handlerName]; } -- (void)_queueData:(NSDictionary *)data responseCallback:(WVJBCallback)responseCallback handlerName:(NSString*)handlerName { +- (void)_queueData:(NSDictionary *)data responseCallback:(WVJBResponseCallback)responseCallback handlerName:(NSString*)handlerName { NSMutableDictionary* message = [NSMutableDictionary dictionaryWithObject:data forKey:@"data"]; if (responseCallback) { @@ -112,7 +112,7 @@ - (void)_flushMessageQueue { #else NSDictionary *message = [NSJSONSerialization JSONObjectWithData:[messageJSON dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil]; #endif - WVJBCallback responseCallback = NULL; + WVJBResponseCallback responseCallback = NULL; if ([message objectForKey:@"callbackId"]) { __block NSString* responseId = [message objectForKey:@"callbackId"]; responseCallback = ^(NSDictionary* data) { From c2eddcb9281f8870558e97025874f6babc39a797 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Thu, 13 Sep 2012 14:34:40 -0700 Subject: [PATCH 020/353] finish up docs --- ExampleApp/ExampleAppDelegate.m | 4 +- README.md | 109 ++++++++++++++++-- .../WebViewJavascriptBridge.h | 2 +- 3 files changed, 104 insertions(+), 11 deletions(-) diff --git a/ExampleApp/ExampleAppDelegate.m b/ExampleApp/ExampleAppDelegate.m index d797dcc0..e3439a2e 100644 --- a/ExampleApp/ExampleAppDelegate.m +++ b/ExampleApp/ExampleAppDelegate.m @@ -51,8 +51,8 @@ - (void)sendMessage:(id)sender { } - (void)callHandler:(id)sender { - [self.javascriptBridge callHandler:@"testJavascriptHandler" data:[NSDictionary dictionaryWithObject:@"Hi there, JS!" forKey:@"greetingFromObjC"] responseCallback:^(id data) { - NSLog(@"testJavascriptHandler responded: %@", data); + [self.javascriptBridge callHandler:@"testJavascriptHandler" data:[NSDictionary dictionaryWithObject:@"Hi there, JS!" forKey:@"greetingFromObjC"] responseCallback:^(id responseData) { + NSLog(@"testJavascriptHandler responded: %@", responseData); }]; } diff --git a/README.md b/README.md index 49f2e2bf..672d8878 100644 --- a/README.md +++ b/README.md @@ -34,8 +34,8 @@ In the dialog that appears: [javascriptBridge send:@"Well hello there"]; [javascriptBridge send:[NSDictionary dictionaryWithObject:@"Foo" forKey:@"Bar"]]; - [javascriptBridge send:@"Give me a response, will you?" responseCallback:^(id data) { - NSLog(@"I got a response! %@", data); + [javascriptBridge send:@"Give me a response, will you?" responseCallback:^(id responseData) { + NSLog(@"I got a response! %@", responseData); }]; 4) Finally, set up the javascript side of things: @@ -59,7 +59,7 @@ This lets you register named handlers for e.g. command handling. You should regi In ObjC: // Register handler - [javascriptBridge registerHandler:@"greetPerson" responseCallback:^(id data, WVJBCallback callback) { + [javascriptBridge registerHandler:@"greetPerson" handler:^(id responseData, WVJBResponseHandler callback) { callback([NSString stringWithFormat:@"Hello, %@", [data objectForKey:@"name"]]); }]; // Call javascript handlers @@ -82,15 +82,19 @@ In javascript: alert("ObjC created greeting: "+ data) }) -### iOS4 support (with JSONKit) +iOS4 support (with JSONKit) +--------------------------- 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. -### ObjC API Reference +API Reference +------------- -- `[WebViewJavascriptBridge javascriptBridgeForWebView:(UIWebView*) handler:(WVJBHandler)]` +### ObjC -Create a javascript bridge for the given webview. +#### `WebViewJavascriptBridge* bridge = [WebViewJavascriptBridge javascriptBridgeForWebView:(UIWebView*)webview handler:(WVJBHandler)handler]` + +Create a javascript bridge for the given UIWebView. Example: @@ -101,7 +105,96 @@ Example: } }] -... More to come soon ... +The handler's `responseCallback` will be a block if javascript sent the message with a function responseCallback, or `nil` otherwise. + +#### `[bridge send:(id)data]` +#### `[bridge send:(id)data responseCallback:(WVJBResponseCallback)responseCallback]` + +Send a message to javascript. Optionally expect a response by giving a `responseCallback` block. + +Example: + + [bridge send:@"Hi"]; + [bridge send:[NSDictionary dictionaryWithObject:@"Foo" forKey:@"Bar"]]; + [bridge send:@"I expect a response!" responseCallback:^(id data) { + NSLog(@"Got response: %@", data); + }]; + +#### `[bridge registerHandler:(NSString*)handlerName handler:(WVJBHandler)handler]` + +Register a handler called `handlerName`. The javascript can then call this handler with `WebViewJavascriptBridge.callHandler("handlerName", function(response) { ... })`. + +Example: + + [bridge registerHandler:@"getScreenHeight" handler:^(id data, WVJBResponseCallback responseCallback) { + responseCallback([NSNumber numberWithInt:[UIScreen mainScreen].bounds.size.height]); + }]; + +#### `[bridge callHandler:(NSString*)handlerName data:(id)data]` +#### `[bridge callHandler:(NSString*)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback]` + +Call the javascript handler called `handlerName`. Optionally expect a response by giving a `responseCallback` block. + +Example: + + [bridge callHandler:@"showAlert" data:@"Hi from ObjC to JS!"]; + [bridge callHandler:@"getCurrentPageUrl" data:nil responseCallback:^(id responseData) { + NSLog(@"Current UIWebView page URL is: %@", responseData); + }]; + + +### Javascript + +#### `document.addEventListener('WebViewJavascriptBridgeReady', function onBridgeReadyHandler() { ... }, false)` + +Always wait for the `WebViewJavascriptBridgeReady` DOM event before using `WebViewJavascriptBridge`. + +Example: + + document.addEventListener('WebViewJavascriptBridgeReady', function() { + // Start using WebViewJavascriptBridge + }, false) + +#### `WebViewJavascriptBridge.init(function messageHandler(data, responseCallback) { ... })` + +Initialize the WebViewJavascriptBridge. This should be called inside of the `'WebViewJavascriptBridgeReady'` event handler. + +The `messageHandler` function will receive all messages sent from ObjC via `[bridge send:(id)data]` and `[bridge send:(id)data responseCallback:(WVJBResponseCallback)responseCallback]`. + +The `responseCallback` will be a function if ObjC sent the message with a `WVJBResponseCallback` block, or `undefined` otherwise. + +Example: + + WebViewJavascriptBridge.init(function(data, responseCallback) { + alert("Got data " + JSON.stringify(data)) + if (responseCallback) { + responseCallback("Right back atcha!") + } + }) + +#### `WebViewJavascriptBridge.send("Hi there!")` +#### `WebViewJavascriptBridge.send({ Foo:"Bar" })` +#### `WebViewJavascriptBridge.send(data, function responseCallback(responseData) { ... })` + +Send a message to ObjC. Optionally expect a response by giving a `responseCallback` function. + +Example: + + WebViewJavascriptBridge.send("Hi there!") + WebViewJavascriptBridge.send("Hi there!", function(response) { + alert("I got a response! "+JSON.stringify(response)) + }) + +#### `WebViewJavascriptBridge.registerHandler("handlerName", function(data, responseCallback) { ... })` + +Register a handler called `handlerName`. The ObjC can then call this handler with `[bridge callHandler:"handlerName" data:@"Foo"]` and `[bridge callHandler:"handlerName" data:@"Foo" responseCallback:^(id responseData) { ... }]` + +Example: + + WebViewJavascriptBridge.registerHandler("showAlert", function(data) { alert(data) }) + WebViewJavascriptBridge.registerHandler("getCurrentPageUrl", function(data, responseCallback) { + responseCallback(document.location.toString()) + }) Contributors ------------ diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.h b/WebViewJavascriptBridge/WebViewJavascriptBridge.h index 7ac1ac70..8a73b38e 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.h +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.h @@ -1,6 +1,6 @@ #import -typedef void (^WVJBResponseCallback)(id data); +typedef void (^WVJBResponseCallback)(id responseData); typedef void (^WVJBHandler)(id data, WVJBResponseCallback responseCallback); @class WebViewJavascriptBridge; From ff6497cdba527defddf6e31eeeb6a5fd73cf86d3 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Thu, 13 Sep 2012 14:41:10 -0700 Subject: [PATCH 021/353] Improve documentation header levels --- README.md | 60 ++++++++++++++----------------------------------------- 1 file changed, 15 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index 672d8878..a5837dbb 100644 --- a/README.md +++ b/README.md @@ -50,49 +50,19 @@ In the dialog that appears: WebViewJavascriptBridge.send('Hello from the javascript') }, false) -5) Optional API: Registered handlers - -This lets you register named handlers for e.g. command handling. You should register handlers - -*Note:* You need to 1) register ObjC handlers before loading the UIWebView, and 2) register javascript handlers before calling `WebViewJavascriptBridge.init`. - -In ObjC: - - // Register handler - [javascriptBridge registerHandler:@"greetPerson" handler:^(id responseData, WVJBResponseHandler callback) { - callback([NSString stringWithFormat:@"Hello, %@", [data objectForKey:@"name"]]); - }]; - // Call javascript handlers - [javascriptBridge callHandler:@"showAlert" data:@"FooBar"]; - [javascriptBridge callHandler:@"getUrl" data:nil callback:^(id data) { - NSLog(@"UIWebView url is %@", data); - }]; - -In javascript: - - // Register handlers - WebViewJavascriptBridge.registerHandler('showAlert', function(data) { - alert(data) - }) - WebViewJavascriptBridge.registerHandler('getUrl', function(data, responseCallback) { - responseCallback(document.location.toString()) - }) - // Call ObjC handler - WebViewJavascriptBridge.callHandler('greetPerson', { name:'Marcus' }, function responseCallback(data) { - alert("ObjC created greeting: "+ data) - }) - iOS4 support (with JSONKit) --------------------------- - 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. +*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. API Reference ------------- ### ObjC -#### `WebViewJavascriptBridge* bridge = [WebViewJavascriptBridge javascriptBridgeForWebView:(UIWebView*)webview handler:(WVJBHandler)handler]` +##### `[WebViewJavascriptBridge javascriptBridgeForWebView:(UIWebView*)webview handler:(WVJBHandler)handler]` Create a javascript bridge for the given UIWebView. @@ -107,8 +77,8 @@ Example: The handler's `responseCallback` will be a block if javascript sent the message with a function responseCallback, or `nil` otherwise. -#### `[bridge send:(id)data]` -#### `[bridge send:(id)data responseCallback:(WVJBResponseCallback)responseCallback]` +##### `[bridge send:(id)data]` +##### `[bridge send:(id)data responseCallback:(WVJBResponseCallback)responseCallback]` Send a message to javascript. Optionally expect a response by giving a `responseCallback` block. @@ -120,7 +90,7 @@ Example: NSLog(@"Got response: %@", data); }]; -#### `[bridge registerHandler:(NSString*)handlerName handler:(WVJBHandler)handler]` +##### `[bridge registerHandler:(NSString*)handlerName handler:(WVJBHandler)handler]` Register a handler called `handlerName`. The javascript can then call this handler with `WebViewJavascriptBridge.callHandler("handlerName", function(response) { ... })`. @@ -130,8 +100,8 @@ Example: responseCallback([NSNumber numberWithInt:[UIScreen mainScreen].bounds.size.height]); }]; -#### `[bridge callHandler:(NSString*)handlerName data:(id)data]` -#### `[bridge callHandler:(NSString*)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback]` +##### `[bridge callHandler:(NSString*)handlerName data:(id)data]` +##### `[bridge callHandler:(NSString*)handlerName data:(id)data responseCallback:(WVJBResponseCallback)callback]` Call the javascript handler called `handlerName`. Optionally expect a response by giving a `responseCallback` block. @@ -145,7 +115,7 @@ Example: ### Javascript -#### `document.addEventListener('WebViewJavascriptBridgeReady', function onBridgeReadyHandler() { ... }, false)` +##### `document.addEventListener('WebViewJavascriptBridgeReady', function onBridgeReadyHandler() { ... }, false)` Always wait for the `WebViewJavascriptBridgeReady` DOM event before using `WebViewJavascriptBridge`. @@ -155,7 +125,7 @@ Example: // Start using WebViewJavascriptBridge }, false) -#### `WebViewJavascriptBridge.init(function messageHandler(data, responseCallback) { ... })` +##### `WebViewJavascriptBridge.init(function messageHandler(data, responseCallback) { ... })` Initialize the WebViewJavascriptBridge. This should be called inside of the `'WebViewJavascriptBridgeReady'` event handler. @@ -172,9 +142,9 @@ Example: } }) -#### `WebViewJavascriptBridge.send("Hi there!")` -#### `WebViewJavascriptBridge.send({ Foo:"Bar" })` -#### `WebViewJavascriptBridge.send(data, function responseCallback(responseData) { ... })` +##### `WebViewJavascriptBridge.send("Hi there!")` +##### `WebViewJavascriptBridge.send({ Foo:"Bar" })` +##### `WebViewJavascriptBridge.send(data, function responseCallback(responseData) { ... })` Send a message to ObjC. Optionally expect a response by giving a `responseCallback` function. @@ -185,7 +155,7 @@ Example: alert("I got a response! "+JSON.stringify(response)) }) -#### `WebViewJavascriptBridge.registerHandler("handlerName", function(data, responseCallback) { ... })` +##### `WebViewJavascriptBridge.registerHandler("handlerName", function(data, responseCallback) { ... })` Register a handler called `handlerName`. The ObjC can then call this handler with `[bridge callHandler:"handlerName" data:@"Foo"]` and `[bridge callHandler:"handlerName" data:@"Foo" responseCallback:^(id responseData) { ... }]` From 7b8d0e719bd86668a6ad650157b809bc7988625b Mon Sep 17 00:00:00 2001 From: ckmcc Date: Tue, 18 Sep 2012 20:59:19 -0500 Subject: [PATCH 022/353] Replace `WVJBCallback` with `WVJBResponseCallback` --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a5837dbb..dac274ca 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ In the dialog that appears: 3) Instantiate a UIWebView and a WebViewJavascriptBridge: UIWebView* webView = [[UIWebView alloc] initWithFrame:self.window.bounds]; - WebViewJavascriptBridge* javascriptBridge = [WebViewJavascriptBridge javascriptBridgeForWebView:webView handler:^(id data, WVJBCallback callback) { + WebViewJavascriptBridge* javascriptBridge = [WebViewJavascriptBridge javascriptBridgeForWebView:webView handler:^(id data, WVJBResponseCallback callback) { NSLog(@"Received message from javascript: %@", data); }]; @@ -68,7 +68,7 @@ Create a javascript bridge for the given UIWebView. Example: - [WebViewJavascriptBridge javascriptBridgeForWebView:webView handler:^(id data, WVJBCallback responseCallback) { + [WebViewJavascriptBridge javascriptBridgeForWebView:webView handler:^(id data, WVJBResponseCallback responseCallback) { NSLog(@"Received message from javascript: %@", data); if (responseCallback) { responseCallback(@"Right back atcha") From 8ac33bfcb26d48de8668c0077eb61a03426702fc Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Tue, 18 Sep 2012 19:34:12 -0700 Subject: [PATCH 023/353] Document the bridge constructor with a UIWebViewDelegate given, and change the signature so as to always put the handler last --- README.md | 6 ++++++ WebViewJavascriptBridge/WebViewJavascriptBridge.h | 2 +- WebViewJavascriptBridge/WebViewJavascriptBridge.m | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index dac274ca..a9af9b8a 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,7 @@ API Reference ### ObjC ##### `[WebViewJavascriptBridge javascriptBridgeForWebView:(UIWebView*)webview handler:(WVJBHandler)handler]` +##### `[WebViewJavascriptBridge javascriptBridgeForWebView:(UIWebView*)webview webViewDelegate:(UIWebViewDelegate*)webViewDelegate handler:(WVJBHandler)handler]` Create a javascript bridge for the given UIWebView. @@ -74,9 +75,14 @@ Example: responseCallback(@"Right back atcha") } }] + + [WebViewJavascriptBridge javascriptBridgeForWebView:webView webViewDelegate:self handler:^(id data, WVJBCallback responseCallback) { /* ... */ }]; The handler's `responseCallback` will be a block if javascript sent the message with a function responseCallback, or `nil` otherwise. +Optionally, pass in `webViewDelegate:(UIWebViewDelegate*)webViewDelegate` if you need to respond to the [UIWebView's lifecycle events](http://developer.apple.com/library/ios/documentation/uikit/reference/UIWebViewDelegate_Protocol/Reference/Reference.html). + + ##### `[bridge send:(id)data]` ##### `[bridge send:(id)data responseCallback:(WVJBResponseCallback)responseCallback]` diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.h b/WebViewJavascriptBridge/WebViewJavascriptBridge.h index 8a73b38e..db053b7d 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.h +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.h @@ -8,7 +8,7 @@ typedef void (^WVJBHandler)(id data, WVJBResponseCallback responseCallback); @interface WebViewJavascriptBridge : NSObject + (id)javascriptBridgeForWebView:(UIWebView*)webView handler:(WVJBHandler)handler; -+ (id)javascriptBridgeForWebView:(UIWebView*)webView handler:(WVJBHandler)handler webViewDelegate:(id )webViewDelegate; ++ (id)javascriptBridgeForWebView:(UIWebView*)webView webViewDelegate:(id )webViewDelegate handler:(WVJBHandler)handler; - (void)send:(id)message; - (void)send:(id)message responseCallback:(WVJBResponseCallback)responseCallback; diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index 301b876e..fb2d39a7 100755 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -27,10 +27,10 @@ @implementation WebViewJavascriptBridge static NSString *QUEUE_HAS_MESSAGE = @"__WVJB_QUEUE_MESSAGE__"; + (id)javascriptBridgeForWebView:(UIWebView *)webView handler:(WVJBHandler)handler { - return [self javascriptBridgeForWebView:webView handler:handler webViewDelegate:nil]; + return [self javascriptBridgeForWebView:webView webViewDelegate:nil handler:handler]; } -+ (id)javascriptBridgeForWebView:(UIWebView *)webView handler:(WVJBHandler)messageHandler webViewDelegate:(id)webViewDelegate { ++ (id)javascriptBridgeForWebView:(UIWebView *)webView webViewDelegate:(id)webViewDelegate handler:(WVJBHandler)messageHandler { WebViewJavascriptBridge* bridge = [[WebViewJavascriptBridge alloc] init]; bridge.messageHandler = messageHandler; bridge.startupMessageQueue = [NSMutableArray array]; From ac1a56ec0bfc8a1e37601a0859d7a069b6523de0 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Tue, 18 Sep 2012 19:55:39 -0700 Subject: [PATCH 024/353] Fix bug found by @drewburch that would cause response messages sent from ObjC to be double-wrapped --- .../WebViewJavascriptBridge.m | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index fb2d39a7..19bf7c26 100755 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -15,7 +15,8 @@ @interface WebViewJavascriptBridge () @property (nonatomic, copy) WVJBHandler messageHandler; - (void)_flushMessageQueue; -- (void)_queueData:(NSDictionary*)data responseCallback:(WVJBResponseCallback)responseCallback handlerName:(NSString*)handlerName; +- (void)_sendData:(NSDictionary*)data responseCallback:(WVJBResponseCallback)responseCallback handlerName:(NSString*)handlerName; +- (void)_queueMessage:(NSDictionary*)message; - (void)_dispatchMessage:(NSDictionary*)message; @end @@ -48,7 +49,7 @@ - (void)send:(NSDictionary *)data { } - (void)send:(NSDictionary *)data responseCallback:(WVJBResponseCallback)responseCallback { - [self _queueData:data responseCallback:responseCallback handlerName:nil]; + [self _sendData:data responseCallback:responseCallback handlerName:nil]; } - (void)callHandler:(NSString *)handlerName { @@ -60,14 +61,14 @@ - (void)callHandler:(NSString *)handlerName data:(id)data { } - (void)callHandler:(NSString *)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback { - [self _queueData:data responseCallback:responseCallback handlerName:handlerName]; + [self _sendData:data responseCallback:responseCallback handlerName:handlerName]; } - (void)registerHandler:(NSString *)handlerName handler:(WVJBHandler)handler { [self.messageHandlers setObject:handler forKey:handlerName]; } -- (void)_queueData:(NSDictionary *)data responseCallback:(WVJBResponseCallback)responseCallback handlerName:(NSString*)handlerName { +- (void)_sendData:(NSDictionary *)data responseCallback:(WVJBResponseCallback)responseCallback handlerName:(NSString*)handlerName { NSMutableDictionary* message = [NSMutableDictionary dictionaryWithObject:data forKey:@"data"]; if (responseCallback) { @@ -79,7 +80,10 @@ - (void)_queueData:(NSDictionary *)data responseCallback:(WVJBResponseCallback)r if (handlerName) { [message setObject:handlerName forKey:@"handlerName"]; } - + [self _queueMessage:message]; +} + +- (void)_queueMessage:(NSDictionary *)message { if (self.startupMessageQueue) { [self.startupMessageQueue addObject:message]; } else { @@ -116,8 +120,8 @@ - (void)_flushMessageQueue { if ([message objectForKey:@"callbackId"]) { __block NSString* responseId = [message objectForKey:@"callbackId"]; responseCallback = ^(NSDictionary* data) { - NSDictionary* response = [NSDictionary dictionaryWithObjectsAndKeys: responseId, @"responseId", data, @"data", nil]; - [self send:response]; + NSDictionary* responseMessage = [NSDictionary dictionaryWithObjectsAndKeys: responseId, @"responseId", data, @"data", nil]; + [self _queueMessage:responseMessage]; }; } From 942c507fb3c2ddaa57684ce9331e6d9740c9e7d4 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Tue, 18 Sep 2012 19:55:52 -0700 Subject: [PATCH 025/353] note intended v2 changes in Changelog --- Changelog | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Changelog b/Changelog index 91094d00..952a3051 100644 --- a/Changelog +++ b/Changelog @@ -1,4 +1,10 @@ -intended v0.0.1 +intended v2.0.0 ++ Messages are objects instead of strings. Supports NSDictionary*/Objects, NSArray*/Arrays, NSNumber*/Number & NSString*/String. ++ Messages are encoded with NSJSONSerialization. Optional fallback to JSONKit for iOS 4 support. ++ Messages can expect responses. A message received with an expected response is accompanied by a WVJBResponseCallback/Function. ++ Handlers can be registered by name, and called with data and an optional expected response. + +v0.0.1 + ObjC: A WebViewJavascriptBridge class (a UIWebViewDelegate) that enables message passing to and from the JS + ObjC: A protocol called WebViewJavascriptBridgeDelegate that lets you handle messages received from the JS + JS: Event when the bridge is ready - document.addEventListener('WebViewJavascriptBridgeReady', function() {}, false) From f179fcf468f6640b0e6fb01cc838ef33ada640a2 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Tue, 18 Sep 2012 20:07:29 -0700 Subject: [PATCH 026/353] improve example app styling and example functionality --- ExampleApp/ExampleApp.html | 22 +++++++++++++++------- ExampleApp/ExampleAppDelegate.m | 3 ++- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/ExampleApp/ExampleApp.html b/ExampleApp/ExampleApp.html index 7bbbde8b..35ed30bb 100644 --- a/ExampleApp/ExampleApp.html +++ b/ExampleApp/ExampleApp.html @@ -1,16 +1,21 @@ - +

Javascript Bridge Demo

+
+ diff --git a/ExampleApp-OSX/en.lproj/Credits.rtf b/ExampleApp-OSX/en.lproj/Credits.rtf new file mode 100644 index 00000000..46576ef2 --- /dev/null +++ b/ExampleApp-OSX/en.lproj/Credits.rtf @@ -0,0 +1,29 @@ +{\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;} +{\colortbl;\red255\green255\blue255;} +\paperw9840\paperh8400 +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural + +\f0\b\fs24 \cf0 Engineering: +\b0 \ + Some people\ +\ + +\b Human Interface Design: +\b0 \ + Some other people\ +\ + +\b Testing: +\b0 \ + Hopefully not nobody\ +\ + +\b Documentation: +\b0 \ + Whoever\ +\ + +\b With special thanks to: +\b0 \ + Mom\ +} diff --git a/ExampleApp-OSX/en.lproj/InfoPlist.strings b/ExampleApp-OSX/en.lproj/InfoPlist.strings new file mode 100644 index 00000000..477b28ff --- /dev/null +++ b/ExampleApp-OSX/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/ExampleApp-OSX/en.lproj/MainMenu.xib b/ExampleApp-OSX/en.lproj/MainMenu.xib new file mode 100644 index 00000000..b4989b1d --- /dev/null +++ b/ExampleApp-OSX/en.lproj/MainMenu.xib @@ -0,0 +1,3614 @@ + + + + 1070 + 11E53 + 2844 + 1138.47 + 569.00 + + 2844 + 1810 + + + IBNSLayoutConstraint + NSButton + NSButtonCell + NSCustomObject + NSMenu + NSMenuItem + NSView + NSWindowTemplate + WebView + + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.WebKitIBPlugin + + + PluginDependencyRecalculationVersion + + + + + NSApplication + + + FirstResponder + + + NSApplication + + + AMainMenu + + + + ExampleApp-OSX + + 1048576 + 2147483647 + + NSImage + NSMenuCheckmark + + + NSImage + NSMenuMixedState + + submenuAction: + + ExampleApp-OSX + + + + About ExampleApp-OSX + + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Preferences… + , + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Services + + 1048576 + 2147483647 + + + submenuAction: + + Services + + _NSServicesMenu + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Hide ExampleApp-OSX + h + 1048576 + 2147483647 + + + + + + Hide Others + h + 1572864 + 2147483647 + + + + + + Show All + + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Quit ExampleApp-OSX + q + 1048576 + 2147483647 + + + + + _NSAppleMenu + + + + + File + + 1048576 + 2147483647 + + + submenuAction: + + File + + + + New + n + 1048576 + 2147483647 + + + + + + Open… + o + 1048576 + 2147483647 + + + + + + Open Recent + + 1048576 + 2147483647 + + + submenuAction: + + Open Recent + + + + Clear Menu + + 1048576 + 2147483647 + + + + + _NSRecentDocumentsMenu + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Close + w + 1048576 + 2147483647 + + + + + + Save… + s + 1048576 + 2147483647 + + + + + + Revert to Saved + + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Page Setup... + P + 1179648 + 2147483647 + + + + + + + Print… + p + 1048576 + 2147483647 + + + + + + + + + Edit + + 1048576 + 2147483647 + + + submenuAction: + + Edit + + + + Undo + z + 1048576 + 2147483647 + + + + + + Redo + Z + 1179648 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Cut + x + 1048576 + 2147483647 + + + + + + Copy + c + 1048576 + 2147483647 + + + + + + Paste + v + 1048576 + 2147483647 + + + + + + Paste and Match Style + V + 1572864 + 2147483647 + + + + + + Delete + + 1048576 + 2147483647 + + + + + + Select All + a + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Find + + 1048576 + 2147483647 + + + submenuAction: + + Find + + + + Find… + f + 1048576 + 2147483647 + + + 1 + + + + Find and Replace… + f + 1572864 + 2147483647 + + + 12 + + + + Find Next + g + 1048576 + 2147483647 + + + 2 + + + + Find Previous + G + 1179648 + 2147483647 + + + 3 + + + + Use Selection for Find + e + 1048576 + 2147483647 + + + 7 + + + + Jump to Selection + j + 1048576 + 2147483647 + + + + + + + + + Spelling and Grammar + + 1048576 + 2147483647 + + + submenuAction: + + Spelling and Grammar + + + + Show Spelling and Grammar + : + 1048576 + 2147483647 + + + + + + Check Document Now + ; + 1048576 + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + Check Spelling While Typing + + 1048576 + 2147483647 + + + + + + Check Grammar With Spelling + + 1048576 + 2147483647 + + + + + + Correct Spelling Automatically + + 2147483647 + + + + + + + + + Substitutions + + 1048576 + 2147483647 + + + submenuAction: + + Substitutions + + + + Show Substitutions + + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + Smart Copy/Paste + f + 1048576 + 2147483647 + + + 1 + + + + Smart Quotes + g + 1048576 + 2147483647 + + + 2 + + + + Smart Dashes + + 2147483647 + + + + + + Smart Links + G + 1179648 + 2147483647 + + + 3 + + + + Text Replacement + + 2147483647 + + + + + + + + + Transformations + + 2147483647 + + + submenuAction: + + Transformations + + + + Make Upper Case + + 2147483647 + + + + + + Make Lower Case + + 2147483647 + + + + + + Capitalize + + 2147483647 + + + + + + + + + Speech + + 1048576 + 2147483647 + + + submenuAction: + + Speech + + + + Start Speaking + + 1048576 + 2147483647 + + + + + + Stop Speaking + + 1048576 + 2147483647 + + + + + + + + + + + + Format + + 2147483647 + + + submenuAction: + + Format + + + + Font + + 2147483647 + + + submenuAction: + + Font + + + + Show Fonts + t + 1048576 + 2147483647 + + + + + + Bold + b + 1048576 + 2147483647 + + + 2 + + + + Italic + i + 1048576 + 2147483647 + + + 1 + + + + Underline + u + 1048576 + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + Bigger + + + 1048576 + 2147483647 + + + 3 + + + + Smaller + - + 1048576 + 2147483647 + + + 4 + + + + YES + YES + + + 2147483647 + + + + + + Kern + + 2147483647 + + + submenuAction: + + Kern + + + + Use Default + + 2147483647 + + + + + + Use None + + 2147483647 + + + + + + Tighten + + 2147483647 + + + + + + Loosen + + 2147483647 + + + + + + + + + Ligatures + + 2147483647 + + + submenuAction: + + Ligatures + + + + Use Default + + 2147483647 + + + + + + Use None + + 2147483647 + + + + + + Use All + + 2147483647 + + + + + + + + + Baseline + + 2147483647 + + + submenuAction: + + Baseline + + + + Use Default + + 2147483647 + + + + + + Superscript + + 2147483647 + + + + + + Subscript + + 2147483647 + + + + + + Raise + + 2147483647 + + + + + + Lower + + 2147483647 + + + + + + + + + YES + YES + + + 2147483647 + + + + + + Show Colors + C + 1048576 + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + Copy Style + c + 1572864 + 2147483647 + + + + + + Paste Style + v + 1572864 + 2147483647 + + + + + _NSFontMenu + + + + + Text + + 2147483647 + + + submenuAction: + + Text + + + + Align Left + { + 1048576 + 2147483647 + + + + + + Center + | + 1048576 + 2147483647 + + + + + + Justify + + 2147483647 + + + + + + Align Right + } + 1048576 + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + Writing Direction + + 2147483647 + + + submenuAction: + + Writing Direction + + + + YES + Paragraph + + 2147483647 + + + + + + CURlZmF1bHQ + + 2147483647 + + + + + + CUxlZnQgdG8gUmlnaHQ + + 2147483647 + + + + + + CVJpZ2h0IHRvIExlZnQ + + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + YES + Selection + + 2147483647 + + + + + + CURlZmF1bHQ + + 2147483647 + + + + + + CUxlZnQgdG8gUmlnaHQ + + 2147483647 + + + + + + CVJpZ2h0IHRvIExlZnQ + + 2147483647 + + + + + + + + + YES + YES + + + 2147483647 + + + + + + Show Ruler + + 2147483647 + + + + + + Copy Ruler + c + 1310720 + 2147483647 + + + + + + Paste Ruler + v + 1310720 + 2147483647 + + + + + + + + + + + + View + + 1048576 + 2147483647 + + + submenuAction: + + View + + + + Show Toolbar + t + 1572864 + 2147483647 + + + + + + Customize Toolbar… + + 1048576 + 2147483647 + + + + + + + + + Window + + 1048576 + 2147483647 + + + submenuAction: + + Window + + + + Minimize + m + 1048576 + 2147483647 + + + + + + Zoom + + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Bring All to Front + + 1048576 + 2147483647 + + + + + _NSWindowsMenu + + + + + Help + + 2147483647 + + + submenuAction: + + Help + + + + ExampleApp-OSX Help + ? + 1048576 + 2147483647 + + + + + _NSHelpMenu + + + + _NSMainMenu + + + 15 + 2 + {{335, 390}, {480, 360}} + 1954021376 + ExampleApp-OSX + NSWindow + + + + + 256 + + + + 256 + + Apple HTML pasteboard type + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple URL pasteboard type + Apple Web Archive pasteboard type + NSColor pasteboard type + NSFilenamesPboardType + NSStringPboardType + NeXT RTFD pasteboard type + NeXT Rich Text Format v1.0 pasteboard type + NeXT TIFF v4.0 pasteboard type + WebURLsWithTitlesPboardType + public.png + public.url + public.url-name + + {{0, 37}, {480, 323}} + + + + _NS:9 + + + + + + + + + + + YES + YES + + + + 268 + {{20, 10}, {97, 19}} + + + + _NS:9 + YES + + -2080374784 + 134217728 + Send message + + LucidaGrande + 12 + 16 + + _NS:9 + + -2038153216 + 164 + + + 400 + 75 + + + + + 268 + {{125, 10}, {86, 19}} + + + _NS:9 + YES + + -2080374784 + 134217728 + Call Handler + + _NS:9 + + -2038153216 + 164 + + + 400 + 75 + + + + {480, 360} + + + + + {{0, 0}, {1280, 778}} + {10000000000000, 10000000000000} + YES + + + AppDelegate + + + NSFontManager + + + + 256 + + Apple HTML pasteboard type + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple URL pasteboard type + Apple Web Archive pasteboard type + NSColor pasteboard type + NSFilenamesPboardType + NSStringPboardType + NeXT RTFD pasteboard type + NeXT Rich Text Format v1.0 pasteboard type + NeXT TIFF v4.0 pasteboard type + WebURLsWithTitlesPboardType + public.png + public.url + public.url-name + + {254, 200} + + + + _NS:9 + + + + YES + YES + + + + + + + terminate: + + + + 449 + + + + orderFrontStandardAboutPanel: + + + + 142 + + + + delegate + + + + 495 + + + + performMiniaturize: + + + + 37 + + + + arrangeInFront: + + + + 39 + + + + print: + + + + 86 + + + + runPageLayout: + + + + 87 + + + + clearRecentDocuments: + + + + 127 + + + + performClose: + + + + 193 + + + + toggleContinuousSpellChecking: + + + + 222 + + + + undo: + + + + 223 + + + + copy: + + + + 224 + + + + checkSpelling: + + + + 225 + + + + paste: + + + + 226 + + + + stopSpeaking: + + + + 227 + + + + cut: + + + + 228 + + + + showGuessPanel: + + + + 230 + + + + redo: + + + + 231 + + + + selectAll: + + + + 232 + + + + startSpeaking: + + + + 233 + + + + delete: + + + + 235 + + + + performZoom: + + + + 240 + + + + performFindPanelAction: + + + + 241 + + + + centerSelectionInVisibleArea: + + + + 245 + + + + toggleGrammarChecking: + + + + 347 + + + + toggleSmartInsertDelete: + + + + 355 + + + + toggleAutomaticQuoteSubstitution: + + + + 356 + + + + toggleAutomaticLinkDetection: + + + + 357 + + + + saveDocument: + + + + 362 + + + + revertDocumentToSaved: + + + + 364 + + + + runToolbarCustomizationPalette: + + + + 365 + + + + toggleToolbarShown: + + + + 366 + + + + hide: + + + + 367 + + + + hideOtherApplications: + + + + 368 + + + + unhideAllApplications: + + + + 370 + + + + newDocument: + + + + 373 + + + + openDocument: + + + + 374 + + + + raiseBaseline: + + + + 426 + + + + lowerBaseline: + + + + 427 + + + + copyFont: + + + + 428 + + + + subscript: + + + + 429 + + + + superscript: + + + + 430 + + + + tightenKerning: + + + + 431 + + + + underline: + + + + 432 + + + + orderFrontColorPanel: + + + + 433 + + + + useAllLigatures: + + + + 434 + + + + loosenKerning: + + + + 435 + + + + pasteFont: + + + + 436 + + + + unscript: + + + + 437 + + + + useStandardKerning: + + + + 438 + + + + useStandardLigatures: + + + + 439 + + + + turnOffLigatures: + + + + 440 + + + + turnOffKerning: + + + + 441 + + + + toggleAutomaticSpellingCorrection: + + + + 456 + + + + orderFrontSubstitutionsPanel: + + + + 458 + + + + toggleAutomaticDashSubstitution: + + + + 461 + + + + toggleAutomaticTextReplacement: + + + + 463 + + + + uppercaseWord: + + + + 464 + + + + capitalizeWord: + + + + 467 + + + + lowercaseWord: + + + + 468 + + + + pasteAsPlainText: + + + + 486 + + + + performFindPanelAction: + + + + 487 + + + + performFindPanelAction: + + + + 488 + + + + performFindPanelAction: + + + + 489 + + + + showHelp: + + + + 493 + + + + alignCenter: + + + + 518 + + + + pasteRuler: + + + + 519 + + + + toggleRuler: + + + + 520 + + + + alignRight: + + + + 521 + + + + copyRuler: + + + + 522 + + + + alignJustified: + + + + 523 + + + + alignLeft: + + + + 524 + + + + makeBaseWritingDirectionNatural: + + + + 525 + + + + makeBaseWritingDirectionLeftToRight: + + + + 526 + + + + makeBaseWritingDirectionRightToLeft: + + + + 527 + + + + makeTextWritingDirectionNatural: + + + + 528 + + + + makeTextWritingDirectionLeftToRight: + + + + 529 + + + + makeTextWritingDirectionRightToLeft: + + + + 530 + + + + performFindPanelAction: + + + + 535 + + + + addFontTrait: + + + + 421 + + + + addFontTrait: + + + + 422 + + + + modifyFont: + + + + 423 + + + + orderFrontFontPanel: + + + + 424 + + + + modifyFont: + + + + 425 + + + + window + + + + 532 + + + + webView + + + + 543 + + + + sendMessage: + + + + 555 + + + + callHandler: + + + + 556 + + + + + + 0 + + + + + + -2 + + + File's Owner + + + -1 + + + First Responder + + + -3 + + + Application + + + 29 + + + + + + + + + + + + + + 19 + + + + + + + + 56 + + + + + + + + 217 + + + + + + + + 83 + + + + + + + + 81 + + + + + + + + + + + + + + + + + 75 + + + + + 78 + + + + + 72 + + + + + 82 + + + + + 124 + + + + + + + + 77 + + + + + 73 + + + + + 79 + + + + + 112 + + + + + 74 + + + + + 125 + + + + + + + + 126 + + + + + 205 + + + + + + + + + + + + + + + + + + + + + + 202 + + + + + 198 + + + + + 207 + + + + + 214 + + + + + 199 + + + + + 203 + + + + + 197 + + + + + 206 + + + + + 215 + + + + + 218 + + + + + + + + 216 + + + + + + + + 200 + + + + + + + + + + + + + 219 + + + + + 201 + + + + + 204 + + + + + 220 + + + + + + + + + + + + + 213 + + + + + 210 + + + + + 221 + + + + + 208 + + + + + 209 + + + + + 57 + + + + + + + + + + + + + + + + + + 58 + + + + + 134 + + + + + 150 + + + + + 136 + + + + + 144 + + + + + 129 + + + + + 143 + + + + + 236 + + + + + 131 + + + + + + + + 149 + + + + + 145 + + + + + 130 + + + + + 24 + + + + + + + + + + + 92 + + + + + 5 + + + + + 239 + + + + + 23 + + + + + 295 + + + + + + + + 296 + + + + + + + + + 297 + + + + + 298 + + + + + 211 + + + + + + + + 212 + + + + + + + + + 195 + + + + + 196 + + + + + 346 + + + + + 348 + + + + + + + + 349 + + + + + + + + + + + + + + 350 + + + + + 351 + + + + + 354 + + + + + 371 + + + + + + + + 372 + + + + + 11 + 0 + + 11 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + + + + 5 + 0 + + 6 + 1 + + 8 + + 1000 + + 6 + 24 + 3 + + + + 3 + 0 + + 4 + 1 + + 8 + + 1000 + + 6 + 24 + 3 + + + + 5 + 0 + + 5 + 1 + + 20 + + 1000 + + 8 + 29 + 3 + + + + 6 + 0 + + 6 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + 3 + 0 + + 3 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + 5 + 0 + + 5 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + + + + + + 375 + + + + + + + + 376 + + + + + + + + + 377 + + + + + + + + 388 + + + + + + + + + + + + + + + + + + + + + + + 389 + + + + + 390 + + + + + 391 + + + + + 392 + + + + + 393 + + + + + 394 + + + + + 395 + + + + + 396 + + + + + 397 + + + + + + + + 398 + + + + + + + + 399 + + + + + + + + 400 + + + + + 401 + + + + + 402 + + + + + 403 + + + + + 404 + + + + + 405 + + + + + + + + + + + + 406 + + + + + 407 + + + + + 408 + + + + + 409 + + + + + 410 + + + + + 411 + + + + + + + + + + 412 + + + + + 413 + + + + + 414 + + + + + 415 + + + + + + + + + + + 416 + + + + + 417 + + + + + 418 + + + + + 419 + + + + + 420 + + + + + 450 + + + + + + + + 451 + + + + + + + + + + 452 + + + + + 453 + + + + + 454 + + + + + 457 + + + + + 459 + + + + + 460 + + + + + 462 + + + + + 465 + + + + + 466 + + + + + 485 + + + + + 490 + + + + + + + + 491 + + + + + + + + 492 + + + + + 494 + + + + + 496 + + + + + + + + 497 + + + + + + + + + + + + + + + + + 498 + + + + + 499 + + + + + 500 + + + + + 501 + + + + + 502 + + + + + 503 + + + + + + + + 504 + + + + + 505 + + + + + 506 + + + + + 507 + + + + + 508 + + + + + + + + + + + + + + + + 509 + + + + + 510 + + + + + 511 + + + + + 512 + + + + + 513 + + + + + 514 + + + + + 515 + + + + + 516 + + + + + 517 + + + + + 534 + + + + + 536 + + + + + 8 + 0 + + 0 + 1 + + 323 + + 1000 + + 3 + 9 + 1 + + + + + + 539 + + + + + 540 + + + + + 542 + + + + + 544 + + + + + 545 + + + + + + + + 546 + + + + + 550 + + + + + 551 + + + + + + + + 552 + + + + + 554 + + + + + 557 + + + + + 558 + + + + + 559 + + + + + + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + {{380, 496}, {480, 360}} + + + + + + + + + + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + + + + com.apple.WebKitIBPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.WebKitIBPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + + + + + 559 + + + + + AppDelegate + NSObject + + id + id + + + + callHandler: + id + + + sendMessage: + id + + + + WebView + NSWindow + + + + webView + WebView + + + window + NSWindow + + + + IBProjectSource + ./Classes/AppDelegate.h + + + + NSLayoutConstraint + NSObject + + IBProjectSource + ./Classes/NSLayoutConstraint.h + + + + + 0 + IBCocoaFramework + YES + 3 + + {11, 11} + {10, 3} + + YES + + diff --git a/ExampleApp-OSX/main.m b/ExampleApp-OSX/main.m new file mode 100644 index 00000000..ae7b871a --- /dev/null +++ b/ExampleApp-OSX/main.m @@ -0,0 +1,14 @@ +// +// main.m +// ExampleApp-OSX +// +// Created by Antoine Lagadec on 07/04/13. +// Copyright (c) 2013 Antoine Lagadec. All rights reserved. +// + +#import + +int main(int argc, char *argv[]) +{ + return NSApplicationMain(argc, (const char **)argv); +} diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge_OSX.h b/WebViewJavascriptBridge/WebViewJavascriptBridge_OSX.h new file mode 100644 index 00000000..9a8b2f4f --- /dev/null +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge_OSX.h @@ -0,0 +1,20 @@ +// +// WebViewJavascriptBridge+OSX.h +// ExampleApp-OSX +// +// Created by Antoine Lagadec on 07/04/13. +// Copyright (c) 2013 Antoine Lagadec. All rights reserved. +// + +#import +#import "WebViewJavascriptBridgeAbstract.h" + +@interface WebViewJavascriptBridge : WebViewJavascriptBridgeAbstract + +@property (nonatomic, strong) WebView *webView; +@property (nonatomic, strong) id webViewDelegate; + ++ (id)bridgeForWebView:(WebView*)webView handler:(WVJBHandler)handler; ++ (id)bridgeForWebView:(WebView*)webView webViewDelegate:(id)webViewDelegate handler:(WVJBHandler)handler; + +@end diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge_OSX.m b/WebViewJavascriptBridge/WebViewJavascriptBridge_OSX.m new file mode 100644 index 00000000..02ee2ed2 --- /dev/null +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge_OSX.m @@ -0,0 +1,96 @@ +// +// WebViewJavascriptBridge+OSX.m +// ExampleApp-OSX +// +// Created by Antoine Lagadec on 07/04/13. +// Copyright (c) 2013 Antoine Lagadec. All rights reserved. +// + +#import "WebViewJavascriptBridge_OSX.h" + +@implementation WebViewJavascriptBridge + ++ (id)bridgeForWebView:(WebView *)webView handler:(WVJBHandler)handler { + return [self bridgeForWebView:webView webViewDelegate:nil handler:handler]; +} + ++ (id)bridgeForWebView:(WebView *)webView webViewDelegate:(id)webViewDelegate handler:(WVJBHandler)messageHandler { + WebViewJavascriptBridge* bridge = [[WebViewJavascriptBridge alloc] init]; + bridge.messageHandler = messageHandler; + bridge.webView = webView; + bridge.webViewDelegate = webViewDelegate; + bridge.messageHandlers = [NSMutableDictionary dictionary]; + [bridge reset]; + + bridge.webView.frameLoadDelegate = bridge; + bridge.webView.resourceLoadDelegate = bridge; + bridge.webView.policyDelegate = bridge; + + return bridge; +} + +- (void)webView:(WebView *)webView didFinishLoadForFrame:(WebFrame *)frame +{ + if (webView != self.webView) { return; } + + if (![[self.webView stringByEvaluatingJavaScriptFromString:@"typeof WebViewJavascriptBridge == 'object'"] isEqualToString:@"true"]) { + NSString *filePath = [[NSBundle mainBundle] pathForResource:@"WebViewJavascriptBridge.js" ofType:@"txt"]; + NSString *js = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; + [self.webView stringByEvaluatingJavaScriptFromString:js]; + } + + if (self.startupMessageQueue) { + for (id queuedMessage in self.startupMessageQueue) { + [self _dispatchMessage:queuedMessage]; + } + self.startupMessageQueue = nil; + } + + if (self.webViewDelegate && [self.webViewDelegate respondsToSelector:@selector(webView:didFinishLoadForFrame:)]) { + [self.webViewDelegate webView:webView didFinishLoadForFrame:frame]; + } +} + +- (void)webView:(WebView *)webView didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame { + if (webView != self.webView) { return; } + if (self.webViewDelegate && [self.webViewDelegate respondsToSelector:@selector(webView:didFailLoadWithError:forFrame:)]) { + [self.webViewDelegate webView:self.webView didFailLoadWithError:error forFrame:frame]; + } +} + +- (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id)listener +{ + if (webView != self.webView) { [listener use]; } + NSURL *url = [request URL]; + if ([[url scheme] isEqualToString:kCustomProtocolScheme]) { + if ([[url host] isEqualToString:kQueueHasMessage]) { + [self _flushMessageQueue]; + } else { + NSLog(@"WebViewJavascriptBridge: WARNING: Received unknown WebViewJavascriptBridge command %@://%@", kCustomProtocolScheme, [url path]); + } + [listener ignore]; + } else if ([self.webView resourceLoadDelegate] + && [self.webViewDelegate respondsToSelector:@selector(webView:decidePolicyForNavigationAction:request:frame:decisionListener:)]) { + [self.webViewDelegate webView:webView decidePolicyForNavigationAction:actionInformation request:request frame:frame decisionListener:listener]; + } else { + [listener use]; + } +} + +- (void)webView:(WebView *)webView didCommitLoadForFrame:(WebFrame *)frame { + if (webView != self.webView) { return; } + if (self.webViewDelegate && [self.webViewDelegate respondsToSelector:@selector(webView:didCommitLoadForFrame:)]) { + [self.webViewDelegate webView:webView didCommitLoadForFrame:frame]; + } +} + +- (NSURLRequest *)webView:(WebView *)webView resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource { + if (webView != self.webView) { return request; } + if (self.webViewDelegate && [self.webViewDelegate respondsToSelector:@selector(webView:resource:willSendRequest:redirectResponse:fromDataSource:)]) { + return [self.webViewDelegate webView:webView resource:identifier willSendRequest:request redirectResponse:redirectResponse fromDataSource:dataSource]; + } + + return request; +} + +@end From 23647a1b20faa0a33934a500de13f296d4b56e2a Mon Sep 17 00:00:00 2001 From: Antoine Lagadec Date: Sun, 7 Apr 2013 15:33:33 +0200 Subject: [PATCH 078/353] Add a workspace for testing facility --- ExampleApp-OSX.xcodeproj/project.pbxproj | 56 +++++++--------- ExampleApp-OSX/en.lproj/Credits.rtf | 29 -------- ExampleApp-iOS.xcodeproj/project.pbxproj | 58 +++++++++------- ExampleApp-iOS/ExampleApp.html | 66 ------------------- .../ExampleApp.html => ExampleApp.html | 0 .../contents.xcworkspacedata | 10 +++ 6 files changed, 65 insertions(+), 154 deletions(-) delete mode 100644 ExampleApp-OSX/en.lproj/Credits.rtf delete mode 100644 ExampleApp-iOS/ExampleApp.html rename ExampleApp-OSX/ExampleApp.html => ExampleApp.html (100%) create mode 100644 WebViewJavascriptBridge.xcworkspace/contents.xcworkspacedata diff --git a/ExampleApp-OSX.xcodeproj/project.pbxproj b/ExampleApp-OSX.xcodeproj/project.pbxproj index 94d32ce7..16b0d16b 100644 --- a/ExampleApp-OSX.xcodeproj/project.pbxproj +++ b/ExampleApp-OSX.xcodeproj/project.pbxproj @@ -10,14 +10,13 @@ 2CA045DA171178E5006DEE8B /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2CA045D9171178E5006DEE8B /* Cocoa.framework */; }; 2CA045E4171178E6006DEE8B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 2CA045E2171178E6006DEE8B /* InfoPlist.strings */; }; 2CA045E6171178E6006DEE8B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CA045E5171178E6006DEE8B /* main.m */; }; - 2CA045EA171178E6006DEE8B /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 2CA045E8171178E6006DEE8B /* Credits.rtf */; }; 2CA045ED171178E6006DEE8B /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CA045EC171178E6006DEE8B /* AppDelegate.m */; }; 2CA045F0171178E6006DEE8B /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2CA045EE171178E6006DEE8B /* MainMenu.xib */; }; - 2CA045FE17117A69006DEE8B /* WebViewJavascriptBridge.js.txt in Resources */ = {isa = PBXBuildFile; fileRef = 2CA045FC17117A69006DEE8B /* WebViewJavascriptBridge.js.txt */; }; - 2CA0460317117A84006DEE8B /* WebViewJavascriptBridge_OSX.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CA0460217117A84006DEE8B /* WebViewJavascriptBridge_OSX.m */; }; 2CA0460517117B56006DEE8B /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2CA0460417117B56006DEE8B /* WebKit.framework */; }; - 2CA0460A17118B08006DEE8B /* ExampleApp.html in Resources */ = {isa = PBXBuildFile; fileRef = 2CA0460917118B08006DEE8B /* ExampleApp.html */; }; - 2CA046161711A1CC006DEE8B /* WebViewJavascriptBridgeAbstract.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CA046151711A1CC006DEE8B /* WebViewJavascriptBridgeAbstract.m */; }; + 2CA046531711AC29006DEE8B /* WebViewJavascriptBridge.js.txt in Resources */ = {isa = PBXBuildFile; fileRef = 2CA0464C1711AC29006DEE8B /* WebViewJavascriptBridge.js.txt */; }; + 2CA046551711AC29006DEE8B /* WebViewJavascriptBridge_OSX.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CA046501711AC29006DEE8B /* WebViewJavascriptBridge_OSX.m */; }; + 2CA046561711AC29006DEE8B /* WebViewJavascriptBridgeAbstract.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CA046521711AC29006DEE8B /* WebViewJavascriptBridgeAbstract.m */; }; + 2CA0465E1711AC96006DEE8B /* ExampleApp.html in Resources */ = {isa = PBXBuildFile; fileRef = 2CA0465D1711AC96006DEE8B /* ExampleApp.html */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -30,17 +29,16 @@ 2CA045E3171178E6006DEE8B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 2CA045E5171178E6006DEE8B /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 2CA045E7171178E6006DEE8B /* ExampleApp-OSX-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ExampleApp-OSX-Prefix.pch"; sourceTree = ""; }; - 2CA045E9171178E6006DEE8B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = en; path = en.lproj/Credits.rtf; sourceTree = ""; }; 2CA045EB171178E6006DEE8B /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 2CA045EC171178E6006DEE8B /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 2CA045EF171178E6006DEE8B /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = ""; }; - 2CA045FC17117A69006DEE8B /* WebViewJavascriptBridge.js.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebViewJavascriptBridge.js.txt; sourceTree = ""; }; - 2CA0460117117A84006DEE8B /* WebViewJavascriptBridge_OSX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridge_OSX.h; sourceTree = ""; }; - 2CA0460217117A84006DEE8B /* WebViewJavascriptBridge_OSX.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge_OSX.m; sourceTree = ""; }; 2CA0460417117B56006DEE8B /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; - 2CA0460917118B08006DEE8B /* ExampleApp.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = ExampleApp.html; sourceTree = ""; }; - 2CA046141711A1CC006DEE8B /* WebViewJavascriptBridgeAbstract.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridgeAbstract.h; sourceTree = ""; }; - 2CA046151711A1CC006DEE8B /* WebViewJavascriptBridgeAbstract.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridgeAbstract.m; sourceTree = ""; }; + 2CA0464C1711AC29006DEE8B /* WebViewJavascriptBridge.js.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebViewJavascriptBridge.js.txt; sourceTree = ""; }; + 2CA0464F1711AC29006DEE8B /* WebViewJavascriptBridge_OSX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridge_OSX.h; sourceTree = ""; }; + 2CA046501711AC29006DEE8B /* WebViewJavascriptBridge_OSX.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge_OSX.m; sourceTree = ""; }; + 2CA046511711AC29006DEE8B /* WebViewJavascriptBridgeAbstract.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridgeAbstract.h; sourceTree = ""; }; + 2CA046521711AC29006DEE8B /* WebViewJavascriptBridgeAbstract.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridgeAbstract.m; sourceTree = ""; }; + 2CA0465D1711AC96006DEE8B /* ExampleApp.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file; name = ExampleApp.html; path = ../ExampleApp.html; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -96,11 +94,11 @@ 2CA045DF171178E5006DEE8B /* ExampleApp-OSX */ = { isa = PBXGroup; children = ( + 2CA0465D1711AC96006DEE8B /* ExampleApp.html */, + 2CA0464B1711AC29006DEE8B /* WebViewJavascriptBridge */, 2CA045EB171178E6006DEE8B /* AppDelegate.h */, 2CA045EC171178E6006DEE8B /* AppDelegate.m */, 2CA045EE171178E6006DEE8B /* MainMenu.xib */, - 2CA0460917118B08006DEE8B /* ExampleApp.html */, - 2CA045FA17117A69006DEE8B /* WebViewJavascriptBridge */, 2CA045E0171178E6006DEE8B /* Supporting Files */, ); path = "ExampleApp-OSX"; @@ -113,19 +111,18 @@ 2CA045E2171178E6006DEE8B /* InfoPlist.strings */, 2CA045E5171178E6006DEE8B /* main.m */, 2CA045E7171178E6006DEE8B /* ExampleApp-OSX-Prefix.pch */, - 2CA045E8171178E6006DEE8B /* Credits.rtf */, ); name = "Supporting Files"; sourceTree = ""; }; - 2CA045FA17117A69006DEE8B /* WebViewJavascriptBridge */ = { + 2CA0464B1711AC29006DEE8B /* WebViewJavascriptBridge */ = { isa = PBXGroup; children = ( - 2CA046141711A1CC006DEE8B /* WebViewJavascriptBridgeAbstract.h */, - 2CA046151711A1CC006DEE8B /* WebViewJavascriptBridgeAbstract.m */, - 2CA045FC17117A69006DEE8B /* WebViewJavascriptBridge.js.txt */, - 2CA0460117117A84006DEE8B /* WebViewJavascriptBridge_OSX.h */, - 2CA0460217117A84006DEE8B /* WebViewJavascriptBridge_OSX.m */, + 2CA0464C1711AC29006DEE8B /* WebViewJavascriptBridge.js.txt */, + 2CA0464F1711AC29006DEE8B /* WebViewJavascriptBridge_OSX.h */, + 2CA046501711AC29006DEE8B /* WebViewJavascriptBridge_OSX.m */, + 2CA046511711AC29006DEE8B /* WebViewJavascriptBridgeAbstract.h */, + 2CA046521711AC29006DEE8B /* WebViewJavascriptBridgeAbstract.m */, ); path = WebViewJavascriptBridge; sourceTree = SOURCE_ROOT; @@ -182,10 +179,9 @@ buildActionMask = 2147483647; files = ( 2CA045E4171178E6006DEE8B /* InfoPlist.strings in Resources */, - 2CA045EA171178E6006DEE8B /* Credits.rtf in Resources */, 2CA045F0171178E6006DEE8B /* MainMenu.xib in Resources */, - 2CA045FE17117A69006DEE8B /* WebViewJavascriptBridge.js.txt in Resources */, - 2CA0460A17118B08006DEE8B /* ExampleApp.html in Resources */, + 2CA046531711AC29006DEE8B /* WebViewJavascriptBridge.js.txt in Resources */, + 2CA0465E1711AC96006DEE8B /* ExampleApp.html in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -198,8 +194,8 @@ files = ( 2CA045E6171178E6006DEE8B /* main.m in Sources */, 2CA045ED171178E6006DEE8B /* AppDelegate.m in Sources */, - 2CA0460317117A84006DEE8B /* WebViewJavascriptBridge_OSX.m in Sources */, - 2CA046161711A1CC006DEE8B /* WebViewJavascriptBridgeAbstract.m in Sources */, + 2CA046551711AC29006DEE8B /* WebViewJavascriptBridge_OSX.m in Sources */, + 2CA046561711AC29006DEE8B /* WebViewJavascriptBridgeAbstract.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -214,14 +210,6 @@ name = InfoPlist.strings; sourceTree = ""; }; - 2CA045E8171178E6006DEE8B /* Credits.rtf */ = { - isa = PBXVariantGroup; - children = ( - 2CA045E9171178E6006DEE8B /* en */, - ); - name = Credits.rtf; - sourceTree = ""; - }; 2CA045EE171178E6006DEE8B /* MainMenu.xib */ = { isa = PBXVariantGroup; children = ( diff --git a/ExampleApp-OSX/en.lproj/Credits.rtf b/ExampleApp-OSX/en.lproj/Credits.rtf deleted file mode 100644 index 46576ef2..00000000 --- a/ExampleApp-OSX/en.lproj/Credits.rtf +++ /dev/null @@ -1,29 +0,0 @@ -{\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;} -{\colortbl;\red255\green255\blue255;} -\paperw9840\paperh8400 -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural - -\f0\b\fs24 \cf0 Engineering: -\b0 \ - Some people\ -\ - -\b Human Interface Design: -\b0 \ - Some other people\ -\ - -\b Testing: -\b0 \ - Hopefully not nobody\ -\ - -\b Documentation: -\b0 \ - Whoever\ -\ - -\b With special thanks to: -\b0 \ - Mom\ -} diff --git a/ExampleApp-iOS.xcodeproj/project.pbxproj b/ExampleApp-iOS.xcodeproj/project.pbxproj index 455727cb..8338241b 100644 --- a/ExampleApp-iOS.xcodeproj/project.pbxproj +++ b/ExampleApp-iOS.xcodeproj/project.pbxproj @@ -8,12 +8,12 @@ /* Begin PBXBuildFile section */ 2CA045BF17117439006DEE8B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 2CA045B717117439006DEE8B /* InfoPlist.strings */; }; - 2CA045C117117439006DEE8B /* ExampleApp.html in Resources */ = {isa = PBXBuildFile; fileRef = 2CA045BB17117439006DEE8B /* ExampleApp.html */; }; 2CA045C217117439006DEE8B /* ExampleAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CA045BD17117439006DEE8B /* ExampleAppDelegate.m */; }; 2CA045C317117439006DEE8B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CA045BE17117439006DEE8B /* main.m */; }; - 2CA045C81711745D006DEE8B /* WebViewJavascriptBridge.js.txt in Resources */ = {isa = PBXBuildFile; fileRef = 2CA045C61711745D006DEE8B /* WebViewJavascriptBridge.js.txt */; }; - 2CA045C91711745D006DEE8B /* WebViewJavascriptBridgeAbstract.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CA045C71711745D006DEE8B /* WebViewJavascriptBridgeAbstract.m */; }; - 2CA0460817117BF9006DEE8B /* WebViewJavascriptBridge_iOS.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CA0460717117BF9006DEE8B /* WebViewJavascriptBridge_iOS.m */; }; + 2CA0465C1711AC8E006DEE8B /* ExampleApp.html in Resources */ = {isa = PBXBuildFile; fileRef = 2CA0465B1711AC8D006DEE8B /* ExampleApp.html */; }; + 2CA046671711ACC2006DEE8B /* WebViewJavascriptBridge.js.txt in Resources */ = {isa = PBXBuildFile; fileRef = 2CA046601711ACC2006DEE8B /* WebViewJavascriptBridge.js.txt */; }; + 2CA046681711ACC2006DEE8B /* WebViewJavascriptBridge_iOS.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CA046621711ACC2006DEE8B /* WebViewJavascriptBridge_iOS.m */; }; + 2CA0466A1711ACC2006DEE8B /* WebViewJavascriptBridgeAbstract.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CA046661711ACC2006DEE8B /* WebViewJavascriptBridgeAbstract.m */; }; 2CEB3EC01602563600548120 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2CEB3EBF1602563600548120 /* UIKit.framework */; }; 2CEB3EC21602563600548120 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2CEB3EC11602563600548120 /* Foundation.framework */; }; 2CEB3EC41602563600548120 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2CEB3EC31602563600548120 /* CoreGraphics.framework */; }; @@ -24,15 +24,15 @@ 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 = ""; }; - 2CA045BB17117439006DEE8B /* ExampleApp.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = ExampleApp.html; sourceTree = ""; }; 2CA045BC17117439006DEE8B /* ExampleAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExampleAppDelegate.h; sourceTree = ""; }; 2CA045BD17117439006DEE8B /* ExampleAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ExampleAppDelegate.m; sourceTree = ""; }; 2CA045BE17117439006DEE8B /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - 2CA045C51711745D006DEE8B /* WebViewJavascriptBridgeAbstract.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridgeAbstract.h; sourceTree = ""; }; - 2CA045C61711745D006DEE8B /* WebViewJavascriptBridge.js.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebViewJavascriptBridge.js.txt; sourceTree = ""; }; - 2CA045C71711745D006DEE8B /* WebViewJavascriptBridgeAbstract.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridgeAbstract.m; sourceTree = ""; }; - 2CA0460617117BF9006DEE8B /* WebViewJavascriptBridge_iOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridge_iOS.h; sourceTree = ""; }; - 2CA0460717117BF9006DEE8B /* WebViewJavascriptBridge_iOS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge_iOS.m; sourceTree = ""; }; + 2CA0465B1711AC8D006DEE8B /* ExampleApp.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = ExampleApp.html; sourceTree = SOURCE_ROOT; }; + 2CA046601711ACC2006DEE8B /* WebViewJavascriptBridge.js.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebViewJavascriptBridge.js.txt; sourceTree = ""; }; + 2CA046611711ACC2006DEE8B /* WebViewJavascriptBridge_iOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridge_iOS.h; sourceTree = ""; }; + 2CA046621711ACC2006DEE8B /* WebViewJavascriptBridge_iOS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge_iOS.m; sourceTree = ""; }; + 2CA046651711ACC2006DEE8B /* WebViewJavascriptBridgeAbstract.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridgeAbstract.h; sourceTree = ""; }; + 2CA046661711ACC2006DEE8B /* WebViewJavascriptBridgeAbstract.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridgeAbstract.m; sourceTree = ""; }; 2CEB3EBB1602563600548120 /* ExampleApp-iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "ExampleApp-iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 2CEB3EBF1602563600548120 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 2CEB3EC11602563600548120 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; @@ -57,26 +57,34 @@ 2CA045B617117439006DEE8B /* ExampleApp-iOS */ = { isa = PBXGroup; children = ( - 2CA045C41711745D006DEE8B /* WebViewJavascriptBridge */, + 2CA0465F1711ACC2006DEE8B /* WebViewJavascriptBridge */, + 2CA0465B1711AC8D006DEE8B /* ExampleApp.html */, + 2CA045BC17117439006DEE8B /* ExampleAppDelegate.h */, + 2CA045BD17117439006DEE8B /* ExampleAppDelegate.m */, + 2CA046211711A94E006DEE8B /* Supporting Files */, + ); + path = "ExampleApp-iOS"; + sourceTree = ""; + }; + 2CA046211711A94E006DEE8B /* Supporting Files */ = { + isa = PBXGroup; + children = ( 2CA045B717117439006DEE8B /* InfoPlist.strings */, 2CA045B917117439006DEE8B /* ExampleApp-iOS-Info.plist */, 2CA045BA17117439006DEE8B /* ExampleApp-iOS-Prefix.pch */, - 2CA045BB17117439006DEE8B /* ExampleApp.html */, - 2CA045BC17117439006DEE8B /* ExampleAppDelegate.h */, - 2CA045BD17117439006DEE8B /* ExampleAppDelegate.m */, 2CA045BE17117439006DEE8B /* main.m */, ); - path = "ExampleApp-iOS"; + name = "Supporting Files"; sourceTree = ""; }; - 2CA045C41711745D006DEE8B /* WebViewJavascriptBridge */ = { + 2CA0465F1711ACC2006DEE8B /* WebViewJavascriptBridge */ = { isa = PBXGroup; children = ( - 2CA045C51711745D006DEE8B /* WebViewJavascriptBridgeAbstract.h */, - 2CA045C61711745D006DEE8B /* WebViewJavascriptBridge.js.txt */, - 2CA045C71711745D006DEE8B /* WebViewJavascriptBridgeAbstract.m */, - 2CA0460617117BF9006DEE8B /* WebViewJavascriptBridge_iOS.h */, - 2CA0460717117BF9006DEE8B /* WebViewJavascriptBridge_iOS.m */, + 2CA046601711ACC2006DEE8B /* WebViewJavascriptBridge.js.txt */, + 2CA046611711ACC2006DEE8B /* WebViewJavascriptBridge_iOS.h */, + 2CA046621711ACC2006DEE8B /* WebViewJavascriptBridge_iOS.m */, + 2CA046651711ACC2006DEE8B /* WebViewJavascriptBridgeAbstract.h */, + 2CA046661711ACC2006DEE8B /* WebViewJavascriptBridgeAbstract.m */, ); path = WebViewJavascriptBridge; sourceTree = SOURCE_ROOT; @@ -162,8 +170,8 @@ files = ( 2CF988CE170E0BA500CA0CC7 /* Default-568h@2x.png in Resources */, 2CA045BF17117439006DEE8B /* InfoPlist.strings in Resources */, - 2CA045C117117439006DEE8B /* ExampleApp.html in Resources */, - 2CA045C81711745D006DEE8B /* WebViewJavascriptBridge.js.txt in Resources */, + 2CA0465C1711AC8E006DEE8B /* ExampleApp.html in Resources */, + 2CA046671711ACC2006DEE8B /* WebViewJavascriptBridge.js.txt in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -176,8 +184,8 @@ files = ( 2CA045C217117439006DEE8B /* ExampleAppDelegate.m in Sources */, 2CA045C317117439006DEE8B /* main.m in Sources */, - 2CA045C91711745D006DEE8B /* WebViewJavascriptBridgeAbstract.m in Sources */, - 2CA0460817117BF9006DEE8B /* WebViewJavascriptBridge_iOS.m in Sources */, + 2CA046681711ACC2006DEE8B /* WebViewJavascriptBridge_iOS.m in Sources */, + 2CA0466A1711ACC2006DEE8B /* WebViewJavascriptBridgeAbstract.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/ExampleApp-iOS/ExampleApp.html b/ExampleApp-iOS/ExampleApp.html deleted file mode 100644 index 5a12d4d2..00000000 --- a/ExampleApp-iOS/ExampleApp.html +++ /dev/null @@ -1,66 +0,0 @@ - - - - -

WebViewJavascriptBridge Demo

- -
- diff --git a/ExampleApp-OSX/ExampleApp.html b/ExampleApp.html similarity index 100% rename from ExampleApp-OSX/ExampleApp.html rename to ExampleApp.html diff --git a/WebViewJavascriptBridge.xcworkspace/contents.xcworkspacedata b/WebViewJavascriptBridge.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..2b523419 --- /dev/null +++ b/WebViewJavascriptBridge.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + From c4fbcd6182be55c17f2bdad43b72ac5ca554ca70 Mon Sep 17 00:00:00 2001 From: Antoine Lagadec Date: Sun, 7 Apr 2013 15:53:56 +0200 Subject: [PATCH 079/353] Update README.md --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b1ead06e..edccdc15 100644 --- a/README.md +++ b/README.md @@ -13,12 +13,13 @@ WebViewJavascriptBridge is used by a range of companies and projects. This list - [EverTrue](http://www.evertrue.com/) - [Game Insight](http://www.game-insight.com/) - [Altralogica](http://www.altralogica.it) +- [Sush.io](http://www.sush.io) - Flutterby Labs - JD Media's [鼎盛中华](https://itunes.apple.com/us/app/ding-sheng-zhong-hua/id537273940?mt=8) Are you using WebViewJavascript at your company? Add it and send us a pull request! -Setup & Examples +Setup & Examples (iOS) ---------------- Just open the Xcode project and hit run to see ExampleApp run. @@ -28,10 +29,11 @@ To use a WebViewJavascriptBridge in your own project: 1) Drag the `WebViewJavascriptBridge` folder into your project. - In the dialog that appears, uncheck "Copy items into destination group's folder" and select "Create groups for any folders" + - Delete OSX files. 2) Import the header file: - #import "WebViewJavascriptBridge.h" + #import "WebViewJavascriptBridge_iOS.h" 3) Instantiate a UIWebView and a WebViewJavascriptBridge: From 5775ebb7533096d0d3d1d509ef02f81be5ebe30d Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Thu, 18 Apr 2013 17:10:32 -0700 Subject: [PATCH 080/353] add disableLogging --- WebViewJavascriptBridge/WebViewJavascriptBridge.h | 1 + WebViewJavascriptBridge/WebViewJavascriptBridge.m | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.h b/WebViewJavascriptBridge/WebViewJavascriptBridge.h index 7eeaee3d..c052ee33 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.h +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.h @@ -7,6 +7,7 @@ typedef void (^WVJBHandler)(id data, WVJBResponseCallback responseCallback); + (id)bridgeForWebView:(UIWebView*)webView handler:(WVJBHandler)handler; + (id)bridgeForWebView:(UIWebView*)webView webViewDelegate:(id )webViewDelegate handler:(WVJBHandler)handler; + (void)enableLogging; ++ (void)disableLogging; - (void)send:(id)message; - (void)send:(id)message responseCallback:(WVJBResponseCallback)responseCallback; - (void)registerHandler:(NSString*)handlerName handler:(WVJBHandler)handler; diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index bf5f9583..ae375fb1 100755 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -45,8 +45,9 @@ + (id)bridgeForWebView:(UIWebView *)webView webViewDelegate:(id Date: Tue, 23 Apr 2013 18:11:21 -0700 Subject: [PATCH 081/353] Reorganize files so that: 1) including WVJB in an OSX or iOS project is simply dragging the one corresponding folder into your project (WebViewJavascriptBridge_iOS/OSX respectively), and 2) put all the example app contents in a single directory --- .../ExampleApp-OSX.xcodeproj}/project.pbxproj | 51 +++++++++------- .../ExampleApp-OSX}/AppDelegate.h | 0 .../ExampleApp-OSX}/AppDelegate.m | 0 .../ExampleApp-OSX}/ExampleApp-OSX-Info.plist | 0 .../ExampleApp-OSX}/ExampleApp-OSX-Prefix.pch | 0 .../en.lproj/InfoPlist.strings | 0 .../ExampleApp-OSX}/en.lproj/MainMenu.xib | 0 .../ExampleApp-OSX}/main.m | 0 .../ExampleApp-iOS.xcodeproj}/project.pbxproj | 57 ++++++++++-------- .../ExampleApp-iOS/Default-568h@2x.png | Bin .../ExampleApp-iOS}/ExampleApp-iOS-Info.plist | 0 .../ExampleApp-iOS}/ExampleApp-iOS-Prefix.pch | 0 .../ExampleApp-iOS}/ExampleAppDelegate.h | 0 .../ExampleApp-iOS}/ExampleAppDelegate.m | 0 .../en.lproj/InfoPlist.strings | 0 .../ExampleApp-iOS}/main.m | 0 .../ExampleApp.html | 0 .../WebViewJavascriptBridge.js.txt | 0 .../WebViewJavascriptBridgeAbstract.h | 0 .../WebViewJavascriptBridgeAbstract.m | 0 .../WebViewJavascriptAbstract | 1 + .../WebViewJavascriptBridge_OSX.h | 0 .../WebViewJavascriptBridge_OSX.m | 0 .../WebViewJavascriptAbstract | 1 + .../WebViewJavascriptBridge_iOS.h | 0 .../WebViewJavascriptBridge_iOS.m | 0 26 files changed, 65 insertions(+), 45 deletions(-) rename {ExampleApp-OSX.xcodeproj => Example Apps/ExampleApp-OSX.xcodeproj}/project.pbxproj (86%) rename {ExampleApp-OSX => Example Apps/ExampleApp-OSX}/AppDelegate.h (100%) rename {ExampleApp-OSX => Example Apps/ExampleApp-OSX}/AppDelegate.m (100%) rename {ExampleApp-OSX => Example Apps/ExampleApp-OSX}/ExampleApp-OSX-Info.plist (100%) rename {ExampleApp-OSX => Example Apps/ExampleApp-OSX}/ExampleApp-OSX-Prefix.pch (100%) rename {ExampleApp-OSX => Example Apps/ExampleApp-OSX}/en.lproj/InfoPlist.strings (100%) rename {ExampleApp-OSX => Example Apps/ExampleApp-OSX}/en.lproj/MainMenu.xib (100%) rename {ExampleApp-OSX => Example Apps/ExampleApp-OSX}/main.m (100%) rename {ExampleApp-iOS.xcodeproj => Example Apps/ExampleApp-iOS.xcodeproj}/project.pbxproj (83%) rename Default-568h@2x.png => Example Apps/ExampleApp-iOS/Default-568h@2x.png (100%) rename {ExampleApp-iOS => Example Apps/ExampleApp-iOS}/ExampleApp-iOS-Info.plist (100%) rename {ExampleApp-iOS => Example Apps/ExampleApp-iOS}/ExampleApp-iOS-Prefix.pch (100%) rename {ExampleApp-iOS => Example Apps/ExampleApp-iOS}/ExampleAppDelegate.h (100%) rename {ExampleApp-iOS => Example Apps/ExampleApp-iOS}/ExampleAppDelegate.m (100%) rename {ExampleApp-iOS => Example Apps/ExampleApp-iOS}/en.lproj/InfoPlist.strings (100%) rename {ExampleApp-iOS => Example Apps/ExampleApp-iOS}/main.m (100%) rename ExampleApp.html => Example Apps/ExampleApp.html (100%) rename {WebViewJavascriptBridge => WebViewJavascriptBridgeAbstract}/WebViewJavascriptBridge.js.txt (100%) rename {WebViewJavascriptBridge => WebViewJavascriptBridgeAbstract}/WebViewJavascriptBridgeAbstract.h (100%) rename {WebViewJavascriptBridge => WebViewJavascriptBridgeAbstract}/WebViewJavascriptBridgeAbstract.m (100%) create mode 120000 WebViewJavascriptBridge_OSX/WebViewJavascriptAbstract rename {WebViewJavascriptBridge => WebViewJavascriptBridge_OSX}/WebViewJavascriptBridge_OSX.h (100%) rename {WebViewJavascriptBridge => WebViewJavascriptBridge_OSX}/WebViewJavascriptBridge_OSX.m (100%) create mode 120000 WebViewJavascriptBridge_iOS/WebViewJavascriptAbstract rename {WebViewJavascriptBridge => WebViewJavascriptBridge_iOS}/WebViewJavascriptBridge_iOS.h (100%) rename {WebViewJavascriptBridge => WebViewJavascriptBridge_iOS}/WebViewJavascriptBridge_iOS.m (100%) diff --git a/ExampleApp-OSX.xcodeproj/project.pbxproj b/Example Apps/ExampleApp-OSX.xcodeproj/project.pbxproj similarity index 86% rename from ExampleApp-OSX.xcodeproj/project.pbxproj rename to Example Apps/ExampleApp-OSX.xcodeproj/project.pbxproj index 16b0d16b..5e5e13ab 100644 --- a/ExampleApp-OSX.xcodeproj/project.pbxproj +++ b/Example Apps/ExampleApp-OSX.xcodeproj/project.pbxproj @@ -13,10 +13,10 @@ 2CA045ED171178E6006DEE8B /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CA045EC171178E6006DEE8B /* AppDelegate.m */; }; 2CA045F0171178E6006DEE8B /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2CA045EE171178E6006DEE8B /* MainMenu.xib */; }; 2CA0460517117B56006DEE8B /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2CA0460417117B56006DEE8B /* WebKit.framework */; }; - 2CA046531711AC29006DEE8B /* WebViewJavascriptBridge.js.txt in Resources */ = {isa = PBXBuildFile; fileRef = 2CA0464C1711AC29006DEE8B /* WebViewJavascriptBridge.js.txt */; }; - 2CA046551711AC29006DEE8B /* WebViewJavascriptBridge_OSX.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CA046501711AC29006DEE8B /* WebViewJavascriptBridge_OSX.m */; }; - 2CA046561711AC29006DEE8B /* WebViewJavascriptBridgeAbstract.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CA046521711AC29006DEE8B /* WebViewJavascriptBridgeAbstract.m */; }; 2CA0465E1711AC96006DEE8B /* ExampleApp.html in Resources */ = {isa = PBXBuildFile; fileRef = 2CA0465D1711AC96006DEE8B /* ExampleApp.html */; }; + 2CAB8695172766DF00BD9ED1 /* WebViewJavascriptBridge.js.txt in Resources */ = {isa = PBXBuildFile; fileRef = 2CAB8690172766DF00BD9ED1 /* WebViewJavascriptBridge.js.txt */; }; + 2CAB8696172766DF00BD9ED1 /* WebViewJavascriptBridgeAbstract.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CAB8692172766DF00BD9ED1 /* WebViewJavascriptBridgeAbstract.m */; }; + 2CAB8697172766DF00BD9ED1 /* WebViewJavascriptBridge_OSX.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CAB8694172766DF00BD9ED1 /* WebViewJavascriptBridge_OSX.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -33,12 +33,12 @@ 2CA045EC171178E6006DEE8B /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 2CA045EF171178E6006DEE8B /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = ""; }; 2CA0460417117B56006DEE8B /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; - 2CA0464C1711AC29006DEE8B /* WebViewJavascriptBridge.js.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebViewJavascriptBridge.js.txt; sourceTree = ""; }; - 2CA0464F1711AC29006DEE8B /* WebViewJavascriptBridge_OSX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridge_OSX.h; sourceTree = ""; }; - 2CA046501711AC29006DEE8B /* WebViewJavascriptBridge_OSX.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge_OSX.m; sourceTree = ""; }; - 2CA046511711AC29006DEE8B /* WebViewJavascriptBridgeAbstract.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridgeAbstract.h; sourceTree = ""; }; - 2CA046521711AC29006DEE8B /* WebViewJavascriptBridgeAbstract.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridgeAbstract.m; sourceTree = ""; }; - 2CA0465D1711AC96006DEE8B /* ExampleApp.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file; name = ExampleApp.html; path = ../ExampleApp.html; sourceTree = ""; }; + 2CA0465D1711AC96006DEE8B /* ExampleApp.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = ExampleApp.html; path = ../ExampleApp.html; sourceTree = ""; }; + 2CAB8690172766DF00BD9ED1 /* WebViewJavascriptBridge.js.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebViewJavascriptBridge.js.txt; sourceTree = ""; }; + 2CAB8691172766DF00BD9ED1 /* WebViewJavascriptBridgeAbstract.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridgeAbstract.h; sourceTree = ""; }; + 2CAB8692172766DF00BD9ED1 /* WebViewJavascriptBridgeAbstract.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridgeAbstract.m; sourceTree = ""; }; + 2CAB8693172766DF00BD9ED1 /* WebViewJavascriptBridge_OSX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridge_OSX.h; sourceTree = ""; }; + 2CAB8694172766DF00BD9ED1 /* WebViewJavascriptBridge_OSX.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge_OSX.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -95,10 +95,10 @@ isa = PBXGroup; children = ( 2CA0465D1711AC96006DEE8B /* ExampleApp.html */, - 2CA0464B1711AC29006DEE8B /* WebViewJavascriptBridge */, 2CA045EB171178E6006DEE8B /* AppDelegate.h */, 2CA045EC171178E6006DEE8B /* AppDelegate.m */, 2CA045EE171178E6006DEE8B /* MainMenu.xib */, + 2CAB868E172766DF00BD9ED1 /* WebViewJavascriptBridge_OSX */, 2CA045E0171178E6006DEE8B /* Supporting Files */, ); path = "ExampleApp-OSX"; @@ -115,17 +115,26 @@ name = "Supporting Files"; sourceTree = ""; }; - 2CA0464B1711AC29006DEE8B /* WebViewJavascriptBridge */ = { + 2CAB868E172766DF00BD9ED1 /* WebViewJavascriptBridge_OSX */ = { isa = PBXGroup; children = ( - 2CA0464C1711AC29006DEE8B /* WebViewJavascriptBridge.js.txt */, - 2CA0464F1711AC29006DEE8B /* WebViewJavascriptBridge_OSX.h */, - 2CA046501711AC29006DEE8B /* WebViewJavascriptBridge_OSX.m */, - 2CA046511711AC29006DEE8B /* WebViewJavascriptBridgeAbstract.h */, - 2CA046521711AC29006DEE8B /* WebViewJavascriptBridgeAbstract.m */, + 2CAB868F172766DF00BD9ED1 /* WebViewJavascriptAbstract */, + 2CAB8693172766DF00BD9ED1 /* WebViewJavascriptBridge_OSX.h */, + 2CAB8694172766DF00BD9ED1 /* WebViewJavascriptBridge_OSX.m */, ); - path = WebViewJavascriptBridge; - sourceTree = SOURCE_ROOT; + name = WebViewJavascriptBridge_OSX; + path = ../../WebViewJavascriptBridge_OSX; + sourceTree = ""; + }; + 2CAB868F172766DF00BD9ED1 /* WebViewJavascriptAbstract */ = { + isa = PBXGroup; + children = ( + 2CAB8690172766DF00BD9ED1 /* WebViewJavascriptBridge.js.txt */, + 2CAB8691172766DF00BD9ED1 /* WebViewJavascriptBridgeAbstract.h */, + 2CAB8692172766DF00BD9ED1 /* WebViewJavascriptBridgeAbstract.m */, + ); + path = WebViewJavascriptAbstract; + sourceTree = ""; }; /* End PBXGroup section */ @@ -180,8 +189,8 @@ files = ( 2CA045E4171178E6006DEE8B /* InfoPlist.strings in Resources */, 2CA045F0171178E6006DEE8B /* MainMenu.xib in Resources */, - 2CA046531711AC29006DEE8B /* WebViewJavascriptBridge.js.txt in Resources */, 2CA0465E1711AC96006DEE8B /* ExampleApp.html in Resources */, + 2CAB8695172766DF00BD9ED1 /* WebViewJavascriptBridge.js.txt in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -194,8 +203,8 @@ files = ( 2CA045E6171178E6006DEE8B /* main.m in Sources */, 2CA045ED171178E6006DEE8B /* AppDelegate.m in Sources */, - 2CA046551711AC29006DEE8B /* WebViewJavascriptBridge_OSX.m in Sources */, - 2CA046561711AC29006DEE8B /* WebViewJavascriptBridgeAbstract.m in Sources */, + 2CAB8696172766DF00BD9ED1 /* WebViewJavascriptBridgeAbstract.m in Sources */, + 2CAB8697172766DF00BD9ED1 /* WebViewJavascriptBridge_OSX.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/ExampleApp-OSX/AppDelegate.h b/Example Apps/ExampleApp-OSX/AppDelegate.h similarity index 100% rename from ExampleApp-OSX/AppDelegate.h rename to Example Apps/ExampleApp-OSX/AppDelegate.h diff --git a/ExampleApp-OSX/AppDelegate.m b/Example Apps/ExampleApp-OSX/AppDelegate.m similarity index 100% rename from ExampleApp-OSX/AppDelegate.m rename to Example Apps/ExampleApp-OSX/AppDelegate.m diff --git a/ExampleApp-OSX/ExampleApp-OSX-Info.plist b/Example Apps/ExampleApp-OSX/ExampleApp-OSX-Info.plist similarity index 100% rename from ExampleApp-OSX/ExampleApp-OSX-Info.plist rename to Example Apps/ExampleApp-OSX/ExampleApp-OSX-Info.plist diff --git a/ExampleApp-OSX/ExampleApp-OSX-Prefix.pch b/Example Apps/ExampleApp-OSX/ExampleApp-OSX-Prefix.pch similarity index 100% rename from ExampleApp-OSX/ExampleApp-OSX-Prefix.pch rename to Example Apps/ExampleApp-OSX/ExampleApp-OSX-Prefix.pch diff --git a/ExampleApp-OSX/en.lproj/InfoPlist.strings b/Example Apps/ExampleApp-OSX/en.lproj/InfoPlist.strings similarity index 100% rename from ExampleApp-OSX/en.lproj/InfoPlist.strings rename to Example Apps/ExampleApp-OSX/en.lproj/InfoPlist.strings diff --git a/ExampleApp-OSX/en.lproj/MainMenu.xib b/Example Apps/ExampleApp-OSX/en.lproj/MainMenu.xib similarity index 100% rename from ExampleApp-OSX/en.lproj/MainMenu.xib rename to Example Apps/ExampleApp-OSX/en.lproj/MainMenu.xib diff --git a/ExampleApp-OSX/main.m b/Example Apps/ExampleApp-OSX/main.m similarity index 100% rename from ExampleApp-OSX/main.m rename to Example Apps/ExampleApp-OSX/main.m diff --git a/ExampleApp-iOS.xcodeproj/project.pbxproj b/Example Apps/ExampleApp-iOS.xcodeproj/project.pbxproj similarity index 83% rename from ExampleApp-iOS.xcodeproj/project.pbxproj rename to Example Apps/ExampleApp-iOS.xcodeproj/project.pbxproj index 8338241b..6a694a05 100644 --- a/ExampleApp-iOS.xcodeproj/project.pbxproj +++ b/Example Apps/ExampleApp-iOS.xcodeproj/project.pbxproj @@ -11,13 +11,13 @@ 2CA045C217117439006DEE8B /* ExampleAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CA045BD17117439006DEE8B /* ExampleAppDelegate.m */; }; 2CA045C317117439006DEE8B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CA045BE17117439006DEE8B /* main.m */; }; 2CA0465C1711AC8E006DEE8B /* ExampleApp.html in Resources */ = {isa = PBXBuildFile; fileRef = 2CA0465B1711AC8D006DEE8B /* ExampleApp.html */; }; - 2CA046671711ACC2006DEE8B /* WebViewJavascriptBridge.js.txt in Resources */ = {isa = PBXBuildFile; fileRef = 2CA046601711ACC2006DEE8B /* WebViewJavascriptBridge.js.txt */; }; - 2CA046681711ACC2006DEE8B /* WebViewJavascriptBridge_iOS.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CA046621711ACC2006DEE8B /* WebViewJavascriptBridge_iOS.m */; }; - 2CA0466A1711ACC2006DEE8B /* WebViewJavascriptBridgeAbstract.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CA046661711ACC2006DEE8B /* WebViewJavascriptBridgeAbstract.m */; }; + 2CAB868B172766B000BD9ED1 /* WebViewJavascriptBridge.js.txt in Resources */ = {isa = PBXBuildFile; fileRef = 2CAB8686172766B000BD9ED1 /* WebViewJavascriptBridge.js.txt */; }; + 2CAB868C172766B000BD9ED1 /* WebViewJavascriptBridgeAbstract.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CAB8688172766B000BD9ED1 /* WebViewJavascriptBridgeAbstract.m */; }; + 2CAB868D172766B000BD9ED1 /* WebViewJavascriptBridge_iOS.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CAB868A172766B000BD9ED1 /* WebViewJavascriptBridge_iOS.m */; }; + 2CAB869B1727684300BD9ED1 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CAB869A1727684300BD9ED1 /* Default-568h@2x.png */; }; 2CEB3EC01602563600548120 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2CEB3EBF1602563600548120 /* UIKit.framework */; }; 2CEB3EC21602563600548120 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2CEB3EC11602563600548120 /* Foundation.framework */; }; 2CEB3EC41602563600548120 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2CEB3EC31602563600548120 /* CoreGraphics.framework */; }; - 2CF988CE170E0BA500CA0CC7 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CF988CD170E0BA500CA0CC7 /* Default-568h@2x.png */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -28,16 +28,16 @@ 2CA045BD17117439006DEE8B /* ExampleAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ExampleAppDelegate.m; sourceTree = ""; }; 2CA045BE17117439006DEE8B /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 2CA0465B1711AC8D006DEE8B /* ExampleApp.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = ExampleApp.html; sourceTree = SOURCE_ROOT; }; - 2CA046601711ACC2006DEE8B /* WebViewJavascriptBridge.js.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebViewJavascriptBridge.js.txt; sourceTree = ""; }; - 2CA046611711ACC2006DEE8B /* WebViewJavascriptBridge_iOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridge_iOS.h; sourceTree = ""; }; - 2CA046621711ACC2006DEE8B /* WebViewJavascriptBridge_iOS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge_iOS.m; sourceTree = ""; }; - 2CA046651711ACC2006DEE8B /* WebViewJavascriptBridgeAbstract.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridgeAbstract.h; sourceTree = ""; }; - 2CA046661711ACC2006DEE8B /* WebViewJavascriptBridgeAbstract.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridgeAbstract.m; sourceTree = ""; }; + 2CAB8686172766B000BD9ED1 /* WebViewJavascriptBridge.js.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebViewJavascriptBridge.js.txt; sourceTree = ""; }; + 2CAB8687172766B000BD9ED1 /* WebViewJavascriptBridgeAbstract.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridgeAbstract.h; sourceTree = ""; }; + 2CAB8688172766B000BD9ED1 /* WebViewJavascriptBridgeAbstract.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridgeAbstract.m; sourceTree = ""; }; + 2CAB8689172766B000BD9ED1 /* WebViewJavascriptBridge_iOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridge_iOS.h; sourceTree = ""; }; + 2CAB868A172766B000BD9ED1 /* WebViewJavascriptBridge_iOS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge_iOS.m; sourceTree = ""; }; + 2CAB869A1727684300BD9ED1 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Default-568h@2x.png"; path = "ExampleApp-iOS/Default-568h@2x.png"; sourceTree = ""; }; 2CEB3EBB1602563600548120 /* ExampleApp-iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "ExampleApp-iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 2CEB3EBF1602563600548120 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 2CEB3EC11602563600548120 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 2CEB3EC31602563600548120 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; - 2CF988CD170E0BA500CA0CC7 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -57,10 +57,10 @@ 2CA045B617117439006DEE8B /* ExampleApp-iOS */ = { isa = PBXGroup; children = ( - 2CA0465F1711ACC2006DEE8B /* WebViewJavascriptBridge */, 2CA0465B1711AC8D006DEE8B /* ExampleApp.html */, 2CA045BC17117439006DEE8B /* ExampleAppDelegate.h */, 2CA045BD17117439006DEE8B /* ExampleAppDelegate.m */, + 2CAB8684172766B000BD9ED1 /* WebViewJavascriptBridge_iOS */, 2CA046211711A94E006DEE8B /* Supporting Files */, ); path = "ExampleApp-iOS"; @@ -77,22 +77,31 @@ name = "Supporting Files"; sourceTree = ""; }; - 2CA0465F1711ACC2006DEE8B /* WebViewJavascriptBridge */ = { + 2CAB8684172766B000BD9ED1 /* WebViewJavascriptBridge_iOS */ = { isa = PBXGroup; children = ( - 2CA046601711ACC2006DEE8B /* WebViewJavascriptBridge.js.txt */, - 2CA046611711ACC2006DEE8B /* WebViewJavascriptBridge_iOS.h */, - 2CA046621711ACC2006DEE8B /* WebViewJavascriptBridge_iOS.m */, - 2CA046651711ACC2006DEE8B /* WebViewJavascriptBridgeAbstract.h */, - 2CA046661711ACC2006DEE8B /* WebViewJavascriptBridgeAbstract.m */, + 2CAB8685172766B000BD9ED1 /* WebViewJavascriptAbstract */, + 2CAB8689172766B000BD9ED1 /* WebViewJavascriptBridge_iOS.h */, + 2CAB868A172766B000BD9ED1 /* WebViewJavascriptBridge_iOS.m */, ); - path = WebViewJavascriptBridge; - sourceTree = SOURCE_ROOT; + name = WebViewJavascriptBridge_iOS; + path = ../../WebViewJavascriptBridge_iOS; + sourceTree = ""; + }; + 2CAB8685172766B000BD9ED1 /* WebViewJavascriptAbstract */ = { + isa = PBXGroup; + children = ( + 2CAB8686172766B000BD9ED1 /* WebViewJavascriptBridge.js.txt */, + 2CAB8687172766B000BD9ED1 /* WebViewJavascriptBridgeAbstract.h */, + 2CAB8688172766B000BD9ED1 /* WebViewJavascriptBridgeAbstract.m */, + ); + path = WebViewJavascriptAbstract; + sourceTree = ""; }; 2CEB3EB01602563600548120 = { isa = PBXGroup; children = ( - 2CF988CD170E0BA500CA0CC7 /* Default-568h@2x.png */, + 2CAB869A1727684300BD9ED1 /* Default-568h@2x.png */, 2CA045B617117439006DEE8B /* ExampleApp-iOS */, 2CEB3EBE1602563600548120 /* Frameworks */, 2CEB3EBC1602563600548120 /* Products */, @@ -168,10 +177,10 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 2CF988CE170E0BA500CA0CC7 /* Default-568h@2x.png in Resources */, 2CA045BF17117439006DEE8B /* InfoPlist.strings in Resources */, 2CA0465C1711AC8E006DEE8B /* ExampleApp.html in Resources */, - 2CA046671711ACC2006DEE8B /* WebViewJavascriptBridge.js.txt in Resources */, + 2CAB868B172766B000BD9ED1 /* WebViewJavascriptBridge.js.txt in Resources */, + 2CAB869B1727684300BD9ED1 /* Default-568h@2x.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -184,8 +193,8 @@ files = ( 2CA045C217117439006DEE8B /* ExampleAppDelegate.m in Sources */, 2CA045C317117439006DEE8B /* main.m in Sources */, - 2CA046681711ACC2006DEE8B /* WebViewJavascriptBridge_iOS.m in Sources */, - 2CA0466A1711ACC2006DEE8B /* WebViewJavascriptBridgeAbstract.m in Sources */, + 2CAB868C172766B000BD9ED1 /* WebViewJavascriptBridgeAbstract.m in Sources */, + 2CAB868D172766B000BD9ED1 /* WebViewJavascriptBridge_iOS.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Default-568h@2x.png b/Example Apps/ExampleApp-iOS/Default-568h@2x.png similarity index 100% rename from Default-568h@2x.png rename to Example Apps/ExampleApp-iOS/Default-568h@2x.png diff --git a/ExampleApp-iOS/ExampleApp-iOS-Info.plist b/Example Apps/ExampleApp-iOS/ExampleApp-iOS-Info.plist similarity index 100% rename from ExampleApp-iOS/ExampleApp-iOS-Info.plist rename to Example Apps/ExampleApp-iOS/ExampleApp-iOS-Info.plist diff --git a/ExampleApp-iOS/ExampleApp-iOS-Prefix.pch b/Example Apps/ExampleApp-iOS/ExampleApp-iOS-Prefix.pch similarity index 100% rename from ExampleApp-iOS/ExampleApp-iOS-Prefix.pch rename to Example Apps/ExampleApp-iOS/ExampleApp-iOS-Prefix.pch diff --git a/ExampleApp-iOS/ExampleAppDelegate.h b/Example Apps/ExampleApp-iOS/ExampleAppDelegate.h similarity index 100% rename from ExampleApp-iOS/ExampleAppDelegate.h rename to Example Apps/ExampleApp-iOS/ExampleAppDelegate.h diff --git a/ExampleApp-iOS/ExampleAppDelegate.m b/Example Apps/ExampleApp-iOS/ExampleAppDelegate.m similarity index 100% rename from ExampleApp-iOS/ExampleAppDelegate.m rename to Example Apps/ExampleApp-iOS/ExampleAppDelegate.m diff --git a/ExampleApp-iOS/en.lproj/InfoPlist.strings b/Example Apps/ExampleApp-iOS/en.lproj/InfoPlist.strings similarity index 100% rename from ExampleApp-iOS/en.lproj/InfoPlist.strings rename to Example Apps/ExampleApp-iOS/en.lproj/InfoPlist.strings diff --git a/ExampleApp-iOS/main.m b/Example Apps/ExampleApp-iOS/main.m similarity index 100% rename from ExampleApp-iOS/main.m rename to Example Apps/ExampleApp-iOS/main.m diff --git a/ExampleApp.html b/Example Apps/ExampleApp.html similarity index 100% rename from ExampleApp.html rename to Example Apps/ExampleApp.html diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.js.txt b/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridge.js.txt similarity index 100% rename from WebViewJavascriptBridge/WebViewJavascriptBridge.js.txt rename to WebViewJavascriptBridgeAbstract/WebViewJavascriptBridge.js.txt diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridgeAbstract.h b/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.h similarity index 100% rename from WebViewJavascriptBridge/WebViewJavascriptBridgeAbstract.h rename to WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.h diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridgeAbstract.m b/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.m similarity index 100% rename from WebViewJavascriptBridge/WebViewJavascriptBridgeAbstract.m rename to WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.m diff --git a/WebViewJavascriptBridge_OSX/WebViewJavascriptAbstract b/WebViewJavascriptBridge_OSX/WebViewJavascriptAbstract new file mode 120000 index 00000000..2cb3269a --- /dev/null +++ b/WebViewJavascriptBridge_OSX/WebViewJavascriptAbstract @@ -0,0 +1 @@ +../WebViewJavascriptBridgeAbstract \ No newline at end of file diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge_OSX.h b/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.h similarity index 100% rename from WebViewJavascriptBridge/WebViewJavascriptBridge_OSX.h rename to WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.h diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge_OSX.m b/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.m similarity index 100% rename from WebViewJavascriptBridge/WebViewJavascriptBridge_OSX.m rename to WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.m diff --git a/WebViewJavascriptBridge_iOS/WebViewJavascriptAbstract b/WebViewJavascriptBridge_iOS/WebViewJavascriptAbstract new file mode 120000 index 00000000..2cb3269a --- /dev/null +++ b/WebViewJavascriptBridge_iOS/WebViewJavascriptAbstract @@ -0,0 +1 @@ +../WebViewJavascriptBridgeAbstract \ No newline at end of file diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge_iOS.h b/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.h similarity index 100% rename from WebViewJavascriptBridge/WebViewJavascriptBridge_iOS.h rename to WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.h diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge_iOS.m b/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m similarity index 100% rename from WebViewJavascriptBridge/WebViewJavascriptBridge_iOS.m rename to WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m From 0c529da77ad45f09a7d075ab55bec968da4334a3 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Tue, 23 Apr 2013 18:11:30 -0700 Subject: [PATCH 082/353] resolve compile-time warning --- .../WebViewJavascriptBridgeAbstract.h | 2 +- .../WebViewJavascriptBridgeAbstract.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.h b/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.h index 11864b6a..a5d3cd83 100644 --- a/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.h +++ b/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.h @@ -12,7 +12,7 @@ typedef void (^WVJBHandler)(id data, WVJBResponseCallback responseCallback); @property (nonatomic, strong) NSMutableArray *startupMessageQueue; @property (nonatomic, strong) NSMutableDictionary *responseCallbacks; @property (nonatomic, strong) NSMutableDictionary *messageHandlers; -@property (atomic, assign) NSInteger uniqueId; +@property (atomic, assign) long uniqueId; @property (nonatomic, copy) WVJBHandler messageHandler; + (void)enableLogging; diff --git a/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.m b/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.m index 830a5581..7e2408a2 100755 --- a/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.m +++ b/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.m @@ -51,7 +51,7 @@ - (void)_sendData:(NSDictionary *)data responseCallback:(WVJBResponseCallback)re NSMutableDictionary* message = [NSMutableDictionary dictionaryWithObject:data forKey:@"data"]; if (responseCallback) { - NSString* callbackId = [NSString stringWithFormat:@"objc_cb_%d", ++self.uniqueId]; + NSString* callbackId = [NSString stringWithFormat:@"objc_cb_%ld", ++self.uniqueId]; self.responseCallbacks[callbackId] = [responseCallback copy]; message[@"callbackId"] = callbackId; } From 8486e00c173627efdc38d9db53718146e09a4cb4 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Tue, 23 Apr 2013 18:26:42 -0700 Subject: [PATCH 083/353] update README instructions to deal with both iOS and OSX --- README.md | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index edccdc15..562b9152 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ WebViewJavascriptBridge ======================= -An iOS bridge for sending messages to and from javascript in a UIWebView. +An iOS/OSX bridge for sending messages between Obj-C and JavaScript in UIWebViews/WebViews. -If you like WebViewJavascriptBridge you should also check out [WebViewProxy](https://github.com/marcuswestin/WebViewProxy). +If you like WebViewJavascriptBridge you may also want to check out [WebViewProxy](https://github.com/marcuswestin/WebViewProxy). In the Wild ----------- -WebViewJavascriptBridge is used by a range of companies and projects. This list was just started and is still very incomplete. +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. - [Yardsale](https://www.getyardsale.com/) - [EverTrue](http://www.evertrue.com/) @@ -17,27 +17,26 @@ 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) -Are you using WebViewJavascript at your company? Add it and send us a pull request! +Setup & Examples (iOS & OSX) +---------------------------- -Setup & Examples (iOS) ----------------- - -Just open the Xcode project and hit run to see ExampleApp run. +Start with the Example Apps/ folder. Open either the iOS or OSX project and hit run to see it in action. To use a WebViewJavascriptBridge in your own project: -1) Drag the `WebViewJavascriptBridge` folder into your project. +1) Drag the `WebViewJavascriptBridge_iOS` or `WebViewJavascriptBridge_OSX` folder into your project. - In the dialog that appears, uncheck "Copy items into destination group's folder" and select "Create groups for any folders" - - Delete OSX files. - + 2) Import the header file: + // for iOS: #import "WebViewJavascriptBridge_iOS.h" + // for OSX: + #import "WebViewJavascriptBridge_OSX.h" -3) Instantiate a UIWebView and a WebViewJavascriptBridge: +3) Instantiate WebViewJavascriptBridge with a UIWebView (iOS) or WebView (OSX): - UIWebView* webView = [[UIWebView alloc] initWithFrame:self.window.bounds]; WebViewJavascriptBridge* bridge = [WebViewJavascriptBridge bridgeForWebView:webView handler:^(id data, WVJBResponseCallback responseCallback) { NSLog(@"Received message from javascript: %@", data); responseCallback(@"Right back atcha"); @@ -72,14 +71,14 @@ API Reference ### ObjC API -##### `[WebViewJavascriptBridge bridgeForWebView:(UIWebView*)webview handler:(WVJBHandler)handler]` -##### `[WebViewJavascriptBridge bridgeForWebView:(UIWebView*)webview webViewDelegate:(UIWebViewDelegate*)webViewDelegate handler:(WVJBHandler)handler]` +##### `[WebViewJavascriptBridge bridgeForWebView:(UIWebView/WebView*)webview handler:(WVJBHandler)handler]` +##### `[WebViewJavascriptBridge bridgeForWebView:(UIWebView/WebView*)webview webViewDelegate:(UIWebViewDelegate*)webViewDelegate handler:(WVJBHandler)handler]` -Create a javascript bridge for the given UIWebView. +Create a javascript bridge for the given web view. The `WVJBResponseCallback` will not be `nil` if the javascript expects a response. -Optionally, pass in `webViewDelegate:(UIWebViewDelegate*)webViewDelegate` if you need to respond to the [UIWebView's lifecycle events](http://developer.apple.com/library/ios/documentation/uikit/reference/UIWebViewDelegate_Protocol/Reference/Reference.html). +Optionally, pass in `webViewDelegate:(UIWebViewDelegate*)webViewDelegate` if you need to respond to the [web view's lifecycle events](http://developer.apple.com/library/ios/documentation/uikit/reference/UIWebViewDelegate_Protocol/Reference/Reference.html). Example: @@ -186,7 +185,7 @@ Example: iOS4 support (with JSONKit) --------------------------- -*Note*: iOS4 support has not yet been tested in v2. +*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. From 6a5cb6530175a24fda759461825c62646d2f6ca2 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Tue, 23 Apr 2013 18:28:28 -0700 Subject: [PATCH 084/353] Add @oakho to list of contributors, and reassign copyright of entire library to include both Marcus Westin and Antoine Lagadec. --- Example Apps/ExampleApp-OSX/AppDelegate.h | 8 -------- Example Apps/ExampleApp-OSX/AppDelegate.m | 8 -------- Example Apps/ExampleApp-OSX/ExampleApp-OSX-Info.plist | 2 +- Example Apps/ExampleApp-OSX/main.m | 8 -------- Example Apps/ExampleApp-iOS/main.m | 8 -------- LICENSE | 2 +- README.md | 4 ++-- WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.h | 8 -------- WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.m | 8 -------- WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.h | 8 -------- WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m | 8 -------- 11 files changed, 4 insertions(+), 68 deletions(-) diff --git a/Example Apps/ExampleApp-OSX/AppDelegate.h b/Example Apps/ExampleApp-OSX/AppDelegate.h index 96bb190a..ddbd75fd 100644 --- a/Example Apps/ExampleApp-OSX/AppDelegate.h +++ b/Example Apps/ExampleApp-OSX/AppDelegate.h @@ -1,11 +1,3 @@ -// -// AppDelegate.h -// ExampleApp-OSX -// -// Created by Antoine Lagadec on 07/04/13. -// Copyright (c) 2013 Antoine Lagadec. All rights reserved. -// - #import #import "WebViewJavascriptBridge_OSX.h" diff --git a/Example Apps/ExampleApp-OSX/AppDelegate.m b/Example Apps/ExampleApp-OSX/AppDelegate.m index ed31863b..4db9997b 100644 --- a/Example Apps/ExampleApp-OSX/AppDelegate.m +++ b/Example Apps/ExampleApp-OSX/AppDelegate.m @@ -1,11 +1,3 @@ -// -// AppDelegate.m -// ExampleApp-OSX -// -// Created by Antoine Lagadec on 07/04/13. -// Copyright (c) 2013 Antoine Lagadec. All rights reserved. -// - #import "AppDelegate.h" @implementation AppDelegate diff --git a/Example Apps/ExampleApp-OSX/ExampleApp-OSX-Info.plist b/Example Apps/ExampleApp-OSX/ExampleApp-OSX-Info.plist index 5a46a8d8..18703404 100644 --- a/Example Apps/ExampleApp-OSX/ExampleApp-OSX-Info.plist +++ b/Example Apps/ExampleApp-OSX/ExampleApp-OSX-Info.plist @@ -25,7 +25,7 @@ LSMinimumSystemVersion ${MACOSX_DEPLOYMENT_TARGET} NSHumanReadableCopyright - Copyright © 2013 Antoine Lagadec. All rights reserved. + Copyright © 2013 Marcus Westin, Antoine Lagadec. All rights reserved. NSMainNibFile MainMenu NSPrincipalClass diff --git a/Example Apps/ExampleApp-OSX/main.m b/Example Apps/ExampleApp-OSX/main.m index ae7b871a..04d99dab 100644 --- a/Example Apps/ExampleApp-OSX/main.m +++ b/Example Apps/ExampleApp-OSX/main.m @@ -1,11 +1,3 @@ -// -// main.m -// ExampleApp-OSX -// -// Created by Antoine Lagadec on 07/04/13. -// Copyright (c) 2013 Antoine Lagadec. All rights reserved. -// - #import int main(int argc, char *argv[]) diff --git a/Example Apps/ExampleApp-iOS/main.m b/Example Apps/ExampleApp-iOS/main.m index a724dc9c..5887dbf1 100644 --- a/Example Apps/ExampleApp-iOS/main.m +++ b/Example Apps/ExampleApp-iOS/main.m @@ -1,11 +1,3 @@ -// -// main.m -// ExampleApp -// -// Created by Marcus Westin on 9/13/12. -// Copyright (c) 2012 Marcus Westin. All rights reserved. -// - #import #import "ExampleAppDelegate.h" diff --git a/LICENSE b/LICENSE index d9d6b12d..1e732703 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2011 Marcus Westin +Copyright (c) 2011-2013 Marcus Westin, Antoine Lagadec Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation diff --git a/README.md b/README.md index 562b9152..ef79353f 100644 --- a/README.md +++ b/README.md @@ -191,8 +191,8 @@ WebViewJavascriptBridge uses `NSJSONSerialization` by default. If you need iOS 4 Contributors ------------ - -- [@marcuswestin](https://github.com/marcuswestin) Marcus Westin +- [@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 diff --git a/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.h b/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.h index 9a8b2f4f..c9943ffa 100644 --- a/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.h +++ b/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.h @@ -1,11 +1,3 @@ -// -// WebViewJavascriptBridge+OSX.h -// ExampleApp-OSX -// -// Created by Antoine Lagadec on 07/04/13. -// Copyright (c) 2013 Antoine Lagadec. All rights reserved. -// - #import #import "WebViewJavascriptBridgeAbstract.h" diff --git a/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.m b/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.m index 02ee2ed2..efe5f8e2 100644 --- a/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.m +++ b/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.m @@ -1,11 +1,3 @@ -// -// WebViewJavascriptBridge+OSX.m -// ExampleApp-OSX -// -// Created by Antoine Lagadec on 07/04/13. -// Copyright (c) 2013 Antoine Lagadec. All rights reserved. -// - #import "WebViewJavascriptBridge_OSX.h" @implementation WebViewJavascriptBridge diff --git a/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.h b/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.h index 3371f49f..69fb7020 100644 --- a/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.h +++ b/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.h @@ -1,11 +1,3 @@ -// -// WebViewJavascriptBridge+iOS.h -// ExampleApp-iOS -// -// Created by Antoine Lagadec on 07/04/13. -// Copyright (c) 2013 Marcus Westin. All rights reserved. -// - #import #import "WebViewJavascriptBridgeAbstract.h" diff --git a/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m b/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m index de493c85..c9c48d24 100644 --- a/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m +++ b/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m @@ -1,11 +1,3 @@ -// -// WebViewJavascriptBridge+iOS.m -// ExampleApp-iOS -// -// Created by Antoine Lagadec on 07/04/13. -// Copyright (c) 2013 Marcus Westin. All rights reserved. -// - #import "WebViewJavascriptBridge_iOS.h" @implementation WebViewJavascriptBridge From 89d96975a95aa18025e4fc0d218699da8f45346b Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Tue, 23 Apr 2013 18:28:58 -0700 Subject: [PATCH 085/353] v3.0.0 with OSX support --- Changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Changelog b/Changelog index 7733b5ac..e5667d04 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,6 @@ +v3.0.0 ++ OSX Support + v2.1.2 + Copy handler and response blocks From 6276d0d54221b8005ef5deb800cc547a6eadebaa Mon Sep 17 00:00:00 2001 From: Peyton Randolph Date: Thu, 6 Jun 2013 14:02:35 -0400 Subject: [PATCH 086/353] add instancetype to class constructors --- WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.h | 4 ++-- WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.h b/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.h index 69fb7020..4f606dcb 100644 --- a/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.h +++ b/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.h @@ -6,7 +6,7 @@ @property (nonatomic, strong) UIWebView *webView; @property (nonatomic, strong) id webViewDelegate; -+ (id)bridgeForWebView:(UIWebView*)webView handler:(WVJBHandler)handler; -+ (id)bridgeForWebView:(UIWebView*)webView webViewDelegate:(id )webViewDelegate handler:(WVJBHandler)handler; ++ (instancetype)bridgeForWebView:(UIWebView*)webView handler:(WVJBHandler)handler; ++ (instancetype)bridgeForWebView:(UIWebView*)webView webViewDelegate:(id )webViewDelegate handler:(WVJBHandler)handler; @end diff --git a/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m b/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m index c9c48d24..bba73560 100644 --- a/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m +++ b/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m @@ -4,11 +4,11 @@ @implementation WebViewJavascriptBridge #pragma mark UIWebViewDelegate -+ (id)bridgeForWebView:(UIWebView *)webView handler:(WVJBHandler)handler { ++ (instancetype)bridgeForWebView:(UIWebView *)webView handler:(WVJBHandler)handler { return [self bridgeForWebView:webView webViewDelegate:nil handler:handler]; } -+ (id)bridgeForWebView:(UIWebView *)webView webViewDelegate:(id)webViewDelegate handler:(WVJBHandler)messageHandler { ++ (instancetype)bridgeForWebView:(UIWebView *)webView webViewDelegate:(id)webViewDelegate handler:(WVJBHandler)messageHandler { WebViewJavascriptBridge* bridge = [[WebViewJavascriptBridge alloc] init]; bridge.messageHandler = messageHandler; bridge.webView = webView; From b06988f14aa92911d9773ef66d53b9822b05f6da Mon Sep 17 00:00:00 2001 From: Peyton Randolph Date: Thu, 6 Jun 2013 14:12:39 -0400 Subject: [PATCH 087/353] fix retain cycle --- .../WebViewJavascriptBridgeAbstract.h | 4 ++-- .../WebViewJavascriptBridgeAbstract.m | 12 ++++++---- .../WebViewJavascriptBridge_iOS.h | 4 ++-- .../WebViewJavascriptBridge_iOS.m | 24 +++++++++++-------- 4 files changed, 25 insertions(+), 19 deletions(-) diff --git a/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.h b/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.h index a5d3cd83..a99690f4 100644 --- a/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.h +++ b/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.h @@ -7,8 +7,8 @@ typedef void (^WVJBHandler)(id data, WVJBResponseCallback responseCallback); @interface WebViewJavascriptBridgeAbstract : NSObject -@property (nonatomic, strong) id webView; -@property (nonatomic, strong) id webViewDelegate; +@property (nonatomic, weak) id webView; +@property (nonatomic, weak) id webViewDelegate; @property (nonatomic, strong) NSMutableArray *startupMessageQueue; @property (nonatomic, strong) NSMutableDictionary *responseCallbacks; @property (nonatomic, strong) NSMutableDictionary *messageHandlers; diff --git a/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.m b/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.m index 7e2408a2..0734e6e7 100755 --- a/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.m +++ b/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.m @@ -79,13 +79,14 @@ - (void)_dispatchMessage:(NSDictionary *)message { messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"]; messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\r" withString:@"\\r"]; messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\f" withString:@"\\f"]; + __strong typeof(self.webView) strongWebView = self.webView; if ([[NSThread currentThread] isMainThread]) { - [self.webView performSelector:@selector(stringByEvaluatingJavaScriptFromString:) + [strongWebView performSelector:@selector(stringByEvaluatingJavaScriptFromString:) withObject:[NSString stringWithFormat: @"WebViewJavascriptBridge._handleMessageFromObjC('%@');", messageJSON]]; } else { dispatch_sync(dispatch_get_main_queue(), ^{ - [self.webView performSelector:@selector(stringByEvaluatingJavaScriptFromString:) + [strongWebView performSelector:@selector(stringByEvaluatingJavaScriptFromString:) withObject:[NSString stringWithFormat: @"WebViewJavascriptBridge._handleMessageFromObjC('%@');", messageJSON]]; }); @@ -93,7 +94,8 @@ - (void)_dispatchMessage:(NSDictionary *)message { } - (void)_flushMessageQueue { - NSString *messageQueueString = [self.webView performSelector: + __strong typeof(self.webView) strongWebView = self.webView; + NSString *messageQueueString = [strongWebView performSelector: @selector(stringByEvaluatingJavaScriptFromString:) withObject:@"WebViewJavascriptBridge._fetchQueue();"]; NSArray* messages = [messageQueueString componentsSeparatedByString:kMessageSeparator]; @@ -112,8 +114,8 @@ - (void)_flushMessageQueue { __block NSString* callbackId = message[@"callbackId"]; if (callbackId) { responseCallback = ^(id responseData) { - NSDictionary* message = @{ @"responseId":callbackId, @"responseData":responseData }; - [self _queueMessage:message]; + NSDictionary* msg = @{ @"responseId":callbackId, @"responseData":responseData }; + [self _queueMessage:msg]; }; } else { responseCallback = ^(id ignoreResponseData) { diff --git a/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.h b/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.h index 69fb7020..22752949 100644 --- a/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.h +++ b/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.h @@ -3,8 +3,8 @@ @interface WebViewJavascriptBridge : WebViewJavascriptBridgeAbstract -@property (nonatomic, strong) UIWebView *webView; -@property (nonatomic, strong) id webViewDelegate; +@property (nonatomic, weak) UIWebView *webView; +@property (nonatomic, weak) id webViewDelegate; + (id)bridgeForWebView:(UIWebView*)webView handler:(WVJBHandler)handler; + (id)bridgeForWebView:(UIWebView*)webView webViewDelegate:(id )webViewDelegate handler:(WVJBHandler)handler; diff --git a/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m b/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m index c9c48d24..a0275c67 100644 --- a/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m +++ b/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m @@ -24,10 +24,10 @@ + (id)bridgeForWebView:(UIWebView *)webView webViewDelegate:(id Date: Thu, 6 Jun 2013 14:53:50 -0400 Subject: [PATCH 088/353] track number of resources left to load, fixing race condition --- .../WebViewJavascriptBridge_iOS.m | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m b/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m index c9c48d24..739bb0ce 100644 --- a/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m +++ b/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m @@ -1,5 +1,11 @@ #import "WebViewJavascriptBridge_iOS.h" +@interface WebViewJavascriptBridge () + +@property (nonatomic, assign) NSUInteger numRequestsLoading; + +@end + @implementation WebViewJavascriptBridge #pragma mark UIWebViewDelegate @@ -9,7 +15,7 @@ + (id)bridgeForWebView:(UIWebView *)webView handler:(WVJBHandler)handler { } + (id)bridgeForWebView:(UIWebView *)webView webViewDelegate:(id)webViewDelegate handler:(WVJBHandler)messageHandler { - WebViewJavascriptBridge* bridge = [[WebViewJavascriptBridge alloc] init]; + WebViewJavascriptBridge* bridge = [[[self class] alloc] init]; bridge.messageHandler = messageHandler; bridge.webView = webView; bridge.webViewDelegate = webViewDelegate; @@ -18,13 +24,16 @@ + (id)bridgeForWebView:(UIWebView *)webView webViewDelegate:(id Date: Thu, 6 Jun 2013 15:00:18 -0400 Subject: [PATCH 089/353] add OS X support --- .../WebViewJavascriptBridge_OSX.m | 18 ++++++++++++++++-- .../WebViewJavascriptBridge_iOS.m | 5 ++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.m b/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.m index efe5f8e2..8c0369b0 100644 --- a/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.m +++ b/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.m @@ -1,5 +1,11 @@ #import "WebViewJavascriptBridge_OSX.h" +@interface WebViewJavascriptBridge () + +@property (nonatomic, assign) NSUInteger numRequestsLoading; + +@end + @implementation WebViewJavascriptBridge + (id)bridgeForWebView:(WebView *)webView handler:(WVJBHandler)handler { @@ -17,7 +23,7 @@ + (id)bridgeForWebView:(WebView *)webView webViewDelegate:(id)webViewDelegate ha bridge.webView.frameLoadDelegate = bridge; bridge.webView.resourceLoadDelegate = bridge; bridge.webView.policyDelegate = bridge; - + return bridge; } @@ -25,7 +31,9 @@ - (void)webView:(WebView *)webView didFinishLoadForFrame:(WebFrame *)frame { if (webView != self.webView) { return; } - if (![[self.webView stringByEvaluatingJavaScriptFromString:@"typeof WebViewJavascriptBridge == 'object'"] isEqualToString:@"true"]) { + self.numRequestsLoading--; + + if (self.numRequestsLoading == 0 && ![[self.webView stringByEvaluatingJavaScriptFromString:@"typeof WebViewJavascriptBridge == 'object'"] isEqualToString:@"true"]) { NSString *filePath = [[NSBundle mainBundle] pathForResource:@"WebViewJavascriptBridge.js" ofType:@"txt"]; NSString *js = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; [self.webView stringByEvaluatingJavaScriptFromString:js]; @@ -45,6 +53,9 @@ - (void)webView:(WebView *)webView didFinishLoadForFrame:(WebFrame *)frame - (void)webView:(WebView *)webView didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame { if (webView != self.webView) { return; } + + self.numRequestsLoading--; + if (self.webViewDelegate && [self.webViewDelegate respondsToSelector:@selector(webView:didFailLoadWithError:forFrame:)]) { [self.webViewDelegate webView:self.webView didFailLoadWithError:error forFrame:frame]; } @@ -78,6 +89,9 @@ - (void)webView:(WebView *)webView didCommitLoadForFrame:(WebFrame *)frame { - (NSURLRequest *)webView:(WebView *)webView resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource { if (webView != self.webView) { return request; } + + self.numRequestsLoading++; + if (self.webViewDelegate && [self.webViewDelegate respondsToSelector:@selector(webView:resource:willSendRequest:redirectResponse:fromDataSource:)]) { return [self.webViewDelegate webView:webView resource:identifier willSendRequest:request redirectResponse:redirectResponse fromDataSource:dataSource]; } diff --git a/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m b/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m index 739bb0ce..0dbe4265 100644 --- a/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m +++ b/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m @@ -23,14 +23,13 @@ + (id)bridgeForWebView:(UIWebView *)webView webViewDelegate:(id Date: Thu, 6 Jun 2013 15:01:10 -0400 Subject: [PATCH 090/353] add OS X support --- WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.h | 4 ++-- WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.m | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.h b/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.h index c9943ffa..af46430d 100644 --- a/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.h +++ b/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.h @@ -6,7 +6,7 @@ @property (nonatomic, strong) WebView *webView; @property (nonatomic, strong) id webViewDelegate; -+ (id)bridgeForWebView:(WebView*)webView handler:(WVJBHandler)handler; -+ (id)bridgeForWebView:(WebView*)webView webViewDelegate:(id)webViewDelegate handler:(WVJBHandler)handler; ++ (instancetype)bridgeForWebView:(WebView*)webView handler:(WVJBHandler)handler; ++ (instancetype)bridgeForWebView:(WebView*)webView webViewDelegate:(id)webViewDelegate handler:(WVJBHandler)handler; @end diff --git a/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.m b/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.m index efe5f8e2..9efed22c 100644 --- a/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.m +++ b/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.m @@ -2,11 +2,11 @@ @implementation WebViewJavascriptBridge -+ (id)bridgeForWebView:(WebView *)webView handler:(WVJBHandler)handler { ++ (instancetype)bridgeForWebView:(WebView *)webView handler:(WVJBHandler)handler { return [self bridgeForWebView:webView webViewDelegate:nil handler:handler]; } -+ (id)bridgeForWebView:(WebView *)webView webViewDelegate:(id)webViewDelegate handler:(WVJBHandler)messageHandler { ++ (instancetype)bridgeForWebView:(WebView *)webView webViewDelegate:(id)webViewDelegate handler:(WVJBHandler)messageHandler { WebViewJavascriptBridge* bridge = [[WebViewJavascriptBridge alloc] init]; bridge.messageHandler = messageHandler; bridge.webView = webView; From 5ec6c29ca01c04cad7037365d596742367dd7e39 Mon Sep 17 00:00:00 2001 From: Peyton Randolph Date: Thu, 6 Jun 2013 15:06:41 -0400 Subject: [PATCH 091/353] add OS X support --- .../WebViewJavascriptBridge_OSX.h | 4 +-- .../WebViewJavascriptBridge_OSX.m | 33 +++++++++++-------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.h b/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.h index c9943ffa..89a89ab4 100644 --- a/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.h +++ b/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.h @@ -3,8 +3,8 @@ @interface WebViewJavascriptBridge : WebViewJavascriptBridgeAbstract -@property (nonatomic, strong) WebView *webView; -@property (nonatomic, strong) id webViewDelegate; +@property (nonatomic, weak) WebView *webView; +@property (nonatomic, weak) id webViewDelegate; + (id)bridgeForWebView:(WebView*)webView handler:(WVJBHandler)handler; + (id)bridgeForWebView:(WebView*)webView webViewDelegate:(id)webViewDelegate handler:(WVJBHandler)handler; diff --git a/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.m b/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.m index efe5f8e2..b90ff37c 100644 --- a/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.m +++ b/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.m @@ -7,7 +7,7 @@ + (id)bridgeForWebView:(WebView *)webView handler:(WVJBHandler)handler { } + (id)bridgeForWebView:(WebView *)webView webViewDelegate:(id)webViewDelegate handler:(WVJBHandler)messageHandler { - WebViewJavascriptBridge* bridge = [[WebViewJavascriptBridge alloc] init]; + WebViewJavascriptBridge* bridge = [[[self class] alloc] init]; bridge.messageHandler = messageHandler; bridge.webView = webView; bridge.webViewDelegate = webViewDelegate; @@ -25,10 +25,10 @@ - (void)webView:(WebView *)webView didFinishLoadForFrame:(WebFrame *)frame { if (webView != self.webView) { return; } - if (![[self.webView stringByEvaluatingJavaScriptFromString:@"typeof WebViewJavascriptBridge == 'object'"] isEqualToString:@"true"]) { + if (![[webView stringByEvaluatingJavaScriptFromString:@"typeof WebViewJavascriptBridge == 'object'"] isEqualToString:@"true"]) { NSString *filePath = [[NSBundle mainBundle] pathForResource:@"WebViewJavascriptBridge.js" ofType:@"txt"]; NSString *js = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; - [self.webView stringByEvaluatingJavaScriptFromString:js]; + [webView stringByEvaluatingJavaScriptFromString:js]; } if (self.startupMessageQueue) { @@ -38,15 +38,17 @@ - (void)webView:(WebView *)webView didFinishLoadForFrame:(WebFrame *)frame self.startupMessageQueue = nil; } - if (self.webViewDelegate && [self.webViewDelegate respondsToSelector:@selector(webView:didFinishLoadForFrame:)]) { - [self.webViewDelegate webView:webView didFinishLoadForFrame:frame]; + __strong typeof(self.webViewDelegate) strongDelegate = self.webViewDelegate; + if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didFinishLoadForFrame:)]) { + [strongDelegate webView:webView didFinishLoadForFrame:frame]; } } - (void)webView:(WebView *)webView didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame { if (webView != self.webView) { return; } - if (self.webViewDelegate && [self.webViewDelegate respondsToSelector:@selector(webView:didFailLoadWithError:forFrame:)]) { - [self.webViewDelegate webView:self.webView didFailLoadWithError:error forFrame:frame]; + __strong typeof(self.webViewDelegate) strongDelegate = self.webViewDelegate; + if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didFailLoadWithError:forFrame:)]) { + [strongDelegate webView:strongDelegate didFailLoadWithError:error forFrame:frame]; } } @@ -54,6 +56,7 @@ - (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary { if (webView != self.webView) { [listener use]; } NSURL *url = [request URL]; + __strong typeof(self.webViewDelegate) strongDelegate = self.webViewDelegate; if ([[url scheme] isEqualToString:kCustomProtocolScheme]) { if ([[url host] isEqualToString:kQueueHasMessage]) { [self _flushMessageQueue]; @@ -61,9 +64,9 @@ - (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary NSLog(@"WebViewJavascriptBridge: WARNING: Received unknown WebViewJavascriptBridge command %@://%@", kCustomProtocolScheme, [url path]); } [listener ignore]; - } else if ([self.webView resourceLoadDelegate] - && [self.webViewDelegate respondsToSelector:@selector(webView:decidePolicyForNavigationAction:request:frame:decisionListener:)]) { - [self.webViewDelegate webView:webView decidePolicyForNavigationAction:actionInformation request:request frame:frame decisionListener:listener]; + } else if ([webView resourceLoadDelegate] + && [strongDelegate respondsToSelector:@selector(webView:decidePolicyForNavigationAction:request:frame:decisionListener:)]) { + [strongDelegate webView:webView decidePolicyForNavigationAction:actionInformation request:request frame:frame decisionListener:listener]; } else { [listener use]; } @@ -71,15 +74,17 @@ - (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary - (void)webView:(WebView *)webView didCommitLoadForFrame:(WebFrame *)frame { if (webView != self.webView) { return; } - if (self.webViewDelegate && [self.webViewDelegate respondsToSelector:@selector(webView:didCommitLoadForFrame:)]) { - [self.webViewDelegate webView:webView didCommitLoadForFrame:frame]; + __strong typeof(self.webViewDelegate) strongDelegate = self.webViewDelegate; + if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didCommitLoadForFrame:)]) { + [strongDelegate webView:webView didCommitLoadForFrame:frame]; } } - (NSURLRequest *)webView:(WebView *)webView resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource { if (webView != self.webView) { return request; } - if (self.webViewDelegate && [self.webViewDelegate respondsToSelector:@selector(webView:resource:willSendRequest:redirectResponse:fromDataSource:)]) { - return [self.webViewDelegate webView:webView resource:identifier willSendRequest:request redirectResponse:redirectResponse fromDataSource:dataSource]; + __strong typeof(self.webViewDelegate) strongDelegate = self.webViewDelegate; + if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:resource:willSendRequest:redirectResponse:fromDataSource:)]) { + return [strongDelegate webView:webView resource:identifier willSendRequest:request redirectResponse:redirectResponse fromDataSource:dataSource]; } return request; From 618fe2ed74c92d8480c5ef9857a7901f4fea104e Mon Sep 17 00:00:00 2001 From: Peyton Randolph Date: Thu, 6 Jun 2013 15:12:10 -0400 Subject: [PATCH 092/353] add weak fallback for iOS 4 --- .../WebViewJavascriptBridgeAbstract.h | 12 ++++++++++-- .../WebViewJavascriptBridge_OSX.h | 4 ++-- .../WebViewJavascriptBridge_iOS.h | 4 ++-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.h b/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.h index a99690f4..de80ba9d 100644 --- a/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.h +++ b/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.h @@ -2,13 +2,21 @@ #define kCustomProtocolScheme @"wvjbscheme" #define kQueueHasMessage @"__WVJB_QUEUE_MESSAGE__" +#if TARGET_OS_IPHONE && defined(__IPHONE_5_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_5_0) + #define WEAK_FALLBACK weak +#elif TARGET_OS_MAC && defined(__MAC_10_7) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_7) + #define WEAK_FALLBACK weak +#else + #define WEAK_FALLBACK unsafe_unretained +#endif + typedef void (^WVJBResponseCallback)(id responseData); typedef void (^WVJBHandler)(id data, WVJBResponseCallback responseCallback); @interface WebViewJavascriptBridgeAbstract : NSObject -@property (nonatomic, weak) id webView; -@property (nonatomic, weak) id webViewDelegate; +@property (nonatomic, WEAK_FALLBACK) id webView; +@property (nonatomic, WEAK_FALLBACK) id webViewDelegate; @property (nonatomic, strong) NSMutableArray *startupMessageQueue; @property (nonatomic, strong) NSMutableDictionary *responseCallbacks; @property (nonatomic, strong) NSMutableDictionary *messageHandlers; diff --git a/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.h b/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.h index 89a89ab4..c55bff02 100644 --- a/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.h +++ b/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.h @@ -3,8 +3,8 @@ @interface WebViewJavascriptBridge : WebViewJavascriptBridgeAbstract -@property (nonatomic, weak) WebView *webView; -@property (nonatomic, weak) id webViewDelegate; +@property (nonatomic, WEAK_FALLBACK) WebView *webView; +@property (nonatomic, WEAK_FALLBACK) id webViewDelegate; + (id)bridgeForWebView:(WebView*)webView handler:(WVJBHandler)handler; + (id)bridgeForWebView:(WebView*)webView webViewDelegate:(id)webViewDelegate handler:(WVJBHandler)handler; diff --git a/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.h b/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.h index 22752949..f1b318a5 100644 --- a/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.h +++ b/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.h @@ -3,8 +3,8 @@ @interface WebViewJavascriptBridge : WebViewJavascriptBridgeAbstract -@property (nonatomic, weak) UIWebView *webView; -@property (nonatomic, weak) id webViewDelegate; +@property (nonatomic, WEAK_FALLBACK) UIWebView *webView; +@property (nonatomic, WEAK_FALLBACK) id webViewDelegate; + (id)bridgeForWebView:(UIWebView*)webView handler:(WVJBHandler)handler; + (id)bridgeForWebView:(UIWebView*)webView webViewDelegate:(id )webViewDelegate handler:(WVJBHandler)handler; From 20ce1b0bcff3caa6e71b024647121498b82517dc Mon Sep 17 00:00:00 2001 From: Peyton Randolph Date: Thu, 6 Jun 2013 15:17:27 -0400 Subject: [PATCH 093/353] nil out delegates on dealloc --- WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.m | 7 +++++++ WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.m b/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.m index b90ff37c..9259e48d 100644 --- a/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.m +++ b/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.m @@ -21,6 +21,13 @@ + (id)bridgeForWebView:(WebView *)webView webViewDelegate:(id)webViewDelegate ha return bridge; } +- (void)dealloc; +{ + self.webView.frameLoadDelegate = nil; + self.webView.resourceLoadDelegate = nil; + self.webView.policyDelegate = nil; +} + - (void)webView:(WebView *)webView didFinishLoadForFrame:(WebFrame *)frame { if (webView != self.webView) { return; } diff --git a/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m b/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m index a0275c67..d05b670c 100644 --- a/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m +++ b/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m @@ -21,6 +21,11 @@ + (id)bridgeForWebView:(UIWebView *)webView webViewDelegate:(id Date: Thu, 6 Jun 2013 12:35:56 -0700 Subject: [PATCH 094/353] Add @peyton to list of contributors --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ef79353f..e9bf51d4 100644 --- a/README.md +++ b/README.md @@ -201,3 +201,4 @@ Contributors - [@pj4533](https://github.com/pj4533) PJ Gray - [@xzeror](https://github.com/xzeror) - [@kelp404](https://github.com/kelp404) +- [@peyton](https://github.com/peyton) Peyton Randolph From 818d49cfc3bece2feee2a9c652520ad3f499e91e Mon Sep 17 00:00:00 2001 From: Peyton Randolph Date: Thu, 6 Jun 2013 16:04:40 -0400 Subject: [PATCH 095/353] Add podspec --- WebViewJavascriptBridge.podspec | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 WebViewJavascriptBridge.podspec diff --git a/WebViewJavascriptBridge.podspec b/WebViewJavascriptBridge.podspec new file mode 100644 index 00000000..79735999 --- /dev/null +++ b/WebViewJavascriptBridge.podspec @@ -0,0 +1,16 @@ +Pod::Spec.new do |s| + s.name = 'WebViewJavascriptBridge' + s.version = '4.0.0pre' + 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' } + s.author = { 'marcuswestin' => 'marcus.westin@gmail.com' } + s.source = { :git => 'https://github.com/peyton/WebViewJavascriptBridge.git' } + s.ios.platform = :ios, '5.0' + s.osx.platform = :osx + s.ios.source_files = 'WebViewJavascriptBridge_iOS/*.{h,m}', 'WebViewJavascriptBridgeAbstract/*.{h,m}' + s.osx.source_files = 'WebViewJavascriptBridge_OSX/*.{h,m}', 'WebViewJavascriptBridgeAbstract/*.{h,m}' + s.resource = 'WebViewJavascriptBridgeAbstract/WebViewJavascriptBridge.js.txt' + s.ios.framework = 'UIKit' + s.osx.framework = 'WebKit' +end From 7f0ec42415e513ea679c467ceb2f41a952aeb0bb Mon Sep 17 00:00:00 2001 From: Peyton Randolph Date: Thu, 6 Jun 2013 16:12:11 -0400 Subject: [PATCH 096/353] fix bug --- WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m | 1 - 1 file changed, 1 deletion(-) diff --git a/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m b/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m index fce01d8f..59311ffe 100644 --- a/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m +++ b/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m @@ -38,7 +38,6 @@ - (void)webViewDidFinishLoad:(UIWebView *)webView { self.numRequestsLoading--; if (self.numRequestsLoading == 0 && ![[webView stringByEvaluatingJavaScriptFromString:@"typeof WebViewJavascriptBridge == 'object'"] isEqualToString:@"true"]) { - if (![[webView stringByEvaluatingJavaScriptFromString:@"typeof WebViewJavascriptBridge == 'object'"] isEqualToString:@"true"]) { NSString *filePath = [[NSBundle mainBundle] pathForResource:@"WebViewJavascriptBridge.js" ofType:@"txt"]; NSString *js = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; [webView stringByEvaluatingJavaScriptFromString:js]; From 95afe41a2cfa5232e61f58dc6a1d932a2274a6e3 Mon Sep 17 00:00:00 2001 From: Peyton Randolph Date: Thu, 6 Jun 2013 16:17:39 -0400 Subject: [PATCH 097/353] add requires_arc --- WebViewJavascriptBridge.podspec | 1 + 1 file changed, 1 insertion(+) diff --git a/WebViewJavascriptBridge.podspec b/WebViewJavascriptBridge.podspec index 79735999..3a2c63cd 100644 --- a/WebViewJavascriptBridge.podspec +++ b/WebViewJavascriptBridge.podspec @@ -5,6 +5,7 @@ Pod::Spec.new do |s| s.homepage = 'http://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/peyton/WebViewJavascriptBridge.git' } s.ios.platform = :ios, '5.0' s.osx.platform = :osx From 4f58e829160543f2adca4e483acf99596e7b70ba Mon Sep 17 00:00:00 2001 From: Peyton Randolph Date: Fri, 7 Jun 2013 07:44:51 -0400 Subject: [PATCH 098/353] point podspec to the parent repo --- WebViewJavascriptBridge.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WebViewJavascriptBridge.podspec b/WebViewJavascriptBridge.podspec index 3a2c63cd..76b49fbd 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/peyton/WebViewJavascriptBridge.git' } + s.source = { :git => 'https://github.com/marcuswestin/WebViewJavascriptBridge.git' } s.ios.platform = :ios, '5.0' s.osx.platform = :osx s.ios.source_files = 'WebViewJavascriptBridge_iOS/*.{h,m}', 'WebViewJavascriptBridgeAbstract/*.{h,m}' From 8f1aaf9b3743d37df178e503f708b9cae3892c0c Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Sat, 8 Jun 2013 01:12:38 -0700 Subject: [PATCH 099/353] Fix #41 - remove __block to avoid losing callbackId. See http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/Blocks/Articles/bxVariables.html "Types of variables" #3 and #4 - we want callbackId to be non-mutable, const --- .../WebViewJavascriptBridgeAbstract.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.m b/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.m index 0734e6e7..98218c31 100755 --- a/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.m +++ b/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.m @@ -111,7 +111,7 @@ - (void)_flushMessageQueue { [self.responseCallbacks removeObjectForKey:responseId]; } else { WVJBResponseCallback responseCallback = NULL; - __block NSString* callbackId = message[@"callbackId"]; + NSString* callbackId = message[@"callbackId"]; if (callbackId) { responseCallback = ^(id responseData) { NSDictionary* msg = @{ @"responseId":callbackId, @"responseData":responseData }; From 2f1623a2642c08ef2b95c7e4f06cab94a924d73b Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Sat, 8 Jun 2013 01:18:57 -0700 Subject: [PATCH 100/353] v3.1.0 --- Changelog | 7 +++++++ WebViewJavascriptBridge.podspec | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Changelog b/Changelog index e5667d04..849cadb2 100644 --- a/Changelog +++ b/Changelog @@ -1,5 +1,12 @@ +v3.1.0 ++ Dont inject the WVJB bridge until all requests have finished loading (61b853) ++ Add podspec file (818d49cfc) ++ Memory leaks fixed (b06988f1, 20ce1b0b) ++ New major contributor @peyton! + v3.0.0 + OSX Support ++ New major contributor @oakho! v2.1.2 + Copy handler and response blocks diff --git a/WebViewJavascriptBridge.podspec b/WebViewJavascriptBridge.podspec index 76b49fbd..647d8328 100644 --- a/WebViewJavascriptBridge.podspec +++ b/WebViewJavascriptBridge.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'WebViewJavascriptBridge' - s.version = '4.0.0pre' + s.version = '3.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 9e6972834d0e6f937086827d6cb3cf963f55aff0 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Sat, 8 Jun 2013 19:54:47 -0700 Subject: [PATCH 101/353] Remove the current OS X based example app, to be replaced in the next commit by a strictly programmatically created app --- .../ExampleApp-OSX.xcodeproj/project.pbxproj | 334 -- Example Apps/ExampleApp-OSX/AppDelegate.h | 14 - Example Apps/ExampleApp-OSX/AppDelegate.m | 51 - .../ExampleApp-OSX/ExampleApp-OSX-Info.plist | 34 - .../ExampleApp-OSX/ExampleApp-OSX-Prefix.pch | 7 - .../ExampleApp-OSX/en.lproj/InfoPlist.strings | 2 - .../ExampleApp-OSX/en.lproj/MainMenu.xib | 3614 ----------------- Example Apps/ExampleApp-OSX/main.m | 6 - 8 files changed, 4062 deletions(-) delete mode 100644 Example Apps/ExampleApp-OSX.xcodeproj/project.pbxproj delete mode 100644 Example Apps/ExampleApp-OSX/AppDelegate.h delete mode 100644 Example Apps/ExampleApp-OSX/AppDelegate.m delete mode 100644 Example Apps/ExampleApp-OSX/ExampleApp-OSX-Info.plist delete mode 100644 Example Apps/ExampleApp-OSX/ExampleApp-OSX-Prefix.pch delete mode 100644 Example Apps/ExampleApp-OSX/en.lproj/InfoPlist.strings delete mode 100644 Example Apps/ExampleApp-OSX/en.lproj/MainMenu.xib delete mode 100644 Example Apps/ExampleApp-OSX/main.m diff --git a/Example Apps/ExampleApp-OSX.xcodeproj/project.pbxproj b/Example Apps/ExampleApp-OSX.xcodeproj/project.pbxproj deleted file mode 100644 index 5e5e13ab..00000000 --- a/Example Apps/ExampleApp-OSX.xcodeproj/project.pbxproj +++ /dev/null @@ -1,334 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 2CA045DA171178E5006DEE8B /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2CA045D9171178E5006DEE8B /* Cocoa.framework */; }; - 2CA045E4171178E6006DEE8B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 2CA045E2171178E6006DEE8B /* InfoPlist.strings */; }; - 2CA045E6171178E6006DEE8B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CA045E5171178E6006DEE8B /* main.m */; }; - 2CA045ED171178E6006DEE8B /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CA045EC171178E6006DEE8B /* AppDelegate.m */; }; - 2CA045F0171178E6006DEE8B /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2CA045EE171178E6006DEE8B /* MainMenu.xib */; }; - 2CA0460517117B56006DEE8B /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2CA0460417117B56006DEE8B /* WebKit.framework */; }; - 2CA0465E1711AC96006DEE8B /* ExampleApp.html in Resources */ = {isa = PBXBuildFile; fileRef = 2CA0465D1711AC96006DEE8B /* ExampleApp.html */; }; - 2CAB8695172766DF00BD9ED1 /* WebViewJavascriptBridge.js.txt in Resources */ = {isa = PBXBuildFile; fileRef = 2CAB8690172766DF00BD9ED1 /* WebViewJavascriptBridge.js.txt */; }; - 2CAB8696172766DF00BD9ED1 /* WebViewJavascriptBridgeAbstract.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CAB8692172766DF00BD9ED1 /* WebViewJavascriptBridgeAbstract.m */; }; - 2CAB8697172766DF00BD9ED1 /* WebViewJavascriptBridge_OSX.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CAB8694172766DF00BD9ED1 /* WebViewJavascriptBridge_OSX.m */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - 2CA045D5171178E5006DEE8B /* ExampleApp-OSX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "ExampleApp-OSX.app"; sourceTree = BUILT_PRODUCTS_DIR; }; - 2CA045D9171178E5006DEE8B /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; - 2CA045DC171178E5006DEE8B /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; - 2CA045DD171178E5006DEE8B /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; - 2CA045DE171178E5006DEE8B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - 2CA045E1171178E6006DEE8B /* ExampleApp-OSX-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ExampleApp-OSX-Info.plist"; sourceTree = ""; }; - 2CA045E3171178E6006DEE8B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; - 2CA045E5171178E6006DEE8B /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - 2CA045E7171178E6006DEE8B /* ExampleApp-OSX-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ExampleApp-OSX-Prefix.pch"; sourceTree = ""; }; - 2CA045EB171178E6006DEE8B /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; - 2CA045EC171178E6006DEE8B /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; - 2CA045EF171178E6006DEE8B /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = ""; }; - 2CA0460417117B56006DEE8B /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; - 2CA0465D1711AC96006DEE8B /* ExampleApp.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = ExampleApp.html; path = ../ExampleApp.html; sourceTree = ""; }; - 2CAB8690172766DF00BD9ED1 /* WebViewJavascriptBridge.js.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebViewJavascriptBridge.js.txt; sourceTree = ""; }; - 2CAB8691172766DF00BD9ED1 /* WebViewJavascriptBridgeAbstract.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridgeAbstract.h; sourceTree = ""; }; - 2CAB8692172766DF00BD9ED1 /* WebViewJavascriptBridgeAbstract.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridgeAbstract.m; sourceTree = ""; }; - 2CAB8693172766DF00BD9ED1 /* WebViewJavascriptBridge_OSX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridge_OSX.h; sourceTree = ""; }; - 2CAB8694172766DF00BD9ED1 /* WebViewJavascriptBridge_OSX.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge_OSX.m; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 2CA045D2171178E5006DEE8B /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 2CA0460517117B56006DEE8B /* WebKit.framework in Frameworks */, - 2CA045DA171178E5006DEE8B /* Cocoa.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 2CA045CA171178E5006DEE8B = { - isa = PBXGroup; - children = ( - 2CA0460417117B56006DEE8B /* WebKit.framework */, - 2CA045DF171178E5006DEE8B /* ExampleApp-OSX */, - 2CA045D8171178E5006DEE8B /* Frameworks */, - 2CA045D6171178E5006DEE8B /* Products */, - ); - sourceTree = ""; - }; - 2CA045D6171178E5006DEE8B /* Products */ = { - isa = PBXGroup; - children = ( - 2CA045D5171178E5006DEE8B /* ExampleApp-OSX.app */, - ); - name = Products; - sourceTree = ""; - }; - 2CA045D8171178E5006DEE8B /* Frameworks */ = { - isa = PBXGroup; - children = ( - 2CA045D9171178E5006DEE8B /* Cocoa.framework */, - 2CA045DB171178E5006DEE8B /* Other Frameworks */, - ); - name = Frameworks; - sourceTree = ""; - }; - 2CA045DB171178E5006DEE8B /* Other Frameworks */ = { - isa = PBXGroup; - children = ( - 2CA045DC171178E5006DEE8B /* AppKit.framework */, - 2CA045DD171178E5006DEE8B /* CoreData.framework */, - 2CA045DE171178E5006DEE8B /* Foundation.framework */, - ); - name = "Other Frameworks"; - sourceTree = ""; - }; - 2CA045DF171178E5006DEE8B /* ExampleApp-OSX */ = { - isa = PBXGroup; - children = ( - 2CA0465D1711AC96006DEE8B /* ExampleApp.html */, - 2CA045EB171178E6006DEE8B /* AppDelegate.h */, - 2CA045EC171178E6006DEE8B /* AppDelegate.m */, - 2CA045EE171178E6006DEE8B /* MainMenu.xib */, - 2CAB868E172766DF00BD9ED1 /* WebViewJavascriptBridge_OSX */, - 2CA045E0171178E6006DEE8B /* Supporting Files */, - ); - path = "ExampleApp-OSX"; - sourceTree = ""; - }; - 2CA045E0171178E6006DEE8B /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 2CA045E1171178E6006DEE8B /* ExampleApp-OSX-Info.plist */, - 2CA045E2171178E6006DEE8B /* InfoPlist.strings */, - 2CA045E5171178E6006DEE8B /* main.m */, - 2CA045E7171178E6006DEE8B /* ExampleApp-OSX-Prefix.pch */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - 2CAB868E172766DF00BD9ED1 /* WebViewJavascriptBridge_OSX */ = { - isa = PBXGroup; - children = ( - 2CAB868F172766DF00BD9ED1 /* WebViewJavascriptAbstract */, - 2CAB8693172766DF00BD9ED1 /* WebViewJavascriptBridge_OSX.h */, - 2CAB8694172766DF00BD9ED1 /* WebViewJavascriptBridge_OSX.m */, - ); - name = WebViewJavascriptBridge_OSX; - path = ../../WebViewJavascriptBridge_OSX; - sourceTree = ""; - }; - 2CAB868F172766DF00BD9ED1 /* WebViewJavascriptAbstract */ = { - isa = PBXGroup; - children = ( - 2CAB8690172766DF00BD9ED1 /* WebViewJavascriptBridge.js.txt */, - 2CAB8691172766DF00BD9ED1 /* WebViewJavascriptBridgeAbstract.h */, - 2CAB8692172766DF00BD9ED1 /* WebViewJavascriptBridgeAbstract.m */, - ); - path = WebViewJavascriptAbstract; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 2CA045D4171178E5006DEE8B /* ExampleApp-OSX */ = { - isa = PBXNativeTarget; - buildConfigurationList = 2CA045F3171178E6006DEE8B /* Build configuration list for PBXNativeTarget "ExampleApp-OSX" */; - buildPhases = ( - 2CA045D1171178E5006DEE8B /* Sources */, - 2CA045D2171178E5006DEE8B /* Frameworks */, - 2CA045D3171178E5006DEE8B /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "ExampleApp-OSX"; - productName = "ExampleApp-OSX"; - productReference = 2CA045D5171178E5006DEE8B /* ExampleApp-OSX.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 2CA045CC171178E5006DEE8B /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0450; - ORGANIZATIONNAME = "Antoine Lagadec"; - }; - buildConfigurationList = 2CA045CF171178E5006DEE8B /* Build configuration list for PBXProject "ExampleApp-OSX" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - ); - mainGroup = 2CA045CA171178E5006DEE8B; - productRefGroup = 2CA045D6171178E5006DEE8B /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 2CA045D4171178E5006DEE8B /* ExampleApp-OSX */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 2CA045D3171178E5006DEE8B /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 2CA045E4171178E6006DEE8B /* InfoPlist.strings in Resources */, - 2CA045F0171178E6006DEE8B /* MainMenu.xib in Resources */, - 2CA0465E1711AC96006DEE8B /* ExampleApp.html in Resources */, - 2CAB8695172766DF00BD9ED1 /* WebViewJavascriptBridge.js.txt in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 2CA045D1171178E5006DEE8B /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 2CA045E6171178E6006DEE8B /* main.m in Sources */, - 2CA045ED171178E6006DEE8B /* AppDelegate.m in Sources */, - 2CAB8696172766DF00BD9ED1 /* WebViewJavascriptBridgeAbstract.m in Sources */, - 2CAB8697172766DF00BD9ED1 /* WebViewJavascriptBridge_OSX.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 2CA045E2171178E6006DEE8B /* InfoPlist.strings */ = { - isa = PBXVariantGroup; - children = ( - 2CA045E3171178E6006DEE8B /* en */, - ); - name = InfoPlist.strings; - sourceTree = ""; - }; - 2CA045EE171178E6006DEE8B /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - 2CA045EF171178E6006DEE8B /* en */, - ); - name = MainMenu.xib; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 2CA045F1171178E6006DEE8B /* Debug */ = { - 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; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_ENABLE_OBJC_EXCEPTIONS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.7; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = macosx; - }; - name = Debug; - }; - 2CA045F2171178E6006DEE8B /* Release */ = { - 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; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = YES; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_ENABLE_OBJC_EXCEPTIONS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.7; - SDKROOT = macosx; - }; - name = Release; - }; - 2CA045F4171178E6006DEE8B /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - COMBINE_HIDPI_IMAGES = YES; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "ExampleApp-OSX/ExampleApp-OSX-Prefix.pch"; - INFOPLIST_FILE = "ExampleApp-OSX/ExampleApp-OSX-Info.plist"; - PRODUCT_NAME = "$(TARGET_NAME)"; - WRAPPER_EXTENSION = app; - }; - name = Debug; - }; - 2CA045F5171178E6006DEE8B /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - COMBINE_HIDPI_IMAGES = YES; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "ExampleApp-OSX/ExampleApp-OSX-Prefix.pch"; - INFOPLIST_FILE = "ExampleApp-OSX/ExampleApp-OSX-Info.plist"; - PRODUCT_NAME = "$(TARGET_NAME)"; - WRAPPER_EXTENSION = app; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 2CA045CF171178E5006DEE8B /* Build configuration list for PBXProject "ExampleApp-OSX" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 2CA045F1171178E6006DEE8B /* Debug */, - 2CA045F2171178E6006DEE8B /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 2CA045F3171178E6006DEE8B /* Build configuration list for PBXNativeTarget "ExampleApp-OSX" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 2CA045F4171178E6006DEE8B /* Debug */, - 2CA045F5171178E6006DEE8B /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 2CA045CC171178E5006DEE8B /* Project object */; -} diff --git a/Example Apps/ExampleApp-OSX/AppDelegate.h b/Example Apps/ExampleApp-OSX/AppDelegate.h deleted file mode 100644 index ddbd75fd..00000000 --- a/Example Apps/ExampleApp-OSX/AppDelegate.h +++ /dev/null @@ -1,14 +0,0 @@ -#import -#import "WebViewJavascriptBridge_OSX.h" - -@interface AppDelegate : NSObject - -@property (assign) IBOutlet NSWindow *window; -@property (weak) IBOutlet WebView *webView; - -- (IBAction)sendMessage:(id)sender; -- (IBAction)callHandler:(id)sender; - -@property (strong, nonatomic) WebViewJavascriptBridge *javascriptBridge; - -@end diff --git a/Example Apps/ExampleApp-OSX/AppDelegate.m b/Example Apps/ExampleApp-OSX/AppDelegate.m deleted file mode 100644 index 4db9997b..00000000 --- a/Example Apps/ExampleApp-OSX/AppDelegate.m +++ /dev/null @@ -1,51 +0,0 @@ -#import "AppDelegate.h" - -@implementation AppDelegate - -@synthesize javascriptBridge = _bridge; - -- (void)applicationDidFinishLaunching:(NSNotification *)aNotification -{ - [WebViewJavascriptBridge enableLogging]; - - _bridge = [WebViewJavascriptBridge bridgeForWebView:self.webView 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:[NSDictionary dictionaryWithObject:@"before ready" forKey:@"foo"]]; - - [self loadExamplePage:self.webView]; - - [_bridge send:@"A string sent from ObjC after Webview has loaded."]; -} - -- (IBAction)sendMessage:(id)sender { - [_bridge send:@"A string sent from ObjC to JS" responseCallback:^(id response) { - NSLog(@"sendMessage got response: %@", response); - }]; -} - -- (IBAction)callHandler:(id)sender { - NSDictionary* data = [NSDictionary dictionaryWithObject:@"Hi there, JS!" forKey:@"greetingFromObjC"]; - [_bridge callHandler:@"testJavascriptHandler" data:data responseCallback:^(id response) { - NSLog(@"testJavascriptHandler responded: %@", response); - }]; -} - -- (void)loadExamplePage:(WebView*)webView { - NSString* htmlPath = [[NSBundle mainBundle] pathForResource:@"ExampleApp" ofType:@"html"]; - NSString* appHtml = [NSString stringWithContentsOfFile:htmlPath encoding:NSUTF8StringEncoding error:nil]; - [[self.webView mainFrame] loadHTMLString:appHtml baseURL:nil]; -} - -@end diff --git a/Example Apps/ExampleApp-OSX/ExampleApp-OSX-Info.plist b/Example Apps/ExampleApp-OSX/ExampleApp-OSX-Info.plist deleted file mode 100644 index 18703404..00000000 --- a/Example Apps/ExampleApp-OSX/ExampleApp-OSX-Info.plist +++ /dev/null @@ -1,34 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - ${EXECUTABLE_NAME} - CFBundleIconFile - - CFBundleIdentifier - example.${PRODUCT_NAME:rfc1034identifier} - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - ${PRODUCT_NAME} - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - LSMinimumSystemVersion - ${MACOSX_DEPLOYMENT_TARGET} - NSHumanReadableCopyright - Copyright © 2013 Marcus Westin, Antoine Lagadec. All rights reserved. - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication - - diff --git a/Example Apps/ExampleApp-OSX/ExampleApp-OSX-Prefix.pch b/Example Apps/ExampleApp-OSX/ExampleApp-OSX-Prefix.pch deleted file mode 100644 index 32daebd5..00000000 --- a/Example Apps/ExampleApp-OSX/ExampleApp-OSX-Prefix.pch +++ /dev/null @@ -1,7 +0,0 @@ -// -// Prefix header for all source files of the 'ExampleApp-OSX' target in the 'ExampleApp-OSX' project -// - -#ifdef __OBJC__ - #import -#endif diff --git a/Example Apps/ExampleApp-OSX/en.lproj/InfoPlist.strings b/Example Apps/ExampleApp-OSX/en.lproj/InfoPlist.strings deleted file mode 100644 index 477b28ff..00000000 --- a/Example Apps/ExampleApp-OSX/en.lproj/InfoPlist.strings +++ /dev/null @@ -1,2 +0,0 @@ -/* Localized versions of Info.plist keys */ - diff --git a/Example Apps/ExampleApp-OSX/en.lproj/MainMenu.xib b/Example Apps/ExampleApp-OSX/en.lproj/MainMenu.xib deleted file mode 100644 index b4989b1d..00000000 --- a/Example Apps/ExampleApp-OSX/en.lproj/MainMenu.xib +++ /dev/null @@ -1,3614 +0,0 @@ - - - - 1070 - 11E53 - 2844 - 1138.47 - 569.00 - - 2844 - 1810 - - - IBNSLayoutConstraint - NSButton - NSButtonCell - NSCustomObject - NSMenu - NSMenuItem - NSView - NSWindowTemplate - WebView - - - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.WebKitIBPlugin - - - PluginDependencyRecalculationVersion - - - - - NSApplication - - - FirstResponder - - - NSApplication - - - AMainMenu - - - - ExampleApp-OSX - - 1048576 - 2147483647 - - NSImage - NSMenuCheckmark - - - NSImage - NSMenuMixedState - - submenuAction: - - ExampleApp-OSX - - - - About ExampleApp-OSX - - 2147483647 - - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Preferences… - , - 1048576 - 2147483647 - - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Services - - 1048576 - 2147483647 - - - submenuAction: - - Services - - _NSServicesMenu - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Hide ExampleApp-OSX - h - 1048576 - 2147483647 - - - - - - Hide Others - h - 1572864 - 2147483647 - - - - - - Show All - - 1048576 - 2147483647 - - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Quit ExampleApp-OSX - q - 1048576 - 2147483647 - - - - - _NSAppleMenu - - - - - File - - 1048576 - 2147483647 - - - submenuAction: - - File - - - - New - n - 1048576 - 2147483647 - - - - - - Open… - o - 1048576 - 2147483647 - - - - - - Open Recent - - 1048576 - 2147483647 - - - submenuAction: - - Open Recent - - - - Clear Menu - - 1048576 - 2147483647 - - - - - _NSRecentDocumentsMenu - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Close - w - 1048576 - 2147483647 - - - - - - Save… - s - 1048576 - 2147483647 - - - - - - Revert to Saved - - 2147483647 - - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Page Setup... - P - 1179648 - 2147483647 - - - - - - - Print… - p - 1048576 - 2147483647 - - - - - - - - - Edit - - 1048576 - 2147483647 - - - submenuAction: - - Edit - - - - Undo - z - 1048576 - 2147483647 - - - - - - Redo - Z - 1179648 - 2147483647 - - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Cut - x - 1048576 - 2147483647 - - - - - - Copy - c - 1048576 - 2147483647 - - - - - - Paste - v - 1048576 - 2147483647 - - - - - - Paste and Match Style - V - 1572864 - 2147483647 - - - - - - Delete - - 1048576 - 2147483647 - - - - - - Select All - a - 1048576 - 2147483647 - - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Find - - 1048576 - 2147483647 - - - submenuAction: - - Find - - - - Find… - f - 1048576 - 2147483647 - - - 1 - - - - Find and Replace… - f - 1572864 - 2147483647 - - - 12 - - - - Find Next - g - 1048576 - 2147483647 - - - 2 - - - - Find Previous - G - 1179648 - 2147483647 - - - 3 - - - - Use Selection for Find - e - 1048576 - 2147483647 - - - 7 - - - - Jump to Selection - j - 1048576 - 2147483647 - - - - - - - - - Spelling and Grammar - - 1048576 - 2147483647 - - - submenuAction: - - Spelling and Grammar - - - - Show Spelling and Grammar - : - 1048576 - 2147483647 - - - - - - Check Document Now - ; - 1048576 - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - Check Spelling While Typing - - 1048576 - 2147483647 - - - - - - Check Grammar With Spelling - - 1048576 - 2147483647 - - - - - - Correct Spelling Automatically - - 2147483647 - - - - - - - - - Substitutions - - 1048576 - 2147483647 - - - submenuAction: - - Substitutions - - - - Show Substitutions - - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - Smart Copy/Paste - f - 1048576 - 2147483647 - - - 1 - - - - Smart Quotes - g - 1048576 - 2147483647 - - - 2 - - - - Smart Dashes - - 2147483647 - - - - - - Smart Links - G - 1179648 - 2147483647 - - - 3 - - - - Text Replacement - - 2147483647 - - - - - - - - - Transformations - - 2147483647 - - - submenuAction: - - Transformations - - - - Make Upper Case - - 2147483647 - - - - - - Make Lower Case - - 2147483647 - - - - - - Capitalize - - 2147483647 - - - - - - - - - Speech - - 1048576 - 2147483647 - - - submenuAction: - - Speech - - - - Start Speaking - - 1048576 - 2147483647 - - - - - - Stop Speaking - - 1048576 - 2147483647 - - - - - - - - - - - - Format - - 2147483647 - - - submenuAction: - - Format - - - - Font - - 2147483647 - - - submenuAction: - - Font - - - - Show Fonts - t - 1048576 - 2147483647 - - - - - - Bold - b - 1048576 - 2147483647 - - - 2 - - - - Italic - i - 1048576 - 2147483647 - - - 1 - - - - Underline - u - 1048576 - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - Bigger - + - 1048576 - 2147483647 - - - 3 - - - - Smaller - - - 1048576 - 2147483647 - - - 4 - - - - YES - YES - - - 2147483647 - - - - - - Kern - - 2147483647 - - - submenuAction: - - Kern - - - - Use Default - - 2147483647 - - - - - - Use None - - 2147483647 - - - - - - Tighten - - 2147483647 - - - - - - Loosen - - 2147483647 - - - - - - - - - Ligatures - - 2147483647 - - - submenuAction: - - Ligatures - - - - Use Default - - 2147483647 - - - - - - Use None - - 2147483647 - - - - - - Use All - - 2147483647 - - - - - - - - - Baseline - - 2147483647 - - - submenuAction: - - Baseline - - - - Use Default - - 2147483647 - - - - - - Superscript - - 2147483647 - - - - - - Subscript - - 2147483647 - - - - - - Raise - - 2147483647 - - - - - - Lower - - 2147483647 - - - - - - - - - YES - YES - - - 2147483647 - - - - - - Show Colors - C - 1048576 - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - Copy Style - c - 1572864 - 2147483647 - - - - - - Paste Style - v - 1572864 - 2147483647 - - - - - _NSFontMenu - - - - - Text - - 2147483647 - - - submenuAction: - - Text - - - - Align Left - { - 1048576 - 2147483647 - - - - - - Center - | - 1048576 - 2147483647 - - - - - - Justify - - 2147483647 - - - - - - Align Right - } - 1048576 - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - Writing Direction - - 2147483647 - - - submenuAction: - - Writing Direction - - - - YES - Paragraph - - 2147483647 - - - - - - CURlZmF1bHQ - - 2147483647 - - - - - - CUxlZnQgdG8gUmlnaHQ - - 2147483647 - - - - - - CVJpZ2h0IHRvIExlZnQ - - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - YES - Selection - - 2147483647 - - - - - - CURlZmF1bHQ - - 2147483647 - - - - - - CUxlZnQgdG8gUmlnaHQ - - 2147483647 - - - - - - CVJpZ2h0IHRvIExlZnQ - - 2147483647 - - - - - - - - - YES - YES - - - 2147483647 - - - - - - Show Ruler - - 2147483647 - - - - - - Copy Ruler - c - 1310720 - 2147483647 - - - - - - Paste Ruler - v - 1310720 - 2147483647 - - - - - - - - - - - - View - - 1048576 - 2147483647 - - - submenuAction: - - View - - - - Show Toolbar - t - 1572864 - 2147483647 - - - - - - Customize Toolbar… - - 1048576 - 2147483647 - - - - - - - - - Window - - 1048576 - 2147483647 - - - submenuAction: - - Window - - - - Minimize - m - 1048576 - 2147483647 - - - - - - Zoom - - 1048576 - 2147483647 - - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Bring All to Front - - 1048576 - 2147483647 - - - - - _NSWindowsMenu - - - - - Help - - 2147483647 - - - submenuAction: - - Help - - - - ExampleApp-OSX Help - ? - 1048576 - 2147483647 - - - - - _NSHelpMenu - - - - _NSMainMenu - - - 15 - 2 - {{335, 390}, {480, 360}} - 1954021376 - ExampleApp-OSX - NSWindow - - - - - 256 - - - - 256 - - Apple HTML pasteboard type - Apple PDF pasteboard type - Apple PICT pasteboard type - Apple URL pasteboard type - Apple Web Archive pasteboard type - NSColor pasteboard type - NSFilenamesPboardType - NSStringPboardType - NeXT RTFD pasteboard type - NeXT Rich Text Format v1.0 pasteboard type - NeXT TIFF v4.0 pasteboard type - WebURLsWithTitlesPboardType - public.png - public.url - public.url-name - - {{0, 37}, {480, 323}} - - - - _NS:9 - - - - - - - - - - - YES - YES - - - - 268 - {{20, 10}, {97, 19}} - - - - _NS:9 - YES - - -2080374784 - 134217728 - Send message - - LucidaGrande - 12 - 16 - - _NS:9 - - -2038153216 - 164 - - - 400 - 75 - - - - - 268 - {{125, 10}, {86, 19}} - - - _NS:9 - YES - - -2080374784 - 134217728 - Call Handler - - _NS:9 - - -2038153216 - 164 - - - 400 - 75 - - - - {480, 360} - - - - - {{0, 0}, {1280, 778}} - {10000000000000, 10000000000000} - YES - - - AppDelegate - - - NSFontManager - - - - 256 - - Apple HTML pasteboard type - Apple PDF pasteboard type - Apple PICT pasteboard type - Apple URL pasteboard type - Apple Web Archive pasteboard type - NSColor pasteboard type - NSFilenamesPboardType - NSStringPboardType - NeXT RTFD pasteboard type - NeXT Rich Text Format v1.0 pasteboard type - NeXT TIFF v4.0 pasteboard type - WebURLsWithTitlesPboardType - public.png - public.url - public.url-name - - {254, 200} - - - - _NS:9 - - - - YES - YES - - - - - - - terminate: - - - - 449 - - - - orderFrontStandardAboutPanel: - - - - 142 - - - - delegate - - - - 495 - - - - performMiniaturize: - - - - 37 - - - - arrangeInFront: - - - - 39 - - - - print: - - - - 86 - - - - runPageLayout: - - - - 87 - - - - clearRecentDocuments: - - - - 127 - - - - performClose: - - - - 193 - - - - toggleContinuousSpellChecking: - - - - 222 - - - - undo: - - - - 223 - - - - copy: - - - - 224 - - - - checkSpelling: - - - - 225 - - - - paste: - - - - 226 - - - - stopSpeaking: - - - - 227 - - - - cut: - - - - 228 - - - - showGuessPanel: - - - - 230 - - - - redo: - - - - 231 - - - - selectAll: - - - - 232 - - - - startSpeaking: - - - - 233 - - - - delete: - - - - 235 - - - - performZoom: - - - - 240 - - - - performFindPanelAction: - - - - 241 - - - - centerSelectionInVisibleArea: - - - - 245 - - - - toggleGrammarChecking: - - - - 347 - - - - toggleSmartInsertDelete: - - - - 355 - - - - toggleAutomaticQuoteSubstitution: - - - - 356 - - - - toggleAutomaticLinkDetection: - - - - 357 - - - - saveDocument: - - - - 362 - - - - revertDocumentToSaved: - - - - 364 - - - - runToolbarCustomizationPalette: - - - - 365 - - - - toggleToolbarShown: - - - - 366 - - - - hide: - - - - 367 - - - - hideOtherApplications: - - - - 368 - - - - unhideAllApplications: - - - - 370 - - - - newDocument: - - - - 373 - - - - openDocument: - - - - 374 - - - - raiseBaseline: - - - - 426 - - - - lowerBaseline: - - - - 427 - - - - copyFont: - - - - 428 - - - - subscript: - - - - 429 - - - - superscript: - - - - 430 - - - - tightenKerning: - - - - 431 - - - - underline: - - - - 432 - - - - orderFrontColorPanel: - - - - 433 - - - - useAllLigatures: - - - - 434 - - - - loosenKerning: - - - - 435 - - - - pasteFont: - - - - 436 - - - - unscript: - - - - 437 - - - - useStandardKerning: - - - - 438 - - - - useStandardLigatures: - - - - 439 - - - - turnOffLigatures: - - - - 440 - - - - turnOffKerning: - - - - 441 - - - - toggleAutomaticSpellingCorrection: - - - - 456 - - - - orderFrontSubstitutionsPanel: - - - - 458 - - - - toggleAutomaticDashSubstitution: - - - - 461 - - - - toggleAutomaticTextReplacement: - - - - 463 - - - - uppercaseWord: - - - - 464 - - - - capitalizeWord: - - - - 467 - - - - lowercaseWord: - - - - 468 - - - - pasteAsPlainText: - - - - 486 - - - - performFindPanelAction: - - - - 487 - - - - performFindPanelAction: - - - - 488 - - - - performFindPanelAction: - - - - 489 - - - - showHelp: - - - - 493 - - - - alignCenter: - - - - 518 - - - - pasteRuler: - - - - 519 - - - - toggleRuler: - - - - 520 - - - - alignRight: - - - - 521 - - - - copyRuler: - - - - 522 - - - - alignJustified: - - - - 523 - - - - alignLeft: - - - - 524 - - - - makeBaseWritingDirectionNatural: - - - - 525 - - - - makeBaseWritingDirectionLeftToRight: - - - - 526 - - - - makeBaseWritingDirectionRightToLeft: - - - - 527 - - - - makeTextWritingDirectionNatural: - - - - 528 - - - - makeTextWritingDirectionLeftToRight: - - - - 529 - - - - makeTextWritingDirectionRightToLeft: - - - - 530 - - - - performFindPanelAction: - - - - 535 - - - - addFontTrait: - - - - 421 - - - - addFontTrait: - - - - 422 - - - - modifyFont: - - - - 423 - - - - orderFrontFontPanel: - - - - 424 - - - - modifyFont: - - - - 425 - - - - window - - - - 532 - - - - webView - - - - 543 - - - - sendMessage: - - - - 555 - - - - callHandler: - - - - 556 - - - - - - 0 - - - - - - -2 - - - File's Owner - - - -1 - - - First Responder - - - -3 - - - Application - - - 29 - - - - - - - - - - - - - - 19 - - - - - - - - 56 - - - - - - - - 217 - - - - - - - - 83 - - - - - - - - 81 - - - - - - - - - - - - - - - - - 75 - - - - - 78 - - - - - 72 - - - - - 82 - - - - - 124 - - - - - - - - 77 - - - - - 73 - - - - - 79 - - - - - 112 - - - - - 74 - - - - - 125 - - - - - - - - 126 - - - - - 205 - - - - - - - - - - - - - - - - - - - - - - 202 - - - - - 198 - - - - - 207 - - - - - 214 - - - - - 199 - - - - - 203 - - - - - 197 - - - - - 206 - - - - - 215 - - - - - 218 - - - - - - - - 216 - - - - - - - - 200 - - - - - - - - - - - - - 219 - - - - - 201 - - - - - 204 - - - - - 220 - - - - - - - - - - - - - 213 - - - - - 210 - - - - - 221 - - - - - 208 - - - - - 209 - - - - - 57 - - - - - - - - - - - - - - - - - - 58 - - - - - 134 - - - - - 150 - - - - - 136 - - - - - 144 - - - - - 129 - - - - - 143 - - - - - 236 - - - - - 131 - - - - - - - - 149 - - - - - 145 - - - - - 130 - - - - - 24 - - - - - - - - - - - 92 - - - - - 5 - - - - - 239 - - - - - 23 - - - - - 295 - - - - - - - - 296 - - - - - - - - - 297 - - - - - 298 - - - - - 211 - - - - - - - - 212 - - - - - - - - - 195 - - - - - 196 - - - - - 346 - - - - - 348 - - - - - - - - 349 - - - - - - - - - - - - - - 350 - - - - - 351 - - - - - 354 - - - - - 371 - - - - - - - - 372 - - - - - 11 - 0 - - 11 - 1 - - 0.0 - - 1000 - - 6 - 24 - 2 - - - - 5 - 0 - - 6 - 1 - - 8 - - 1000 - - 6 - 24 - 3 - - - - 3 - 0 - - 4 - 1 - - 8 - - 1000 - - 6 - 24 - 3 - - - - 5 - 0 - - 5 - 1 - - 20 - - 1000 - - 8 - 29 - 3 - - - - 6 - 0 - - 6 - 1 - - 0.0 - - 1000 - - 8 - 29 - 3 - - - - 3 - 0 - - 3 - 1 - - 0.0 - - 1000 - - 8 - 29 - 3 - - - - 5 - 0 - - 5 - 1 - - 0.0 - - 1000 - - 8 - 29 - 3 - - - - - - - - - 375 - - - - - - - - 376 - - - - - - - - - 377 - - - - - - - - 388 - - - - - - - - - - - - - - - - - - - - - - - 389 - - - - - 390 - - - - - 391 - - - - - 392 - - - - - 393 - - - - - 394 - - - - - 395 - - - - - 396 - - - - - 397 - - - - - - - - 398 - - - - - - - - 399 - - - - - - - - 400 - - - - - 401 - - - - - 402 - - - - - 403 - - - - - 404 - - - - - 405 - - - - - - - - - - - - 406 - - - - - 407 - - - - - 408 - - - - - 409 - - - - - 410 - - - - - 411 - - - - - - - - - - 412 - - - - - 413 - - - - - 414 - - - - - 415 - - - - - - - - - - - 416 - - - - - 417 - - - - - 418 - - - - - 419 - - - - - 420 - - - - - 450 - - - - - - - - 451 - - - - - - - - - - 452 - - - - - 453 - - - - - 454 - - - - - 457 - - - - - 459 - - - - - 460 - - - - - 462 - - - - - 465 - - - - - 466 - - - - - 485 - - - - - 490 - - - - - - - - 491 - - - - - - - - 492 - - - - - 494 - - - - - 496 - - - - - - - - 497 - - - - - - - - - - - - - - - - - 498 - - - - - 499 - - - - - 500 - - - - - 501 - - - - - 502 - - - - - 503 - - - - - - - - 504 - - - - - 505 - - - - - 506 - - - - - 507 - - - - - 508 - - - - - - - - - - - - - - - - 509 - - - - - 510 - - - - - 511 - - - - - 512 - - - - - 513 - - - - - 514 - - - - - 515 - - - - - 516 - - - - - 517 - - - - - 534 - - - - - 536 - - - - - 8 - 0 - - 0 - 1 - - 323 - - 1000 - - 3 - 9 - 1 - - - - - - 539 - - - - - 540 - - - - - 542 - - - - - 544 - - - - - 545 - - - - - - - - 546 - - - - - 550 - - - - - 551 - - - - - - - - 552 - - - - - 554 - - - - - 557 - - - - - 558 - - - - - 559 - - - - - - - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - {{380, 496}, {480, 360}} - - - - - - - - - - - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - - - - - com.apple.WebKitIBPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.WebKitIBPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - - - - - - 559 - - - - - AppDelegate - NSObject - - id - id - - - - callHandler: - id - - - sendMessage: - id - - - - WebView - NSWindow - - - - webView - WebView - - - window - NSWindow - - - - IBProjectSource - ./Classes/AppDelegate.h - - - - NSLayoutConstraint - NSObject - - IBProjectSource - ./Classes/NSLayoutConstraint.h - - - - - 0 - IBCocoaFramework - YES - 3 - - {11, 11} - {10, 3} - - YES - - diff --git a/Example Apps/ExampleApp-OSX/main.m b/Example Apps/ExampleApp-OSX/main.m deleted file mode 100644 index 04d99dab..00000000 --- a/Example Apps/ExampleApp-OSX/main.m +++ /dev/null @@ -1,6 +0,0 @@ -#import - -int main(int argc, char *argv[]) -{ - return NSApplicationMain(argc, (const char **)argv); -} From b85f3ff273be12aec831808be7c681206493ea78 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Sat, 8 Jun 2013 19:58:03 -0700 Subject: [PATCH 102/353] Create an OS X example app that creates everything in code --- .../ExampleApp-OSX.xcodeproj/project.pbxproj | 340 ++++++++++++++++++ Example Apps/ExampleApp-OSX/AppDelegate.h | 15 + Example Apps/ExampleApp-OSX/AppDelegate.m | 87 +++++ .../ExampleApp-OSX/ExampleApp-OSX-Info.plist | 34 ++ .../ExampleApp-OSX/ExampleApp-OSX-Prefix.pch | 7 + Example Apps/ExampleApp-OSX/ExampleApp.html | 66 ++++ .../ExampleApp-OSX/en.lproj/Credits.rtf | 29 ++ .../ExampleApp-OSX/en.lproj/InfoPlist.strings | 2 + Example Apps/ExampleApp-OSX/main.m | 14 + 9 files changed, 594 insertions(+) create mode 100644 Example Apps/ExampleApp-OSX.xcodeproj/project.pbxproj create mode 100644 Example Apps/ExampleApp-OSX/AppDelegate.h create mode 100644 Example Apps/ExampleApp-OSX/AppDelegate.m create mode 100644 Example Apps/ExampleApp-OSX/ExampleApp-OSX-Info.plist create mode 100644 Example Apps/ExampleApp-OSX/ExampleApp-OSX-Prefix.pch create mode 100644 Example Apps/ExampleApp-OSX/ExampleApp.html create mode 100644 Example Apps/ExampleApp-OSX/en.lproj/Credits.rtf create mode 100644 Example Apps/ExampleApp-OSX/en.lproj/InfoPlist.strings create mode 100644 Example Apps/ExampleApp-OSX/main.m diff --git a/Example Apps/ExampleApp-OSX.xcodeproj/project.pbxproj b/Example Apps/ExampleApp-OSX.xcodeproj/project.pbxproj new file mode 100644 index 00000000..248a1e84 --- /dev/null +++ b/Example Apps/ExampleApp-OSX.xcodeproj/project.pbxproj @@ -0,0 +1,340 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 2C136A2517641106004C7401 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2C136A2417641106004C7401 /* Cocoa.framework */; }; + 2C136A2F17641106004C7401 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 2C136A2D17641106004C7401 /* InfoPlist.strings */; }; + 2C136A3117641106004C7401 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C136A3017641106004C7401 /* main.m */; }; + 2C136A3517641106004C7401 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 2C136A3317641106004C7401 /* Credits.rtf */; }; + 2C136A3817641106004C7401 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C136A3717641106004C7401 /* AppDelegate.m */; }; + 2C136A4217641236004C7401 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2C136A4117641236004C7401 /* WebKit.framework */; }; + 2C136A4E176421B9004C7401 /* ExampleApp.html in Resources */ = {isa = PBXBuildFile; fileRef = 2C136A4D176421B9004C7401 /* ExampleApp.html */; }; + 2C136A5617642680004C7401 /* WebViewJavascriptBridge.js.txt in Resources */ = {isa = PBXBuildFile; fileRef = 2C136A5117642680004C7401 /* WebViewJavascriptBridge.js.txt */; }; + 2C136A5717642680004C7401 /* WebViewJavascriptBridgeAbstract.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C136A5317642680004C7401 /* WebViewJavascriptBridgeAbstract.m */; }; + 2C136A5817642680004C7401 /* WebViewJavascriptBridge_OSX.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C136A5517642680004C7401 /* WebViewJavascriptBridge_OSX.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 2C136A2117641106004C7401 /* ExampleApp-OSX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "ExampleApp-OSX.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 2C136A2417641106004C7401 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 2C136A2717641106004C7401 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; + 2C136A2817641106004C7401 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; + 2C136A2917641106004C7401 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 2C136A2C17641106004C7401 /* ExampleApp-OSX-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ExampleApp-OSX-Info.plist"; sourceTree = ""; }; + 2C136A2E17641106004C7401 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 2C136A3017641106004C7401 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 2C136A3217641106004C7401 /* ExampleApp-OSX-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ExampleApp-OSX-Prefix.pch"; sourceTree = ""; }; + 2C136A3417641106004C7401 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = en; path = en.lproj/Credits.rtf; sourceTree = ""; }; + 2C136A3617641106004C7401 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 2C136A3717641106004C7401 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 2C136A4117641236004C7401 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; + 2C136A4D176421B9004C7401 /* ExampleApp.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = ExampleApp.html; sourceTree = ""; }; + 2C136A5117642680004C7401 /* WebViewJavascriptBridge.js.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebViewJavascriptBridge.js.txt; sourceTree = ""; }; + 2C136A5217642680004C7401 /* WebViewJavascriptBridgeAbstract.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridgeAbstract.h; sourceTree = ""; }; + 2C136A5317642680004C7401 /* WebViewJavascriptBridgeAbstract.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridgeAbstract.m; sourceTree = ""; }; + 2C136A5417642680004C7401 /* WebViewJavascriptBridge_OSX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridge_OSX.h; sourceTree = ""; }; + 2C136A5517642680004C7401 /* WebViewJavascriptBridge_OSX.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge_OSX.m; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 2C136A1E17641106004C7401 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 2C136A4217641236004C7401 /* WebKit.framework in Frameworks */, + 2C136A2517641106004C7401 /* Cocoa.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 2C136A1817641106004C7401 = { + isa = PBXGroup; + children = ( + 2C136A4117641236004C7401 /* WebKit.framework */, + 2C136A2A17641106004C7401 /* ExampleApp-OSX */, + 2C136A2317641106004C7401 /* Frameworks */, + 2C136A2217641106004C7401 /* Products */, + ); + sourceTree = ""; + }; + 2C136A2217641106004C7401 /* Products */ = { + isa = PBXGroup; + children = ( + 2C136A2117641106004C7401 /* ExampleApp-OSX.app */, + ); + name = Products; + sourceTree = ""; + }; + 2C136A2317641106004C7401 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 2C136A2417641106004C7401 /* Cocoa.framework */, + 2C136A2617641106004C7401 /* Other Frameworks */, + ); + name = Frameworks; + sourceTree = ""; + }; + 2C136A2617641106004C7401 /* Other Frameworks */ = { + isa = PBXGroup; + children = ( + 2C136A2717641106004C7401 /* AppKit.framework */, + 2C136A2817641106004C7401 /* CoreData.framework */, + 2C136A2917641106004C7401 /* Foundation.framework */, + ); + name = "Other Frameworks"; + sourceTree = ""; + }; + 2C136A2A17641106004C7401 /* ExampleApp-OSX */ = { + isa = PBXGroup; + children = ( + 2C136A3617641106004C7401 /* AppDelegate.h */, + 2C136A3717641106004C7401 /* AppDelegate.m */, + 2C136A4D176421B9004C7401 /* ExampleApp.html */, + 2C136A4F17642680004C7401 /* WebViewJavascriptBridge_OSX */, + 2C136A2B17641106004C7401 /* Supporting Files */, + ); + path = "ExampleApp-OSX"; + sourceTree = ""; + }; + 2C136A2B17641106004C7401 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 2C136A2C17641106004C7401 /* ExampleApp-OSX-Info.plist */, + 2C136A2D17641106004C7401 /* InfoPlist.strings */, + 2C136A3017641106004C7401 /* main.m */, + 2C136A3217641106004C7401 /* ExampleApp-OSX-Prefix.pch */, + 2C136A3317641106004C7401 /* Credits.rtf */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 2C136A4F17642680004C7401 /* WebViewJavascriptBridge_OSX */ = { + isa = PBXGroup; + children = ( + 2C136A5017642680004C7401 /* WebViewJavascriptAbstract */, + 2C136A5417642680004C7401 /* WebViewJavascriptBridge_OSX.h */, + 2C136A5517642680004C7401 /* WebViewJavascriptBridge_OSX.m */, + ); + name = WebViewJavascriptBridge_OSX; + path = ../../WebViewJavascriptBridge_OSX; + sourceTree = ""; + }; + 2C136A5017642680004C7401 /* WebViewJavascriptAbstract */ = { + isa = PBXGroup; + children = ( + 2C136A5117642680004C7401 /* WebViewJavascriptBridge.js.txt */, + 2C136A5217642680004C7401 /* WebViewJavascriptBridgeAbstract.h */, + 2C136A5317642680004C7401 /* WebViewJavascriptBridgeAbstract.m */, + ); + path = WebViewJavascriptAbstract; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 2C136A2017641106004C7401 /* ExampleApp-OSX */ = { + isa = PBXNativeTarget; + buildConfigurationList = 2C136A3E17641106004C7401 /* Build configuration list for PBXNativeTarget "ExampleApp-OSX" */; + buildPhases = ( + 2C136A1D17641106004C7401 /* Sources */, + 2C136A1E17641106004C7401 /* Frameworks */, + 2C136A1F17641106004C7401 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "ExampleApp-OSX"; + productName = "ExampleApp-OSX"; + productReference = 2C136A2117641106004C7401 /* ExampleApp-OSX.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 2C136A1917641106004C7401 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0460; + ORGANIZATIONNAME = "Marcus Westin"; + }; + buildConfigurationList = 2C136A1C17641106004C7401 /* Build configuration list for PBXProject "ExampleApp-OSX" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 2C136A1817641106004C7401; + productRefGroup = 2C136A2217641106004C7401 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 2C136A2017641106004C7401 /* ExampleApp-OSX */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 2C136A1F17641106004C7401 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2C136A2F17641106004C7401 /* InfoPlist.strings in Resources */, + 2C136A3517641106004C7401 /* Credits.rtf in Resources */, + 2C136A4E176421B9004C7401 /* ExampleApp.html in Resources */, + 2C136A5617642680004C7401 /* WebViewJavascriptBridge.js.txt in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 2C136A1D17641106004C7401 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2C136A3117641106004C7401 /* main.m in Sources */, + 2C136A3817641106004C7401 /* AppDelegate.m in Sources */, + 2C136A5717642680004C7401 /* WebViewJavascriptBridgeAbstract.m in Sources */, + 2C136A5817642680004C7401 /* WebViewJavascriptBridge_OSX.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 2C136A2D17641106004C7401 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 2C136A2E17641106004C7401 /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; + 2C136A3317641106004C7401 /* Credits.rtf */ = { + isa = PBXVariantGroup; + children = ( + 2C136A3417641106004C7401 /* en */, + ); + name = Credits.rtf; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 2C136A3C17641106004C7401 /* Debug */ = { + 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; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.8; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + 2C136A3D17641106004C7401 /* Release */ = { + 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; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.8; + SDKROOT = macosx; + }; + name = Release; + }; + 2C136A3F17641106004C7401 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "ExampleApp-OSX/ExampleApp-OSX-Prefix.pch"; + INFOPLIST_FILE = "ExampleApp-OSX/ExampleApp-OSX-Info.plist"; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + 2C136A4017641106004C7401 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "ExampleApp-OSX/ExampleApp-OSX-Prefix.pch"; + INFOPLIST_FILE = "ExampleApp-OSX/ExampleApp-OSX-Info.plist"; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 2C136A1C17641106004C7401 /* Build configuration list for PBXProject "ExampleApp-OSX" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2C136A3C17641106004C7401 /* Debug */, + 2C136A3D17641106004C7401 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 2C136A3E17641106004C7401 /* Build configuration list for PBXNativeTarget "ExampleApp-OSX" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2C136A3F17641106004C7401 /* Debug */, + 2C136A4017641106004C7401 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 2C136A1917641106004C7401 /* Project object */; +} diff --git a/Example Apps/ExampleApp-OSX/AppDelegate.h b/Example Apps/ExampleApp-OSX/AppDelegate.h new file mode 100644 index 00000000..6d91daf4 --- /dev/null +++ b/Example Apps/ExampleApp-OSX/AppDelegate.h @@ -0,0 +1,15 @@ +// +// AppDelegate.h +// ExampleApp-OSX +// +// Created by Marcus Westin on 6/8/13. +// Copyright (c) 2013 Marcus Westin. All rights reserved. +// + +#import + +@interface AppDelegate : NSObject + +@property (assign) IBOutlet NSWindow *window; + +@end diff --git a/Example Apps/ExampleApp-OSX/AppDelegate.m b/Example Apps/ExampleApp-OSX/AppDelegate.m new file mode 100644 index 00000000..03724e00 --- /dev/null +++ b/Example Apps/ExampleApp-OSX/AppDelegate.m @@ -0,0 +1,87 @@ +// +// AppDelegate.m +// ExampleApp-OSX +// +// Created by Marcus Westin on 6/8/13. +// Copyright (c) 2013 Marcus Westin. All rights reserved. +// + +#import "AppDelegate.h" +#import +#import "WebViewJavascriptBridge_OSX.h" + +@implementation AppDelegate { + WebView* _webView; + WebViewJavascriptBridge* _bridge; +} + +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification +{ + [self _createViews]; + [self _createBridge]; + [self _createObjcButtons]; + [self _loadPage]; +} + +- (void)_createBridge { + _bridge = [WebViewJavascriptBridge bridgeForWebView:_webView 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:[NSDictionary dictionaryWithObject:@"before ready" forKey:@"foo"]]; +} + +- (void)_createObjcButtons { + NSButton *messageButton = [[NSButton alloc] initWithFrame:NSMakeRect(5, 0, 120, 40)]; + [messageButton setTitle:@"Send message"]; + [messageButton setBezelStyle:NSRoundedBezelStyle]; + [messageButton setTarget:self]; + [messageButton setAction:@selector(_sendMessage)]; + [_webView addSubview:messageButton]; + + NSButton *callbackButton = [[NSButton alloc] initWithFrame:NSMakeRect(120, 0, 120, 40)]; + [callbackButton setTitle:@"Call handler"]; + [callbackButton setBezelStyle:NSRoundedBezelStyle]; + [callbackButton setTarget:self]; + [callbackButton setAction:@selector(_callHandler)]; + [_webView addSubview:callbackButton]; +} + +- (void)_sendMessage { + [_bridge send:@"A string sent from ObjC to JS" responseCallback:^(id response) { + NSLog(@"sendMessage got response: %@", response); + }]; +} + +- (void)_callHandler { + NSDictionary* data = [NSDictionary dictionaryWithObject:@"Hi there, JS!" forKey:@"greetingFromObjC"]; + [_bridge callHandler:@"testJavascriptHandler" data:data responseCallback:^(id response) { + NSLog(@"testJavascriptHandler responded: %@", response); + }]; +} + +- (void)_createViews { + NSView* contentView = _window.contentView; + _webView = [[WebView alloc] initWithFrame:contentView.frame]; + [_webView setAutoresizingMask:(NSViewHeightSizable | NSViewWidthSizable)]; + [contentView addSubview:_webView]; +} + +- (void)_loadPage { + NSString* htmlPath = [[NSBundle mainBundle] pathForResource:@"ExampleApp" ofType:@"html"]; + NSString* html = [NSString stringWithContentsOfFile:htmlPath encoding:NSUTF8StringEncoding error:nil]; + [[_webView mainFrame] loadHTMLString:html baseURL:nil]; +} + + +@end diff --git a/Example Apps/ExampleApp-OSX/ExampleApp-OSX-Info.plist b/Example Apps/ExampleApp-OSX/ExampleApp-OSX-Info.plist new file mode 100644 index 00000000..14097880 --- /dev/null +++ b/Example Apps/ExampleApp-OSX/ExampleApp-OSX-Info.plist @@ -0,0 +1,34 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + + CFBundleIdentifier + WebViewJavascriptBridge.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSMinimumSystemVersion + ${MACOSX_DEPLOYMENT_TARGET} + NSHumanReadableCopyright + Copyright © 2013 Marcus Westin. All rights reserved. + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/Example Apps/ExampleApp-OSX/ExampleApp-OSX-Prefix.pch b/Example Apps/ExampleApp-OSX/ExampleApp-OSX-Prefix.pch new file mode 100644 index 00000000..32daebd5 --- /dev/null +++ b/Example Apps/ExampleApp-OSX/ExampleApp-OSX-Prefix.pch @@ -0,0 +1,7 @@ +// +// Prefix header for all source files of the 'ExampleApp-OSX' target in the 'ExampleApp-OSX' project +// + +#ifdef __OBJC__ + #import +#endif diff --git a/Example Apps/ExampleApp-OSX/ExampleApp.html b/Example Apps/ExampleApp-OSX/ExampleApp.html new file mode 100644 index 00000000..9272e3f3 --- /dev/null +++ b/Example Apps/ExampleApp-OSX/ExampleApp.html @@ -0,0 +1,66 @@ + + + + +

WebViewJavascriptBridge Demo

+ +
+ diff --git a/Example Apps/ExampleApp-OSX/en.lproj/Credits.rtf b/Example Apps/ExampleApp-OSX/en.lproj/Credits.rtf new file mode 100644 index 00000000..46576ef2 --- /dev/null +++ b/Example Apps/ExampleApp-OSX/en.lproj/Credits.rtf @@ -0,0 +1,29 @@ +{\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;} +{\colortbl;\red255\green255\blue255;} +\paperw9840\paperh8400 +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural + +\f0\b\fs24 \cf0 Engineering: +\b0 \ + Some people\ +\ + +\b Human Interface Design: +\b0 \ + Some other people\ +\ + +\b Testing: +\b0 \ + Hopefully not nobody\ +\ + +\b Documentation: +\b0 \ + Whoever\ +\ + +\b With special thanks to: +\b0 \ + Mom\ +} diff --git a/Example Apps/ExampleApp-OSX/en.lproj/InfoPlist.strings b/Example Apps/ExampleApp-OSX/en.lproj/InfoPlist.strings new file mode 100644 index 00000000..477b28ff --- /dev/null +++ b/Example Apps/ExampleApp-OSX/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Example Apps/ExampleApp-OSX/main.m b/Example Apps/ExampleApp-OSX/main.m new file mode 100644 index 00000000..0999e46a --- /dev/null +++ b/Example Apps/ExampleApp-OSX/main.m @@ -0,0 +1,14 @@ +// +// main.m +// ExampleApp-OSX +// +// Created by Marcus Westin on 6/8/13. +// Copyright (c) 2013 Marcus Westin. All rights reserved. +// + +#import + +int main(int argc, char *argv[]) +{ + return NSApplicationMain(argc, (const char **)argv); +} From a21cdd4e17bd17068e525c16b0f269c4a063b20d Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Sat, 8 Jun 2013 20:00:16 -0700 Subject: [PATCH 103/353] Use the same ExampleApp.html file in the OSX example app as the iOS example app uses --- .../ExampleApp-OSX.xcodeproj/project.pbxproj | 8 +-- Example Apps/ExampleApp-OSX/ExampleApp.html | 66 ------------------- 2 files changed, 4 insertions(+), 70 deletions(-) delete mode 100644 Example Apps/ExampleApp-OSX/ExampleApp.html diff --git a/Example Apps/ExampleApp-OSX.xcodeproj/project.pbxproj b/Example Apps/ExampleApp-OSX.xcodeproj/project.pbxproj index 248a1e84..34b8c107 100644 --- a/Example Apps/ExampleApp-OSX.xcodeproj/project.pbxproj +++ b/Example Apps/ExampleApp-OSX.xcodeproj/project.pbxproj @@ -13,10 +13,10 @@ 2C136A3517641106004C7401 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 2C136A3317641106004C7401 /* Credits.rtf */; }; 2C136A3817641106004C7401 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C136A3717641106004C7401 /* AppDelegate.m */; }; 2C136A4217641236004C7401 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2C136A4117641236004C7401 /* WebKit.framework */; }; - 2C136A4E176421B9004C7401 /* ExampleApp.html in Resources */ = {isa = PBXBuildFile; fileRef = 2C136A4D176421B9004C7401 /* ExampleApp.html */; }; 2C136A5617642680004C7401 /* WebViewJavascriptBridge.js.txt in Resources */ = {isa = PBXBuildFile; fileRef = 2C136A5117642680004C7401 /* WebViewJavascriptBridge.js.txt */; }; 2C136A5717642680004C7401 /* WebViewJavascriptBridgeAbstract.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C136A5317642680004C7401 /* WebViewJavascriptBridgeAbstract.m */; }; 2C136A5817642680004C7401 /* WebViewJavascriptBridge_OSX.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C136A5517642680004C7401 /* WebViewJavascriptBridge_OSX.m */; }; + 2C136A5A17642704004C7401 /* ExampleApp.html in Resources */ = {isa = PBXBuildFile; fileRef = 2C136A5917642704004C7401 /* ExampleApp.html */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -33,12 +33,12 @@ 2C136A3617641106004C7401 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 2C136A3717641106004C7401 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 2C136A4117641236004C7401 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; - 2C136A4D176421B9004C7401 /* ExampleApp.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = ExampleApp.html; sourceTree = ""; }; 2C136A5117642680004C7401 /* WebViewJavascriptBridge.js.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebViewJavascriptBridge.js.txt; sourceTree = ""; }; 2C136A5217642680004C7401 /* WebViewJavascriptBridgeAbstract.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridgeAbstract.h; sourceTree = ""; }; 2C136A5317642680004C7401 /* WebViewJavascriptBridgeAbstract.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridgeAbstract.m; sourceTree = ""; }; 2C136A5417642680004C7401 /* WebViewJavascriptBridge_OSX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridge_OSX.h; sourceTree = ""; }; 2C136A5517642680004C7401 /* WebViewJavascriptBridge_OSX.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge_OSX.m; sourceTree = ""; }; + 2C136A5917642704004C7401 /* ExampleApp.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = ExampleApp.html; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -96,7 +96,7 @@ children = ( 2C136A3617641106004C7401 /* AppDelegate.h */, 2C136A3717641106004C7401 /* AppDelegate.m */, - 2C136A4D176421B9004C7401 /* ExampleApp.html */, + 2C136A5917642704004C7401 /* ExampleApp.html */, 2C136A4F17642680004C7401 /* WebViewJavascriptBridge_OSX */, 2C136A2B17641106004C7401 /* Supporting Files */, ); @@ -189,8 +189,8 @@ files = ( 2C136A2F17641106004C7401 /* InfoPlist.strings in Resources */, 2C136A3517641106004C7401 /* Credits.rtf in Resources */, - 2C136A4E176421B9004C7401 /* ExampleApp.html in Resources */, 2C136A5617642680004C7401 /* WebViewJavascriptBridge.js.txt in Resources */, + 2C136A5A17642704004C7401 /* ExampleApp.html in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Example Apps/ExampleApp-OSX/ExampleApp.html b/Example Apps/ExampleApp-OSX/ExampleApp.html deleted file mode 100644 index 9272e3f3..00000000 --- a/Example Apps/ExampleApp-OSX/ExampleApp.html +++ /dev/null @@ -1,66 +0,0 @@ - - - - -

WebViewJavascriptBridge Demo

- -
- From 668573f8e740775c08c0c41333289b6172d91a5e Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Fri, 14 Jun 2013 11:14:52 -0700 Subject: [PATCH 104/353] Remove numRequestsLoading from the OSX bridge. Since didFinishLoadForFrame fires when the entire document has loaded (rather than when any individual resource has loaded), numRequestsLoading is simply not required for OS X and causes problems --- .../WebViewJavascriptBridge_OSX.m | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.m b/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.m index b442802a..5a29a0a3 100644 --- a/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.m +++ b/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.m @@ -1,11 +1,5 @@ #import "WebViewJavascriptBridge_OSX.h" -@interface WebViewJavascriptBridge () - -@property (nonatomic, assign) NSUInteger numRequestsLoading; - -@end - @implementation WebViewJavascriptBridge + (instancetype)bridgeForWebView:(WebView *)webView handler:(WVJBHandler)handler { @@ -38,9 +32,7 @@ - (void)webView:(WebView *)webView didFinishLoadForFrame:(WebFrame *)frame { if (webView != self.webView) { return; } - self.numRequestsLoading--; - - if (self.numRequestsLoading == 0 && ![[webView stringByEvaluatingJavaScriptFromString:@"typeof WebViewJavascriptBridge == 'object'"] isEqualToString:@"true"]) { + if (![[webView stringByEvaluatingJavaScriptFromString:@"typeof WebViewJavascriptBridge == 'object'"] isEqualToString:@"true"]) { NSString *filePath = [[NSBundle mainBundle] pathForResource:@"WebViewJavascriptBridge.js" ofType:@"txt"]; NSString *js = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; [webView stringByEvaluatingJavaScriptFromString:js]; @@ -62,8 +54,6 @@ - (void)webView:(WebView *)webView didFinishLoadForFrame:(WebFrame *)frame - (void)webView:(WebView *)webView didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame { if (webView != self.webView) { return; } - self.numRequestsLoading--; - __strong typeof(self.webViewDelegate) strongDelegate = self.webViewDelegate; if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didFailLoadWithError:forFrame:)]) { [strongDelegate webView:strongDelegate didFailLoadWithError:error forFrame:frame]; @@ -101,8 +91,6 @@ - (void)webView:(WebView *)webView didCommitLoadForFrame:(WebFrame *)frame { - (NSURLRequest *)webView:(WebView *)webView resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource { if (webView != self.webView) { return request; } - self.numRequestsLoading++; - __strong typeof(self.webViewDelegate) strongDelegate = self.webViewDelegate; if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:resource:willSendRequest:redirectResponse:fromDataSource:)]) { return [strongDelegate webView:webView resource:identifier willSendRequest:request redirectResponse:redirectResponse fromDataSource:dataSource]; From baf4a06d0867d11a856be578b9d9f8c19b8e4203 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Fri, 14 Jun 2013 11:20:11 -0700 Subject: [PATCH 105/353] Import WebKit in conditional OSX macro of WebViewJavascriptBridgeAbstract to avoid compiler warnings about stringByEvaluatingJavaScriptFromString: selector being undefined --- .../WebViewJavascriptBridgeAbstract.h | 1 + WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.h | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.h b/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.h index de80ba9d..30301c57 100644 --- a/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.h +++ b/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.h @@ -6,6 +6,7 @@ #define WEAK_FALLBACK weak #elif TARGET_OS_MAC && defined(__MAC_10_7) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_7) #define WEAK_FALLBACK weak + #import #else #define WEAK_FALLBACK unsafe_unretained #endif diff --git a/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.h b/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.h index d674fa20..41e5305e 100644 --- a/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.h +++ b/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.h @@ -1,4 +1,3 @@ -#import #import "WebViewJavascriptBridgeAbstract.h" @interface WebViewJavascriptBridge : WebViewJavascriptBridgeAbstract From 57ee322a4c5310eadd28b28f4d8522cd54123301 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Fri, 14 Jun 2013 13:16:26 -0700 Subject: [PATCH 106/353] Simplify setup and file organization by doing away with the Abstract/iOS/OSX seperation. Instead, we manage the iOS/OSX platform specific part using macros --- .../ExampleApp-OSX.xcodeproj/project.pbxproj | 42 +- Example Apps/ExampleApp-OSX/AppDelegate.m | 2 +- .../ExampleApp-iOS.xcodeproj/project.pbxproj | 52 +-- .../ExampleApp-iOS/ExampleAppDelegate.h | 2 +- README.md | 7 +- WebViewJavascriptBridge.podspec | 4 +- .../WebViewJavascriptBridge.h | 51 +++ .../WebViewJavascriptBridge.js.txt | 0 .../WebViewJavascriptBridge.m | 378 ++++++++++++++++++ .../WebViewJavascriptBridgeAbstract.h | 48 --- .../WebViewJavascriptBridgeAbstract.m | 171 -------- .../WebViewJavascriptAbstract | 1 - .../WebViewJavascriptBridge_OSX.h | 11 - .../WebViewJavascriptBridge_OSX.m | 102 ----- .../WebViewJavascriptAbstract | 1 - .../WebViewJavascriptBridge_iOS.h | 12 - .../WebViewJavascriptBridge_iOS.m | 99 ----- 17 files changed, 468 insertions(+), 515 deletions(-) create mode 100644 WebViewJavascriptBridge/WebViewJavascriptBridge.h rename {WebViewJavascriptBridgeAbstract => WebViewJavascriptBridge}/WebViewJavascriptBridge.js.txt (100%) create mode 100644 WebViewJavascriptBridge/WebViewJavascriptBridge.m delete mode 100644 WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.h delete mode 100755 WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.m delete mode 120000 WebViewJavascriptBridge_OSX/WebViewJavascriptAbstract delete mode 100644 WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.h delete mode 100644 WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.m delete mode 120000 WebViewJavascriptBridge_iOS/WebViewJavascriptAbstract delete mode 100644 WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.h delete mode 100644 WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m diff --git a/Example Apps/ExampleApp-OSX.xcodeproj/project.pbxproj b/Example Apps/ExampleApp-OSX.xcodeproj/project.pbxproj index 34b8c107..18313cd6 100644 --- a/Example Apps/ExampleApp-OSX.xcodeproj/project.pbxproj +++ b/Example Apps/ExampleApp-OSX.xcodeproj/project.pbxproj @@ -13,10 +13,9 @@ 2C136A3517641106004C7401 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 2C136A3317641106004C7401 /* Credits.rtf */; }; 2C136A3817641106004C7401 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C136A3717641106004C7401 /* AppDelegate.m */; }; 2C136A4217641236004C7401 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2C136A4117641236004C7401 /* WebKit.framework */; }; - 2C136A5617642680004C7401 /* WebViewJavascriptBridge.js.txt in Resources */ = {isa = PBXBuildFile; fileRef = 2C136A5117642680004C7401 /* WebViewJavascriptBridge.js.txt */; }; - 2C136A5717642680004C7401 /* WebViewJavascriptBridgeAbstract.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C136A5317642680004C7401 /* WebViewJavascriptBridgeAbstract.m */; }; - 2C136A5817642680004C7401 /* WebViewJavascriptBridge_OSX.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C136A5517642680004C7401 /* WebViewJavascriptBridge_OSX.m */; }; 2C136A5A17642704004C7401 /* ExampleApp.html in Resources */ = {isa = PBXBuildFile; fileRef = 2C136A5917642704004C7401 /* ExampleApp.html */; }; + 2C1562C5176BA9FF00B4AE50 /* WebViewJavascriptBridge.js.txt in Resources */ = {isa = PBXBuildFile; fileRef = 2C1562C3176BA9FF00B4AE50 /* WebViewJavascriptBridge.js.txt */; }; + 2C1562C6176BA9FF00B4AE50 /* WebViewJavascriptBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C1562C4176BA9FF00B4AE50 /* WebViewJavascriptBridge.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -33,12 +32,10 @@ 2C136A3617641106004C7401 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 2C136A3717641106004C7401 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 2C136A4117641236004C7401 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; - 2C136A5117642680004C7401 /* WebViewJavascriptBridge.js.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebViewJavascriptBridge.js.txt; sourceTree = ""; }; - 2C136A5217642680004C7401 /* WebViewJavascriptBridgeAbstract.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridgeAbstract.h; sourceTree = ""; }; - 2C136A5317642680004C7401 /* WebViewJavascriptBridgeAbstract.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridgeAbstract.m; sourceTree = ""; }; - 2C136A5417642680004C7401 /* WebViewJavascriptBridge_OSX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridge_OSX.h; sourceTree = ""; }; - 2C136A5517642680004C7401 /* WebViewJavascriptBridge_OSX.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge_OSX.m; sourceTree = ""; }; 2C136A5917642704004C7401 /* ExampleApp.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = ExampleApp.html; sourceTree = SOURCE_ROOT; }; + 2C1562C2176BA9FF00B4AE50 /* WebViewJavascriptBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridge.h; sourceTree = ""; }; + 2C1562C3176BA9FF00B4AE50 /* WebViewJavascriptBridge.js.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebViewJavascriptBridge.js.txt; sourceTree = ""; }; + 2C1562C4176BA9FF00B4AE50 /* WebViewJavascriptBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -97,7 +94,7 @@ 2C136A3617641106004C7401 /* AppDelegate.h */, 2C136A3717641106004C7401 /* AppDelegate.m */, 2C136A5917642704004C7401 /* ExampleApp.html */, - 2C136A4F17642680004C7401 /* WebViewJavascriptBridge_OSX */, + 2C1562C1176BA9FF00B4AE50 /* WebViewJavascriptBridge */, 2C136A2B17641106004C7401 /* Supporting Files */, ); path = "ExampleApp-OSX"; @@ -115,25 +112,15 @@ name = "Supporting Files"; sourceTree = ""; }; - 2C136A4F17642680004C7401 /* WebViewJavascriptBridge_OSX */ = { + 2C1562C1176BA9FF00B4AE50 /* WebViewJavascriptBridge */ = { isa = PBXGroup; children = ( - 2C136A5017642680004C7401 /* WebViewJavascriptAbstract */, - 2C136A5417642680004C7401 /* WebViewJavascriptBridge_OSX.h */, - 2C136A5517642680004C7401 /* WebViewJavascriptBridge_OSX.m */, + 2C1562C2176BA9FF00B4AE50 /* WebViewJavascriptBridge.h */, + 2C1562C3176BA9FF00B4AE50 /* WebViewJavascriptBridge.js.txt */, + 2C1562C4176BA9FF00B4AE50 /* WebViewJavascriptBridge.m */, ); - name = WebViewJavascriptBridge_OSX; - path = ../../WebViewJavascriptBridge_OSX; - sourceTree = ""; - }; - 2C136A5017642680004C7401 /* WebViewJavascriptAbstract */ = { - isa = PBXGroup; - children = ( - 2C136A5117642680004C7401 /* WebViewJavascriptBridge.js.txt */, - 2C136A5217642680004C7401 /* WebViewJavascriptBridgeAbstract.h */, - 2C136A5317642680004C7401 /* WebViewJavascriptBridgeAbstract.m */, - ); - path = WebViewJavascriptAbstract; + name = WebViewJavascriptBridge; + path = ../../WebViewJavascriptBridge; sourceTree = ""; }; /* End PBXGroup section */ @@ -187,9 +174,9 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 2C1562C5176BA9FF00B4AE50 /* WebViewJavascriptBridge.js.txt in Resources */, 2C136A2F17641106004C7401 /* InfoPlist.strings in Resources */, 2C136A3517641106004C7401 /* Credits.rtf in Resources */, - 2C136A5617642680004C7401 /* WebViewJavascriptBridge.js.txt in Resources */, 2C136A5A17642704004C7401 /* ExampleApp.html in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -202,9 +189,8 @@ buildActionMask = 2147483647; files = ( 2C136A3117641106004C7401 /* main.m in Sources */, + 2C1562C6176BA9FF00B4AE50 /* WebViewJavascriptBridge.m in Sources */, 2C136A3817641106004C7401 /* AppDelegate.m in Sources */, - 2C136A5717642680004C7401 /* WebViewJavascriptBridgeAbstract.m in Sources */, - 2C136A5817642680004C7401 /* WebViewJavascriptBridge_OSX.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Example Apps/ExampleApp-OSX/AppDelegate.m b/Example Apps/ExampleApp-OSX/AppDelegate.m index 03724e00..d4b230c6 100644 --- a/Example Apps/ExampleApp-OSX/AppDelegate.m +++ b/Example Apps/ExampleApp-OSX/AppDelegate.m @@ -8,7 +8,7 @@ #import "AppDelegate.h" #import -#import "WebViewJavascriptBridge_OSX.h" +#import "WebViewJavascriptBridge.h" @implementation AppDelegate { WebView* _webView; diff --git a/Example Apps/ExampleApp-iOS.xcodeproj/project.pbxproj b/Example Apps/ExampleApp-iOS.xcodeproj/project.pbxproj index 6a694a05..b71010e5 100644 --- a/Example Apps/ExampleApp-iOS.xcodeproj/project.pbxproj +++ b/Example Apps/ExampleApp-iOS.xcodeproj/project.pbxproj @@ -7,13 +7,12 @@ objects = { /* 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 */; }; 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 */; }; 2CA0465C1711AC8E006DEE8B /* ExampleApp.html in Resources */ = {isa = PBXBuildFile; fileRef = 2CA0465B1711AC8D006DEE8B /* ExampleApp.html */; }; - 2CAB868B172766B000BD9ED1 /* WebViewJavascriptBridge.js.txt in Resources */ = {isa = PBXBuildFile; fileRef = 2CAB8686172766B000BD9ED1 /* WebViewJavascriptBridge.js.txt */; }; - 2CAB868C172766B000BD9ED1 /* WebViewJavascriptBridgeAbstract.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CAB8688172766B000BD9ED1 /* WebViewJavascriptBridgeAbstract.m */; }; - 2CAB868D172766B000BD9ED1 /* WebViewJavascriptBridge_iOS.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CAB868A172766B000BD9ED1 /* WebViewJavascriptBridge_iOS.m */; }; 2CAB869B1727684300BD9ED1 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CAB869A1727684300BD9ED1 /* Default-568h@2x.png */; }; 2CEB3EC01602563600548120 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2CEB3EBF1602563600548120 /* UIKit.framework */; }; 2CEB3EC21602563600548120 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2CEB3EC11602563600548120 /* Foundation.framework */; }; @@ -21,6 +20,9 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 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 = ""; }; 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 = ""; }; @@ -28,11 +30,6 @@ 2CA045BD17117439006DEE8B /* ExampleAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ExampleAppDelegate.m; sourceTree = ""; }; 2CA045BE17117439006DEE8B /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 2CA0465B1711AC8D006DEE8B /* ExampleApp.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = ExampleApp.html; sourceTree = SOURCE_ROOT; }; - 2CAB8686172766B000BD9ED1 /* WebViewJavascriptBridge.js.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebViewJavascriptBridge.js.txt; sourceTree = ""; }; - 2CAB8687172766B000BD9ED1 /* WebViewJavascriptBridgeAbstract.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridgeAbstract.h; sourceTree = ""; }; - 2CAB8688172766B000BD9ED1 /* WebViewJavascriptBridgeAbstract.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridgeAbstract.m; sourceTree = ""; }; - 2CAB8689172766B000BD9ED1 /* WebViewJavascriptBridge_iOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridge_iOS.h; sourceTree = ""; }; - 2CAB868A172766B000BD9ED1 /* WebViewJavascriptBridge_iOS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge_iOS.m; sourceTree = ""; }; 2CAB869A1727684300BD9ED1 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Default-568h@2x.png"; path = "ExampleApp-iOS/Default-568h@2x.png"; sourceTree = ""; }; 2CEB3EBB1602563600548120 /* ExampleApp-iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "ExampleApp-iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 2CEB3EBF1602563600548120 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; @@ -54,13 +51,24 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 2C1562A7176B9F5400B4AE50 /* WebViewJavascriptBridge */ = { + isa = PBXGroup; + children = ( + 2C1562B4176B9F8400B4AE50 /* WebViewJavascriptBridge.js.txt */, + 2C1562A8176B9F6200B4AE50 /* WebViewJavascriptBridge.h */, + 2C1562A9176B9F6200B4AE50 /* WebViewJavascriptBridge.m */, + ); + name = WebViewJavascriptBridge; + path = ../../WebViewJavascriptBridge; + sourceTree = ""; + }; 2CA045B617117439006DEE8B /* ExampleApp-iOS */ = { isa = PBXGroup; children = ( 2CA0465B1711AC8D006DEE8B /* ExampleApp.html */, 2CA045BC17117439006DEE8B /* ExampleAppDelegate.h */, 2CA045BD17117439006DEE8B /* ExampleAppDelegate.m */, - 2CAB8684172766B000BD9ED1 /* WebViewJavascriptBridge_iOS */, + 2C1562A7176B9F5400B4AE50 /* WebViewJavascriptBridge */, 2CA046211711A94E006DEE8B /* Supporting Files */, ); path = "ExampleApp-iOS"; @@ -77,27 +85,6 @@ name = "Supporting Files"; sourceTree = ""; }; - 2CAB8684172766B000BD9ED1 /* WebViewJavascriptBridge_iOS */ = { - isa = PBXGroup; - children = ( - 2CAB8685172766B000BD9ED1 /* WebViewJavascriptAbstract */, - 2CAB8689172766B000BD9ED1 /* WebViewJavascriptBridge_iOS.h */, - 2CAB868A172766B000BD9ED1 /* WebViewJavascriptBridge_iOS.m */, - ); - name = WebViewJavascriptBridge_iOS; - path = ../../WebViewJavascriptBridge_iOS; - sourceTree = ""; - }; - 2CAB8685172766B000BD9ED1 /* WebViewJavascriptAbstract */ = { - isa = PBXGroup; - children = ( - 2CAB8686172766B000BD9ED1 /* WebViewJavascriptBridge.js.txt */, - 2CAB8687172766B000BD9ED1 /* WebViewJavascriptBridgeAbstract.h */, - 2CAB8688172766B000BD9ED1 /* WebViewJavascriptBridgeAbstract.m */, - ); - path = WebViewJavascriptAbstract; - sourceTree = ""; - }; 2CEB3EB01602563600548120 = { isa = PBXGroup; children = ( @@ -177,9 +164,9 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 2C1562B5176B9F8400B4AE50 /* WebViewJavascriptBridge.js.txt in Resources */, 2CA045BF17117439006DEE8B /* InfoPlist.strings in Resources */, 2CA0465C1711AC8E006DEE8B /* ExampleApp.html in Resources */, - 2CAB868B172766B000BD9ED1 /* WebViewJavascriptBridge.js.txt in Resources */, 2CAB869B1727684300BD9ED1 /* Default-568h@2x.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -191,10 +178,9 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 2C1562C0176BA63500B4AE50 /* WebViewJavascriptBridge.m in Sources */, 2CA045C217117439006DEE8B /* ExampleAppDelegate.m in Sources */, 2CA045C317117439006DEE8B /* main.m in Sources */, - 2CAB868C172766B000BD9ED1 /* WebViewJavascriptBridgeAbstract.m in Sources */, - 2CAB868D172766B000BD9ED1 /* WebViewJavascriptBridge_iOS.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Example Apps/ExampleApp-iOS/ExampleAppDelegate.h b/Example Apps/ExampleApp-iOS/ExampleAppDelegate.h index b85422c5..5fc2d78b 100644 --- a/Example Apps/ExampleApp-iOS/ExampleAppDelegate.h +++ b/Example Apps/ExampleApp-iOS/ExampleAppDelegate.h @@ -1,5 +1,5 @@ #import -#import "WebViewJavascriptBridge_iOS.h" +#import "WebViewJavascriptBridge.h" @interface ExampleAppDelegate : UIResponder diff --git a/README.md b/README.md index e9bf51d4..3a8cec56 100644 --- a/README.md +++ b/README.md @@ -24,16 +24,13 @@ Start with the Example Apps/ folder. Open either the iOS or OSX project and hit To use a WebViewJavascriptBridge in your own project: -1) Drag the `WebViewJavascriptBridge_iOS` or `WebViewJavascriptBridge_OSX` folder into your project. +1) Drag the `WebViewJavascriptBridge` folder into your project. - In the dialog that appears, uncheck "Copy items into destination group's folder" and select "Create groups for any folders" 2) Import the header file: - // for iOS: - #import "WebViewJavascriptBridge_iOS.h" - // for OSX: - #import "WebViewJavascriptBridge_OSX.h" + #import "WebViewJavascriptBridge.h" 3) Instantiate WebViewJavascriptBridge with a UIWebView (iOS) or WebView (OSX): diff --git a/WebViewJavascriptBridge.podspec b/WebViewJavascriptBridge.podspec index 647d8328..2471c7fa 100644 --- a/WebViewJavascriptBridge.podspec +++ b/WebViewJavascriptBridge.podspec @@ -9,8 +9,8 @@ Pod::Spec.new do |s| s.source = { :git => 'https://github.com/marcuswestin/WebViewJavascriptBridge.git' } s.ios.platform = :ios, '5.0' s.osx.platform = :osx - s.ios.source_files = 'WebViewJavascriptBridge_iOS/*.{h,m}', 'WebViewJavascriptBridgeAbstract/*.{h,m}' - s.osx.source_files = 'WebViewJavascriptBridge_OSX/*.{h,m}', 'WebViewJavascriptBridgeAbstract/*.{h,m}' + s.ios.source_files = 'WebViewJavascriptBridge/*.{h,m}' + s.osx.source_files = 'WebViewJavascriptBridge/*.{h,m}' s.resource = 'WebViewJavascriptBridgeAbstract/WebViewJavascriptBridge.js.txt' s.ios.framework = 'UIKit' s.osx.framework = 'WebKit' diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.h b/WebViewJavascriptBridge/WebViewJavascriptBridge.h new file mode 100644 index 00000000..141cd848 --- /dev/null +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.h @@ -0,0 +1,51 @@ +// +// WebViewJavascriptBridge.h +// ExampleApp-iOS +// +// Created by Marcus Westin on 6/14/13. +// Copyright (c) 2013 Marcus Westin. All rights reserved. +// + +#import + +#define kMessageSeparator @"__WVJB_MESSAGE_SEPERATOR__" +#define kCustomProtocolScheme @"wvjbscheme" +#define kQueueHasMessage @"__WVJB_QUEUE_MESSAGE__" + +#if TARGET_OS_IPHONE && defined(__IPHONE_5_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_5_0) + #define WVJB_WEAK_FALLBACK weak +#elif TARGET_OS_MAC && defined(__MAC_10_7) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_7) + #define WVJB_WEAK_FALLBACK weak +#else + #define WVJB_WEAK_FALLBACK unsafe_unretained +#endif + +#if defined __MAC_OS_X_VERSION_MAX_ALLOWED + #import + #define WVJB_PLATFORM_OSX + #define WVJB_WEBVIEW_TYPE WebView + #define WVJB_WEBVIEW_DELEGATE_TYPE NSObject +#elif defined __IPHONE_OS_VERSION_MAX_ALLOWED + #define WVJB_PLATFORM_IOS + #define WVJB_WEBVIEW_TYPE UIWebView + #define WVJB_WEBVIEW_DELEGATE_TYPE NSObject +#endif + +typedef void (^WVJBResponseCallback)(id responseData); +typedef void (^WVJBHandler)(id data, WVJBResponseCallback responseCallback); + +@interface WebViewJavascriptBridge : WVJB_WEBVIEW_DELEGATE_TYPE + ++ (instancetype)bridgeForWebView:(WVJB_WEBVIEW_TYPE*)webView handler:(WVJBHandler)handler; ++ (instancetype)bridgeForWebView:(WVJB_WEBVIEW_TYPE*)webView webViewDelegate:(WVJB_WEBVIEW_DELEGATE_TYPE*)webViewDelegate handler:(WVJBHandler)handler; ++ (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 diff --git a/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridge.js.txt b/WebViewJavascriptBridge/WebViewJavascriptBridge.js.txt similarity index 100% rename from WebViewJavascriptBridgeAbstract/WebViewJavascriptBridge.js.txt rename to WebViewJavascriptBridge/WebViewJavascriptBridge.js.txt diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m new file mode 100644 index 00000000..6d67b5d2 --- /dev/null +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -0,0 +1,378 @@ +// +// WebViewJavascriptBridge.m +// ExampleApp-iOS +// +// Created by Marcus Westin on 6/14/13. +// Copyright (c) 2013 Marcus Westin. All rights reserved. +// + +#import "WebViewJavascriptBridge.h" + +@implementation WebViewJavascriptBridge { + __weak WVJB_WEBVIEW_TYPE* _webView; + __weak id _webViewDelegate; + NSMutableArray* _startupMessageQueue; + NSMutableDictionary* _responseCallbacks; + NSMutableDictionary* _messageHandlers; + long _uniqueId; + WVJBHandler _messageHandler; + +#if defined WVJB_PLATFORM_IOS + NSUInteger _numRequestsLoading; +#endif + +} + +/* API + *****/ + +static bool logging = false; ++ (void)enableLogging { logging = true; } + ++ (instancetype)bridgeForWebView:(WVJB_WEBVIEW_TYPE*)webView handler:(WVJBHandler)handler { + return [self bridgeForWebView:webView webViewDelegate:nil handler:handler]; +} + ++ (instancetype)bridgeForWebView:(WVJB_WEBVIEW_TYPE*)webView webViewDelegate:(WVJB_WEBVIEW_DELEGATE_TYPE*)webViewDelegate handler:(WVJBHandler)messageHandler { + WebViewJavascriptBridge* bridge = [[WebViewJavascriptBridge alloc] init]; + [bridge _platformSpecificSetup:webView webViewDelegate:webViewDelegate handler:messageHandler]; + [bridge reset]; + return bridge; +} + +- (void)send:(NSDictionary *)data { + [self send:data responseCallback:nil]; +} + +- (void)send:(NSDictionary *)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; +} + +/* Platform agnostic internals + *****************************/ + +- (void)dealloc { + [self _platformSpecificDealloc]; + + _webView = nil; + _webViewDelegate = nil; + _startupMessageQueue = nil; + _responseCallbacks = nil; + _messageHandlers = nil; + _messageHandler = nil; +} + +- (void)_sendData:(NSDictionary *)data responseCallback:(WVJBResponseCallback)responseCallback handlerName:(NSString*)handlerName { + NSMutableDictionary* message = [NSMutableDictionary dictionaryWithObject:data forKey:@"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:(NSDictionary *)message { + if (_startupMessageQueue) { + [_startupMessageQueue addObject:message]; + } else { + [self _dispatchMessage:message]; + } +} + +- (void)_dispatchMessage:(NSDictionary *)message { + NSString *messageJSON = [self _serializeMessage:message]; + [self _log:@"sending" 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"]; + + NSString* javascriptCommand = [NSString stringWithFormat:@"WebViewJavascriptBridge._handleMessageFromObjC('%@');", messageJSON]; + if ([[NSThread currentThread] isMainThread]) { + [_webView stringByEvaluatingJavaScriptFromString:javascriptCommand]; + } else { + __strong WVJB_WEBVIEW_TYPE* strongWebView = _webView; + dispatch_sync(dispatch_get_main_queue(), ^{ + [strongWebView stringByEvaluatingJavaScriptFromString:javascriptCommand]; + }); + } +} + +- (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]; + + 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) { + NSDictionary* msg = @{ @"responseId":callbackId, @"responseData":responseData }; + [self _queueMessage:msg]; + }; + } else { + responseCallback = ^(id ignoreResponseData) { + // Do nothing + }; + } + + WVJBHandler handler; + if (message[@"handlerName"]) { + handler = _messageHandlers[message[@"handlerName"]]; + if (!handler) { return NSLog(@"WVJB Warning: No handler for %@", message[@"handlerName"]); } + } else { + handler = _messageHandler; + } + + @try { + NSDictionary* data = message[@"data"]; + if (!data || ((id)data) == [NSNull null]) { data = [NSDictionary dictionary]; } + handler(data, responseCallback); + } + @catch (NSException *exception) { + NSLog(@"WebViewJavascriptBridge: WARNING: objc handler threw. %@ %@", message, exception); + } + } + } +} + +- (NSString *)_serializeMessage:(NSDictionary *)message { +#if defined _JSONKIT_H_ + return [message JSONString]; +#else + 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 +} + +- (void)_log:(NSString *)action json:(NSString *)json { + if (!logging) { return; } + if (json.length > 500) { + NSLog(@"WVJB %@: %@", action, [[json substringToIndex:500] stringByAppendingString:@" [...]"]); + } else { + NSLog(@"WVJB %@: %@", action, json); + } +} + + + +/* Platform specific internals: OSX + **********************************/ +#if defined WVJB_PLATFORM_OSX + +- (void) _platformSpecificSetup:(WVJB_WEBVIEW_TYPE*)webView webViewDelegate:(WVJB_WEBVIEW_DELEGATE_TYPE*)webViewDelegate handler:(WVJBHandler)messageHandler { + _messageHandler = messageHandler; + _webView = webView; + _webViewDelegate = webViewDelegate; + _messageHandlers = [NSMutableDictionary dictionary]; + + _webView.frameLoadDelegate = self; + _webView.resourceLoadDelegate = self; + _webView.policyDelegate = self; +} + +- (void) _platformSpecificDealloc { + _webView.frameLoadDelegate = nil; + _webView.resourceLoadDelegate = nil; + _webView.policyDelegate = nil; +} + +- (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"]; + NSString *js = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; + [webView stringByEvaluatingJavaScriptFromString:js]; + } + + if (_startupMessageQueue) { + for (id queuedMessage in _startupMessageQueue) { + [self _dispatchMessage:queuedMessage]; + } + _startupMessageQueue = nil; + } + + if (_webViewDelegate && [_webViewDelegate respondsToSelector:@selector(webView:didFinishLoadForFrame:)]) { + [_webViewDelegate webView:webView didFinishLoadForFrame:frame]; + } +} + +- (void)webView:(WebView *)webView didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame { + if (webView != _webView) { return; } + + if (_webViewDelegate && [_webViewDelegate respondsToSelector:@selector(webView:didFailLoadWithError:forFrame:)]) { + [_webViewDelegate webView:webView didFailLoadWithError:error forFrame:frame]; + } +} + +- (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id)listener +{ + if (webView != _webView) { [listener use]; } + + NSURL *url = [request URL]; + if ([[url scheme] isEqualToString:kCustomProtocolScheme]) { + if ([[url host] isEqualToString:kQueueHasMessage]) { + [self _flushMessageQueue]; + } else { + NSLog(@"WebViewJavascriptBridge: WARNING: Received unknown WebViewJavascriptBridge command %@://%@", kCustomProtocolScheme, [url path]); + } + [listener ignore]; + } else if (_webViewDelegate && [_webViewDelegate respondsToSelector:@selector(webView:decidePolicyForNavigationAction:request:frame:decisionListener:)]) { + [_webViewDelegate webView:webView decidePolicyForNavigationAction:actionInformation request:request frame:frame decisionListener:listener]; + } else { + [listener use]; + } +} + +- (void)webView:(WebView *)webView didCommitLoadForFrame:(WebFrame *)frame { + if (webView != _webView) { return; } + + if (_webViewDelegate && [_webViewDelegate respondsToSelector:@selector(webView:didCommitLoadForFrame:)]) { + [_webViewDelegate webView:webView didCommitLoadForFrame:frame]; + } +} + +- (NSURLRequest *)webView:(WebView *)webView resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource { + if (webView != _webView) { return request; } + + if (_webViewDelegate && [_webViewDelegate respondsToSelector:@selector(webView:resource:willSendRequest:redirectResponse:fromDataSource:)]) { + return [_webViewDelegate webView:webView resource:identifier willSendRequest:request redirectResponse:redirectResponse fromDataSource:dataSource]; + } + + return request; +} + + + +/* Platform specific internals: OSX + **********************************/ +#elif defined WVJB_PLATFORM_IOS + +- (void) _platformSpecificSetup:(WVJB_WEBVIEW_TYPE*)webView webViewDelegate:(id)webViewDelegate handler:(WVJBHandler)messageHandler { + _messageHandler = messageHandler; + _webView = webView; + _webViewDelegate = webViewDelegate; + _messageHandlers = [NSMutableDictionary dictionary]; + _webView.delegate = self; +} + +- (void) _platformSpecificDealloc { + _webView.delegate = nil; +} + +- (void)webViewDidFinishLoad:(UIWebView *)webView { + if (webView != _webView) { return; } + + _numRequestsLoading--; + + if (_numRequestsLoading == 0 && ![[webView stringByEvaluatingJavaScriptFromString:@"typeof WebViewJavascriptBridge == 'object'"] isEqualToString:@"true"]) { + NSString *filePath = [[NSBundle mainBundle] pathForResource:@"WebViewJavascriptBridge.js" ofType:@"txt"]; + NSString *js = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; + [webView stringByEvaluatingJavaScriptFromString:js]; + } + + if (_startupMessageQueue) { + for (id queuedMessage in _startupMessageQueue) { + [self _dispatchMessage:queuedMessage]; + } + _startupMessageQueue = nil; + } + + __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; + if (strongDelegate && [strongDelegate respondsToSelector:@selector(webViewDidFinishLoad:)]) { + [strongDelegate webViewDidFinishLoad:webView]; + } +} + +- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { + if (webView != _webView) { return; } + + _numRequestsLoading--; + + __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; + if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didFailLoadWithError:)]) { + [strongDelegate webView:webView didFailLoadWithError: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; + if ([[url scheme] isEqualToString:kCustomProtocolScheme]) { + if ([[url host] isEqualToString:kQueueHasMessage]) { + [self _flushMessageQueue]; + } else { + NSLog(@"WebViewJavascriptBridge: WARNING: Received unknown WebViewJavascriptBridge command %@://%@", kCustomProtocolScheme, [url path]); + } + return NO; + } else if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:shouldStartLoadWithRequest:navigationType:)]) { + return [strongDelegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType]; + } else { + return YES; + } +} + +- (void)webViewDidStartLoad:(UIWebView *)webView { + if (webView != _webView) { return; } + + _numRequestsLoading++; + + __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; + if (strongDelegate && [strongDelegate respondsToSelector:@selector(webViewDidStartLoad:)]) { + [strongDelegate webViewDidStartLoad:webView]; + } +} + +#endif + +@end diff --git a/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.h b/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.h deleted file mode 100644 index 30301c57..00000000 --- a/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.h +++ /dev/null @@ -1,48 +0,0 @@ -#define kMessageSeparator @"__WVJB_MESSAGE_SEPERATOR__" -#define kCustomProtocolScheme @"wvjbscheme" -#define kQueueHasMessage @"__WVJB_QUEUE_MESSAGE__" - -#if TARGET_OS_IPHONE && defined(__IPHONE_5_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_5_0) - #define WEAK_FALLBACK weak -#elif TARGET_OS_MAC && defined(__MAC_10_7) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_7) - #define WEAK_FALLBACK weak - #import -#else - #define WEAK_FALLBACK unsafe_unretained -#endif - -typedef void (^WVJBResponseCallback)(id responseData); -typedef void (^WVJBHandler)(id data, WVJBResponseCallback responseCallback); - -@interface WebViewJavascriptBridgeAbstract : NSObject - -@property (nonatomic, WEAK_FALLBACK) id webView; -@property (nonatomic, WEAK_FALLBACK) id webViewDelegate; -@property (nonatomic, strong) NSMutableArray *startupMessageQueue; -@property (nonatomic, strong) NSMutableDictionary *responseCallbacks; -@property (nonatomic, strong) NSMutableDictionary *messageHandlers; -@property (atomic, assign) long uniqueId; -@property (nonatomic, copy) WVJBHandler messageHandler; - -+ (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 - -@interface WebViewJavascriptBridgeAbstract (Protected) - -- (void)_flushMessageQueue; -- (void)_sendData:(NSDictionary*)data responseCallback:(WVJBResponseCallback)responseCallback handlerName:(NSString*)handlerName; -- (void)_queueMessage:(NSDictionary*)message; -- (void)_dispatchMessage:(NSDictionary*)message; -- (NSString*)_serializeMessage:(NSDictionary*)message; -- (NSDictionary*)_deserializeMessageJSON:(NSString*)messageJSON; -- (void)_log:(NSString*)type json:(NSString*)output; - -@end diff --git a/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.m b/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.m deleted file mode 100755 index 98218c31..00000000 --- a/WebViewJavascriptBridgeAbstract/WebViewJavascriptBridgeAbstract.m +++ /dev/null @@ -1,171 +0,0 @@ -#import "WebViewJavascriptBridgeAbstract.h" - -#ifdef USE_JSONKIT - #import "JSONKit.h" -#endif - -@interface WebViewJavascriptBridgeAbstract () - -@end - -@implementation WebViewJavascriptBridgeAbstract - -static bool logging = false; -+ (void)enableLogging { logging = true; } - -- (void)send:(NSDictionary *)data { - [self send:data responseCallback:nil]; -} - -- (void)send:(NSDictionary *)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 { - self.messageHandlers[handlerName] = [handler copy]; -} - -- (void)reset { - self.startupMessageQueue = [NSMutableArray array]; - self.responseCallbacks = [NSMutableDictionary dictionary]; - self.uniqueId = 0; -} - -@end - -@implementation WebViewJavascriptBridgeAbstract (Protected) - -- (void)_sendData:(NSDictionary *)data responseCallback:(WVJBResponseCallback)responseCallback handlerName:(NSString*)handlerName { - NSMutableDictionary* message = [NSMutableDictionary dictionaryWithObject:data forKey:@"data"]; - - if (responseCallback) { - NSString* callbackId = [NSString stringWithFormat:@"objc_cb_%ld", ++self.uniqueId]; - self.responseCallbacks[callbackId] = [responseCallback copy]; - message[@"callbackId"] = callbackId; - } - - if (handlerName) { - message[@"handlerName"] = handlerName; - } - [self _queueMessage:message]; -} - -- (void)_queueMessage:(NSDictionary *)message { - if (self.startupMessageQueue) { - [self.startupMessageQueue addObject:message]; - } else { - [self _dispatchMessage:message]; - } -} - -- (void)_dispatchMessage:(NSDictionary *)message { - NSString *messageJSON = [self _serializeMessage:message]; - [self _log:@"sending" 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"]; - __strong typeof(self.webView) strongWebView = self.webView; - if ([[NSThread currentThread] isMainThread]) { - [strongWebView performSelector:@selector(stringByEvaluatingJavaScriptFromString:) - withObject:[NSString stringWithFormat: - @"WebViewJavascriptBridge._handleMessageFromObjC('%@');", messageJSON]]; - } else { - dispatch_sync(dispatch_get_main_queue(), ^{ - [strongWebView performSelector:@selector(stringByEvaluatingJavaScriptFromString:) - withObject:[NSString stringWithFormat: - @"WebViewJavascriptBridge._handleMessageFromObjC('%@');", messageJSON]]; - }); - } -} - -- (void)_flushMessageQueue { - __strong typeof(self.webView) strongWebView = self.webView; - NSString *messageQueueString = [strongWebView performSelector: - @selector(stringByEvaluatingJavaScriptFromString:) withObject:@"WebViewJavascriptBridge._fetchQueue();"]; - - NSArray* messages = [messageQueueString componentsSeparatedByString:kMessageSeparator]; - for (NSString *messageJSON in messages) { - [self _log:@"receivd" json:messageJSON]; - - NSDictionary* message = [self _deserializeMessageJSON:messageJSON]; - - NSString* responseId = message[@"responseId"]; - if (responseId) { - WVJBResponseCallback responseCallback = self.responseCallbacks[responseId]; - responseCallback(message[@"responseData"]); - [self.responseCallbacks removeObjectForKey:responseId]; - } else { - WVJBResponseCallback responseCallback = NULL; - NSString* callbackId = message[@"callbackId"]; - if (callbackId) { - responseCallback = ^(id responseData) { - NSDictionary* msg = @{ @"responseId":callbackId, @"responseData":responseData }; - [self _queueMessage:msg]; - }; - } else { - responseCallback = ^(id ignoreResponseData) { - // Do nothing - }; - } - - WVJBHandler handler; - if (message[@"handlerName"]) { - handler = self.messageHandlers[message[@"handlerName"]]; - if (!handler) { return NSLog(@"WVJB Warning: No handler for %@", message[@"handlerName"]); } - } else { - handler = self.messageHandler; - } - - @try { - NSDictionary* data = message[@"data"]; - if (!data || ((id)data) == [NSNull null]) { data = [NSDictionary dictionary]; } - handler(data, responseCallback); - } - @catch (NSException *exception) { - NSLog(@"WebViewJavascriptBridge: WARNING: objc handler threw. %@ %@", message, exception); - } - } - } -} - -- (NSString *)_serializeMessage:(NSDictionary *)message { -#ifdef USE_JSONKIT - return [message JSONString]; -#else - return [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:message options:0 error:nil] encoding:NSUTF8StringEncoding]; -#endif -} - -- (NSDictionary *)_deserializeMessageJSON:(NSString *)messageJSON { -#ifdef USE_JSONKIT - return [messageJSON objectFromJSONString]; -#else - return [NSJSONSerialization JSONObjectWithData:[messageJSON dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil]; -#endif -} - -- (void)_log:(NSString *)action json:(NSString *)json { - if (!logging) { return; } - if (json.length > 500) { - NSLog(@"WVJB %@: %@", action, [[json substringToIndex:500] stringByAppendingString:@" [...]"]); - } else { - NSLog(@"WVJB %@: %@", action, json); - } -} - -@end diff --git a/WebViewJavascriptBridge_OSX/WebViewJavascriptAbstract b/WebViewJavascriptBridge_OSX/WebViewJavascriptAbstract deleted file mode 120000 index 2cb3269a..00000000 --- a/WebViewJavascriptBridge_OSX/WebViewJavascriptAbstract +++ /dev/null @@ -1 +0,0 @@ -../WebViewJavascriptBridgeAbstract \ No newline at end of file diff --git a/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.h b/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.h deleted file mode 100644 index 41e5305e..00000000 --- a/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.h +++ /dev/null @@ -1,11 +0,0 @@ -#import "WebViewJavascriptBridgeAbstract.h" - -@interface WebViewJavascriptBridge : WebViewJavascriptBridgeAbstract - -@property (nonatomic, WEAK_FALLBACK) WebView *webView; -@property (nonatomic, WEAK_FALLBACK) id webViewDelegate; - -+ (instancetype)bridgeForWebView:(WebView*)webView handler:(WVJBHandler)handler; -+ (instancetype)bridgeForWebView:(WebView*)webView webViewDelegate:(id)webViewDelegate handler:(WVJBHandler)handler; - -@end diff --git a/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.m b/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.m deleted file mode 100644 index 5a29a0a3..00000000 --- a/WebViewJavascriptBridge_OSX/WebViewJavascriptBridge_OSX.m +++ /dev/null @@ -1,102 +0,0 @@ -#import "WebViewJavascriptBridge_OSX.h" - -@implementation WebViewJavascriptBridge - -+ (instancetype)bridgeForWebView:(WebView *)webView handler:(WVJBHandler)handler { - return [self bridgeForWebView:webView webViewDelegate:nil handler:handler]; -} - -+ (instancetype)bridgeForWebView:(WebView *)webView webViewDelegate:(id)webViewDelegate handler:(WVJBHandler)messageHandler { - WebViewJavascriptBridge* bridge = [[[self class] alloc] init]; - bridge.messageHandler = messageHandler; - bridge.webView = webView; - bridge.webViewDelegate = webViewDelegate; - bridge.messageHandlers = [NSMutableDictionary dictionary]; - [bridge reset]; - - bridge.webView.frameLoadDelegate = bridge; - bridge.webView.resourceLoadDelegate = bridge; - bridge.webView.policyDelegate = bridge; - - return bridge; -} - -- (void)dealloc; -{ - self.webView.frameLoadDelegate = nil; - self.webView.resourceLoadDelegate = nil; - self.webView.policyDelegate = nil; -} - -- (void)webView:(WebView *)webView didFinishLoadForFrame:(WebFrame *)frame -{ - if (webView != self.webView) { return; } - - if (![[webView stringByEvaluatingJavaScriptFromString:@"typeof WebViewJavascriptBridge == 'object'"] isEqualToString:@"true"]) { - NSString *filePath = [[NSBundle mainBundle] pathForResource:@"WebViewJavascriptBridge.js" ofType:@"txt"]; - NSString *js = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; - [webView stringByEvaluatingJavaScriptFromString:js]; - } - - if (self.startupMessageQueue) { - for (id queuedMessage in self.startupMessageQueue) { - [self _dispatchMessage:queuedMessage]; - } - self.startupMessageQueue = nil; - } - - __strong typeof(self.webViewDelegate) strongDelegate = self.webViewDelegate; - if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didFinishLoadForFrame:)]) { - [strongDelegate webView:webView didFinishLoadForFrame:frame]; - } -} - -- (void)webView:(WebView *)webView didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame { - if (webView != self.webView) { return; } - - __strong typeof(self.webViewDelegate) strongDelegate = self.webViewDelegate; - if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didFailLoadWithError:forFrame:)]) { - [strongDelegate webView:strongDelegate didFailLoadWithError:error forFrame:frame]; - } -} - -- (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id)listener -{ - if (webView != self.webView) { [listener use]; } - NSURL *url = [request URL]; - __strong typeof(self.webViewDelegate) strongDelegate = self.webViewDelegate; - if ([[url scheme] isEqualToString:kCustomProtocolScheme]) { - if ([[url host] isEqualToString:kQueueHasMessage]) { - [self _flushMessageQueue]; - } else { - NSLog(@"WebViewJavascriptBridge: WARNING: Received unknown WebViewJavascriptBridge command %@://%@", kCustomProtocolScheme, [url path]); - } - [listener ignore]; - } else if ([webView resourceLoadDelegate] - && [strongDelegate respondsToSelector:@selector(webView:decidePolicyForNavigationAction:request:frame:decisionListener:)]) { - [strongDelegate webView:webView decidePolicyForNavigationAction:actionInformation request:request frame:frame decisionListener:listener]; - } else { - [listener use]; - } -} - -- (void)webView:(WebView *)webView didCommitLoadForFrame:(WebFrame *)frame { - if (webView != self.webView) { return; } - __strong typeof(self.webViewDelegate) strongDelegate = self.webViewDelegate; - if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didCommitLoadForFrame:)]) { - [strongDelegate webView:webView didCommitLoadForFrame:frame]; - } -} - -- (NSURLRequest *)webView:(WebView *)webView resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource { - if (webView != self.webView) { return request; } - - __strong typeof(self.webViewDelegate) strongDelegate = self.webViewDelegate; - if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:resource:willSendRequest:redirectResponse:fromDataSource:)]) { - return [strongDelegate webView:webView resource:identifier willSendRequest:request redirectResponse:redirectResponse fromDataSource:dataSource]; - } - - return request; -} - -@end diff --git a/WebViewJavascriptBridge_iOS/WebViewJavascriptAbstract b/WebViewJavascriptBridge_iOS/WebViewJavascriptAbstract deleted file mode 120000 index 2cb3269a..00000000 --- a/WebViewJavascriptBridge_iOS/WebViewJavascriptAbstract +++ /dev/null @@ -1 +0,0 @@ -../WebViewJavascriptBridgeAbstract \ No newline at end of file diff --git a/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.h b/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.h deleted file mode 100644 index b4dc7406..00000000 --- a/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.h +++ /dev/null @@ -1,12 +0,0 @@ -#import -#import "WebViewJavascriptBridgeAbstract.h" - -@interface WebViewJavascriptBridge : WebViewJavascriptBridgeAbstract - -@property (nonatomic, WEAK_FALLBACK) UIWebView *webView; -@property (nonatomic, WEAK_FALLBACK) id webViewDelegate; - -+ (instancetype)bridgeForWebView:(UIWebView*)webView handler:(WVJBHandler)handler; -+ (instancetype)bridgeForWebView:(UIWebView*)webView webViewDelegate:(id )webViewDelegate handler:(WVJBHandler)handler; - -@end diff --git a/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m b/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m deleted file mode 100644 index 59311ffe..00000000 --- a/WebViewJavascriptBridge_iOS/WebViewJavascriptBridge_iOS.m +++ /dev/null @@ -1,99 +0,0 @@ -#import "WebViewJavascriptBridge_iOS.h" - -@interface WebViewJavascriptBridge () - -@property (nonatomic, assign) NSUInteger numRequestsLoading; - -@end - -@implementation WebViewJavascriptBridge - -#pragma mark UIWebViewDelegate - -+ (instancetype)bridgeForWebView:(UIWebView *)webView handler:(WVJBHandler)handler { - return [self bridgeForWebView:webView webViewDelegate:nil handler:handler]; -} - -+ (instancetype)bridgeForWebView:(UIWebView *)webView webViewDelegate:(id)webViewDelegate handler:(WVJBHandler)messageHandler { - WebViewJavascriptBridge* bridge = [[[self class] alloc] init]; - bridge.messageHandler = messageHandler; - bridge.webView = webView; - bridge.webViewDelegate = webViewDelegate; - bridge.messageHandlers = [NSMutableDictionary dictionary]; - [bridge reset]; - - [webView setDelegate:bridge]; - - return bridge; -} - -- (void)dealloc; -{ - self.webView.delegate = nil; -} - -- (void)webViewDidFinishLoad:(UIWebView *)webView { - if (webView != self.webView) { return; } - - self.numRequestsLoading--; - - if (self.numRequestsLoading == 0 && ![[webView stringByEvaluatingJavaScriptFromString:@"typeof WebViewJavascriptBridge == 'object'"] isEqualToString:@"true"]) { - NSString *filePath = [[NSBundle mainBundle] pathForResource:@"WebViewJavascriptBridge.js" ofType:@"txt"]; - NSString *js = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; - [webView stringByEvaluatingJavaScriptFromString:js]; - } - - if (self.startupMessageQueue) { - for (id queuedMessage in self.startupMessageQueue) { - [self _dispatchMessage:queuedMessage]; - } - self.startupMessageQueue = nil; - } - - __strong typeof(self.webViewDelegate) strongDelegate = self.webViewDelegate; - if (strongDelegate && [strongDelegate respondsToSelector:@selector(webViewDidFinishLoad:)]) { - [strongDelegate webViewDidFinishLoad:webView]; - } -} - -- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { - if (webView != self.webView) { return; } - - self.numRequestsLoading--; - - __strong typeof(self.webViewDelegate) strongDelegate = self.webViewDelegate; - if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didFailLoadWithError:)]) { - [strongDelegate webView:webView didFailLoadWithError:error]; - } -} - -- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { - if (webView != self.webView) { return YES; } - NSURL *url = [request URL]; - __strong typeof(self.webViewDelegate) strongDelegate = self.webViewDelegate; - if ([[url scheme] isEqualToString:kCustomProtocolScheme]) { - if ([[url host] isEqualToString:kQueueHasMessage]) { - [self _flushMessageQueue]; - } else { - NSLog(@"WebViewJavascriptBridge: WARNING: Received unknown WebViewJavascriptBridge command %@://%@", kCustomProtocolScheme, [url path]); - } - return NO; - } else if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:shouldStartLoadWithRequest:navigationType:)]) { - return [strongDelegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType]; - } else { - return YES; - } -} - -- (void)webViewDidStartLoad:(UIWebView *)webView { - if (webView != self.webView) { return; } - - self.numRequestsLoading++; - - __strong typeof(self.webViewDelegate) strongDelegate = self.webViewDelegate; - if (strongDelegate && [strongDelegate respondsToSelector:@selector(webViewDidStartLoad:)]) { - [strongDelegate webViewDidStartLoad:webView]; - } -} - -@end From 254ea00267f8c1e03727885f4e1e0fd5f5c78be8 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Fri, 14 Jun 2013 13:17:58 -0700 Subject: [PATCH 107/353] If the webview is not our webview then we should not be making nagivation action decisions for it. --- WebViewJavascriptBridge/WebViewJavascriptBridge.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index 6d67b5d2..710331b4 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -256,7 +256,7 @@ - (void)webView:(WebView *)webView didFailLoadWithError:(NSError *)error forFram - (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id)listener { - if (webView != _webView) { [listener use]; } + if (webView != _webView) { return; } NSURL *url = [request URL]; if ([[url scheme] isEqualToString:kCustomProtocolScheme]) { From 090fc95e40a01ef392ef1d8e4ff346fce5579eed Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Fri, 14 Jun 2013 13:21:46 -0700 Subject: [PATCH 108/353] v4.0.0 --- Changelog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Changelog b/Changelog index 849cadb2..374927ba 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,7 @@ +v4.0.0 ++ Consolidate platform-specific code into a single WebViewJavascriptBridge.m/h using macros (57ee322a4c5310eadd28b28f4d8522cd54123301) ++ Bugfix: Don't make navigation decisions for webviews we don't control (254ea00267f8c1e03727885f4e1e0fd5f5c78be8) + v3.1.0 + Dont inject the WVJB bridge until all requests have finished loading (61b853) + Add podspec file (818d49cfc) From 2b4a68c4188ae4499469f6a6fb194377b3fa010d Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Wed, 19 Jun 2013 14:17:56 -0700 Subject: [PATCH 109/353] Fix #45: Use __has_feature for arc weak support --- WebViewJavascriptBridge/WebViewJavascriptBridge.h | 8 -------- WebViewJavascriptBridge/WebViewJavascriptBridge.m | 11 +++++++++-- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.h b/WebViewJavascriptBridge/WebViewJavascriptBridge.h index 141cd848..836d0c52 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.h +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.h @@ -12,14 +12,6 @@ #define kCustomProtocolScheme @"wvjbscheme" #define kQueueHasMessage @"__WVJB_QUEUE_MESSAGE__" -#if TARGET_OS_IPHONE && defined(__IPHONE_5_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_5_0) - #define WVJB_WEAK_FALLBACK weak -#elif TARGET_OS_MAC && defined(__MAC_10_7) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_7) - #define WVJB_WEAK_FALLBACK weak -#else - #define WVJB_WEAK_FALLBACK unsafe_unretained -#endif - #if defined __MAC_OS_X_VERSION_MAX_ALLOWED #import #define WVJB_PLATFORM_OSX diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index 710331b4..bbd2c760 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -8,9 +8,16 @@ #import "WebViewJavascriptBridge.h" +#if __has_feature(objc_arc_weak) + #define WVJB_WEAK __weak +#else + #define WVJB_WEAK __unsafe_unretained +#endif + + @implementation WebViewJavascriptBridge { - __weak WVJB_WEBVIEW_TYPE* _webView; - __weak id _webViewDelegate; + WVJB_WEAK WVJB_WEBVIEW_TYPE* _webView; + WVJB_WEAK id _webViewDelegate; NSMutableArray* _startupMessageQueue; NSMutableDictionary* _responseCallbacks; NSMutableDictionary* _messageHandlers; From c3503532f6ee364de5915e945f2d9e5d2671959f Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Wed, 19 Jun 2013 14:18:13 -0700 Subject: [PATCH 110/353] Add @wangjinhua to list of contributors --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3a8cec56..6edd5797 100644 --- a/README.md +++ b/README.md @@ -199,3 +199,4 @@ Contributors - [@xzeror](https://github.com/xzeror) - [@kelp404](https://github.com/kelp404) - [@peyton](https://github.com/peyton) Peyton Randolph +- [@wangjinhua](https://github.com/wangjinhua) From 832e1ae2adc5483f6a92612436dbf1201c6e0a36 Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Wed, 19 Jun 2013 14:18:32 -0700 Subject: [PATCH 111/353] Ensure that the response callback gets called, even if no handler has been defined --- WebViewJavascriptBridge/WebViewJavascriptBridge.m | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index bbd2c760..58ef2e70 100644 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -166,7 +166,10 @@ - (void)_flushMessageQueue { WVJBHandler handler; if (message[@"handlerName"]) { handler = _messageHandlers[message[@"handlerName"]]; - if (!handler) { return NSLog(@"WVJB Warning: No handler for %@", message[@"handlerName"]); } + if (!handler) { + NSLog(@"WVJB Warning: No handler for %@", message[@"handlerName"]); + return responseCallback(@{}); + } } else { handler = _messageHandler; } From d45feacdce95d8d00bfec0fb5c2252b8ade440ba Mon Sep 17 00:00:00 2001 From: Marcus Westin Date: Wed, 19 Jun 2013 14:19:38 -0700 Subject: [PATCH 112/353] v4.0.1 --- Changelog | 3 +++ WebViewJavascriptBridge.podspec | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Changelog b/Changelog index 374927ba..632f803f 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,6 @@ +v4.0.1 ++ Fix detection of arc_weak support + v4.0.0 + Consolidate platform-specific code into a single WebViewJavascriptBridge.m/h using macros (57ee322a4c5310eadd28b28f4d8522cd54123301) + Bugfix: Don't make navigation decisions for webviews we don't control (254ea00267f8c1e03727885f4e1e0fd5f5c78be8) diff --git a/WebViewJavascriptBridge.podspec b/WebViewJavascriptBridge.podspec index 2471c7fa..ff4ac0bd 100644 --- a/WebViewJavascriptBridge.podspec +++ b/WebViewJavascriptBridge.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'WebViewJavascriptBridge' - s.version = '3.1.0' + s.version = '4.0.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 3ba0b84cce4d9c910f3c3c75c32ff6b3c0c28fe1 Mon Sep 17 00:00:00 2001 From: jacob berkman Date: Mon, 29 Jul 2013 21:47:10 -0700 Subject: [PATCH 113/353] 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 114/353] 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 1afebc96ccf53b5d0371256bfca828b021f1a56f Mon Sep 17 00:00:00 2001 From: Antoine Lagadec Date: Thu, 5 Sep 2013 14:05:47 +0200 Subject: [PATCH 115/353] Readd MainMenu.xib and change target down to 10.7 --- .../ExampleApp-OSX.xcodeproj/project.pbxproj | 6 + Example Apps/ExampleApp-OSX/MainMenu.xib | 3614 +++++++++++++++++ 2 files changed, 3620 insertions(+) create mode 100644 Example Apps/ExampleApp-OSX/MainMenu.xib diff --git a/Example Apps/ExampleApp-OSX.xcodeproj/project.pbxproj b/Example Apps/ExampleApp-OSX.xcodeproj/project.pbxproj index 18313cd6..1a78a146 100644 --- a/Example Apps/ExampleApp-OSX.xcodeproj/project.pbxproj +++ b/Example Apps/ExampleApp-OSX.xcodeproj/project.pbxproj @@ -16,6 +16,7 @@ 2C136A5A17642704004C7401 /* ExampleApp.html in Resources */ = {isa = PBXBuildFile; fileRef = 2C136A5917642704004C7401 /* ExampleApp.html */; }; 2C1562C5176BA9FF00B4AE50 /* WebViewJavascriptBridge.js.txt in Resources */ = {isa = PBXBuildFile; fileRef = 2C1562C3176BA9FF00B4AE50 /* WebViewJavascriptBridge.js.txt */; }; 2C1562C6176BA9FF00B4AE50 /* WebViewJavascriptBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C1562C4176BA9FF00B4AE50 /* WebViewJavascriptBridge.m */; }; + 2CF17F5317D8AACF006E828B /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2CF17F5217D8AACF006E828B /* MainMenu.xib */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -36,6 +37,7 @@ 2C1562C2176BA9FF00B4AE50 /* WebViewJavascriptBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridge.h; sourceTree = ""; }; 2C1562C3176BA9FF00B4AE50 /* WebViewJavascriptBridge.js.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebViewJavascriptBridge.js.txt; sourceTree = ""; }; 2C1562C4176BA9FF00B4AE50 /* WebViewJavascriptBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge.m; sourceTree = ""; }; + 2CF17F5217D8AACF006E828B /* MainMenu.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainMenu.xib; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -94,6 +96,7 @@ 2C136A3617641106004C7401 /* AppDelegate.h */, 2C136A3717641106004C7401 /* AppDelegate.m */, 2C136A5917642704004C7401 /* ExampleApp.html */, + 2CF17F5217D8AACF006E828B /* MainMenu.xib */, 2C1562C1176BA9FF00B4AE50 /* WebViewJavascriptBridge */, 2C136A2B17641106004C7401 /* Supporting Files */, ); @@ -178,6 +181,7 @@ 2C136A2F17641106004C7401 /* InfoPlist.strings in Resources */, 2C136A3517641106004C7401 /* Credits.rtf in Resources */, 2C136A5A17642704004C7401 /* ExampleApp.html in Resources */, + 2CF17F5317D8AACF006E828B /* MainMenu.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -282,6 +286,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "ExampleApp-OSX/ExampleApp-OSX-Prefix.pch"; INFOPLIST_FILE = "ExampleApp-OSX/ExampleApp-OSX-Info.plist"; + MACOSX_DEPLOYMENT_TARGET = 10.7; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; @@ -294,6 +299,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "ExampleApp-OSX/ExampleApp-OSX-Prefix.pch"; INFOPLIST_FILE = "ExampleApp-OSX/ExampleApp-OSX-Info.plist"; + MACOSX_DEPLOYMENT_TARGET = 10.7; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; diff --git a/Example Apps/ExampleApp-OSX/MainMenu.xib b/Example Apps/ExampleApp-OSX/MainMenu.xib new file mode 100644 index 00000000..b7140d43 --- /dev/null +++ b/Example Apps/ExampleApp-OSX/MainMenu.xib @@ -0,0 +1,3614 @@ + + + + 1070 + 11E53 + 2844 + 1138.47 + 569.00 + + 2844 + 1810 + + + IBNSLayoutConstraint + NSButton + NSButtonCell + NSCustomObject + NSMenu + NSMenuItem + NSView + NSWindowTemplate + WebView + + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.WebKitIBPlugin + + + PluginDependencyRecalculationVersion + + + + + NSApplication + + + FirstResponder + + + NSApplication + + + AMainMenu + + + + ExampleApp-OSX + + 1048576 + 2147483647 + + NSImage + NSMenuCheckmark + + + NSImage + NSMenuMixedState + + submenuAction: + + ExampleApp-OSX + + + + About ExampleApp-OSX + + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Preferences… + , + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Services + + 1048576 + 2147483647 + + + submenuAction: + + Services + + _NSServicesMenu + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Hide ExampleApp-OSX + h + 1048576 + 2147483647 + + + + + + Hide Others + h + 1572864 + 2147483647 + + + + + + Show All + + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Quit ExampleApp-OSX + q + 1048576 + 2147483647 + + + + + _NSAppleMenu + + + + + File + + 1048576 + 2147483647 + + + submenuAction: + + File + + + + New + n + 1048576 + 2147483647 + + + + + + Open… + o + 1048576 + 2147483647 + + + + + + Open Recent + + 1048576 + 2147483647 + + + submenuAction: + + Open Recent + + + + Clear Menu + + 1048576 + 2147483647 + + + + + _NSRecentDocumentsMenu + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Close + w + 1048576 + 2147483647 + + + + + + Save… + s + 1048576 + 2147483647 + + + + + + Revert to Saved + + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Page Setup... + P + 1179648 + 2147483647 + + + + + + + Print… + p + 1048576 + 2147483647 + + + + + + + + + Edit + + 1048576 + 2147483647 + + + submenuAction: + + Edit + + + + Undo + z + 1048576 + 2147483647 + + + + + + Redo + Z + 1179648 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Cut + x + 1048576 + 2147483647 + + + + + + Copy + c + 1048576 + 2147483647 + + + + + + Paste + v + 1048576 + 2147483647 + + + + + + Paste and Match Style + V + 1572864 + 2147483647 + + + + + + Delete + + 1048576 + 2147483647 + + + + + + Select All + a + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Find + + 1048576 + 2147483647 + + + submenuAction: + + Find + + + + Find… + f + 1048576 + 2147483647 + + + 1 + + + + Find and Replace… + f + 1572864 + 2147483647 + + + 12 + + + + Find Next + g + 1048576 + 2147483647 + + + 2 + + + + Find Previous + G + 1179648 + 2147483647 + + + 3 + + + + Use Selection for Find + e + 1048576 + 2147483647 + + + 7 + + + + Jump to Selection + j + 1048576 + 2147483647 + + + + + + + + + Spelling and Grammar + + 1048576 + 2147483647 + + + submenuAction: + + Spelling and Grammar + + + + Show Spelling and Grammar + : + 1048576 + 2147483647 + + + + + + Check Document Now + ; + 1048576 + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + Check Spelling While Typing + + 1048576 + 2147483647 + + + + + + Check Grammar With Spelling + + 1048576 + 2147483647 + + + + + + Correct Spelling Automatically + + 2147483647 + + + + + + + + + Substitutions + + 1048576 + 2147483647 + + + submenuAction: + + Substitutions + + + + Show Substitutions + + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + Smart Copy/Paste + f + 1048576 + 2147483647 + + + 1 + + + + Smart Quotes + g + 1048576 + 2147483647 + + + 2 + + + + Smart Dashes + + 2147483647 + + + + + + Smart Links + G + 1179648 + 2147483647 + + + 3 + + + + Text Replacement + + 2147483647 + + + + + + + + + Transformations + + 2147483647 + + + submenuAction: + + Transformations + + + + Make Upper Case + + 2147483647 + + + + + + Make Lower Case + + 2147483647 + + + + + + Capitalize + + 2147483647 + + + + + + + + + Speech + + 1048576 + 2147483647 + + + submenuAction: + + Speech + + + + Start Speaking + + 1048576 + 2147483647 + + + + + + Stop Speaking + + 1048576 + 2147483647 + + + + + + + + + + + + Format + + 2147483647 + + + submenuAction: + + Format + + + + Font + + 2147483647 + + + submenuAction: + + Font + + + + Show Fonts + t + 1048576 + 2147483647 + + + + + + Bold + b + 1048576 + 2147483647 + + + 2 + + + + Italic + i + 1048576 + 2147483647 + + + 1 + + + + Underline + u + 1048576 + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + Bigger + + + 1048576 + 2147483647 + + + 3 + + + + Smaller + - + 1048576 + 2147483647 + + + 4 + + + + YES + YES + + + 2147483647 + + + + + + Kern + + 2147483647 + + + submenuAction: + + Kern + + + + Use Default + + 2147483647 + + + + + + Use None + + 2147483647 + + + + + + Tighten + + 2147483647 + + + + + + Loosen + + 2147483647 + + + + + + + + + Ligatures + + 2147483647 + + + submenuAction: + + Ligatures + + + + Use Default + + 2147483647 + + + + + + Use None + + 2147483647 + + + + + + Use All + + 2147483647 + + + + + + + + + Baseline + + 2147483647 + + + submenuAction: + + Baseline + + + + Use Default + + 2147483647 + + + + + + Superscript + + 2147483647 + + + + + + Subscript + + 2147483647 + + + + + + Raise + + 2147483647 + + + + + + Lower + + 2147483647 + + + + + + + + + YES + YES + + + 2147483647 + + + + + + Show Colors + C + 1048576 + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + Copy Style + c + 1572864 + 2147483647 + + + + + + Paste Style + v + 1572864 + 2147483647 + + + + + _NSFontMenu + + + + + Text + + 2147483647 + + + submenuAction: + + Text + + + + Align Left + { + 1048576 + 2147483647 + + + + + + Center + | + 1048576 + 2147483647 + + + + + + Justify + + 2147483647 + + + + + + Align Right + } + 1048576 + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + Writing Direction + + 2147483647 + + + submenuAction: + + Writing Direction + + + + YES + Paragraph + + 2147483647 + + + + + + CURlZmF1bHQ + + 2147483647 + + + + + + CUxlZnQgdG8gUmlnaHQ + + 2147483647 + + + + + + CVJpZ2h0IHRvIExlZnQ + + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + YES + Selection + + 2147483647 + + + + + + CURlZmF1bHQ + + 2147483647 + + + + + + CUxlZnQgdG8gUmlnaHQ + + 2147483647 + + + + + + CVJpZ2h0IHRvIExlZnQ + + 2147483647 + + + + + + + + + YES + YES + + + 2147483647 + + + + + + Show Ruler + + 2147483647 + + + + + + Copy Ruler + c + 1310720 + 2147483647 + + + + + + Paste Ruler + v + 1310720 + 2147483647 + + + + + + + + + + + + View + + 1048576 + 2147483647 + + + submenuAction: + + View + + + + Show Toolbar + t + 1572864 + 2147483647 + + + + + + Customize Toolbar… + + 1048576 + 2147483647 + + + + + + + + + Window + + 1048576 + 2147483647 + + + submenuAction: + + Window + + + + Minimize + m + 1048576 + 2147483647 + + + + + + Zoom + + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Bring All to Front + + 1048576 + 2147483647 + + + + + _NSWindowsMenu + + + + + Help + + 2147483647 + + + submenuAction: + + Help + + + + ExampleApp-OSX Help + ? + 1048576 + 2147483647 + + + + + _NSHelpMenu + + + + _NSMainMenu + + + 15 + 2 + {{335, 390}, {480, 360}} + 1954021376 + ExampleApp-OSX + NSWindow + + + + + 256 + + + + 256 + + Apple HTML pasteboard type + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple URL pasteboard type + Apple Web Archive pasteboard type + NSColor pasteboard type + NSFilenamesPboardType + NSStringPboardType + NeXT RTFD pasteboard type + NeXT Rich Text Format v1.0 pasteboard type + NeXT TIFF v4.0 pasteboard type + WebURLsWithTitlesPboardType + public.png + public.url + public.url-name + + {{0, 37}, {480, 323}} + + + + _NS:9 + + + + + + + + + + + YES + YES + + + + 268 + {{20, 10}, {97, 19}} + + + + _NS:9 + YES + + -2080374784 + 134217728 + Send message + + LucidaGrande + 12 + 16 + + _NS:9 + + -2038153216 + 164 + + + 400 + 75 + + + + + 268 + {{125, 10}, {86, 19}} + + + _NS:9 + YES + + -2080374784 + 134217728 + Call Handler + + _NS:9 + + -2038153216 + 164 + + + 400 + 75 + + + + {480, 360} + + + + + {{0, 0}, {1280, 778}} + {10000000000000, 10000000000000} + YES + + + AppDelegate + + + NSFontManager + + + + 256 + + Apple HTML pasteboard type + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple URL pasteboard type + Apple Web Archive pasteboard type + NSColor pasteboard type + NSFilenamesPboardType + NSStringPboardType + NeXT RTFD pasteboard type + NeXT Rich Text Format v1.0 pasteboard type + NeXT TIFF v4.0 pasteboard type + WebURLsWithTitlesPboardType + public.png + public.url + public.url-name + + {254, 200} + + + + _NS:9 + + + + YES + YES + + + + + + + terminate: + + + + 449 + + + + orderFrontStandardAboutPanel: + + + + 142 + + + + delegate + + + + 495 + + + + performMiniaturize: + + + + 37 + + + + arrangeInFront: + + + + 39 + + + + print: + + + + 86 + + + + runPageLayout: + + + + 87 + + + + clearRecentDocuments: + + + + 127 + + + + performClose: + + + + 193 + + + + toggleContinuousSpellChecking: + + + + 222 + + + + undo: + + + + 223 + + + + copy: + + + + 224 + + + + checkSpelling: + + + + 225 + + + + paste: + + + + 226 + + + + stopSpeaking: + + + + 227 + + + + cut: + + + + 228 + + + + showGuessPanel: + + + + 230 + + + + redo: + + + + 231 + + + + selectAll: + + + + 232 + + + + startSpeaking: + + + + 233 + + + + delete: + + + + 235 + + + + performZoom: + + + + 240 + + + + performFindPanelAction: + + + + 241 + + + + centerSelectionInVisibleArea: + + + + 245 + + + + toggleGrammarChecking: + + + + 347 + + + + toggleSmartInsertDelete: + + + + 355 + + + + toggleAutomaticQuoteSubstitution: + + + + 356 + + + + toggleAutomaticLinkDetection: + + + + 357 + + + + saveDocument: + + + + 362 + + + + revertDocumentToSaved: + + + + 364 + + + + runToolbarCustomizationPalette: + + + + 365 + + + + toggleToolbarShown: + + + + 366 + + + + hide: + + + + 367 + + + + hideOtherApplications: + + + + 368 + + + + unhideAllApplications: + + + + 370 + + + + newDocument: + + + + 373 + + + + openDocument: + + + + 374 + + + + raiseBaseline: + + + + 426 + + + + lowerBaseline: + + + + 427 + + + + copyFont: + + + + 428 + + + + subscript: + + + + 429 + + + + superscript: + + + + 430 + + + + tightenKerning: + + + + 431 + + + + underline: + + + + 432 + + + + orderFrontColorPanel: + + + + 433 + + + + useAllLigatures: + + + + 434 + + + + loosenKerning: + + + + 435 + + + + pasteFont: + + + + 436 + + + + unscript: + + + + 437 + + + + useStandardKerning: + + + + 438 + + + + useStandardLigatures: + + + + 439 + + + + turnOffLigatures: + + + + 440 + + + + turnOffKerning: + + + + 441 + + + + toggleAutomaticSpellingCorrection: + + + + 456 + + + + orderFrontSubstitutionsPanel: + + + + 458 + + + + toggleAutomaticDashSubstitution: + + + + 461 + + + + toggleAutomaticTextReplacement: + + + + 463 + + + + uppercaseWord: + + + + 464 + + + + capitalizeWord: + + + + 467 + + + + lowercaseWord: + + + + 468 + + + + pasteAsPlainText: + + + + 486 + + + + performFindPanelAction: + + + + 487 + + + + performFindPanelAction: + + + + 488 + + + + performFindPanelAction: + + + + 489 + + + + showHelp: + + + + 493 + + + + alignCenter: + + + + 518 + + + + pasteRuler: + + + + 519 + + + + toggleRuler: + + + + 520 + + + + alignRight: + + + + 521 + + + + copyRuler: + + + + 522 + + + + alignJustified: + + + + 523 + + + + alignLeft: + + + + 524 + + + + makeBaseWritingDirectionNatural: + + + + 525 + + + + makeBaseWritingDirectionLeftToRight: + + + + 526 + + + + makeBaseWritingDirectionRightToLeft: + + + + 527 + + + + makeTextWritingDirectionNatural: + + + + 528 + + + + makeTextWritingDirectionLeftToRight: + + + + 529 + + + + makeTextWritingDirectionRightToLeft: + + + + 530 + + + + performFindPanelAction: + + + + 535 + + + + addFontTrait: + + + + 421 + + + + addFontTrait: + + + + 422 + + + + modifyFont: + + + + 423 + + + + orderFrontFontPanel: + + + + 424 + + + + modifyFont: + + + + 425 + + + + window + + + + 532 + + + + webView + + + + 543 + + + + sendMessage: + + + + 555 + + + + callHandler: + + + + 556 + + + + + + 0 + + + + + + -2 + + + File's Owner + + + -1 + + + First Responder + + + -3 + + + Application + + + 29 + + + + + + + + + + + + + + 19 + + + + + + + + 56 + + + + + + + + 217 + + + + + + + + 83 + + + + + + + + 81 + + + + + + + + + + + + + + + + + 75 + + + + + 78 + + + + + 72 + + + + + 82 + + + + + 124 + + + + + + + + 77 + + + + + 73 + + + + + 79 + + + + + 112 + + + + + 74 + + + + + 125 + + + + + + + + 126 + + + + + 205 + + + + + + + + + + + + + + + + + + + + + + 202 + + + + + 198 + + + + + 207 + + + + + 214 + + + + + 199 + + + + + 203 + + + + + 197 + + + + + 206 + + + + + 215 + + + + + 218 + + + + + + + + 216 + + + + + + + + 200 + + + + + + + + + + + + + 219 + + + + + 201 + + + + + 204 + + + + + 220 + + + + + + + + + + + + + 213 + + + + + 210 + + + + + 221 + + + + + 208 + + + + + 209 + + + + + 57 + + + + + + + + + + + + + + + + + + 58 + + + + + 134 + + + + + 150 + + + + + 136 + + + + + 144 + + + + + 129 + + + + + 143 + + + + + 236 + + + + + 131 + + + + + + + + 149 + + + + + 145 + + + + + 130 + + + + + 24 + + + + + + + + + + + 92 + + + + + 5 + + + + + 239 + + + + + 23 + + + + + 295 + + + + + + + + 296 + + + + + + + + + 297 + + + + + 298 + + + + + 211 + + + + + + + + 212 + + + + + + + + + 195 + + + + + 196 + + + + + 346 + + + + + 348 + + + + + + + + 349 + + + + + + + + + + + + + + 350 + + + + + 351 + + + + + 354 + + + + + 371 + + + + + + + + 372 + + + + + 11 + 0 + + 11 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + + + + 5 + 0 + + 6 + 1 + + 8 + + 1000 + + 6 + 24 + 3 + + + + 3 + 0 + + 4 + 1 + + 8 + + 1000 + + 6 + 24 + 3 + + + + 5 + 0 + + 5 + 1 + + 20 + + 1000 + + 8 + 29 + 3 + + + + 6 + 0 + + 6 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + 3 + 0 + + 3 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + 5 + 0 + + 5 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + + + + + + 375 + + + + + + + + 376 + + + + + + + + + 377 + + + + + + + + 388 + + + + + + + + + + + + + + + + + + + + + + + 389 + + + + + 390 + + + + + 391 + + + + + 392 + + + + + 393 + + + + + 394 + + + + + 395 + + + + + 396 + + + + + 397 + + + + + + + + 398 + + + + + + + + 399 + + + + + + + + 400 + + + + + 401 + + + + + 402 + + + + + 403 + + + + + 404 + + + + + 405 + + + + + + + + + + + + 406 + + + + + 407 + + + + + 408 + + + + + 409 + + + + + 410 + + + + + 411 + + + + + + + + + + 412 + + + + + 413 + + + + + 414 + + + + + 415 + + + + + + + + + + + 416 + + + + + 417 + + + + + 418 + + + + + 419 + + + + + 420 + + + + + 450 + + + + + + + + 451 + + + + + + + + + + 452 + + + + + 453 + + + + + 454 + + + + + 457 + + + + + 459 + + + + + 460 + + + + + 462 + + + + + 465 + + + + + 466 + + + + + 485 + + + + + 490 + + + + + + + + 491 + + + + + + + + 492 + + + + + 494 + + + + + 496 + + + + + + + + 497 + + + + + + + + + + + + + + + + + 498 + + + + + 499 + + + + + 500 + + + + + 501 + + + + + 502 + + + + + 503 + + + + + + + + 504 + + + + + 505 + + + + + 506 + + + + + 507 + + + + + 508 + + + + + + + + + + + + + + + + 509 + + + + + 510 + + + + + 511 + + + + + 512 + + + + + 513 + + + + + 514 + + + + + 515 + + + + + 516 + + + + + 517 + + + + + 534 + + + + + 536 + + + + + 8 + 0 + + 0 + 1 + + 323 + + 1000 + + 3 + 9 + 1 + + + + + + 539 + + + + + 540 + + + + + 542 + + + + + 544 + + + + + 545 + + + + + + + + 546 + + + + + 550 + + + + + 551 + + + + + + + + 552 + + + + + 554 + + + + + 557 + + + + + 558 + + + + + 559 + + + + + + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + {{380, 496}, {480, 360}} + + + + + + + + + + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + + + + com.apple.WebKitIBPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.WebKitIBPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + + + + + 559 + + + + + AppDelegate + NSObject + + id + id + + + + callHandler: + id + + + sendMessage: + id + + + + WebView + NSWindow + + + + webView + WebView + + + window + NSWindow + + + + IBProjectSource + ./Classes/AppDelegate.h + + + + NSLayoutConstraint + NSObject + + IBProjectSource + ./Classes/NSLayoutConstraint.h + + + + + 0 + IBCocoaFramework + YES + 3 + + {11, 11} + {10, 3} + + YES + + From 1df2260564178ed46becd36420e334d78ff1e14a Mon Sep 17 00:00:00 2001 From: Antoine Lagadec Date: Thu, 5 Sep 2013 16:28:15 +0200 Subject: [PATCH 116/353] OSX - Empty Main Menu layout --- Example Apps/ExampleApp-OSX/MainMenu.xib | 6852 ++++++++++------------ 1 file changed, 3241 insertions(+), 3611 deletions(-) diff --git a/Example Apps/ExampleApp-OSX/MainMenu.xib b/Example Apps/ExampleApp-OSX/MainMenu.xib index b7140d43..7dd49232 100644 --- a/Example Apps/ExampleApp-OSX/MainMenu.xib +++ b/Example Apps/ExampleApp-OSX/MainMenu.xib @@ -1,3614 +1,3244 @@ - - 1070 - 11E53 - 2844 - 1138.47 - 569.00 - - 2844 - 1810 - - - IBNSLayoutConstraint - NSButton - NSButtonCell - NSCustomObject - NSMenu - NSMenuItem - NSView - NSWindowTemplate - WebView - - - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.WebKitIBPlugin - - - PluginDependencyRecalculationVersion - - - - - NSApplication - - - FirstResponder - - - NSApplication - - - AMainMenu - - - - ExampleApp-OSX - - 1048576 - 2147483647 - - NSImage - NSMenuCheckmark - - - NSImage - NSMenuMixedState - - submenuAction: - - ExampleApp-OSX - - - - About ExampleApp-OSX - - 2147483647 - - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Preferences… - , - 1048576 - 2147483647 - - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Services - - 1048576 - 2147483647 - - - submenuAction: - - Services - - _NSServicesMenu - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Hide ExampleApp-OSX - h - 1048576 - 2147483647 - - - - - - Hide Others - h - 1572864 - 2147483647 - - - - - - Show All - - 1048576 - 2147483647 - - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Quit ExampleApp-OSX - q - 1048576 - 2147483647 - - - - - _NSAppleMenu - - - - - File - - 1048576 - 2147483647 - - - submenuAction: - - File - - - - New - n - 1048576 - 2147483647 - - - - - - Open… - o - 1048576 - 2147483647 - - - - - - Open Recent - - 1048576 - 2147483647 - - - submenuAction: - - Open Recent - - - - Clear Menu - - 1048576 - 2147483647 - - - - - _NSRecentDocumentsMenu - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Close - w - 1048576 - 2147483647 - - - - - - Save… - s - 1048576 - 2147483647 - - - - - - Revert to Saved - - 2147483647 - - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Page Setup... - P - 1179648 - 2147483647 - - - - - - - Print… - p - 1048576 - 2147483647 - - - - - - - - - Edit - - 1048576 - 2147483647 - - - submenuAction: - - Edit - - - - Undo - z - 1048576 - 2147483647 - - - - - - Redo - Z - 1179648 - 2147483647 - - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Cut - x - 1048576 - 2147483647 - - - - - - Copy - c - 1048576 - 2147483647 - - - - - - Paste - v - 1048576 - 2147483647 - - - - - - Paste and Match Style - V - 1572864 - 2147483647 - - - - - - Delete - - 1048576 - 2147483647 - - - - - - Select All - a - 1048576 - 2147483647 - - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Find - - 1048576 - 2147483647 - - - submenuAction: - - Find - - - - Find… - f - 1048576 - 2147483647 - - - 1 - - - - Find and Replace… - f - 1572864 - 2147483647 - - - 12 - - - - Find Next - g - 1048576 - 2147483647 - - - 2 - - - - Find Previous - G - 1179648 - 2147483647 - - - 3 - - - - Use Selection for Find - e - 1048576 - 2147483647 - - - 7 - - - - Jump to Selection - j - 1048576 - 2147483647 - - - - - - - - - Spelling and Grammar - - 1048576 - 2147483647 - - - submenuAction: - - Spelling and Grammar - - - - Show Spelling and Grammar - : - 1048576 - 2147483647 - - - - - - Check Document Now - ; - 1048576 - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - Check Spelling While Typing - - 1048576 - 2147483647 - - - - - - Check Grammar With Spelling - - 1048576 - 2147483647 - - - - - - Correct Spelling Automatically - - 2147483647 - - - - - - - - - Substitutions - - 1048576 - 2147483647 - - - submenuAction: - - Substitutions - - - - Show Substitutions - - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - Smart Copy/Paste - f - 1048576 - 2147483647 - - - 1 - - - - Smart Quotes - g - 1048576 - 2147483647 - - - 2 - - - - Smart Dashes - - 2147483647 - - - - - - Smart Links - G - 1179648 - 2147483647 - - - 3 - - - - Text Replacement - - 2147483647 - - - - - - - - - Transformations - - 2147483647 - - - submenuAction: - - Transformations - - - - Make Upper Case - - 2147483647 - - - - - - Make Lower Case - - 2147483647 - - - - - - Capitalize - - 2147483647 - - - - - - - - - Speech - - 1048576 - 2147483647 - - - submenuAction: - - Speech - - - - Start Speaking - - 1048576 - 2147483647 - - - - - - Stop Speaking - - 1048576 - 2147483647 - - - - - - - - - - - - Format - - 2147483647 - - - submenuAction: - - Format - - - - Font - - 2147483647 - - - submenuAction: - - Font - - - - Show Fonts - t - 1048576 - 2147483647 - - - - - - Bold - b - 1048576 - 2147483647 - - - 2 - - - - Italic - i - 1048576 - 2147483647 - - - 1 - - - - Underline - u - 1048576 - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - Bigger - + - 1048576 - 2147483647 - - - 3 - - - - Smaller - - - 1048576 - 2147483647 - - - 4 - - - - YES - YES - - - 2147483647 - - - - - - Kern - - 2147483647 - - - submenuAction: - - Kern - - - - Use Default - - 2147483647 - - - - - - Use None - - 2147483647 - - - - - - Tighten - - 2147483647 - - - - - - Loosen - - 2147483647 - - - - - - - - - Ligatures - - 2147483647 - - - submenuAction: - - Ligatures - - - - Use Default - - 2147483647 - - - - - - Use None - - 2147483647 - - - - - - Use All - - 2147483647 - - - - - - - - - Baseline - - 2147483647 - - - submenuAction: - - Baseline - - - - Use Default - - 2147483647 - - - - - - Superscript - - 2147483647 - - - - - - Subscript - - 2147483647 - - - - - - Raise - - 2147483647 - - - - - - Lower - - 2147483647 - - - - - - - - - YES - YES - - - 2147483647 - - - - - - Show Colors - C - 1048576 - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - Copy Style - c - 1572864 - 2147483647 - - - - - - Paste Style - v - 1572864 - 2147483647 - - - - - _NSFontMenu - - - - - Text - - 2147483647 - - - submenuAction: - - Text - - - - Align Left - { - 1048576 - 2147483647 - - - - - - Center - | - 1048576 - 2147483647 - - - - - - Justify - - 2147483647 - - - - - - Align Right - } - 1048576 - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - Writing Direction - - 2147483647 - - - submenuAction: - - Writing Direction - - - - YES - Paragraph - - 2147483647 - - - - - - CURlZmF1bHQ - - 2147483647 - - - - - - CUxlZnQgdG8gUmlnaHQ - - 2147483647 - - - - - - CVJpZ2h0IHRvIExlZnQ - - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - YES - Selection - - 2147483647 - - - - - - CURlZmF1bHQ - - 2147483647 - - - - - - CUxlZnQgdG8gUmlnaHQ - - 2147483647 - - - - - - CVJpZ2h0IHRvIExlZnQ - - 2147483647 - - - - - - - - - YES - YES - - - 2147483647 - - - - - - Show Ruler - - 2147483647 - - - - - - Copy Ruler - c - 1310720 - 2147483647 - - - - - - Paste Ruler - v - 1310720 - 2147483647 - - - - - - - - - - - - View - - 1048576 - 2147483647 - - - submenuAction: - - View - - - - Show Toolbar - t - 1572864 - 2147483647 - - - - - - Customize Toolbar… - - 1048576 - 2147483647 - - - - - - - - - Window - - 1048576 - 2147483647 - - - submenuAction: - - Window - - - - Minimize - m - 1048576 - 2147483647 - - - - - - Zoom - - 1048576 - 2147483647 - - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Bring All to Front - - 1048576 - 2147483647 - - - - - _NSWindowsMenu - - - - - Help - - 2147483647 - - - submenuAction: - - Help - - - - ExampleApp-OSX Help - ? - 1048576 - 2147483647 - - - - - _NSHelpMenu - - - - _NSMainMenu - - - 15 - 2 - {{335, 390}, {480, 360}} - 1954021376 - ExampleApp-OSX - NSWindow - - - - - 256 - - - - 256 - - Apple HTML pasteboard type - Apple PDF pasteboard type - Apple PICT pasteboard type - Apple URL pasteboard type - Apple Web Archive pasteboard type - NSColor pasteboard type - NSFilenamesPboardType - NSStringPboardType - NeXT RTFD pasteboard type - NeXT Rich Text Format v1.0 pasteboard type - NeXT TIFF v4.0 pasteboard type - WebURLsWithTitlesPboardType - public.png - public.url - public.url-name - - {{0, 37}, {480, 323}} - - - - _NS:9 - - - - - - - - - - - YES - YES - - - - 268 - {{20, 10}, {97, 19}} - - - - _NS:9 - YES - - -2080374784 - 134217728 - Send message - - LucidaGrande - 12 - 16 - - _NS:9 - - -2038153216 - 164 - - - 400 - 75 - - - - - 268 - {{125, 10}, {86, 19}} - - - _NS:9 - YES - - -2080374784 - 134217728 - Call Handler - - _NS:9 - - -2038153216 - 164 - - - 400 - 75 - - - - {480, 360} - - - - - {{0, 0}, {1280, 778}} - {10000000000000, 10000000000000} - YES - - - AppDelegate - - - NSFontManager - - - - 256 - - Apple HTML pasteboard type - Apple PDF pasteboard type - Apple PICT pasteboard type - Apple URL pasteboard type - Apple Web Archive pasteboard type - NSColor pasteboard type - NSFilenamesPboardType - NSStringPboardType - NeXT RTFD pasteboard type - NeXT Rich Text Format v1.0 pasteboard type - NeXT TIFF v4.0 pasteboard type - WebURLsWithTitlesPboardType - public.png - public.url - public.url-name - - {254, 200} - - - - _NS:9 - - - - YES - YES - - - - - - - terminate: - - - - 449 - - - - orderFrontStandardAboutPanel: - - - - 142 - - - - delegate - - - - 495 - - - - performMiniaturize: - - - - 37 - - - - arrangeInFront: - - - - 39 - - - - print: - - - - 86 - - - - runPageLayout: - - - - 87 - - - - clearRecentDocuments: - - - - 127 - - - - performClose: - - - - 193 - - - - toggleContinuousSpellChecking: - - - - 222 - - - - undo: - - - - 223 - - - - copy: - - - - 224 - - - - checkSpelling: - - - - 225 - - - - paste: - - - - 226 - - - - stopSpeaking: - - - - 227 - - - - cut: - - - - 228 - - - - showGuessPanel: - - - - 230 - - - - redo: - - - - 231 - - - - selectAll: - - - - 232 - - - - startSpeaking: - - - - 233 - - - - delete: - - - - 235 - - - - performZoom: - - - - 240 - - - - performFindPanelAction: - - - - 241 - - - - centerSelectionInVisibleArea: - - - - 245 - - - - toggleGrammarChecking: - - - - 347 - - - - toggleSmartInsertDelete: - - - - 355 - - - - toggleAutomaticQuoteSubstitution: - - - - 356 - - - - toggleAutomaticLinkDetection: - - - - 357 - - - - saveDocument: - - - - 362 - - - - revertDocumentToSaved: - - - - 364 - - - - runToolbarCustomizationPalette: - - - - 365 - - - - toggleToolbarShown: - - - - 366 - - - - hide: - - - - 367 - - - - hideOtherApplications: - - - - 368 - - - - unhideAllApplications: - - - - 370 - - - - newDocument: - - - - 373 - - - - openDocument: - - - - 374 - - - - raiseBaseline: - - - - 426 - - - - lowerBaseline: - - - - 427 - - - - copyFont: - - - - 428 - - - - subscript: - - - - 429 - - - - superscript: - - - - 430 - - - - tightenKerning: - - - - 431 - - - - underline: - - - - 432 - - - - orderFrontColorPanel: - - - - 433 - - - - useAllLigatures: - - - - 434 - - - - loosenKerning: - - - - 435 - - - - pasteFont: - - - - 436 - - - - unscript: - - - - 437 - - - - useStandardKerning: - - - - 438 - - - - useStandardLigatures: - - - - 439 - - - - turnOffLigatures: - - - - 440 - - - - turnOffKerning: - - - - 441 - - - - toggleAutomaticSpellingCorrection: - - - - 456 - - - - orderFrontSubstitutionsPanel: - - - - 458 - - - - toggleAutomaticDashSubstitution: - - - - 461 - - - - toggleAutomaticTextReplacement: - - - - 463 - - - - uppercaseWord: - - - - 464 - - - - capitalizeWord: - - - - 467 - - - - lowercaseWord: - - - - 468 - - - - pasteAsPlainText: - - - - 486 - - - - performFindPanelAction: - - - - 487 - - - - performFindPanelAction: - - - - 488 - - - - performFindPanelAction: - - - - 489 - - - - showHelp: - - - - 493 - - - - alignCenter: - - - - 518 - - - - pasteRuler: - - - - 519 - - - - toggleRuler: - - - - 520 - - - - alignRight: - - - - 521 - - - - copyRuler: - - - - 522 - - - - alignJustified: - - - - 523 - - - - alignLeft: - - - - 524 - - - - makeBaseWritingDirectionNatural: - - - - 525 - - - - makeBaseWritingDirectionLeftToRight: - - - - 526 - - - - makeBaseWritingDirectionRightToLeft: - - - - 527 - - - - makeTextWritingDirectionNatural: - - - - 528 - - - - makeTextWritingDirectionLeftToRight: - - - - 529 - - - - makeTextWritingDirectionRightToLeft: - - - - 530 - - - - performFindPanelAction: - - - - 535 - - - - addFontTrait: - - - - 421 - - - - addFontTrait: - - - - 422 - - - - modifyFont: - - - - 423 - - - - orderFrontFontPanel: - - - - 424 - - - - modifyFont: - - - - 425 - - - - window - - - - 532 - - - - webView - - - - 543 - - - - sendMessage: - - - - 555 - - - - callHandler: - - - - 556 - - - - - - 0 - - - - - - -2 - - - File's Owner - - - -1 - - - First Responder - - - -3 - - - Application - - - 29 - - - - - - - - - - - - - - 19 - - - - - - - - 56 - - - - - - - - 217 - - - - - - - - 83 - - - - - - - - 81 - - - - - - - - - - - - - - - - - 75 - - - - - 78 - - - - - 72 - - - - - 82 - - - - - 124 - - - - - - - - 77 - - - - - 73 - - - - - 79 - - - - - 112 - - - - - 74 - - - - - 125 - - - - - - - - 126 - - - - - 205 - - - - - - - - - - - - - - - - - - - - - - 202 - - - - - 198 - - - - - 207 - - - - - 214 - - - - - 199 - - - - - 203 - - - - - 197 - - - - - 206 - - - - - 215 - - - - - 218 - - - - - - - - 216 - - - - - - - - 200 - - - - - - - - - - - - - 219 - - - - - 201 - - - - - 204 - - - - - 220 - - - - - - - - - - - - - 213 - - - - - 210 - - - - - 221 - - - - - 208 - - - - - 209 - - - - - 57 - - - - - - - - - - - - - - - - - - 58 - - - - - 134 - - - - - 150 - - - - - 136 - - - - - 144 - - - - - 129 - - - - - 143 - - - - - 236 - - - - - 131 - - - - - - - - 149 - - - - - 145 - - - - - 130 - - - - - 24 - - - - - - - - - - - 92 - - - - - 5 - - - - - 239 - - - - - 23 - - - - - 295 - - - - - - - - 296 - - - - - - - - - 297 - - - - - 298 - - - - - 211 - - - - - - - - 212 - - - - - - - - - 195 - - - - - 196 - - - - - 346 - - - - - 348 - - - - - - - - 349 - - - - - - - - - - - - - - 350 - - - - - 351 - - - - - 354 - - - - - 371 - - - - - - - - 372 - - - - - 11 - 0 - - 11 - 1 - - 0.0 - - 1000 - - 6 - 24 - 2 - - - - 5 - 0 - - 6 - 1 - - 8 - - 1000 - - 6 - 24 - 3 - - - - 3 - 0 - - 4 - 1 - - 8 - - 1000 - - 6 - 24 - 3 - - - - 5 - 0 - - 5 - 1 - - 20 - - 1000 - - 8 - 29 - 3 - - - - 6 - 0 - - 6 - 1 - - 0.0 - - 1000 - - 8 - 29 - 3 - - - - 3 - 0 - - 3 - 1 - - 0.0 - - 1000 - - 8 - 29 - 3 - - - - 5 - 0 - - 5 - 1 - - 0.0 - - 1000 - - 8 - 29 - 3 - - - - - - - - - 375 - - - - - - - - 376 - - - - - - - - - 377 - - - - - - - - 388 - - - - - - - - - - - - - - - - - - - - - - - 389 - - - - - 390 - - - - - 391 - - - - - 392 - - - - - 393 - - - - - 394 - - - - - 395 - - - - - 396 - - - - - 397 - - - - - - - - 398 - - - - - - - - 399 - - - - - - - - 400 - - - - - 401 - - - - - 402 - - - - - 403 - - - - - 404 - - - - - 405 - - - - - - - - - - - - 406 - - - - - 407 - - - - - 408 - - - - - 409 - - - - - 410 - - - - - 411 - - - - - - - - - - 412 - - - - - 413 - - - - - 414 - - - - - 415 - - - - - - - - - - - 416 - - - - - 417 - - - - - 418 - - - - - 419 - - - - - 420 - - - - - 450 - - - - - - - - 451 - - - - - - - - - - 452 - - - - - 453 - - - - - 454 - - - - - 457 - - - - - 459 - - - - - 460 - - - - - 462 - - - - - 465 - - - - - 466 - - - - - 485 - - - - - 490 - - - - - - - - 491 - - - - - - - - 492 - - - - - 494 - - - - - 496 - - - - - - - - 497 - - - - - - - - - - - - - - - - - 498 - - - - - 499 - - - - - 500 - - - - - 501 - - - - - 502 - - - - - 503 - - - - - - - - 504 - - - - - 505 - - - - - 506 - - - - - 507 - - - - - 508 - - - - - - - - - - - - - - - - 509 - - - - - 510 - - - - - 511 - - - - - 512 - - - - - 513 - - - - - 514 - - - - - 515 - - - - - 516 - - - - - 517 - - - - - 534 - - - - - 536 - - - - - 8 - 0 - - 0 - 1 - - 323 - - 1000 - - 3 - 9 - 1 - - - - - - 539 - - - - - 540 - - - - - 542 - - - - - 544 - - - - - 545 - - - - - - - - 546 - - - - - 550 - - - - - 551 - - - - - - - - 552 - - - - - 554 - - - - - 557 - - - - - 558 - - - - - 559 - - - - - - - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - {{380, 496}, {480, 360}} - - - - - - - - - - - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - - - - - com.apple.WebKitIBPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.WebKitIBPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - - - - - - 559 - - - - - AppDelegate - NSObject - - id - id - - - - callHandler: - id - - - sendMessage: - id - - - - WebView - NSWindow - - - - webView - WebView - - - window - NSWindow - - - - IBProjectSource - ./Classes/AppDelegate.h - - - - NSLayoutConstraint - NSObject - - IBProjectSource - ./Classes/NSLayoutConstraint.h - - - - - 0 - IBCocoaFramework - YES - 3 - - {11, 11} - {10, 3} - - YES - + + 1070 + 11E53 + 2844 + 1138.47 + 569.00 + + 2844 + 1810 + + + NSCustomObject + NSMenu + NSMenuItem + NSView + NSWindowTemplate + WebView + + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.WebKitIBPlugin + + + PluginDependencyRecalculationVersion + + + + + NSApplication + + + FirstResponder + + + NSApplication + + + AMainMenu + + + + ExampleApp-OSX + + 1048576 + 2147483647 + + NSImage + NSMenuCheckmark + + + NSImage + NSMenuMixedState + + submenuAction: + + ExampleApp-OSX + + + + About ExampleApp-OSX + + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Preferences… + , + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Services + + 1048576 + 2147483647 + + + submenuAction: + + Services + + _NSServicesMenu + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Hide ExampleApp-OSX + h + 1048576 + 2147483647 + + + + + + Hide Others + h + 1572864 + 2147483647 + + + + + + Show All + + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Quit ExampleApp-OSX + q + 1048576 + 2147483647 + + + + + _NSAppleMenu + + + + + File + + 1048576 + 2147483647 + + + submenuAction: + + File + + + + New + n + 1048576 + 2147483647 + + + + + + Open… + o + 1048576 + 2147483647 + + + + + + Open Recent + + 1048576 + 2147483647 + + + submenuAction: + + Open Recent + + + + Clear Menu + + 1048576 + 2147483647 + + + + + _NSRecentDocumentsMenu + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Close + w + 1048576 + 2147483647 + + + + + + Save… + s + 1048576 + 2147483647 + + + + + + Revert to Saved + + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Page Setup... + P + 1179648 + 2147483647 + + + + + + + Print… + p + 1048576 + 2147483647 + + + + + + + + + Edit + + 1048576 + 2147483647 + + + submenuAction: + + Edit + + + + Undo + z + 1048576 + 2147483647 + + + + + + Redo + Z + 1179648 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Cut + x + 1048576 + 2147483647 + + + + + + Copy + c + 1048576 + 2147483647 + + + + + + Paste + v + 1048576 + 2147483647 + + + + + + Paste and Match Style + V + 1572864 + 2147483647 + + + + + + Delete + + 1048576 + 2147483647 + + + + + + Select All + a + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Find + + 1048576 + 2147483647 + + + submenuAction: + + Find + + + + Find… + f + 1048576 + 2147483647 + + + 1 + + + + Find and Replace… + f + 1572864 + 2147483647 + + + 12 + + + + Find Next + g + 1048576 + 2147483647 + + + 2 + + + + Find Previous + G + 1179648 + 2147483647 + + + 3 + + + + Use Selection for Find + e + 1048576 + 2147483647 + + + 7 + + + + Jump to Selection + j + 1048576 + 2147483647 + + + + + + + + + Spelling and Grammar + + 1048576 + 2147483647 + + + submenuAction: + + Spelling and Grammar + + + + Show Spelling and Grammar + : + 1048576 + 2147483647 + + + + + + Check Document Now + ; + 1048576 + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + Check Spelling While Typing + + 1048576 + 2147483647 + + + + + + Check Grammar With Spelling + + 1048576 + 2147483647 + + + + + + Correct Spelling Automatically + + 2147483647 + + + + + + + + + Substitutions + + 1048576 + 2147483647 + + + submenuAction: + + Substitutions + + + + Show Substitutions + + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + Smart Copy/Paste + f + 1048576 + 2147483647 + + + 1 + + + + Smart Quotes + g + 1048576 + 2147483647 + + + 2 + + + + Smart Dashes + + 2147483647 + + + + + + Smart Links + G + 1179648 + 2147483647 + + + 3 + + + + Text Replacement + + 2147483647 + + + + + + + + + Transformations + + 2147483647 + + + submenuAction: + + Transformations + + + + Make Upper Case + + 2147483647 + + + + + + Make Lower Case + + 2147483647 + + + + + + Capitalize + + 2147483647 + + + + + + + + + Speech + + 1048576 + 2147483647 + + + submenuAction: + + Speech + + + + Start Speaking + + 1048576 + 2147483647 + + + + + + Stop Speaking + + 1048576 + 2147483647 + + + + + + + + + + + + Format + + 2147483647 + + + submenuAction: + + Format + + + + Font + + 2147483647 + + + submenuAction: + + Font + + + + Show Fonts + t + 1048576 + 2147483647 + + + + + + Bold + b + 1048576 + 2147483647 + + + 2 + + + + Italic + i + 1048576 + 2147483647 + + + 1 + + + + Underline + u + 1048576 + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + Bigger + + + 1048576 + 2147483647 + + + 3 + + + + Smaller + - + 1048576 + 2147483647 + + + 4 + + + + YES + YES + + + 2147483647 + + + + + + Kern + + 2147483647 + + + submenuAction: + + Kern + + + + Use Default + + 2147483647 + + + + + + Use None + + 2147483647 + + + + + + Tighten + + 2147483647 + + + + + + Loosen + + 2147483647 + + + + + + + + + Ligatures + + 2147483647 + + + submenuAction: + + Ligatures + + + + Use Default + + 2147483647 + + + + + + Use None + + 2147483647 + + + + + + Use All + + 2147483647 + + + + + + + + + Baseline + + 2147483647 + + + submenuAction: + + Baseline + + + + Use Default + + 2147483647 + + + + + + Superscript + + 2147483647 + + + + + + Subscript + + 2147483647 + + + + + + Raise + + 2147483647 + + + + + + Lower + + 2147483647 + + + + + + + + + YES + YES + + + 2147483647 + + + + + + Show Colors + C + 1048576 + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + Copy Style + c + 1572864 + 2147483647 + + + + + + Paste Style + v + 1572864 + 2147483647 + + + + + _NSFontMenu + + + + + Text + + 2147483647 + + + submenuAction: + + Text + + + + Align Left + { + 1048576 + 2147483647 + + + + + + Center + | + 1048576 + 2147483647 + + + + + + Justify + + 2147483647 + + + + + + Align Right + } + 1048576 + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + Writing Direction + + 2147483647 + + + submenuAction: + + Writing Direction + + + + YES + Paragraph + + 2147483647 + + + + + + CURlZmF1bHQ + + 2147483647 + + + + + + CUxlZnQgdG8gUmlnaHQ + + 2147483647 + + + + + + CVJpZ2h0IHRvIExlZnQ + + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + YES + Selection + + 2147483647 + + + + + + CURlZmF1bHQ + + 2147483647 + + + + + + CUxlZnQgdG8gUmlnaHQ + + 2147483647 + + + + + + CVJpZ2h0IHRvIExlZnQ + + 2147483647 + + + + + + + + + YES + YES + + + 2147483647 + + + + + + Show Ruler + + 2147483647 + + + + + + Copy Ruler + c + 1310720 + 2147483647 + + + + + + Paste Ruler + v + 1310720 + 2147483647 + + + + + + + + + + + + View + + 1048576 + 2147483647 + + + submenuAction: + + View + + + + Show Toolbar + t + 1572864 + 2147483647 + + + + + + Customize Toolbar… + + 1048576 + 2147483647 + + + + + + + + + Window + + 1048576 + 2147483647 + + + submenuAction: + + Window + + + + Minimize + m + 1048576 + 2147483647 + + + + + + Zoom + + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Bring All to Front + + 1048576 + 2147483647 + + + + + _NSWindowsMenu + + + + + Help + + 2147483647 + + + submenuAction: + + Help + + + + ExampleApp-OSX Help + ? + 1048576 + 2147483647 + + + + + _NSHelpMenu + + + + _NSMainMenu + + + 15 + 2 + {{335, 390}, {480, 360}} + 1954021376 + ExampleApp-OSX + NSWindow + + + + + 256 + {480, 360} + + + + + {{0, 0}, {1280, 778}} + {10000000000000, 10000000000000} + YES + + + AppDelegate + + + NSFontManager + + + + 256 + + Apple HTML pasteboard type + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple URL pasteboard type + Apple Web Archive pasteboard type + NSColor pasteboard type + NSFilenamesPboardType + NSStringPboardType + NeXT RTFD pasteboard type + NeXT Rich Text Format v1.0 pasteboard type + NeXT TIFF v4.0 pasteboard type + WebURLsWithTitlesPboardType + public.png + public.url + public.url-name + + {254, 200} + + + _NS:9 + + + + + + + + + + + YES + YES + + + + + + + terminate: + + + + 449 + + + + orderFrontStandardAboutPanel: + + + + 142 + + + + delegate + + + + 495 + + + + performMiniaturize: + + + + 37 + + + + arrangeInFront: + + + + 39 + + + + print: + + + + 86 + + + + runPageLayout: + + + + 87 + + + + clearRecentDocuments: + + + + 127 + + + + performClose: + + + + 193 + + + + toggleContinuousSpellChecking: + + + + 222 + + + + undo: + + + + 223 + + + + copy: + + + + 224 + + + + checkSpelling: + + + + 225 + + + + paste: + + + + 226 + + + + stopSpeaking: + + + + 227 + + + + cut: + + + + 228 + + + + showGuessPanel: + + + + 230 + + + + redo: + + + + 231 + + + + selectAll: + + + + 232 + + + + startSpeaking: + + + + 233 + + + + delete: + + + + 235 + + + + performZoom: + + + + 240 + + + + performFindPanelAction: + + + + 241 + + + + centerSelectionInVisibleArea: + + + + 245 + + + + toggleGrammarChecking: + + + + 347 + + + + toggleSmartInsertDelete: + + + + 355 + + + + toggleAutomaticQuoteSubstitution: + + + + 356 + + + + toggleAutomaticLinkDetection: + + + + 357 + + + + saveDocument: + + + + 362 + + + + revertDocumentToSaved: + + + + 364 + + + + runToolbarCustomizationPalette: + + + + 365 + + + + toggleToolbarShown: + + + + 366 + + + + hide: + + + + 367 + + + + hideOtherApplications: + + + + 368 + + + + unhideAllApplications: + + + + 370 + + + + newDocument: + + + + 373 + + + + openDocument: + + + + 374 + + + + raiseBaseline: + + + + 426 + + + + lowerBaseline: + + + + 427 + + + + copyFont: + + + + 428 + + + + subscript: + + + + 429 + + + + superscript: + + + + 430 + + + + tightenKerning: + + + + 431 + + + + underline: + + + + 432 + + + + orderFrontColorPanel: + + + + 433 + + + + useAllLigatures: + + + + 434 + + + + loosenKerning: + + + + 435 + + + + pasteFont: + + + + 436 + + + + unscript: + + + + 437 + + + + useStandardKerning: + + + + 438 + + + + useStandardLigatures: + + + + 439 + + + + turnOffLigatures: + + + + 440 + + + + turnOffKerning: + + + + 441 + + + + toggleAutomaticSpellingCorrection: + + + + 456 + + + + orderFrontSubstitutionsPanel: + + + + 458 + + + + toggleAutomaticDashSubstitution: + + + + 461 + + + + toggleAutomaticTextReplacement: + + + + 463 + + + + uppercaseWord: + + + + 464 + + + + capitalizeWord: + + + + 467 + + + + lowercaseWord: + + + + 468 + + + + pasteAsPlainText: + + + + 486 + + + + performFindPanelAction: + + + + 487 + + + + performFindPanelAction: + + + + 488 + + + + performFindPanelAction: + + + + 489 + + + + showHelp: + + + + 493 + + + + alignCenter: + + + + 518 + + + + pasteRuler: + + + + 519 + + + + toggleRuler: + + + + 520 + + + + alignRight: + + + + 521 + + + + copyRuler: + + + + 522 + + + + alignJustified: + + + + 523 + + + + alignLeft: + + + + 524 + + + + makeBaseWritingDirectionNatural: + + + + 525 + + + + makeBaseWritingDirectionLeftToRight: + + + + 526 + + + + makeBaseWritingDirectionRightToLeft: + + + + 527 + + + + makeTextWritingDirectionNatural: + + + + 528 + + + + makeTextWritingDirectionLeftToRight: + + + + 529 + + + + makeTextWritingDirectionRightToLeft: + + + + 530 + + + + performFindPanelAction: + + + + 535 + + + + addFontTrait: + + + + 421 + + + + addFontTrait: + + + + 422 + + + + modifyFont: + + + + 423 + + + + orderFrontFontPanel: + + + + 424 + + + + modifyFont: + + + + 425 + + + + window + + + + 532 + + + + + + 0 + + + + + + -2 + + + File's Owner + + + -1 + + + First Responder + + + -3 + + + Application + + + 29 + + + + + + + + + + + + + + 19 + + + + + + + + 56 + + + + + + + + 217 + + + + + + + + 83 + + + + + + + + 81 + + + + + + + + + + + + + + + + + 75 + + + + + 78 + + + + + 72 + + + + + 82 + + + + + 124 + + + + + + + + 77 + + + + + 73 + + + + + 79 + + + + + 112 + + + + + 74 + + + + + 125 + + + + + + + + 126 + + + + + 205 + + + + + + + + + + + + + + + + + + + + + + 202 + + + + + 198 + + + + + 207 + + + + + 214 + + + + + 199 + + + + + 203 + + + + + 197 + + + + + 206 + + + + + 215 + + + + + 218 + + + + + + + + 216 + + + + + + + + 200 + + + + + + + + + + + + + 219 + + + + + 201 + + + + + 204 + + + + + 220 + + + + + + + + + + + + + 213 + + + + + 210 + + + + + 221 + + + + + 208 + + + + + 209 + + + + + 57 + + + + + + + + + + + + + + + + + + 58 + + + + + 134 + + + + + 150 + + + + + 136 + + + + + 144 + + + + + 129 + + + + + 143 + + + + + 236 + + + + + 131 + + + + + + + + 149 + + + + + 145 + + + + + 130 + + + + + 24 + + + + + + + + + + + 92 + + + + + 5 + + + + + 239 + + + + + 23 + + + + + 295 + + + + + + + + 296 + + + + + + + + + 297 + + + + + 298 + + + + + 211 + + + + + + + + 212 + + + + + + + + + 195 + + + + + 196 + + + + + 346 + + + + + 348 + + + + + + + + 349 + + + + + + + + + + + + + + 350 + + + + + 351 + + + + + 354 + + + + + 375 + + + + + + + + 376 + + + + + + + + + 377 + + + + + + + + 388 + + + + + + + + + + + + + + + + + + + + + + + 389 + + + + + 390 + + + + + 391 + + + + + 392 + + + + + 393 + + + + + 394 + + + + + 395 + + + + + 396 + + + + + 397 + + + + + + + + 398 + + + + + + + + 399 + + + + + + + + 400 + + + + + 401 + + + + + 402 + + + + + 403 + + + + + 404 + + + + + 405 + + + + + + + + + + + + 406 + + + + + 407 + + + + + 408 + + + + + 409 + + + + + 410 + + + + + 411 + + + + + + + + + + 412 + + + + + 413 + + + + + 414 + + + + + 415 + + + + + + + + + + + 416 + + + + + 417 + + + + + 418 + + + + + 419 + + + + + 420 + + + + + 450 + + + + + + + + 451 + + + + + + + + + + 452 + + + + + 453 + + + + + 454 + + + + + 457 + + + + + 459 + + + + + 460 + + + + + 462 + + + + + 465 + + + + + 466 + + + + + 485 + + + + + 490 + + + + + + + + 491 + + + + + + + + 492 + + + + + 494 + + + + + 496 + + + + + + + + 497 + + + + + + + + + + + + + + + + + 498 + + + + + 499 + + + + + 500 + + + + + 501 + + + + + 502 + + + + + 503 + + + + + + + + 504 + + + + + 505 + + + + + 506 + + + + + 507 + + + + + 508 + + + + + + + + + + + + + + + + 509 + + + + + 510 + + + + + 511 + + + + + 512 + + + + + 513 + + + + + 514 + + + + + 515 + + + + + 516 + + + + + 517 + + + + + 534 + + + + + 544 + + + + + 371 + + + + + + + + 372 + + + + + + + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + {{380, 496}, {480, 360}} + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.WebKitIBPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + + + + + 559 + + + + + AppDelegate + NSObject + + window + NSWindow + + + window + + window + NSWindow + + + + IBProjectSource + ./Classes/AppDelegate.h + + + + + 0 + IBCocoaFramework + YES + 3 + + {11, 11} + {10, 3} + + YES + From 4859217465ebea744698eeaf1eb97a148f4121ea Mon Sep 17 00:00:00 2001 From: Miles Matthias Date: Fri, 13 Sep 2013 21:29:17 -0600 Subject: [PATCH 117/353] 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 118/353] 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 119/353] 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 120/353] 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 121/353] 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 122/353] 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 123/353] 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 124/353] 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 125/353] 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 126/353] 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 127/353] 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 128/353] 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 129/353] 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 130/353] 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 131/353] 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 132/353] 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 133/353] 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 134/353] 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 135/353] 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 136/353] 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 137/353] 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 138/353] 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 139/353] 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 140/353] 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 141/353] #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 142/353] 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 143/353] 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 144/353] 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 145/353] 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 146/353] 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 147/353] 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 148/353] 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 149/353] 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 150/353] 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 151/353] 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 152/353] 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 153/353] 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 154/353] 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 155/353] 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 156/353] 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 157/353] 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 158/353] 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 159/353] 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 160/353] 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 161/353] [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 162/353] [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 163/353] 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 164/353] 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 165/353] 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 166/353] 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 167/353] 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 168/353] 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 @@ +