令和元年のご時世でもWebViewでラッピングしたアプリを作りたいという要望は多くSwiftUIでWebViewを使う方法について調べたのでメモ
ソースコードはGithubにも上げてあります
開発環境
- MacOS: 10.14.6
- Xcode: 11.1
実装
WKWebViewのセットアップ
WKWebViewがないので、UIViewRepresentable を利用してWKWebViewを表示するViewを用意する
import SwiftUI
import WebKit
struct WebView: UIViewRepresentable {
var loadUrl:String
func makeUIView(context: Context) -> WKWebView {
return WKWebView()
}
func updateUIView(_ uiView: WKWebView, context: Context) {
uiView.load(URLRequest(url: URL(string: loadUrl)!))
}
}
このWebViewを使えばWebサイトの表示ができる。
import SwiftUI
struct ContentView: View {
var body: some View {
WebView(loadUrl: "https://www.apple.com")
}
}
画面遷移を検知する
単純にさっきのWebViewにDelegate追加してstruct WebView: UIViewRepresentable, WKWebViewDelegateみたいにできればいいけど、Classではなく、structなのでエラーが出てしまいdelegateをそのまま実装できない。
今回はObserverを使ってURLの変化を検知して対応した。さっきのWebViewにObservableObjectを追加する感じ。
class observable: ObservableObject {
@Published var observation:NSKeyValueObservation?
}
struct WebView: UIViewRepresentable {
var loadUrl:String
@ObservedObject var observe = observable()
func makeUIView(context: Context) -> WKWebView {
return WKWebView()
}
func updateUIView(_ uiView: WKWebView, context: Context) {
observe.observation = uiView.observe(\WKWebView.url, options: .new) { view, change in
if let url = uiView.url {
print("Page loaded: \(url)")
}
}
uiView.load(URLRequest(url: URL(string: loadUrl)!))
}
}
ここではWKWebViewのurlを比べているけど、titleや他のプロパティでも可能なので、ロード中かどうか知りたければisLoadingをobserveするようにすれば大丈夫。