Smart Communication Design Company
ホーム > ナレッジ > Blog > Apps Blog > 2016年5月 > WKWebViewを使ってNativeとWebページで情報をやり取りする方法

WKWebViewを使ってNativeとWebページで情報をやり取りする方法


インタラクションエンジニア 白石

iOS8から使えるようになったWKWebViewはUIWebViewよりもJavaScriptとの連携が強化されています。 WKWebViewを使うことでアプリ側独自のJavaScriptを既存Webページに読み込ませ、実行させるということが簡単にできるようになりました。 (ブラウザでユーザースクリプトを実行させるというようなことがNativeでもできる) WKWebViewを使ったユーザースクリプト実行方法のサンプルを紹介します。

ATS(App Transport Security)を無効にするInfo.plistの設定

iOS9からhttpでリクエストを送るとhttpsに置き換わってしまいます。 テストをするためにinfo.plistに下記を追加してhttpsに置き換わるのを無効にします。

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>

Swiftコード

WKWebViewを使うために「WebKit Framework」インポートします。 Swift上でJavaScriptコードを文字列として記述するのは大変なので別ファイルで用意(test.js)しました。 ユーザースクリプト(WKUserScript)を作成する際のinjectionTimeでJavaScriptの注入タイミングを指定できます。 JavaScriptで実行した結果を受け取りたい場合はWKUserContentControllerのaddScriptMessageHandlerで設定します。 WKWebViewのデリゲートWKScriptMessageHandlerのuserContentControllerメソッドを追加します。 このuserContentControllerメソッドでJavaScriptからのメッセージが受け取れます。 下記のコードでは受け取ったメッセージをコンソールに出しています。

import UIKit
import WebKit

class ViewController: UIViewController, WKNavigationDelegate, WKScriptMessageHandler {

    var webView : WKWebView?

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        var jsSource = ""
        // JavaScriptコードはtest.jsという名前で別ファイルに用意します
        let path = NSBundle.mainBundle().pathForResource("test", ofType: "js")!
        if let data = NSData(contentsOfFile: path){
            jsSource = String(NSString(data: data, encoding: NSUTF8StringEncoding)!)
        }
        // WKUserScriptを作成、injectionTimeにJavaScriptを実行するタイミングを指定します
        let userScript1 = WKUserScript(source: jsSource, injectionTime: WKUserScriptInjectionTime.AtDocumentEnd, forMainFrameOnly: true)

        // JavaScript側の実行結果などを受け取りたい場合はコールバックを設定します
        let controller = WKUserContentController()
        controller.addUserScript(userScript1)
        controller.addScriptMessageHandler(self, name: "callbackHandler")

        let configuration = WKWebViewConfiguration()
        configuration.userContentController = controller

        self.webView = WKWebView(frame: view.bounds, configuration: configuration)

        self.view = self.webView
        let urlString = "https://www.mitsue.co.jp/"
        let encodedUrlString = urlString.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())
        let url = NSURL(string: encodedUrlString!)
        let request = NSURLRequest(URL: url!)
        self.webView!.loadRequest(request)
    }

    func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) {
        // addScriptMessageHandlerで指定したコールバック名を判断して処理を分岐させることができます
        if(message.name == "callbackHandler") {
            print(message.body)
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

JavaScriptコード

jQueryを使っていないサイトの場合に備えてjQueryを読み込ませる処理を行っています。 このスクリプトでは「www.mitsue.co.jp」内のお知らせとキャンペーン情報を取得し、Native側に送っています。 JavaScriptで「webkit.messageHandlers.Native側で設定したコールバック名.postMessage("Native側に送りたい情報");」とするだけでNative側にメッセージを送ることができます。

(function (callback) {
    // jQueryを使っていないサイトの場合用にjQueryを読み込みます
    var script = document.createElement("script");
    script.setAttribute("src", "//code.jquery.com/jquery-2.0.0.min.js");
    script.addEventListener('load', function() {
        var script = document.createElement("script");
        script.textContent = "(" + callback.toString() + ")(jQuery.noConflict(true));";
        document.body.appendChild(script);
    }, false);
    document.body.appendChild(script);
})(function ($) {
    $('div.news').each(function() {
        // www.mitsue.co.jp内のお知らせとキャンペーンの情報を取得してNative側に送ります
        // webkit.messageHandlers.Native側で設定したコールバック名.postMessage("Native側に送りたい情報");
        webkit.messageHandlers.callbackHandler.postMessage($(this).find('a').html());
    });
});

実行結果

eachの中で連続して送ってもNative側では正常に受け取ることができます。

WKWebView上のJavaScriptから送信したデータをNative側で読み取るコードを実行した画面

この技術を使うことで既存Webページ上の必要な情報のみをNative側に取り込み、アプリ独自の見せ方をさせるというようなことができるようになります。