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

  • 相关阅读:
    windows环境python2.7安装MySQLdb
    查找文件中除了注释以外的中文
    python2的reload模块
    虚拟机网络连接NAT模式,本地用Xshell连接
    PHP中逻辑运算符的高效用法---&&和||
    mysql 的 alter table 操作性能小提示
    MySQL优化指南
    UTF-8的BOM含义
    MySQL中 指定字段排序函数field()的用法
    MySQL PROFILE 跟踪语句各阶段性能开销
  • 原文地址:https://www.cnblogs.com/feng9exe/p/13289035.html
Copyright © 2011-2022 走看看