WebViewを使ったアプリを作成しているが、OSや端末等でJavascriptの設定をする必要がある
例えば別タブ、別ウィンドウで開く場合はWebView側で設定が必要
以下にOSごとの対応方法を記述しておく
Android Kotlin & Jetpack Compose
import android.view.ViewGroup
import android.webkit.WebView
import androidx.compose.runtime.Composable
import androidx.compose.ui.viewinterop.AndroidView
// WebView.settingsを設定する
AndroidView(
factory = { context ->
WebView(context).apply {
// WebViewの高さを指定 これを設定しないとCSSのvhが効かなくなる
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
settings.apply {
// JavaScript有効化
settings.javaScriptEnabled = true
// loadWithOverviewMode, useWideViewPortをtrueにすると別ウィンドウの画面がWebViewの幅に合わせて表示される
loadWithOverviewMode = true // trueの場合にはHTMLのwidthがWebViewより大きい時に全体を表示するようによしなに調整される
useWideViewPort = true // ダブルタップによるズームイン・ズームアウトの有効化
}
}
}
)
iOS Swift & SwiftUI
import SwiftUI
import WebKit
struct CustomWebView: UIViewRepresentable {
func makeUIView(context: Context) -> WKWebView {
let webView = WKWebView()
// jsのアラート、確認ダイアログなどのUI処理、新しいページ(target="_blank"など)を開く必要があるときの制御
webView.uiDelegate = context.coordinator
// JavaScript有効化
webView.configuration.defaultWebpagePreferences.allowsContentJavaScript = true
return webView
}
func updateUIView(_ uiView: WKWebView, context: Context) {}
func makeCoordinator() -> Coordinator {
Coordinator(parent: self)
}
}
extension CustomWebView {
// AndroidでいうWebViewClient
class Coordinator: NSObject, WKUIDelegate {
private let parent: CustomWebView
init(parent: CustomWebView) {
// parentを設定しておくとCoodinatorから参照できて引数の肥大化を防げる、かも
self.parent = parent
}
// JavaScriptのwindow.openをハンドリング 新しいウィンドウを作らずに今のWebViewで読み込む
func webView(_ webView: WKWebView,
createWebViewWith configuration: WKWebViewConfiguration,
for navigationAction: WKNavigationAction,
windowFeatures: WKWindowFeatures) -> WKWebView? {
// 別タブだったら現在のwebViewで表示する実装例
if navigationAction.targetFrame?.isMainFrame != true {
webView.load(navigationAction.request)
}
return nil
}
// JavaScriptのalertイベントをハンドリング
func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
let alert = UIAlertController(title: "Hey, Listen!", message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default))
let controller = getRootController()
controller?.present(alert, animated: true)
completionHandler()
}
// JavaScriptのconfirmイベントをハンドリング
func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert)
alert.addAction(.init(title: "OK", style: .default, handler: { _ in
completionHandler(true)
}))
alert.addAction(.init(title: "キャンセル", style: .cancel, handler: { _ in
completionHandler(false)
}))
let controller = getRootController()
controller?.present(alert, animated: true)
}
// JavaScriptのpromptイベントをハンドリング
func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) {
let alert = UIAlertController(title: nil, message: prompt, preferredStyle: .alert)
alert.addTextField { textField in
textField.text = defaultText
}
alert.addAction(.init(title: "OK", style: .default, handler: { _ in
completionHandler(alert.textFields?.first?.text)
}))
alert.addAction(.init(title: "キャンセル", style: .cancel, handler: { _ in
completionHandler(nil)
}))
let controller = getRootController()
controller?.present(alert, animated: true)
}
// アクティブな画面のControllerを取得
private func getRootController() -> UIViewController? {
let window = UIApplication.shared.connectedScenes
.filter { $0.activationState == .foregroundActive }
.compactMap { $0 as? UIWindowScene }
.first?.windows.filter { $0.isKeyWindow }.first as UIWindow?
guard let rootController = window?.rootViewController else {
return nil
}
return rootController
}
}
}
swiftのgetRootControllerの内容はリンクの記事を参考にさせていただきました

「The Ultimate Guide to WKWebView」をSwiftUIで実装する #13 - Showing custom UI - - Qiita
「The Ultimate Guide to WKWebView」をSwiftUIで実装してみるの、 13個目になります。12個目を投稿以降、しばらくサボっていてごめんなさい。 今回はWebViewで新しいウィンドウを開く方法についてです。...

コメント