SwiftUIでWebViewを使う（WKWebViewのObservableObject化）

[SwiftUIでWebViewを使う](https://qiita.com/wiii_na/items/36123cf901839a8038e2)を参考にした。

```swift
import SwiftUI
import WebKit

public class SUIWebBrowserObject: WKWebView, WKNavigationDelegate, ObservableObject {
    private var observers: [NSKeyValueObservation?] = []
    
    private func subscriber<Value>(for keyPath: KeyPath<SUIWebBrowserObject, Value>) -> NSKeyValueObservation {
        observe(keyPath, options: [.prior]) { object, change in
            if change.isPrior {
                self.objectWillChange.send()
            }
        }
    }
    
    private func setupObservers() {
        observers = [
            subscriber(for: \.title),
            subscriber(for: \.url),
            subscriber(for: \.isLoading),
            subscriber(for: \.estimatedProgress),
            subscriber(for: \.hasOnlySecureContent),
            subscriber(for: \.serverTrust),
            subscriber(for: \.canGoBack),
            subscriber(for: \.canGoForward)
        ]
    }
    
    public override init(frame: CGRect = .zero, configuration: WKWebViewConfiguration = WKWebViewConfiguration()) {
        super.init(frame: frame, configuration: configuration)
        navigationDelegate = self
        setupObservers()
    }
    
    public required init?(coder: NSCoder) {
        super.init(coder: coder)
        navigationDelegate = self
        setupObservers()
    }
}

public struct SUIWebBrowserView: UIViewRepresentable {
    public typealias UIViewType = UIView
    
    private var browserObject: SUIWebBrowserObject
    
    public init(browserObject: SUIWebBrowserObject) {
        self.browserObject = browserObject
    }
    
    public func makeUIView(context: Self.Context) -> Self.UIViewType {
        browserObject
    }
    
    public func updateUIView(_ uiView: Self.UIViewType, context: Self.Context) {
        //
    }
}

struct WebBrowser: View {
    @ObservedObject var browser = SUIWebBrowserObject()
    
    init(address: String) {
        guard let a = address.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else { return }
        guard let u = URL(string: a) else { return }
        browser.load(URLRequest(url: u))
    }
    
    func ItemImage(systemName: String) -> some View {
        Image(systemName: systemName)
            .imageScale(.large).aspectRatio(contentMode: .fit)
            .frame(width: 32, height: 32)
    }
    
    var Title: Text {
        Text(verbatim: browser.url?.absoluteString.removingPercentEncoding ?? "")
    }
    
    var LItems: some View {
        HStack {
            Button(action: {
                self.browser.goBack()
            }) {
                ItemImage(systemName: "chevron.left")
            }.disabled(!browser.canGoBack)
        }
    }
    
    var TItems: some View {
        HStack {
            Button(action: {
                if self.browser.isLoading {
                    self.browser.stopLoading()
                } else {
                    self.browser.reload()
                }
            }) {
                ItemImage(systemName: browser.isLoading
                    ? "xmark" 
                    : "arrow.clockwise"
                )
            }
        }
    }
    
    var body: some View {
        NavigationView {
            SUIWebBrowserView(browserObject: browser)
                .navigationBarTitle(Title, displayMode: .inline)
                .navigationBarItems(leading: LItems, trailing: TItems)
        }.navigationViewStyle(StackNavigationViewStyle())
    }
}

struct ContentView: View {
    var body: some View {
        WebBrowser(address: "https://www.apple.com/jp/")
    }
}
```

![75049C07-A975-4E53-9230-7B6EFD503215.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91569/cf2571e1-a46f-da90-13e2-250cb2bfa81c.jpeg)

WKWebViewをObservableObject化した`SUIWebBrowserObject`と、そのビューワーとなる`SUIWebBrowserView`を使って自由なUIのカスタムウェブブラウザを簡単に作れるようになった。