WKWebViewのJavaScriptとNativeの連携(使用例付き)
⭐️WKUserScript
概要
- 任意のJSからWKUserScriptを作成して、WebViewのインスタンス生成前にScript挿入処理を行うことでJSの処理をWebViewに反映できる
使用例
- 下記コードでは以下2つのJSをexcutableJSScript()で作成して実行しています
- WebView内ページでメニューボタンを非表示にする
- WebViewで拡大・縮小しないようにする
override func viewDidLoad() {
super.viewDidLoad()
let controller = WKUserContentController()
// controllerにWKUserScriptを追加
controller.addUserScript(excutableJSScript())
// WKWebView インスタンス生成時に適用
let configuration = WKWebViewConfiguration()
configuration.userContentController = controller
webView = WKWebView(frame: view.frame, configuration: configuration)
view.addSubview(webView)
}
// 任意の WKUserScriptを作成
private func excutableJSScript() -> WKUserScript {
// メニューアイコン非表示処理のscript
let disableWebMenuIconScript = "WebView内ページのメニューアイコンを非表示にするJS"
// 拡大・縮小無効処理のscript
let disableWebViewScalingScript = "拡大・縮小無効にするJS"
// 2つのScriptを足して1つのScriptにする
let excutableJSScript = WKUserScript(source: disableWebMenuIconScript + disableWebViewScalingScript, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
return excutableJSScript
}
⭐️evaluateJavaScript()
概要
- すでにインスタンス生成したWebViewに対してJSを反映する
使用例
- ネイティブで取得した値をWeb側にJSで渡してあげる
- WebView内の要素を取得してアプリに表示させる
下記コードではユーザIDを取得するJSを使用して、クロージャで取得したIDを処理しています
_viewController?.webView.evaluateJavaScript("document.querySelector('#user_id').innerText", completionHandler: { userID, error in
if let userID = userID as? String {
Repro.set(userID: userID) // Repro(Push配信サービス)にIDを送る処理
}
if let error {
print(error)
}
})
注意点・備考
- インスタンスがあって、WebView内の要素を取得したいときはWebViewの読み込みが完了してからじゃないとできない(以前、読み込み前に呼び出して何も取得できなくて、困った時がありました…)
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
print("読み込み完了")
}
- クロージャを引数にとっているので、処理完了後に別の処理を呼び出すことも可能
func evaluateJavaScript(_ javaScriptString: String, completionHandler: ((Any?, Error?) -> Void)? = nil)
⭐️decidePolicyFor
概要
- リンク先が特定外のときはブラウザで開いたりする時に使用
- WKNavigationDelegateで定義されているメソッド
使用例
- 下記コードでは
shouldAllowURL()
でURLがWebViewで開くべきURLだったらtrue
、ブラウザで開くべきであればfalse
を返して、判断しています。
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
if let url = navigationAction.request.url {
if !URLAllowList.shared.shouldAllowURL(url) { // リンク先が特定外のときはブラウザで開く
UIApplication.shared.open(url)
decisionHandler(.cancel)
return
}
}
decisionHandler(.allow)
}
⭐️runJavaScriptAlertPanelWithMessage
概要
- Web側で仕込まれたJSのアラートパネルをWebViewにも表示、ボタンアクションを実行できる
- WKUIDelegateで定義
使用例
func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
// 受け取ったメッセージでアラートを作成
let alert = UIAlertController(title: nil,
message: message,
preferredStyle: .alert)
let action = UIAlertAction(title: "OK", style: .default) { _ in
// OKボタン押下時の処理
completionHandler()
}
alert.addAction(action)
present(alert, animated: true, completion: nil)
}
⭐️runJavaScriptConfirmPanelWithMessage
概要
- Web側で仕込まれたJSのコンファームパネルを表示、ボタンアクションを実行できる
- WKUIDelegateで定義
使用例
func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
// 受け取ったメッセージでアラートを作成
let alert = UIAlertController(title: nil,
message: message,
preferredStyle: .alert)
// キャンセルアクション
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { _ in
completionHandler(false)
}
// OKアクション
let okAction = UIAlertAction(title: "OK", style: .default) { _ in
completionHandler(true)
}
alert.addAction(cancelAction)
alert.addAction(okAction)
present(alert, animated: true, completion: nil)
}