// // WKWebViewJavascriptBridge.m // // Created by @LokiMeyburg on 10/15/14. // Copyright (c) 2014 @LokiMeyburg. All rights reserved. // #import "WKWebViewJavascriptBridge.h" #if defined supportsWKWebView @implementation WKWebViewJavascriptBridge { __weak WKWebView* _webView; __weak id _webViewDelegate; long _uniqueId; WebViewJavascriptBridgeBase *_base; } /* API *****/ + (void)enableLogging { [WebViewJavascriptBridgeBase enableLogging]; } + (instancetype)bridgeForWebView:(WKWebView*)webView { WKWebViewJavascriptBridge* bridge = [[self alloc] init]; [bridge _setupInstance:webView]; [bridge reset]; return bridge; } - (void)send:(id)data { [self send:data responseCallback:nil]; } - (void)send:(id)data responseCallback:(WVJBResponseCallback)responseCallback { [_base 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 { [_base sendData:data responseCallback:responseCallback handlerName:handlerName]; } - (void)registerHandler:(NSString *)handlerName handler:(WVJBHandler)handler { _base.messageHandlers[handlerName] = [handler copy]; } - (void)removeHandler:(NSString *)handlerName { [_base.messageHandlers removeObjectForKey:handlerName]; } - (void)reset { [_base reset]; } - (void)setWebViewDelegate:(id)webViewDelegate { _webViewDelegate = webViewDelegate; } - (void)disableJavscriptAlertBoxSafetyTimeout { [_base disableJavscriptAlertBoxSafetyTimeout]; } /* Internals ***********/ - (void)dealloc { _base = nil; _webView = nil; _webViewDelegate = nil; _webView.navigationDelegate = nil; } /* WKWebView Specific Internals ******************************/ - (void) _setupInstance:(WKWebView*)webView { _webView = webView; _webView.navigationDelegate = self; _base = [[WebViewJavascriptBridgeBase alloc] init]; _base.delegate = self; } - (void)WKFlushMessageQueue { [_webView evaluateJavaScript:[_base webViewJavascriptFetchQueyCommand] completionHandler:^(NSString* result, NSError* error) { if (error != nil) { NSLog(@"WebViewJavascriptBridge: WARNING: Error when trying to fetch data from WKWebView: %@", error); } [_base flushMessageQueue:result]; }]; } - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation { if (webView != _webView) { return; } __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didFinishNavigation:)]) { [strongDelegate webView:webView didFinishNavigation:navigation]; } } - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler { if (webView != _webView) { return; } __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:decidePolicyForNavigationResponse:decisionHandler:)]) { [strongDelegate webView:webView decidePolicyForNavigationResponse:navigationResponse decisionHandler:decisionHandler]; } else { decisionHandler(WKNavigationResponsePolicyAllow); } } - (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler { if (webView != _webView) { return; } __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didReceiveAuthenticationChallenge:completionHandler:)]) { [strongDelegate webView:webView didReceiveAuthenticationChallenge:challenge completionHandler:completionHandler]; } else { completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); } } - (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 ([_base isWebViewJavascriptBridgeURL:url]) { if ([_base isBridgeLoadedURL:url]) { [_base injectJavascriptFile]; } else if ([_base isQueueMessageURL:url]) { [self WKFlushMessageQueue]; } else { [_base logUnkownMessage:url]; } decisionHandler(WKNavigationActionPolicyCancel); return; } if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:decidePolicyForNavigationAction:decisionHandler:)]) { [_webViewDelegate webView:webView decidePolicyForNavigationAction:navigationAction decisionHandler:decisionHandler]; } else { decisionHandler(WKNavigationActionPolicyAllow); } } - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation { if (webView != _webView) { return; } __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; } __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didFailNavigation:withError:)]) { [strongDelegate webView:webView didFailNavigation:navigation withError:error]; } } - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error { if (webView != _webView) { return; } __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didFailProvisionalNavigation:withError:)]) { [strongDelegate webView:webView didFailProvisionalNavigation:navigation withError:error]; } } - (NSString*) _evaluateJavascript:(NSString*)javascriptCommand { [_webView evaluateJavaScript:javascriptCommand completionHandler:nil]; return NULL; } @end #endif