From f39324d731045a664c90e20926e484b0397e9bbc Mon Sep 17 00:00:00 2001 From: lokimeyburg Date: Tue, 14 Oct 2014 13:51:10 -0700 Subject: [PATCH 01/22] 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 02/22] 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 @@ +