Search code examples
iosobjective-cuiwebviewwkwebview

UIWebView delegate method shouldStartLoadWithRequest: equivalent in WKWebView?


I have a module inside my iOS 7+ app which is a UIWebView. The html page loads a javascript that creates custom-shaped buttons (using the Raphaeljs library). With UIWebView, I set delegate to self. The delegate method webView: shouldStartLoadWithRequest: navigationType: is called each time one of my custom button is pressed. The requests should not be handled by the html, but rather by the iOS code. So I used a request convention (read somewhere here on stackoverflow) using "inapp" as the scheme of my requests. I then check for the host and take the appropriate action.

This code works fine on iOS 7. But the web views appear blank on iOS 8 (bug?), so I decided to use WKWebView for iOS 8 devices. The web views now render fine (and amazingly faster!), but my buttons have no effect.

I tried using - (WKNaviation *)loadRequest:(NSURLRequest *)request, but it's not called.

I can't find a direct equivalent of the UIWebView delegate method webView: shouldStartLoadWithRequest: navigationType:. What's the best way of handling those requests with WKWebView?


Solution

  • Re-reading your description it looks like what you actually need to know about is how to reimplement a Javascript/Objective-C bridge using WKWebView.

    I've just done this myself, following the tutorial at http://tetontech.wordpress.com/2014/07/17/objective-c-wkwebview-to-javascript-and-back/ and the info at http://nshipster.com/wkwebkit/

    WKWebView has a built-in way of communicating between Javascript and Objective-C/Swift: WKScriptMessageHandler.

    First, include the WebKit headers and WKScriptMessageHandler protocol in your view controller's header:

    #import <UIKit/UIKit.h>
    #import <WebKit/WebKit.h>
    @interface ViewController : UIViewController <WKScriptMessageHandler>
    
    @end
    

    The when initialising your WKWebView, you need to configure it with a script message handler. Name it whatever you want, but to me it seems like naming it for your app makes sense.

        WKWebViewConfiguration *theConfiguration = 
              [[WKWebViewConfiguration alloc] init];
        [theConfiguration.userContentController 
              addScriptMessageHandler:self name:@"myApp"];
    
        _theWebView = [[WKWebView alloc] initWithFrame:self.view.frame 
                          configuration:theConfiguration];
        [_theWebView loadRequest:request];
        [self.view addSubview:_theWebView];
    

    Now, implement userContentController:didReceiveScriptMessage:. This fires when your webview receives a message, so it does the work you were previously doing with webView:shouldStartLoadWithRequest:navigationType:.

    - (void)userContentController:(WKUserContentController *)userContentController 
                            didReceiveScriptMessage:(WKScriptMessage *)message {
        NSDictionary *sentData = (NSDictionary *)message.body;
        NSString *messageString = sentData[@"message"];
        NSLog(@"Message received: %@", messageString);
    }
    

    You're now ready to receive messages from Javascript. The function call you need to add to your Javascript is this:

    window.webkit.messageHandlers.myApp.postMessage({"message":"Hello there"});