zoukankan      html  css  js  c++  java
  • Using JavaScript with WKWebView in iOS 8

    With iOS 8 Apple has added a ton of user-facing goodness. The Health app, Apple Pay, and expanded TouchID capabilities — just a few things everyday users will be happy about. On the sdk side they’ve added a lot of cool things as well, but one I’m excited about is the addition of WKWebView. This is very similar to the related–but less powerful–UIWebView available since iOS 2. UIWebView offers simple methods for loading a remote url, navigating forwards and back, and even running basic JavaScript. In contrast WKWebView offers a full-blown configuration (via WKWebViewConfiguration), navigation (via WKNavigationDelegate), estimated loading progress, and evaluating JavaScript.

    In this example I’m using two components, evaluateJavaScript on the web view and addScriptMessageHandler on the controller to demonstrate passing information between the JavaScript runtime and the native application. This bidirectional communication enables all sorts of interesting hybrid application possibilities.

    Overview

    High-level Communications

    At a high level passing information from native code to the JavaScript runtime is done by calling the evaluateJavaScript method on a WKWebView object. You can pass a block to capture errors but I’m not exploring that here. Passing information from JavaScript land to the iOS application uses the overly verbose Objective-C-style window.webkit.messageHandlers.NAME.postMessage function where NAME is whatever you call the script handler.

    Creating Objects

    Code Diagram

    There are three main objects that need to be setup for this to work.

    • WKWebView instance (called webView)
    • WKWebViewConfiguration instance (called configuration)
    • WKUserContentController instance (called controller)

    The constructor for WKWebView takes a configuration parameter. This allows an instance of WKWebViewConfiguration to be passed and additional settings configured. The important property is userContentController, an instance of WKUserContentController. This controller has a method called addScriptMessageHandler which is how messages from JavaScript land are sent to the native application. This is a big chunk of boilerplate that needs to get setup before the WKWebView can be loaded. Thankfully it’s not all bad.

    Oh right, the ViewController needs to match the protocol defined by WKScriptMessageHandler. This means implementing the userContentController delegate method. Onwards to the code examples.

    Implementation

    Start by importing WebKit and declaring that ViewControllerimplements the WKScriptMessageHandler protocol. This is done in the header file (ViewController.h).

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

    Moving to ViewController.m, start with the url constant and @interface declaration. I’ve setup a JSBin which helps with the example.

    #define k_JSBIN_URL @"http://jsbin.com/meniw"
    
    @interface ViewController ()
    @property (strong, nonatomic) WKWebView *webView;
    
    @end
    

    The guts of the next part relate to the overly-verbose object instantiations described above.

    Creating a WKWebViewConfiguration object so a controller can be added to it.

        WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc]
                                                 init];
    

    Creating the WKUserContentController.

    WKUserContentController *controller = [[WKUserContentController alloc]
                                           init];
    

    Adding a script handler to the controller and setting the userContentController property on the configuration.

    [controller addScriptMessageHandler:self name:@"observe"];
    configuration.userContentController = controller;
    

    Create an NSURL object and instantiate the WebView.

    NSURL *jsbin = [NSURL URLWithString:k_JSBIN_URL];
    
    _webView = [[WKWebView alloc] initWithFrame:self.view.frame
                                  configuration:configuration];
    

    Load up webView with the url and add it to the view.

    [_webView loadRequest:[NSURLRequest requestWithURL:jsbin]];
    [self.view addSubview:_webView];
    

    The last piece is setting up the didReceiveScriptMessage method with some handling logic for processing received messages. Here I demonstrate dynamically pulling information from the device using the message passed from JavaScript-land.

    - (void)userContentController:(WKUserContentController *)userContentController
          didReceiveScriptMessage:(WKScriptMessage *)message {
    
        // Log out the message received
        NSLog(@"Received event %@", message.body);
    
        // Then pull something from the device using the message body
        NSString *version = [[UIDevice currentDevice] valueForKey:message.body];
    
        // Execute some JavaScript using the result
        NSString *exec_template = @"set_headline("received: %@");";
        NSString *exec = [NSString stringWithFormat:exec_template, version];
        [_webView evaluateJavaScript:exec completionHandler:nil];
    }
    

    Of course, none of this would work well without some JavaScript running on the other end.

    Start by setting up a bare-bones html page.

    <h2 id="headline">loading...</h2>
    <select id="selector">
        <option value="systemVersion" selected>iOS Version</option>
        <option value="systemName">System Name</option>
        <option value="name">Device Name</option>
        <option value="model">Device Model</option>
        <option value="userInterfaceIdiom">User Interface</option>
        <option value="identifierForVendor">Vendor ID</option>
    </select>
    

    Then sprinkle in some JavaScript with functions to send a message to the native side and handle a receiving call.

    var headline = $("#headline");
    var selection = $("#selector");
    
    function set_headline (text) {
        headline.text(text);
    }
    
    function call_native () {
        var prop = selection.val();
        set_headline("asked for " + prop + "...");
        window.webkit.messageHandlers.observe.postMessage(prop);
    }
    
    setTimeout(call_native, 1000);
    
    selection.on("change", call_native);
    

    Here’s a quick demo video of everything working.

    Full source for both the iOS application and html components is on GitHub under joshkehn/JSMessageExample.


    Future Applications

    With these new APIs available in iOS 8 it will be interesting to see the direction existing projects — like Cordova and Appcelerator Titanium — take and what new frameworks and tooling is built to better support these hybrid applications. Is Apple now encouraging this kind of hybrid application? I’m sure they are. Fully native applications offered speed and performance in the early days of mobile, but with new optimizations to JavaScript engines and better css/html features that gap is rapidly closing. I’m excited to see what comes next.

    http://www.joshuakehn.com/2014/10/29/using-javascript-with-wkwebview-in-ios-8.html

  • 相关阅读:
    hdu2049
    hdu2047
    hdu2568
    hdu2570
    推流摄像头推RTMP视频流至EasyDSS视频直播点播平台Chrome浏览器无法播放如何解决?
    RTMP推流协议视频智能分析/人脸识别/直播点播平台EasyDSS接口调用注意事项介绍
    【解决方案】人脸识别/智能分析视频安防服务平台EasyCVR如何打造智慧人社局培训办事机构远程监控系统?
    【解决方案】RTMP推流协议视频智能分析/直播点播/人脸识别平台EasyDSS打造智能多媒体展厅解决方案
    【解决方案】视频智能分析/人脸识别平台EasyDSS实现景区智慧旅游体系,VR+大数据打造风景区实时视频
    RTMP推流协议视频智能分析平台EasyDSS直播点播系统新版本无法完成推流以及录像回看排查过程
  • 原文地址:https://www.cnblogs.com/feng9exe/p/13289035.html
Copyright © 2011-2022 走看看