【swift】WKWebViewでWebViewからネイティブへデータを受け取る方法
WRITER
ロッキーカナイ
SwiftやObjective-CでiOS開発や、Flutterを用いたiOS/Androidアプリ開発、PHPでLaravelを使ったWebアプリ開発などをしてます。趣味は猫と戯れる事、キックボクシングにハマってます。ちなみに名前のロッキーカナイは以前よく昼飯を食べてた所。
どうもこんにちは。iOSをメインに開発しているロッキーカナイです。
WebViewを使ったアプリを開発していると、WebView側からデータを受け取りたい場面が出てきます。
今回行うのはWeb上のボタンをクリックしたら、ネイティブでデータを受け取る方法を紹介したいと思います。
環境について
Xcode 9.3
Mac 10.13.4
ローカル環境 MAMP 4.1.1
実装の紹介
はじめに
WebViewで表示させるサイトが必要になるので、MAMPを使ったローカル環境を使用しhtmlへアクセスし表示させます。
サーバ上にhtmlファイルを配置できる方は無視しちゃってね。
Xcodeでの作業
適当にプロジェクトを新規作成しましょう。
次に今回ローカル環境へのアクセスをするのでInfo.plistにApp Transport Security Settings / Allow Arbitrary Loads = YESの設定を追加します。

httpでリクエストを送るとiOS9よりhttpsに置き換わる仕様の為、httpでもリクエストを行えるように設定しました。
次にViewController側のコーディングです。
import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate, WKScriptMessageHandler {
    var webView: WKWebView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // javascriptを呼び出しを可能にするWKUserContentControllerクラスの生成
        let userController = WKUserContentController()
        userController.add(self, name: "callbackHandler")
        
        // WKWebViewの設定を行う為のWKWebViewConfigurationクラスの生成
        let webConfiguration = WKWebViewConfiguration()
        webConfiguration.userContentController = userController
        
        // WKWebView生成
        webView = WKWebView(frame: CGRect(x: 0,
                                          y: 0,
                                      width: self.view.frame.size.width,
                                     height: self.view.frame.size.height),
                    configuration: webConfiguration)
        webView.navigationDelegate = self
        webView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(webView)
        
        // 表示するアドレス設定
        let request = URLRequest(url: URL(string: "http://localhost:8888")!)
        self.webView.load(request)
    }
    // WKScriptMessageHandlerプロトコル
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        if(message.name == "callbackHandler") {
            print(message.body)
        }
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}WebKitのインポートを忘れずに!
viewDidLoadメソッド内で、WKWebViewの生成と設定を行っており、ローカル環境のhttp://localhost:8888を表示します。(サーバ上にhtmlファイルを配置する方は、該当アドレスに変更してください)
Webの作業
次にhtml側のコーディングです。
<html>
  <head>
    <meta charset="utf-8">
    <title>テスト</title>
  </head>
  <body>
    <script>
      function OnButtonClick() {
          window.webkit.messageHandlers.callbackHandler.postMessage("webViewから呼び出し");
      }
    </script>
    <input type="button" value="Webからネイティブにメッセージ送信" onclick="OnButtonClick();" style="width:80%;height:100px;margin:10%;font-size:36px;">
  </body>
</html>webViewにボタンを用意しクリックするとOnButtonClickがコールされwindow.webkit.messageHandlers.callbackHandler.
postMessage(“webViewから呼び出し”);が実行されます。
これをネイティブのfunc userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage)で受け取ります。
実装確認
XcodeをRunすると、シュミレータで以下のように表示されます。

このボタンをクリックすると。

ログが出力されました。
問題なくWebView側からデータを受け取る事が出来ました!!
最後に
現在行っている開発業務で、WebViewからデータを受け取る実装が必要になりましたので、調べた結果を今回まとめてみました。
今回は文字データの取得ですが、実際にはJSONデータなどを使われると思いますので、次回もしかしたら、JSONデータを取得する方法をご紹介するかもしれません。しないかもしれません。
ではでは、よいSwiftライフをお楽しみください〜