はじめに
ネイティブとローカルのJavascript間で値の受け渡しがやりたかったので調査しました
基本ローカルではなくサーバ側にJavascriptがある場合でも同じコードで動くはずです
Swift4, iOS9以降で動作確認しています
HTMLファイル構成
以下のようにしました。
注意として、ファイル構成はこれでなければいけないということはではありません
ディレクトリ名などわかりやすい名前をつけていただければと思います
WebPage
|-css
| -style.css
|-javascript
| -js.js
-index.html
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を読み込む際、実際のディレクトリ階層とは異なり、同階層として読み込まれているためなのかなと思っています
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と双方向で値の受け渡しができるようになりました
最後に
今回のコードはこちらにおいています