Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
60
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

Organization

iOS WKWebView ネイティブとローカルJavascript連携

はじめに

ネイティブとローカルのJavascript間で値の受け渡しがやりたかったので調査しました
基本ローカルではなくサーバ側にJavascriptがある場合でも同じコードで動くはずです
Swift4, iOS9以降で動作確認しています

HTMLファイル構成

以下のようにしました。
注意として、ファイル構成はこれでなければいけないということはではありません
ディレクトリ名などわかりやすい名前をつけていただければと思います

WebPage
  |-css
  |  -style.css
  |-javascript
  |  -js.js
   -index.html

画像だと以下の感じとなります
スクリーンショット 2017-12-16 16.09.13.png

HTMLのソース

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width">
        <link rel="stylesheet" type="text/css" href="style.css">
        <title>ページタイトル</title>
    </head>
    <body>
        <h1 id="title">タイトル</h1>

        <script type="text/javascript" src="js.js"></script>
    </body>
</html>

cssやjavascriptの読み込みが./css/〜./javascript/〜となっておらず、同階層として扱っている点に注意してください
調べていないので間違っているかもですが、ネイティブでHTMLを読み込む際、実際のディレクトリ階層とは異なり、同階層として読み込まれているためなのかなと思っています
スクリーンショット 2017-12-16 17.35.48.png

WKWebViewを使う準備

WKWebViewを使うにはWebKitをimportする必要があります

import WebKit

ローカルファイル読み込み

// index.htmlのパスを取得する
let path: String = Bundle.main.path(forResource: "index", ofType: "html")!
let localHtmlUrl: URL = URL(fileURLWithPath: path, isDirectory: false)
// ローカルのHTMLページを読み込む
webView.loadFileURL(localHtmlUrl, allowingReadAccessTo: localHtmlUrl)

Javascript → ネイティブ

宣言にWKScriptMessageHandlerを追加

class ViewController: UIViewController, WKScriptMessageHandler {

WKScriptMessageHandlerプロトコルのメソッドを実装

以下のuserContentControllerメソッドでJavascriptから値を受け取れます

func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {

}

WKUserContentControllerを設定

let webCfg: WKWebViewConfiguration = WKWebViewConfiguration()
let userController: WKUserContentController = WKUserContentController()
userController.add(self, name: "callbackHandler")
webCfg.userContentController = userController

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

ポイントはuserController.add(self, name: "callbackHandler")部分で、
ここで設定した"callbackHandler"がJavascriptから呼ばれると
WKScriptMessageHandler プロトコルのuserControllerメソッドが実行されます

userContentControllerの中身を実装

func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
    if(message.name == "callbackHandler") {
        print("\(message.body)")
    }
}

message.bodyにJavascriptから渡ってくる値が格納されています

Javascript側のコード

webkit.messageHandlers.<定義した文字列>.postMessage()
でネイティブ側に値を渡せます。今回は定義した文字列が"callbackHandler"なので以下のようになります

webkit.messageHandlers.callbackHandler.postMessage("Message from Javascript");

ネイティブ → Javascript

WKWebViewのevaluateJavaScriptメソッドを使います

宣言にWKNavigationDelegateを追加

class ViewController: UIViewController, WKNavigationDelegate {

処理の委譲先を指定

webView.navigationDelegate = self

WKNavigationDelegateの didFinish メソッドを実装

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    // Javascriptに渡す値
    let param: String = "jsCallTest"
    // Javascript側で実行する関数
    let execJsFunc: String = "test(\"\(param)\");"
    webView.evaluateJavaScript(execJsFunc, completionHandler: { (object, error) -> Void in
        // jsの関数実行結果
        // js側で戻り値を返すこともできる
    })
}

didFinishで行なっている理由は、HTMLのロードが終わってからでないとJavascriptのコードを実行できないためです
HTMLロード前に実行すると、Javascriptのメソッドが見つからず、evaluateJavaScriptのcompletionHandlerでerrorが返ってきます

Javascript側のコード

function test(val) {
    // テスト用に id タイトルを変更
    var h1 = document.getElementById("title");
    h1.textContent = val;
}

以上でローカルのJavascriptと双方向で値の受け渡しができるようになりました

最後に

今回のコードはこちらにおいています

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
60
Help us understand the problem. What are the problem?